From a6433d43f3fd2dfb3ea8c06eff7fc9f07c9a56eb Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 26 Nov 2011 03:40:32 +0100 Subject: [PATCH] Do not try to infer a type from the null literal. --- ICSharpCode.NRefactory.CSharp/Resolver/Log.cs | 12 +++--- .../Resolver/MemberLookup.cs | 39 ++++++++++--------- .../Resolver/TypeInference.cs | 10 +++-- .../CSharp/Resolver/InvocationTests.cs | 18 +++++++++ .../CSharp/Resolver/TypeInferenceTests.cs | 17 ++++++++ 5 files changed, 69 insertions(+), 27 deletions(-) diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/Log.cs b/ICSharpCode.NRefactory.CSharp/Resolver/Log.cs index 68ad63b953..c3d43c2f4d 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/Log.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/Log.cs @@ -40,19 +40,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver [Conditional(logEnabled ? "DEBUG" : "LOG_DISABLED")] internal static void WriteLine(string text) { -// Debug.WriteLine(text); + Debug.WriteLine(text); } [Conditional(logEnabled ? "DEBUG" : "LOG_DISABLED")] internal static void WriteLine(string format, params object[] args) { -// Debug.WriteLine(format, args); + Debug.WriteLine(format, args); } [Conditional(logEnabled ? "DEBUG" : "LOG_DISABLED")] internal static void WriteCollection(string text, IEnumerable lines) { -/* #if DEBUG + #if DEBUG T[] arr = lines.ToArray(); if (arr.Length == 0) { Debug.WriteLine(text + ""); @@ -62,19 +62,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Debug.WriteLine(new string(' ', text.Length) + (arr[i] != null ? arr[i].ToString() : "")); } } - #endif*/ + #endif } [Conditional(logEnabled ? "DEBUG" : "LOG_DISABLED")] public static void Indent() { -// Debug.Indent(); + Debug.Indent(); } [Conditional(logEnabled ? "DEBUG" : "LOG_DISABLED")] public static void Unindent() { -// Debug.Unindent(); + Debug.Unindent(); } } } diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs b/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs index d3c8a70adb..ed6af79d73 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/MemberLookup.cs @@ -86,28 +86,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return false; case Accessibility.Private: // check for members of outer classes (private members of outer classes can be accessed) - var lookupTypeDefinition = currentTypeDefinition; - while (lookupTypeDefinition != null) { - if (entity.DeclaringTypeDefinition.Equals (lookupTypeDefinition)) + for (var t = currentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) { + if (t.Equals(entity.DeclaringTypeDefinition)) return true; - lookupTypeDefinition = lookupTypeDefinition.DeclaringTypeDefinition; } return false; case Accessibility.Public: return true; case Accessibility.Protected: - // For static members and type definitions, we do not require the qualifying reference - // to be derived from the current class (allowProtectedAccess). - return (allowProtectedAccess || entity.IsStatic || entity.EntityType == EntityType.TypeDefinition) - && IsProtectedAccessible(entity.DeclaringTypeDefinition); + return IsProtectedAccessible(allowProtectedAccess, entity); case Accessibility.Internal: return IsInternalAccessible(entity.ParentAssembly); case Accessibility.ProtectedOrInternal: - return (allowProtectedAccess && IsProtectedAccessible(entity.DeclaringTypeDefinition)) - || IsInternalAccessible(entity.ParentAssembly); + return IsInternalAccessible(entity.ParentAssembly) || IsProtectedAccessible(allowProtectedAccess, entity); case Accessibility.ProtectedAndInternal: - return (allowProtectedAccess && IsProtectedAccessible(entity.DeclaringTypeDefinition)) - && IsInternalAccessible(entity.ParentAssembly); + return IsInternalAccessible(entity.ParentAssembly) && IsProtectedAccessible(allowProtectedAccess, entity); default: throw new Exception("Invalid value for Accessibility"); } @@ -118,13 +111,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return assembly != null && currentAssembly != null && assembly.InternalsVisibleTo(currentAssembly); } - bool IsProtectedAccessible(ITypeDefinition declaringType) + bool IsProtectedAccessible(bool allowProtectedAccess, IEntity entity) { - if (declaringType.Equals (currentTypeDefinition)) - return true; - // PERF: this might hurt performance as this method is called several times (once for each member) - // make sure resolving base types is cheap (caches?) or cache within the MemberLookup instance - return currentTypeDefinition != null && currentTypeDefinition.IsDerivedFrom(declaringType); + // For static members and type definitions, we do not require the qualifying reference + // to be derived from the current class (allowProtectedAccess). + if (entity.IsStatic || entity.EntityType == EntityType.TypeDefinition) + allowProtectedAccess = true; + + for (var t = currentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) { + if (t.Equals(entity.DeclaringTypeDefinition)) + return true; + + // PERF: this might hurt performance as this method is called several times (once for each member) + // make sure resolving base types is cheap (caches?) or cache within the MemberLookup instance + if (allowProtectedAccess && currentTypeDefinition.IsDerivedFrom(entity.DeclaringTypeDefinition)) + return true; + } + return false; } #endregion diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs b/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs index c1c9ecd760..215bf7afa2 100644 --- a/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs +++ b/ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs @@ -271,8 +271,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - IType U = Ei.Type; - if (U != SpecialType.UnknownType) { + if (IsValidType(Ei.Type)) { if (Ti is ByReferenceType) { MakeExactInference(Ei.Type, Ti); } else { @@ -282,6 +281,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } + static bool IsValidType(IType type) + { + return type.Kind != TypeKind.Unknown && type.Kind != TypeKind.Null; + } + bool PhaseTwo() { // C# 4.0 spec: ยง7.5.2.2 The second phase @@ -516,7 +520,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return; } // Otherwise, if E is an expression with type U, then a lower-bound inference is made from U to T. - if (e.Type != SpecialType.UnknownType) { + if (IsValidType(e.Type)) { MakeLowerBoundInference(e.Type, t); } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs index 1c0fb6aada..c01f877ebd 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs @@ -475,5 +475,23 @@ class A { Assert.IsFalse(rr.IsError); Assert.AreEqual("ILeft.Method", rr.Member.FullName); } + + [Test] + public void AcceptVisitor() + { + string program = @" +interface IVisitor { } +class Test : IVisitor { + void M() { + $Accept(this, null)$; + } + S Accept(IVisitor v, T input) { } +}"; + var rr = Resolve(program); + Assert.IsFalse(rr.IsError); + var typeArguments = ((SpecializedMethod)rr.Member).TypeArguments; + Assert.AreEqual("System.Object", typeArguments[0].ReflectionName); + Assert.AreEqual("System.Object", typeArguments[1].ReflectionName); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs index bed53b3129..bfb50a6d78 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs @@ -90,6 +90,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver out success)); Assert.IsTrue(success); } + + [Test] + public void InferFromObjectAndFromNullLiteral() + { + // M(T a, T b); + ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T"); + + // M(new object(), null); + bool success; + Assert.AreEqual( + new [] { compilation.FindType(KnownTypeCode.Object) }, + ti.InferTypeArguments(new [] { tp }, + new [] { new ResolveResult(compilation.FindType(KnownTypeCode.Object)), new ResolveResult(SpecialType.NullType) }, + new [] { tp, tp }, + out success)); + Assert.IsTrue(success); + } #endregion #region Inference with Method Groups