From 7414e9ad6a1edd7a4eb79af54f5841bb5fc0ef31 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 10 Feb 2008 14:55:02 +0000 Subject: [PATCH] Fixed several minor code completion bugs. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2949 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/PythonAstWalker.cs | 23 ++-- .../ParserService/ParseProjectContent.cs | 11 +- .../Services/ParserService/ParserService.cs | 40 +++--- src/Main/Base/Test/NRefactoryResolverTests.cs | 115 +++++++++++++++++- .../Project/Src/Ambience.cs | 1 + .../Project/Src/CSharp/CSharpAmbience.cs | 2 +- .../Project/Src/CecilReader.cs | 5 +- .../Src/Implementations/AbstractReturnType.cs | 5 +- .../Src/Implementations/CombinedReturnType.cs | 2 +- .../Src/Implementations/DefaultMethod.cs | 2 +- .../Src/Implementations/DefaultReturnType.cs | 7 ++ .../Src/Implementations/GetClassReturnType.cs | 14 --- .../Src/Implementations/ProxyReturnType.cs | 11 +- .../Implementations/SearchClassReturnType.cs | 29 ++--- .../Project/Src/MemberLookupHelper.cs | 27 ++-- .../NRefactoryResolver/NRefactoryResolver.cs | 8 +- .../Src/NRefactoryResolver/ResolveVisitor.cs | 32 ++++- .../Project/Src/ResolveResult.cs | 36 ++++++ 18 files changed, 267 insertions(+), 103 deletions(-) diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs index f6ad58747a..fa4932153e 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs @@ -73,7 +73,12 @@ namespace ICSharpCode.PythonBinding DomRegion bodyRegion = GetBodyRegion(node.Body); DomRegion region = GetMethodRegion(node); - DefaultMethod method = new DefaultMethod(methodName, CreateReturnType(methodName, currentClass), ModifierEnum.Public, region, bodyRegion, currentClass); + DefaultMethod method; + if (methodName == "__init__") { + method = new Constructor(ModifierEnum.Public, region, bodyRegion, currentClass); + } else { + method = new DefaultMethod(methodName, new DefaultReturnType(currentClass), ModifierEnum.Public, region, bodyRegion, currentClass); + } foreach (IParameter parameter in ConvertParameters(node.Parameters)) { method.Parameters.Add(parameter); } @@ -105,7 +110,7 @@ namespace ICSharpCode.PythonBinding /// Note that SharpDevelop line numbers are zero based but the /// DomRegion values are one based. IronPython columns are zero /// based but the lines are one based. - /// Also note that IronPython seems to get the end column + /// Also note that IronPython seems to get the end column /// incorrect for classes. /// DomRegion GetBodyRegion(Node node) @@ -140,18 +145,6 @@ namespace ICSharpCode.PythonBinding return new DomRegion(statement.Start.Line, statement.Start.Column + 1, statement.Start.Line, statement.Body.Start.Column + 2); } - /// - /// Creates a return type from the current class and method name. - /// If the method name is __init__ then this method returns null. - /// - IReturnType CreateReturnType(string methodName, IClass c) - { - if (methodName == "__init__") { - return null; - } - return new DefaultReturnType(currentClass); - } - /// /// Looks for any base types for the class defined in the /// list of expressions and adds them to the class. @@ -174,7 +167,7 @@ namespace ICSharpCode.PythonBinding /// void AddBaseType(IClass c, string name) { - c.BaseTypes.Add(new SearchClassReturnType(c.ProjectContent, c, 0, 0, name, 0)); + c.BaseTypes.Add(new SearchClassReturnType(c.ProjectContent, c, 0, 0, name, 0)); } /// diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs index 7c797f6960..0f896b8e57 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs @@ -48,16 +48,21 @@ namespace ICSharpCode.SharpDevelop ProjectService.ProjectItemAdded += OnProjectItemAdded; ProjectService.ProjectItemRemoved += OnProjectItemRemoved; UpdateDefaultImports(items); - progressMonitor.BeginTask("Resolving references for " + project.Name, 0, false); + // TODO: Translate me + progressMonitor.TaskName = "Resolving references for " + project.Name + "..."; project.ResolveAssemblyReferences(); - progressMonitor.Done(); foreach (ProjectItem item in items) { if (!initializing) return; // abort initialization if (item.ItemType == ItemType.Reference || item.ItemType == ItemType.ProjectReference || item.ItemType == ItemType.COMReference) { - AddReference(item as ReferenceProjectItem, false); + ReferenceProjectItem reference = item as ReferenceProjectItem; + if (reference != null) { + // TODO: Translate me + progressMonitor.TaskName = "Loading " + reference.ShortName + "..."; + AddReference(reference, false); + } } } UpdateReferenceInterDependencies(); diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index c16c3d2b15..3bc3853668 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -172,26 +172,32 @@ namespace ICSharpCode.SharpDevelop } } WorkbenchSingleton.SafeThreadAsyncCall(ProjectService.ParserServiceCreatedProjectContents); - int workAmount = 0; - foreach (ParseProjectContent newContent in createdContents) { - if (abortLoadSolutionProjectsThread) return; - try { - newContent.Initialize1(progressMonitor); - workAmount += newContent.GetInitializationWorkAmount(); - } catch (Exception e) { - MessageService.ShowError(e, "Error while initializing project references:" + newContent); + try { + progressMonitor.BeginTask("Loading references...", createdContents.Count, false); + int workAmount = 0; + for (int i = 0; i < createdContents.Count; i++) { + if (abortLoadSolutionProjectsThread) return; + ParseProjectContent newContent = createdContents[i]; + progressMonitor.WorkDone = i; + try { + newContent.Initialize1(progressMonitor); + workAmount += newContent.GetInitializationWorkAmount(); + } catch (Exception e) { + MessageService.ShowError(e, "Error while initializing project references:" + newContent); + } } - } - progressMonitor.BeginTask("${res:ICSharpCode.SharpDevelop.Internal.ParserService.Parsing}...", workAmount, false); - foreach (ParseProjectContent newContent in createdContents) { - if (abortLoadSolutionProjectsThread) break; - try { - newContent.Initialize2(progressMonitor); - } catch (Exception e) { - MessageService.ShowError(e, "Error while initializing project contents:" + newContent); + progressMonitor.BeginTask("${res:ICSharpCode.SharpDevelop.Internal.ParserService.Parsing}...", workAmount, false); + foreach (ParseProjectContent newContent in createdContents) { + if (abortLoadSolutionProjectsThread) return; + try { + newContent.Initialize2(progressMonitor); + } catch (Exception e) { + MessageService.ShowError(e, "Error while initializing project contents:" + newContent); + } } + } finally { + progressMonitor.Done(); } - progressMonitor.Done(); } static void InitAddedProject(object state) diff --git a/src/Main/Base/Test/NRefactoryResolverTests.cs b/src/Main/Base/Test/NRefactoryResolverTests.cs index 4fda21c4e7..6b9266e8e8 100644 --- a/src/Main/Base/Test/NRefactoryResolverTests.cs +++ b/src/Main/Base/Test/NRefactoryResolverTests.cs @@ -278,6 +278,48 @@ interface IInterface2 { ResolveResult result = Resolve(program, "new ThisClassDoesNotExist()", 3); Assert.IsNull(result); } + + [Test] + public void OverriddenMethodCallTest() + { + string program = @"class A { + void Method() { + + } + + public abstract int GetRandomNumber(); +} +class B : A { + public override int GetRandomNumber() { + return 4; // chosen by fair dice roll. + // guaranteed to be random + } +} +"; + MemberResolveResult result = Resolve(program, "new B().GetRandomNumber()", 3); + Assert.AreEqual("B.GetRandomNumber", result.ResolvedMember.FullyQualifiedName); + } + + [Test] + public void OverriddenMethodCallTest2() + { + string program = @"class A { + void Method() { + + } + + public abstract int GetRandomNumber(string a, A b); +} +class B : A { + public override int GetRandomNumber(string b, A a) { + return 4; // chosen by fair dice roll. + // guaranteed to be random + } +} +"; + MemberResolveResult result = Resolve(program, "new B().GetRandomNumber(\"x\", this)", 3); + Assert.AreEqual("B.GetRandomNumber", result.ResolvedMember.FullyQualifiedName); + } [Test] public void MethodCallTest() @@ -1039,7 +1081,7 @@ End Class Assert.AreEqual("B", result.ResolvedType.FullyQualifiedName); Assert.IsTrue(ContainsMember(result.GetCompletionData(result.CallingClass.ProjectContent), mrr.ResolvedMember.FullyQualifiedName)); - result = ResolveVB(program, "mybase", 7); + result = ResolveVB(program, "mybase", 7); Assert.AreEqual("B", result.ResolvedType.FullyQualifiedName); Assert.IsFalse(ContainsMember(result.GetCompletionData(result.CallingClass.ProjectContent), mrr.ResolvedMember.FullyQualifiedName)); } @@ -1099,7 +1141,7 @@ class B { ArrayList cd = result.GetCompletionData(lastPC); Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup"); result = Resolve(program, "b.member", 4); - Assert.IsNotNull(result, "member should be found even though it is not visible!"); + Assert.IsTrue(result != null && result.IsValid, "member should be found even though it is not visible!"); } [Test] @@ -1120,7 +1162,7 @@ class B { ArrayList cd = result.GetCompletionData(lastPC); Assert.IsTrue(MemberExists(cd, "member"), "member should be in completion lookup"); result = Resolve(program, "a.member", 4); - Assert.IsNotNull(result, "member should be found!"); + Assert.IsTrue(result != null && result.IsValid, "member should be found!"); } [Test] @@ -1141,7 +1183,7 @@ class B { ArrayList cd = result.GetCompletionData(lastPC); Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup"); result = Resolve(program, "b.member", 4); - Assert.IsNotNull(result, "member should be found even though it is not visible!"); + Assert.IsTrue(result != null && result.IsValid, "member should be found even though it is not visible!"); } [Test] @@ -1162,7 +1204,70 @@ class B { ArrayList cd = result.GetCompletionData(lastPC); Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup"); result = Resolve(program, "b.member", 4); - Assert.IsNotNull(result, "member should be found even though it is not visible!"); + Assert.IsTrue(result != null && result.IsValid, "member should be found even though it is not visible!"); + } + + [Test] + public void ProtectedMemberVisibleWhenUsingBaseReference() + { + string program = @"using System; +class A : B { + void TestMethod(B b) { + + } +} +class B { + protected int member; +} +"; + ResolveResult result = Resolve(program, "base", 4); + Assert.IsNotNull(result); + ArrayList cd = result.GetCompletionData(lastPC); + Assert.IsTrue(MemberExists(cd, "member"), "member should be in completion lookup"); + result = Resolve(program, "base.member", 4); + Assert.IsTrue(result != null && result.IsValid, "member should be found!"); + } + + [Test] + public void ProtectedMethodInvisibleWhenNotUsingReferenceOfCurrentTypeTest() + { + string program = @"using System; +class A : B { + void TestMethod(B b) { + + } +} +class B { + protected int Method(); +} +"; + ResolveResult result = Resolve(program, "b", 4); + Assert.IsNotNull(result); + ArrayList cd = result.GetCompletionData(lastPC); + Assert.IsFalse(MemberExists(cd, "Method"), "member should not be in completion lookup"); + result = Resolve(program, "b.Method()", 4); + Assert.IsTrue(result != null && result.IsValid, "method should be found even though it is invisible!"); + } + + [Test] + public void ProtectedMethodVisibleWhenUsingBaseReference() + { + string program = @"using System; +class A : B { + void TestMethod(B b) { + + } +} +class B { + protected int Method(); +} +"; + ResolveResult result = Resolve(program, "base", 4); + Assert.IsNotNull(result); + ArrayList cd = result.GetCompletionData(lastPC); + Assert.IsTrue(MemberExists(cd, "Method"), "member should be in completion lookup"); + result = Resolve(program, "base.Method()", 4); + Assert.IsTrue(result != null && result.IsValid, "method should be found!"); } bool MemberExists(ArrayList members, string name) diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Ambience.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Ambience.cs index 468ae6e10b..e41ca7415a 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Ambience.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Ambience.cs @@ -125,6 +125,7 @@ namespace ICSharpCode.SharpDevelop.Dom return conversionFlags; } set { + CheckThread(); conversionFlags = value; } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/CSharpAmbience.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/CSharpAmbience.cs index e48ab4a864..fcf85879eb 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/CSharpAmbience.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/CSharpAmbience.cs @@ -382,7 +382,7 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp builder.Append(GetModifier(m)); } - if (m.ReturnType != null && ShowReturnType) { + if (!m.IsConstructor && m.ReturnType != null && ShowReturnType) { builder.Append(Convert(m.ReturnType)); builder.Append(' '); } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs index f73434c4ac..13887dbef5 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs @@ -338,7 +338,10 @@ namespace ICSharpCode.SharpDevelop.Dom } } - m.ReturnType = CreateType(this.ProjectContent, m, method.ReturnType.ReturnType); + if (method.IsConstructor) + m.ReturnType = this.DefaultReturnType; + else + m.ReturnType = CreateType(this.ProjectContent, m, method.ReturnType.ReturnType); AddAttributes(CompilationUnit.ProjectContent, m.Attributes, method.CustomAttributes); if (this.ClassType == ClassType.Interface) { m.Modifiers = ModifierEnum.Public | ModifierEnum.Abstract; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs index 886ef12c7f..43d8e21c5f 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs @@ -41,10 +41,7 @@ namespace ICSharpCode.SharpDevelop.Dom public override int GetHashCode() { - if (fullyQualifiedName == null) - return 0; - else - return fullyQualifiedName.GetHashCode(); + return DefaultReturnType.GetHashCode(this); } string fullyQualifiedName = null; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/CombinedReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/CombinedReturnType.cs index 6da949b90a..6f2da88c64 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/CombinedReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/CombinedReturnType.cs @@ -11,7 +11,7 @@ using System.Collections.Generic; namespace ICSharpCode.SharpDevelop.Dom { /// - /// Combines multiple return types for use in contraints. + /// Combines multiple return types for use in constraints. /// public sealed class CombinedReturnType : AbstractReturnType { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs index 4c7a89096e..63fe46c47c 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs @@ -165,7 +165,7 @@ namespace ICSharpCode.SharpDevelop.Dom public virtual bool IsConstructor { get { - return ReturnType == null || Name == "#ctor"; + return Name == "#ctor"; } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs index c6c821eca7..1b04b0699f 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs @@ -35,6 +35,13 @@ namespace ICSharpCode.SharpDevelop.Dom } } + public static int GetHashCode(IReturnType rt) + { + if (rt == null) + return 0; + return (rt.FullyQualifiedName ?? "").GetHashCode() ^ rt.TypeArgumentCount; + } + IClass c; public DefaultReturnType(IClass c) diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GetClassReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GetClassReturnType.cs index 5518881812..b1a4935462 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GetClassReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GetClassReturnType.cs @@ -39,20 +39,6 @@ namespace ICSharpCode.SharpDevelop.Dom } } - public override bool Equals(IReturnType o) - { - IReturnType rt = o as IReturnType; - if (rt != null && rt.IsDefaultReturnType) - return DefaultReturnType.Equals(this, rt); - else - return false; - } - - public override int GetHashCode() - { - return content.GetHashCode() ^ fullName.GetHashCode() ^ (typeArgumentCount * 5); - } - public override IReturnType BaseType { get { IClass c = content.GetClass(fullName, typeArgumentCount); diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs index 23aa551fd1..32376b8075 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs @@ -21,14 +21,17 @@ namespace ICSharpCode.SharpDevelop.Dom public sealed override bool Equals(object obj) { - if (obj == this) - return true; - else - return Equals(obj as IReturnType); + return Equals(obj as IReturnType); } public virtual bool Equals(IReturnType other) { + // this check is necessary because the underlying Equals implementation + // expects to be able to retrieve the base type of "other" - which fails when + // this==other and therefore other.busy. + if (other == this) + return true; + IReturnType baseType = BaseType; bool tmp = (baseType != null && TryEnter()) ? baseType.Equals(other) : false; busy = false; diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs index 2461d26f62..8c7d49d4a3 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs @@ -41,23 +41,6 @@ namespace ICSharpCode.SharpDevelop.Dom shortName = name.Substring(pos + 1); } - public override bool Equals(IReturnType o) - { - IReturnType rt2 = o as IReturnType; - if (rt2 != null && rt2.IsDefaultReturnType) - return DefaultReturnType.Equals(this, rt2); - else - return false; - } - - public override int GetHashCode() - { - unchecked { - return declaringClass.GetHashCode() ^ name.GetHashCode() - ^ (typeParameterCount << 16 + caretLine << 8 + caretColumn); - } - } - // we need to use a static Dictionary as cache to provide a easy was to clear all cached // BaseTypes. // When the cached BaseTypes could not be cleared as soon as the parse information is updated @@ -102,22 +85,26 @@ namespace ICSharpCode.SharpDevelop.Dom public override IReturnType BaseType { get { - if (isSearching) - return null; IReturnType type; lock (cache) { + if (isSearching) + return null; + if (cache.TryGetValue(this, out type)) return type; + + isSearching = true; } try { - isSearching = true; type = pc.SearchType(new SearchTypeRequest(name, typeParameterCount, declaringClass, caretLine, caretColumn)).Result; lock (cache) { + isSearching = false; cache[this] = type; } return type; - } finally { + } catch { isSearching = false; + throw; } } } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs index 9f1ce73fe0..91649491fa 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs @@ -34,15 +34,17 @@ namespace ICSharpCode.SharpDevelop.Dom public static List> LookupMember( IReturnType type, string name, IClass callingClass, - LanguageProperties language, bool isInvocation) + LanguageProperties language, bool isInvocation, bool? isClassInInheritanceTree) { if (language == null) throw new ArgumentNullException("language"); - bool isClassInInheritanceTree = false; - IClass underlyingClass = type.GetUnderlyingClass(); - if (underlyingClass != null) - isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass); + if (isClassInInheritanceTree == null) { + isClassInInheritanceTree = false; + IClass underlyingClass = type.GetUnderlyingClass(); + if (underlyingClass != null) + isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass); + } IEnumerable members; if (language == LanguageProperties.VBNet && language.NameComparer.Equals(name, "New")) { @@ -51,7 +53,7 @@ namespace ICSharpCode.SharpDevelop.Dom members = GetAllMembers(type).Where(m => language.NameComparer.Equals(m.Name, name)); } - return LookupMember(members, callingClass, isClassInInheritanceTree, isInvocation); + return LookupMember(members, callingClass, (bool)isClassInInheritanceTree, isInvocation); } class SignatureComparer : IEqualityComparer @@ -180,13 +182,20 @@ namespace ICSharpCode.SharpDevelop.Dom /// public static List GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language) { - if (language == null) - throw new ArgumentNullException("language"); - bool isClassInInheritanceTree = false; IClass underlyingClass = rt.GetUnderlyingClass(); if (underlyingClass != null) isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass); + return GetAccessibleMembers(rt, callingClass, language, isClassInInheritanceTree); + } + + /// + /// Gets all accessible members, including indexers and constructors. + /// + public static List GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language, bool isClassInInheritanceTree) + { + if (language == null) + throw new ArgumentNullException("language"); List result = new List(); foreach (var g in GetAllMembers(rt).GroupBy(m => m.Name, language.NameComparer)) { diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs index 98a2fe1f28..05c682950f 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs @@ -572,7 +572,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver ResolveResult rr = ResolveMember(tmp.DefaultReturnType, identifier, identifierExpression.TypeArguments, identifierExpression.Parent is InvocationExpression, - false); + false, null); if (rr != null && rr.IsValid) return rr; // also try to resolve the member in outer classes @@ -588,7 +588,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver ResolveResult rr = ResolveMember(c.DefaultReturnType, identifier, identifierExpression.TypeArguments, identifierExpression.Parent is InvocationExpression, - false); + false, null); if (rr != null && rr.IsValid) return rr; } @@ -626,9 +626,9 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver #region ResolveMember internal ResolveResult ResolveMember(IReturnType declaringType, string memberName, List typeArguments, bool isInvocation, - bool allowExtensionMethods) + bool allowExtensionMethods, bool? isClassInInheritanceTree) { - List> members = MemberLookupHelper.LookupMember(declaringType, memberName, callingClass, languageProperties, isInvocation); + List> members = MemberLookupHelper.LookupMember(declaringType, memberName, callingClass, languageProperties, isInvocation, isClassInInheritanceTree); if (members != null && typeArguments != null && typeArguments.Count != 0) { List typeArgs = typeArguments.ConvertAll(r => TypeVisitor.CreateReturnType(r, this)); diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/ResolveVisitor.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/ResolveVisitor.cs index 5f35747953..264e35d7ef 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/ResolveVisitor.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/ResolveVisitor.cs @@ -118,7 +118,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver return new VBBaseOrThisReferenceInConstructorResolveResult( resolver.CallingClass, resolver.CallingMember, resolver.CallingClass.BaseType); } else { - return CreateResolveResult(resolver.CallingClass.BaseType); + return new BaseResolveResult(resolver.CallingClass, resolver.CallingMember, resolver.CallingClass.BaseType); } } @@ -296,7 +296,11 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver if (firstResult == null) firstResult = result; } - return CreateMemberResolveResult(firstResult); + if (firstResult != null) { + return CreateMemberResolveResult(firstResult); + } else { + return FallbackResolveMethod(invocationExpression, mgrr, argumentTypes); + } } else if (rr != null && rr.ResolvedType != null) { IClass c = rr.ResolvedType.GetUnderlyingClass(); if (c != null && c.ClassType == ClassType.Delegate) { @@ -319,6 +323,26 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver return null; } + ResolveResult FallbackResolveMethod(InvocationExpression invocation, MethodGroupResolveResult mgrr, IReturnType[] argumentTypes) + { + // method not found, let's try if we can find a method if we violate the + // accessibility rules + MemberReferenceExpression mre = invocation.TargetObject as MemberReferenceExpression; + if (mre != null) { + List methods = mgrr.ContainingType.GetMethods().Where(m => resolver.IsSameName(m.Name, mre.MemberName)).ToList(); + bool resultIsAcceptable; + IMethod result = MemberLookupHelper.FindOverload( + methods, + argumentTypes, out resultIsAcceptable); + if (result != null) { + return CreateMemberResolveResult(result); + } + } + + // TODO: method still not found, now return invalid ResolveResult describing the expected method + return null; + } + public override object VisitLambdaExpression(LambdaExpression lambdaExpression, object data) { return null; @@ -357,7 +381,9 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver return resolver.ResolveMember(type, memberReferenceExpression.MemberName, memberReferenceExpression.TypeArguments, memberReferenceExpression.Parent is InvocationExpression, - typeRR == null /* allow extension methods only for non-static method calls */); + typeRR == null, // allow extension methods only for non-static method calls + targetRR is BaseResolveResult ? (bool?)true : null // allow calling protected members using "base." + ); } return null; } diff --git a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs index dea3667dfc..f954f6a8f2 100644 --- a/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs +++ b/src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs @@ -705,6 +705,42 @@ namespace ICSharpCode.SharpDevelop.Dom } #endregion + #region BaseResolveResult + /// + /// Is used for "base"/"MyBase" expression. + /// The completion list always shows protected members. + /// + public sealed class BaseResolveResult : ResolveResult + { + public BaseResolveResult(IClass callingClass, IMember callingMember, IReturnType baseClassType) + : base(callingClass, callingMember, baseClassType) + { + } + + public override ArrayList GetCompletionData(IProjectContent projectContent) + { + if (this.ResolvedType == null) return null; + ArrayList res = new ArrayList(); + + foreach (IMember m in MemberLookupHelper.GetAccessibleMembers(this.ResolvedType, this.CallingClass, projectContent.Language, true)) { + if (projectContent.Language.ShowMember(m, false)) + res.Add(m); + } + + if (this.CallingClass != null) { + AddExtensions(projectContent.Language, res, this.CallingClass, this.ResolvedType); + } + + return res; + } + + public override ResolveResult Clone() + { + return new BaseResolveResult(this.CallingClass, this.CallingMember, this.ResolvedType); + } + } + #endregion + #region UnknownIdentifierResolveResult public class UnknownIdentifierResolveResult : ResolveResult {