From b59597ec25ee9eff229c31fcab8d4ed8ce2db8ad Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 9 Oct 2010 12:10:57 +0200 Subject: [PATCH] Fixed some issues with GetBaseTypes/GetAllBaseTypes. --- .../TypeSystem/GetAllBaseTypesTest.cs | 34 ++++++++++++---- .../TypeSystem/ExtensionMethods.cs | 10 ++--- .../Implementation/DefaultTypeDefinition.cs | 40 +++++++++++-------- 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs index 804f8ffcbd..1709c9f145 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/GetAllBaseTypesTest.cs @@ -70,7 +70,6 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.AreEqual(new [] { c }, c.GetAllBaseTypes(context).ToArray()); } - [Test] public void ClassDerivingFromTwoInstanciationsOfIEnumerable() { @@ -78,14 +77,33 @@ namespace ICSharpCode.NRefactory.TypeSystem DefaultTypeDefinition c = new DefaultTypeDefinition(mscorlib, string.Empty, "C"); c.BaseTypes.Add(typeof(IEnumerable).ToTypeReference()); c.BaseTypes.Add(typeof(IEnumerable).ToTypeReference()); - Assert.AreEqual(new [] { - c, - c.BaseTypes[0].Resolve(context), - c.BaseTypes[1].Resolve(context), - mscorlib.GetClass(typeof(IEnumerable)), - mscorlib.GetClass(typeof(object)) - }, + IType[] expected = { + c, + c.BaseTypes[0].Resolve(context), + c.BaseTypes[1].Resolve(context), + mscorlib.GetClass(typeof(IEnumerable)), + mscorlib.GetClass(typeof(object)) + }; + Assert.AreEqual(expected, c.GetAllBaseTypes(context).OrderBy(t => t.DotNetName).ToArray()); } + + [Test] + public void StructImplementingIEquatable() + { + // struct S : IEquatable {} + // don't use a Cecil-loaded struct for this test; we're testing the implicit addition of System.ValueType + DefaultTypeDefinition s = new DefaultTypeDefinition(mscorlib, string.Empty, "S"); + s.ClassType = ClassType.Struct; + s.BaseTypes.Add(new ParameterizedType(mscorlib.GetClass(typeof(IEquatable<>)), new[] { s })); + IType[] expected = { + s, + s.BaseTypes[0].Resolve(context), + mscorlib.GetClass(typeof(object)), + mscorlib.GetClass(typeof(ValueType)) + }; + Assert.AreEqual(expected, + s.GetAllBaseTypes(context).OrderBy(t => t.DotNetName).ToArray()); + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs b/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs index b489106a47..04f9db19b5 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs @@ -43,11 +43,11 @@ namespace ICSharpCode.NRefactory.TypeSystem } // Avoid outputting a type more than once - necessary for "diamond" multiple inheritance // (e.g. C implements I1 and I2, and both interfaces derive from Object) - if (output.Contains(type)) - return; - output.Add(type); - foreach (IType baseType in type.GetBaseTypes(context)) { - CollectAllBaseTypes(baseType, context, activeTypeDefinitions, output); + if (!output.Contains(type)) { + output.Add(type); + foreach (IType baseType in type.GetBaseTypes(context)) { + CollectAllBaseTypes(baseType, context, activeTypeDefinitions, output); + } } if (def != null) activeTypeDefinitions.Pop(); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs index f58d5fc531..0456d008fa 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs @@ -318,30 +318,36 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IEnumerable GetBaseTypes(ITypeResolveContext context) { - if (baseTypes == null || baseTypes.Count == 0) { - if (this.FullName == "System.Object") - return EmptyList.Instance; + bool hasNonInterface = false; + if (baseTypes != null) { + foreach (ITypeReference baseTypeRef in baseTypes) { + IType baseType = baseTypeRef.Resolve(context); + ITypeDefinition baseTypeDef = baseType.GetDefinition(); + if (baseTypeDef == null || baseTypeDef.ClassType != ClassType.Interface) + hasNonInterface = true; + yield return baseType; + } + } + if (!hasNonInterface && !(this.Name == "Object" && this.Namespace == "System" && this.TypeParameterCount == 0)) { + Type primitiveBaseType; switch (classType) { case ClassType.Enum: - return GetPrimitiveBaseType(typeof(Enum), context); + primitiveBaseType = typeof(Enum); + break; case ClassType.Struct: - return GetPrimitiveBaseType(typeof(ValueType), context); + primitiveBaseType = typeof(ValueType); + break; case ClassType.Delegate: - return GetPrimitiveBaseType(typeof(Delegate), context); + primitiveBaseType = typeof(Delegate); + break; default: - return GetPrimitiveBaseType(typeof(object), context); + primitiveBaseType = typeof(object); + break; } + IType t = context.GetClass(primitiveBaseType); + if (t != null) + yield return t; } - return baseTypes.Select(t => t.Resolve(context)).Where(t => t != SharedTypes.UnknownType); - } - - static IEnumerable GetPrimitiveBaseType(Type type, ITypeResolveContext context) - { - IType t = context.GetClass(type); - if (t != null) - return new [] { t }; - else - return EmptyList.Instance; } public virtual ITypeDefinition GetCompoundClass()