diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs index 7f2477feb5..9281e3105b 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs @@ -1,4 +1,4 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// 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 @@ -1161,15 +1161,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (resolveExpr != null) { var initRR = Resolve(resolveExpr); var returnTypeRef = initRR.Type.ToTypeReference(); - var property = new DefaultUnresolvedProperty { - Name = name, + var property = new DefaultUnresolvedProperty(); + property.Name = name; + property.Accessibility = Accessibility.Public; + property.ReturnType = returnTypeRef; + property.Getter = new DefaultUnresolvedMethod { + Name = "get_" + name, Accessibility = Accessibility.Public, ReturnType = returnTypeRef, - Getter = new DefaultUnresolvedMethod { - Name = "get_" + name, - Accessibility = Accessibility.Public, - ReturnType = returnTypeRef - } + EntityType = EntityType.Accessor, + AccessorOwner = property }; unresolvedProperties.Add(property); members.Add(new AnonymousTypeMember(expr, initRR)); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AnonymousTypeTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AnonymousTypeTests.cs index d68b918355..3cc35d536f 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AnonymousTypeTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/AnonymousTypeTests.cs @@ -96,5 +96,68 @@ class TestClass { Assert.That(result.Type.GetProperties().Select(p => p.Name), Is.EquivalentTo(new[] { "a", "b", "c" })); Assert.That(result.Type.GetProperties().Single(p => p.Name == "c").ReturnType.GetProperties().Select(p => p.Name), Is.EquivalentTo(new[] { "d", "e", "f" })); } + + [Test] + public void DeclaringTypeIsSetCorrectlyForMembersOfAnonymousType() + { + string program = @"using System; +class TestClass { + void F() { + var o = $new { Prop = 0 }$; + } +}"; + var result = Resolve(program); + var prop = result.Type.GetProperties().Single(); + Assert.That(prop.DeclaringType, Is.EqualTo(result.Type)); + Assert.That(prop.Getter.DeclaringType, Is.EqualTo(result.Type)); + Assert.That(prop.Getter.IsAccessor, Is.True); + Assert.That(prop.Getter.AccessorOwner, Is.EqualTo(prop)); + Assert.That(prop.Setter, Is.Null); + } + + [Test] + public void CanRoundtripAnonymousTypeThroughTypeReference() + { + string program = @"using System; +class TestClass { + void F() { + var o = $new { Prop = 0 }$; + } +}"; + var result = Resolve(program); + Assert.AreEqual(TypeKind.Anonymous, result.Type.Kind); + IType typeAfterRoundtrip = result.Type.ToTypeReference().Resolve(result.Member.Compilation); + Assert.AreEqual(result.Type, typeAfterRoundtrip); + } + + [Test] + public void CanRoundtripAnonymousTypePropertyThroughMemberReference() + { + string program = @"using System; +class TestClass { + void F() { + var o = $new { Prop = 0 }$; + } +}"; + var result = Resolve(program); + IProperty prop = result.Type.GetProperties().Single(); + IProperty propAfterRoundtrip = (IProperty)prop.ToMemberReference().Resolve(result.Member.Compilation.TypeResolveContext); + Assert.AreEqual(prop, propAfterRoundtrip); + } + + [Test] + public void CanRoundtripAnonymousTypeGetterThroughMemberReference() + { + string program = @"using System; +class TestClass { + void F() { + var o = $new { Prop = 0 }$; + } +}"; + var result = Resolve(program); + IMethod getter = result.Type.GetProperties().Single().Getter; + IMethod getterAfterRoundtrip = (IMethod)getter.ToMemberReference().Resolve(result.Member.Compilation.TypeResolveContext); + Assert.AreEqual(getter, getterAfterRoundtrip); + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/AnonymousType.cs b/ICSharpCode.NRefactory/TypeSystem/AnonymousType.cs index 5060e1a72d..e858dbffe8 100644 --- a/ICSharpCode.NRefactory/TypeSystem/AnonymousType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/AnonymousType.cs @@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.TypeSystem this.resolvedProperties = new ProjectedList(context, unresolvedProperties, (c, p) => new AnonymousTypeProperty(p, c, this)); } - sealed class AnonymousTypeProperty : DefaultResolvedProperty, IEntity + sealed class AnonymousTypeProperty : DefaultResolvedProperty { readonly AnonymousType declaringType; @@ -55,7 +55,7 @@ namespace ICSharpCode.NRefactory.TypeSystem this.declaringType = declaringType; } - IType IEntity.DeclaringType { + public override IType DeclaringType { get { return declaringType; } } @@ -69,6 +69,41 @@ namespace ICSharpCode.NRefactory.TypeSystem { return declaringType.GetHashCode() ^ unchecked(27 * this.Name.GetHashCode()); } + + protected override IMethod CreateResolvedAccessor(IUnresolvedMethod unresolvedAccessor) + { + return new AnonymousTypeAccessor(unresolvedAccessor, context, this); + } + } + + sealed class AnonymousTypeAccessor : DefaultResolvedMethod + { + readonly AnonymousTypeProperty owner; + + public AnonymousTypeAccessor(IUnresolvedMethod unresolved, ITypeResolveContext parentContext, AnonymousTypeProperty owner) + : base(unresolved, parentContext, isExtensionMethod: false) + { + this.owner = owner; + } + + public override IMember AccessorOwner { + get { return owner; } + } + + public override IType DeclaringType { + get { return owner.DeclaringType; } + } + + public override bool Equals(object obj) + { + AnonymousTypeAccessor p = obj as AnonymousTypeAccessor; + return p != null && this.Name == p.Name && owner.DeclaringType.Equals(p.owner.DeclaringType); + } + + public override int GetHashCode() + { + return owner.DeclaringType.GetHashCode() ^ unchecked(27 * this.Name.GetHashCode()); + } } public override ITypeReference ToTypeReference() diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedEntity.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedEntity.cs index 411b102929..26285b0cb3 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedEntity.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedEntity.cs @@ -57,8 +57,8 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return parentContext.CurrentTypeDefinition; } } - public IType DeclaringType { - get { return parentContext.CurrentTypeDefinition; } + public virtual IType DeclaringType { + get { return parentContext.CurrentTypeDefinition ?? (IType)SpecialType.UnknownType; } } public IAssembly ParentAssembly { diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs index e81dc29871..839c74acea 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractResolvedMember.cs @@ -142,8 +142,13 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (result != null) { return result; } else { - return LazyInit.GetOrSet(ref accessorField, (IMethod)unresolvedAccessor.CreateResolved(context)); + return LazyInit.GetOrSet(ref accessorField, CreateResolvedAccessor(unresolvedAccessor)); } } + + protected virtual IMethod CreateResolvedAccessor(IUnresolvedMethod unresolvedAccessor) + { + return (IMethod)unresolvedAccessor.CreateResolved(context); + } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs index 2b5b1d22ab..9eb4e66613 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultResolvedMethod.cs @@ -224,7 +224,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation get { return null; } } - public IMember AccessorOwner { + public virtual IMember AccessorOwner { get { var reference = ((IUnresolvedMethod)unresolved).AccessorOwner; if (reference != null) @@ -261,8 +261,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation StringBuilder b = new StringBuilder("["); b.Append(this.EntityType); b.Append(' '); - b.Append(this.DeclaringType.ReflectionName); - b.Append('.'); + if (this.DeclaringType.Kind != TypeKind.Unknown) { + b.Append(this.DeclaringType.ReflectionName); + b.Append('.'); + } b.Append(this.Name); if (this.TypeParameters.Count > 0) { b.Append("``");