From cbb1fe5008dfcd7144c29d65ff4f6bbfbb65d660 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 18 May 2012 18:23:19 +0200 Subject: [PATCH] Fixed some issues resolving members. --- .../TypeSystemTests.cs | 13 ++++++++++--- .../CSharp/Parser/TypeSystemConvertVisitorTests.cs | 11 +++++++++++ .../Implementation/AbstractUnresolvedMember.cs | 2 +- .../Implementation/DefaultMemberReference.cs | 7 ++++--- .../TypeSystem/Implementation/DummyTypeParameter.cs | 5 +++++ ...xplicitInterfaceImplementationMemberReference.cs | 9 ++++++--- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/ICSharpCode.NRefactory.ConsistencyCheck/TypeSystemTests.cs b/ICSharpCode.NRefactory.ConsistencyCheck/TypeSystemTests.cs index 5c8b6a3aa4..381a4c7a51 100644 --- a/ICSharpCode.NRefactory.ConsistencyCheck/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.ConsistencyCheck/TypeSystemTests.cs @@ -56,17 +56,24 @@ namespace ICSharpCode.NRefactory.ConsistencyCheck { foreach (var project in solution.Projects) { var compilation = project.Compilation; - var context = new SimpleTypeResolveContext(compilation.MainAssembly); + var assemblyContext = new SimpleTypeResolveContext(compilation.MainAssembly); foreach (var typeDef in compilation.MainAssembly.GetAllTypeDefinitions()) { foreach (var part in typeDef.Parts) { - if (!typeDef.Equals(part.Resolve(context))) + if (!typeDef.Equals(part.Resolve(assemblyContext))) throw new InvalidOperationException(); } foreach (var member in typeDef.Members) { - var resolvedMember = member.UnresolvedMember.Resolve(context); + var resolvedMember = member.UnresolvedMember.Resolve(assemblyContext); if (!member.Equals(resolvedMember)) throw new InvalidOperationException(); } + // ToMemberReference() requires an appropriate generic context if the member + // contains open generics; otherwise the main context of the compilation is sufficient. + ITypeResolveContext context; + if (typeDef.TypeParameterCount > 0) + context = new SimpleTypeResolveContext(typeDef); + else + context = compilation.TypeResolveContext; // Include (potentially specialized) inherited members when testing ToMemberReference() foreach (var member in typeDef.GetMembers()) { var resolvedMember = member.ToMemberReference().Resolve(context); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs index 1c6a1c2c2e..7f5922f1ae 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs @@ -107,6 +107,17 @@ namespace ICSharpCode.NRefactory.CSharp.Parser } } + [Test] + public void ExplicitImplementationOfUnifiedMethods_ToMemberReference() + { + IType type = compilation.FindType(typeof(ExplicitGenericInterfaceImplementationWithUnifiableMethods)); + Assert.AreEqual(2, type.GetMethods(m => m.IsExplicitInterfaceImplementation).Count()); + foreach (IMethod method in type.GetMethods(m => m.IsExplicitInterfaceImplementation)) { + IMethod resolvedMethod = (IMethod)method.ToMemberReference().Resolve(compilation.TypeResolveContext); + Assert.AreEqual(method, resolvedMethod); + } + } + [Test] public void PartialMethodWithImplementation() { diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractUnresolvedMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractUnresolvedMember.cs index c41290cef9..c7469621c6 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractUnresolvedMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractUnresolvedMember.cs @@ -213,7 +213,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation return method; } else if (method.IsExplicitInterfaceImplementation && method.ImplementedInterfaceMembers.Count == 1) { IType explicitInterfaceType = explicitInterfaceTypeReference.Resolve(contextForMethod); - if (explicitInterfaceTypeReference.Equals(method.ImplementedInterfaceMembers[0].DeclaringType)) + if (explicitInterfaceType.Equals(method.ImplementedInterfaceMembers[0].DeclaringType)) return method; } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultMemberReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultMemberReference.cs index 6e26291fa6..632207e621 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultMemberReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultMemberReference.cs @@ -24,7 +24,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation { /// /// References an entity by its type and name. - /// This class can be used to refer to fields, events, and parameterless properties. + /// This class can be used to refer to all members except for constructors and explicit interface implementations. /// /// /// Resolving a DefaultMemberReference requires a context that provides enough information for resolving the declaring type reference @@ -64,11 +64,12 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation IEnumerable members; if (entityType == EntityType.Method) { members = type.GetMethods( - m => m.Name == name && m.EntityType == EntityType.Method && m.TypeParameters.Count == typeParameterCount, + m => m.Name == name && m.EntityType == EntityType.Method + && m.TypeParameters.Count == typeParameterCount && !m.IsExplicitInterfaceImplementation, GetMemberOptions.IgnoreInheritedMembers); } else { members = type.GetMembers( - m => m.Name == name && m.EntityType == entityType, + m => m.Name == name && m.EntityType == entityType && !m.IsExplicitInterfaceImplementation, GetMemberOptions.IgnoreInheritedMembers); } var resolvedParameterTypes = parameterTypes.Resolve(context); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs index d6658dfe39..b95b9d66b6 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DummyTypeParameter.cs @@ -138,6 +138,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } + public override string ToString() + { + return ReflectionName + " (dummy)"; + } + public override bool? IsReferenceType { get { return null; } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs index 2da8ffe870..89377284b5 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs @@ -28,6 +28,9 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// Resolving an ExplicitInterfaceImplementationMemberReference requires a context /// that provides enough information for resolving the declaring type reference /// and the interface member reference. + /// Note that the interface member reference is resolved in 'context.WithCurrentTypeDefinition(declaringType.GetDefinition())' + /// - this is done to ensure that open generics in the interface member reference resolve to the type parameters of the + /// declaring type. /// [Serializable] public sealed class ExplicitInterfaceImplementationMemberReference : IMemberReference @@ -51,11 +54,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IMember Resolve(ITypeResolveContext context) { - IMember interfaceMember = interfaceMemberReference.Resolve(context); + IType declaringType = typeReference.Resolve(context); + IMember interfaceMember = interfaceMemberReference.Resolve(context.WithCurrentTypeDefinition(declaringType.GetDefinition())); if (interfaceMember == null) return null; - IType type = typeReference.Resolve(context); - var members = type.GetMembers( + var members = declaringType.GetMembers( m => m.EntityType == interfaceMember.EntityType && m.IsExplicitInterfaceImplementation, GetMemberOptions.IgnoreInheritedMembers); return members.FirstOrDefault(m => m.ImplementedInterfaceMembers.Count == 1 && interfaceMember.Equals(m.ImplementedInterfaceMembers[0]));