diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs index 9ab5bd1d4f..7dc1a3ba05 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeSystemConvertVisitorTests.cs @@ -53,6 +53,13 @@ namespace ICSharpCode.NRefactory.CSharp.Parser .SetAssemblyName(typeof(TypeSystemTests).Assembly.GetName().Name); } + [Test] + public void ConvertStandaloneTypeReference() + { + var typeRef = new MemberType(new SimpleType("System"), "Array").ToTypeReference(); + Assert.AreEqual(compilation.FindType(KnownTypeCode.Array), typeRef.Resolve(compilation.TypeResolveContext)); + } + [Test] public void ExplicitDisposableImplementation() { @@ -82,10 +89,21 @@ namespace ICSharpCode.NRefactory.CSharp.Parser } [Test] - public void ConvertStandaloneTypeReference() + public void ExplicitImplementationOfUnifiedMethods() { - var typeRef = new MemberType(new SimpleType("System"), "Array").ToTypeReference(); - Assert.AreEqual(compilation.FindType(KnownTypeCode.Array), typeRef.Resolve(compilation.TypeResolveContext)); + IType type = compilation.FindType(typeof(ExplicitGenericInterfaceImplementationWithUnifiableMethods)); + Assert.AreEqual(2, type.GetMethods(m => m.IsExplicitInterfaceImplementation).Count()); + foreach (IMethod method in type.GetMethods(m => m.IsExplicitInterfaceImplementation)) { + Assert.AreEqual(1, method.InterfaceImplementations.Count, method.ToString()); + Assert.AreEqual("System.Int32", method.Parameters.Single().Type.ReflectionName); + IMethod interfaceMethod = (IMethod)method.InterfaceImplementations.Single(); + Assert.AreEqual("System.Int32", interfaceMethod.Parameters.Single().Type.ReflectionName); + var genericParamType = ((IMethod)method.MemberDefinition).Parameters.Single().Type; + var interfaceGenericParamType = ((IMethod)interfaceMethod.MemberDefinition).Parameters.Single().Type; + Assert.AreEqual(TypeKind.TypeParameter, genericParamType.Kind); + Assert.AreEqual(TypeKind.TypeParameter, interfaceGenericParamType.Kind); + Assert.AreEqual(genericParamType.ReflectionName, interfaceGenericParamType.ReflectionName); + } } } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs index 0f2c4e41a3..2397ced4af 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.TestCase.cs @@ -186,4 +186,21 @@ namespace ICSharpCode.NRefactory.TypeSystem.TestCase void IGenericInterface.Test(string a, T b) {} void IGenericInterface.Test(string a, ref T b) {} } + + public interface IGenericInterfaceWithUnifiableMethods + { + void Test(T a); + void Test(S a); + } + + public class ImplementationOfUnifiedMethods : IGenericInterfaceWithUnifiableMethods + { + public void Test(int a) {} + } + + public class ExplicitGenericInterfaceImplementationWithUnifiableMethods : IGenericInterfaceWithUnifiableMethods + { + void IGenericInterfaceWithUnifiableMethods.Test(T a) {} + void IGenericInterfaceWithUnifiableMethods.Test(S a) {} + } } diff --git a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs index 8bf380b047..0dba287915 100644 --- a/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs +++ b/ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs @@ -676,5 +676,17 @@ namespace ICSharpCode.NRefactory.TypeSystem Assert.AreEqual("System.Double", arg.Type.ReflectionName); Assert.AreEqual(1.0, arg.ConstantValue); } + + [Test, Ignore("Getting implicit interface implementations is not yet implemented.")] + public void ImplicitImplementationOfUnifiedMethods() + { + ITypeDefinition type = GetTypeDefinition(typeof(ImplementationOfUnifiedMethods)); + IMethod test = type.Methods.Single(m => m.Name == "Test"); + Assert.AreEqual(2, test.InterfaceImplementations.Count); + Assert.AreEqual("Int32", ((IMethod)test.InterfaceImplementations[0]).Parameters.Single().Type.Name); + Assert.AreEqual("Int32", ((IMethod)test.InterfaceImplementations[1]).Parameters.Single().Type.Name); + Assert.AreEqual("T", ((IMethod)test.InterfaceImplementations[0].MemberDefinition).Parameters.Single().Type.Name); + Assert.AreEqual("S", ((IMethod)test.InterfaceImplementations[1].MemberDefinition).Parameters.Single().Type.Name); + } } } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 0e2095437b..29f26e4738 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -161,6 +161,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs index 1e91647e85..f32e65b7ef 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/ExplicitInterfaceImplementationMemberReference.cs @@ -24,7 +24,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation /// /// References a member that is an explicit interface implementation. /// - public class ExplicitInterfaceImplementationMemberReference : IMemberReference + [Serializable] + public sealed class ExplicitInterfaceImplementationMemberReference : IMemberReference { ITypeReference typeReference; IMemberReference interfaceMemberReference; diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs index 94af4875a5..8b0c628c2c 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMember.cs @@ -20,6 +20,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; +using ICSharpCode.NRefactory.Utils; namespace ICSharpCode.NRefactory.TypeSystem.Implementation { @@ -50,7 +52,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public virtual IMemberReference ToMemberReference() { - return new DefaultMemberReference(this.EntityType, this.DeclaringType.ToTypeReference(), this.Name); + return new SpecializingMemberReference(declaringType.ToTypeReference(), memberDefinition.ToMemberReference()); } internal static TypeVisitor GetSubstitution(IType declaringType) @@ -127,8 +129,30 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return memberDefinition.Attributes; } } - IList IMember.InterfaceImplementations { - get { throw new NotImplementedException(); } + IList interfaceImplementations; + + public IList InterfaceImplementations { + get { + return LazyInitializer.EnsureInitialized(ref interfaceImplementations, FindInterfaceImplementations); + } + } + + IList FindInterfaceImplementations() + { + var definitionImplementations = memberDefinition.InterfaceImplementations; + IMember[] result = new IMember[definitionImplementations.Count]; + for (int i = 0; i < result.Length; i++) { + result[i] = Specialize(definitionImplementations[i]); + } + return result; + } + + /// + /// Specialize another member using the same type arguments as this member. + /// + protected virtual IMember Specialize(IMember otherMember) + { + return SpecializingMemberReference.CreateSpecializedMember(declaringType, memberDefinition, null); } public bool IsExplicitInterfaceImplementation { @@ -275,13 +299,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return parameters; } } - public override IMemberReference ToMemberReference() - { - return new DefaultMemberReference( - this.EntityType, this.DeclaringType.ToTypeReference(), this.Name, 0, - this.Parameters.Select(p => p.Type.ToTypeReference()).ToList()); - } - public override string ToString() { StringBuilder b = new StringBuilder("["); diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs index 0d5e1f6ed0..d698a9661c 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializedMethod.cs @@ -97,14 +97,22 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public override IMemberReference ToMemberReference() { - if (this.TypeParameters.Count == 0) - return base.ToMemberReference(); - // TODO: Implement SpecializedMethod.ToMemberReference() - throw new NotImplementedException(); + return new SpecializingMemberReference( + this.DeclaringType.ToTypeReference(), + this.MemberDefinition.ToMemberReference(), + typeArguments.Select(ta => ta.ToTypeReference()).ToList() + ); + } + + protected override IMember Specialize(IMember otherMember) + { + return SpecializingMemberReference.CreateSpecializedMember(this.DeclaringType, this.MemberDefinition, typeArguments); } /// /// Gets the type arguments passed to this method. + /// If only the type parameters for the class were specified and the generic method + /// itself is not specialized yet, this property will return an empty list. /// public IList TypeArguments { get { return typeArguments; } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs new file mode 100644 index 0000000000..6faecc92a8 --- /dev/null +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SpecializingMemberReference.cs @@ -0,0 +1,73 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; + +namespace ICSharpCode.NRefactory.TypeSystem.Implementation +{ + [Serializable] + public sealed class SpecializingMemberReference : IMemberReference + { + ITypeReference declaringTypeReference; + IMemberReference memberDefinitionReference; + IList typeArgumentReferences; + + public SpecializingMemberReference(ITypeReference declaringTypeReference, IMemberReference memberDefinitionReference, IList typeArgumentReferences = null) + { + if (declaringTypeReference == null) + throw new ArgumentNullException("declaringTypeReference"); + if (memberDefinitionReference == null) + throw new ArgumentNullException("memberDefinitionReference"); + this.declaringTypeReference = declaringTypeReference; + this.memberDefinitionReference = memberDefinitionReference; + this.typeArgumentReferences = typeArgumentReferences; + } + + public IMember Resolve(ITypeResolveContext context) + { + var declaringType = declaringTypeReference.Resolve(context); + var memberDefinition = memberDefinitionReference.Resolve(context); + IType[] typeArguments = null; + if (typeArgumentReferences != null) { + typeArguments = new IType[typeArgumentReferences.Count]; + for (int i = 0; i < typeArguments.Length; i++) { + typeArguments[i] = typeArgumentReferences[i].Resolve(context); + } + } + return CreateSpecializedMember(declaringType, memberDefinition, typeArguments); + } + + internal static IMember CreateSpecializedMember(IType declaringType, IMember memberDefinition, IList typeArguments) + { + if (memberDefinition == null) { + return null; + } else if (memberDefinition is IMethod) { + return new SpecializedMethod(declaringType, (IMethod)memberDefinition, typeArguments); + } else if (memberDefinition is IProperty) { + return new SpecializedProperty(declaringType, (IProperty)memberDefinition); + } else if (memberDefinition is IField) { + return new SpecializedField(declaringType, (IField)memberDefinition); + } else if (memberDefinition is IEvent) { + return new SpecializedEvent(declaringType, (IEvent)memberDefinition); + } else { + throw new NotSupportedException("Unknown IMember: " + memberDefinition); + } + } + } +}