From 4d4f1f42b78c1097c8c934097c977ee3b953d14c Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 25 Nov 2011 21:07:50 +0100 Subject: [PATCH] Fixed various resolver bugs. --- .../Resolver/CSharpResolver.cs | 9 +++- ICSharpCode.NRefactory.CSharp/Resolver/Log.cs | 2 +- .../Resolver/MemberLookup.cs | 2 +- .../Resolver/ResolveVisitor.cs | 16 +++++- .../CSharp/Resolver/LambdaTests.cs | 12 +++++ .../CSharp/Resolver/MemberLookupTests.cs | 52 +++++++++++++++++++ .../CSharp/Resolver/ResolverTestBase.cs | 6 ++- .../ICSharpCode.NRefactory.csproj | 1 + .../Semantics/ThisResolveResult.cs | 34 ++++++++++++ 9 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 ICSharpCode.NRefactory/Semantics/ThisResolveResult.cs diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs index 412adaa9e8..2f94c64721 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs @@ -1830,7 +1830,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { ITypeDefinition t = CurrentTypeDefinition; if (t != null) { - return new ResolveResult(t); + if (t.TypeParameterCount != 0) { + // Self-parameterize the type + return new ThisResolveResult(new ParameterizedType(t, t.TypeParameters)); + } else { + return new ThisResolveResult(t); + } } return ErrorResult; } @@ -1844,7 +1849,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (t != null) { foreach (IType baseType in t.DirectBaseTypes) { if (baseType.Kind != TypeKind.Unknown && baseType.Kind != TypeKind.Interface) { - return new ResolveResult(baseType); + return new ThisResolveResult(baseType); } } } diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/Log.cs b/ICSharpCode.NRefactory.CSharp/Resolver/Log.cs index 11053b90df..c3d43c2f4d 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/Log.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/Log.cs @@ -35,7 +35,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// static class Log { - const bool logEnabled = true; + const bool logEnabled = false; [Conditional(logEnabled ? "DEBUG" : "LOG_DISABLED")] internal static void WriteLine(string text) diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs b/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs index b91bff91b2..d3c8a70adb 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs @@ -236,7 +236,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver bool targetIsTypeParameter = targetResolveResult.Type.Kind == TypeKind.TypeParameter; - bool allowProtectedAccess = IsProtectedAccessAllowed(targetResolveResult.Type); + bool allowProtectedAccess = (targetResolveResult is ThisResolveResult || IsProtectedAccessAllowed(targetResolveResult.Type)); Predicate nestedTypeFilter = delegate(ITypeDefinition entity) { return entity.Name == name && IsAccessible(entity, allowProtectedAccess); }; diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs index cfed75855d..89d04f8c5d 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs @@ -743,6 +743,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } IParameterizedMember pm = resolver.CurrentMember as IParameterizedMember; + if (pm == null && resolver.CurrentTypeDefinition != null) { + // Also consider delegate parameters: + pm = resolver.CurrentTypeDefinition.GetDelegateInvokeMethod(); + // pm will be null if the current type isn't a delegate + } if (pm != null) { foreach (IParameter p in pm.Parameters) { if (p.Name == name) { @@ -750,6 +755,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } } + return errorResult; } else { return null; @@ -1653,7 +1659,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver AstNodeCollection parameterDeclarations, AstNode body, bool isAnonymousMethod, bool hasParameterList, bool isAsync) { - List parameters = new List(); + List parameters = (hasParameterList || parameterDeclarations.Any()) ? new List() : null; resolver.PushBlock(); bool oldIsWithinLambdaExpression = resolver.IsWithinLambdaExpression; resolver.IsWithinLambdaExpression = true; @@ -3019,6 +3025,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (!resolverEnabled) return null; KnownTypeCode typeCode = TypeSystemConvertVisitor.GetTypeCodeForPrimitiveType(primitiveType.Keyword); + if (typeCode == KnownTypeCode.None && primitiveType.Parent is Constraint && primitiveType.Role == Constraint.BaseTypeRole) { + switch (primitiveType.Keyword) { + case "class": + case "struct": + case "new": + return voidResult; + } + } IType type = resolver.Compilation.FindType(typeCode); return new TypeResolveResult(type); } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs index 89cfef1c1b..6bdab5b599 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs @@ -380,6 +380,18 @@ class TestClass { Assert.AreEqual("System.Converter`2[[``0],[System.Int32]]", crr.Type.ReflectionName); } + [Test] + public void AnonymousMethodWithoutParameterList() + { + string program = @"using System; +class TestClass { + event EventHandler Ev = $delegate {}$; +}"; + var rr = Resolve(program); + Assert.IsFalse(rr.IsError); + Assert.IsFalse(rr.HasParameterList); + } + /* TODO write test for this class A { diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MemberLookupTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MemberLookupTests.cs index d0187510a6..9e37b36040 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MemberLookupTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/MemberLookupTests.cs @@ -209,5 +209,57 @@ public class Test { var mrr = Resolve(program); Assert.AreEqual("Foo`1+TestFoo[[Test]]", mrr.Type.ReflectionName); } + + [Test] + public void ProtectedBaseMethodCall() + { + string program = @"using System; +public class Base { + protected virtual void M() {} +} +public class Test : Base { + protected override void M() { + $base.M()$; + } +}"; + var rr = Resolve(program); + Assert.IsFalse(rr.IsError); + Assert.AreEqual("Base.M", rr.Member.FullName); + } + + [Test] + public void ProtectedBaseFieldAccess() + { + string program = @"using System; +public class Base { + protected int Field; +} +public class Test : Base { + public new int Field; + protected override void M() { + $base.Field$ = 1; + } +}"; + var rr = Resolve(program); + Assert.IsFalse(rr.IsError); + Assert.AreEqual("Base.Field", rr.Member.FullName); + } + + [Test] + public void ThisHasSameTypeAsFieldInGenericClass() + { + string program = @"using System; +public struct C { + public C(C other) { + $M(this, other)$; + } + static void M(T a, T b) {} +} +"; + var rr = Resolve(program); + Assert.IsFalse(rr.IsError); + Assert.AreEqual("C`1[[`0]]", rr.Arguments[0].Type.ReflectionName); + Assert.AreEqual("C`1[[`0]]", rr.Arguments[1].Type.ReflectionName); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs index 214a1413a8..7cba4c32a7 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ResolverTestBase.cs @@ -190,7 +190,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { ResolveResult rr = Resolve(code); Assert.IsNotNull(rr); - Assert.IsTrue(rr.GetType() == typeof(T), "Resolve should be " + typeof(T).Name + ", but was " + rr.GetType().Name); + if (typeof(T) == typeof(LambdaResolveResult)) { + Assert.IsTrue(rr is LambdaResolveResult, "Resolve should be " + typeof(T).Name + ", but was " + rr.GetType().Name); + } else { + Assert.IsTrue(rr.GetType() == typeof(T), "Resolve should be " + typeof(T).Name + ", but was " + rr.GetType().Name); + } return (T)rr; } diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 85cf4ca50d..1001c57aa8 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -94,6 +94,7 @@ + diff --git a/ICSharpCode.NRefactory/Semantics/ThisResolveResult.cs b/ICSharpCode.NRefactory/Semantics/ThisResolveResult.cs new file mode 100644 index 0000000000..831b47638a --- /dev/null +++ b/ICSharpCode.NRefactory/Semantics/ThisResolveResult.cs @@ -0,0 +1,34 @@ +// 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 ICSharpCode.NRefactory.TypeSystem; + +namespace ICSharpCode.NRefactory.Semantics +{ + /// + /// Represents the 'this' reference. + /// Also used for the 'base' reference. + /// + public class ThisResolveResult : ResolveResult + { + public ThisResolveResult(IType type) : base(type) + { + } + } +}