Browse Source

Fixed several minor code completion bugs.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2949 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 18 years ago
parent
commit
7414e9ad6a
  1. 23
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs
  2. 11
      src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs
  3. 40
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
  4. 115
      src/Main/Base/Test/NRefactoryResolverTests.cs
  5. 1
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Ambience.cs
  6. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/CSharpAmbience.cs
  7. 5
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CecilReader.cs
  8. 5
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs
  9. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/CombinedReturnType.cs
  10. 2
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs
  11. 7
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultReturnType.cs
  12. 14
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/GetClassReturnType.cs
  13. 11
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/ProxyReturnType.cs
  14. 29
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs
  15. 27
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs
  16. 8
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/NRefactoryResolver.cs
  17. 32
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/ResolveVisitor.cs
  18. 36
      src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs

23
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonAstWalker.cs

@ -73,7 +73,12 @@ namespace ICSharpCode.PythonBinding
DomRegion bodyRegion = GetBodyRegion(node.Body); DomRegion bodyRegion = GetBodyRegion(node.Body);
DomRegion region = GetMethodRegion(node); 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)) { foreach (IParameter parameter in ConvertParameters(node.Parameters)) {
method.Parameters.Add(parameter); method.Parameters.Add(parameter);
} }
@ -105,7 +110,7 @@ namespace ICSharpCode.PythonBinding
/// Note that SharpDevelop line numbers are zero based but the /// Note that SharpDevelop line numbers are zero based but the
/// DomRegion values are one based. IronPython columns are zero /// DomRegion values are one based. IronPython columns are zero
/// based but the lines are one based. /// 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. /// incorrect for classes.
/// </remarks> /// </remarks>
DomRegion GetBodyRegion(Node node) 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); return new DomRegion(statement.Start.Line, statement.Start.Column + 1, statement.Start.Line, statement.Body.Start.Column + 2);
} }
/// <summary>
/// Creates a return type from the current class and method name.
/// If the method name is __init__ then this method returns null.
/// </summary>
IReturnType CreateReturnType(string methodName, IClass c)
{
if (methodName == "__init__") {
return null;
}
return new DefaultReturnType(currentClass);
}
/// <summary> /// <summary>
/// Looks for any base types for the class defined in the /// Looks for any base types for the class defined in the
/// list of expressions and adds them to the class. /// list of expressions and adds them to the class.
@ -174,7 +167,7 @@ namespace ICSharpCode.PythonBinding
/// </summary> /// </summary>
void AddBaseType(IClass c, string name) 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));
} }
/// <summary> /// <summary>

11
src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs

@ -48,16 +48,21 @@ namespace ICSharpCode.SharpDevelop
ProjectService.ProjectItemAdded += OnProjectItemAdded; ProjectService.ProjectItemAdded += OnProjectItemAdded;
ProjectService.ProjectItemRemoved += OnProjectItemRemoved; ProjectService.ProjectItemRemoved += OnProjectItemRemoved;
UpdateDefaultImports(items); UpdateDefaultImports(items);
progressMonitor.BeginTask("Resolving references for " + project.Name, 0, false); // TODO: Translate me
progressMonitor.TaskName = "Resolving references for " + project.Name + "...";
project.ResolveAssemblyReferences(); project.ResolveAssemblyReferences();
progressMonitor.Done();
foreach (ProjectItem item in items) { foreach (ProjectItem item in items) {
if (!initializing) return; // abort initialization if (!initializing) return; // abort initialization
if (item.ItemType == ItemType.Reference if (item.ItemType == ItemType.Reference
|| item.ItemType == ItemType.ProjectReference || item.ItemType == ItemType.ProjectReference
|| item.ItemType == ItemType.COMReference) || 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(); UpdateReferenceInterDependencies();

40
src/Main/Base/Project/Src/Services/ParserService/ParserService.cs

@ -172,26 +172,32 @@ namespace ICSharpCode.SharpDevelop
} }
} }
WorkbenchSingleton.SafeThreadAsyncCall(ProjectService.ParserServiceCreatedProjectContents); WorkbenchSingleton.SafeThreadAsyncCall(ProjectService.ParserServiceCreatedProjectContents);
int workAmount = 0; try {
foreach (ParseProjectContent newContent in createdContents) { progressMonitor.BeginTask("Loading references...", createdContents.Count, false);
if (abortLoadSolutionProjectsThread) return; int workAmount = 0;
try { for (int i = 0; i < createdContents.Count; i++) {
newContent.Initialize1(progressMonitor); if (abortLoadSolutionProjectsThread) return;
workAmount += newContent.GetInitializationWorkAmount(); ParseProjectContent newContent = createdContents[i];
} catch (Exception e) { progressMonitor.WorkDone = i;
MessageService.ShowError(e, "Error while initializing project references:" + newContent); 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);
progressMonitor.BeginTask("${res:ICSharpCode.SharpDevelop.Internal.ParserService.Parsing}...", workAmount, false); foreach (ParseProjectContent newContent in createdContents) {
foreach (ParseProjectContent newContent in createdContents) { if (abortLoadSolutionProjectsThread) return;
if (abortLoadSolutionProjectsThread) break; try {
try { newContent.Initialize2(progressMonitor);
newContent.Initialize2(progressMonitor); } catch (Exception e) {
} catch (Exception e) { MessageService.ShowError(e, "Error while initializing project contents:" + newContent);
MessageService.ShowError(e, "Error while initializing project contents:" + newContent); }
} }
} finally {
progressMonitor.Done();
} }
progressMonitor.Done();
} }
static void InitAddedProject(object state) static void InitAddedProject(object state)

115
src/Main/Base/Test/NRefactoryResolverTests.cs

@ -278,6 +278,48 @@ interface IInterface2 {
ResolveResult result = Resolve(program, "new ThisClassDoesNotExist()", 3); ResolveResult result = Resolve(program, "new ThisClassDoesNotExist()", 3);
Assert.IsNull(result); 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<MemberResolveResult>(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<MemberResolveResult>(program, "new B().GetRandomNumber(\"x\", this)", 3);
Assert.AreEqual("B.GetRandomNumber", result.ResolvedMember.FullyQualifiedName);
}
[Test] [Test]
public void MethodCallTest() public void MethodCallTest()
@ -1039,7 +1081,7 @@ End Class
Assert.AreEqual("B", result.ResolvedType.FullyQualifiedName); Assert.AreEqual("B", result.ResolvedType.FullyQualifiedName);
Assert.IsTrue(ContainsMember(result.GetCompletionData(result.CallingClass.ProjectContent), mrr.ResolvedMember.FullyQualifiedName)); Assert.IsTrue(ContainsMember(result.GetCompletionData(result.CallingClass.ProjectContent), mrr.ResolvedMember.FullyQualifiedName));
result = ResolveVB<ResolveResult>(program, "mybase", 7); result = ResolveVB<BaseResolveResult>(program, "mybase", 7);
Assert.AreEqual("B", result.ResolvedType.FullyQualifiedName); Assert.AreEqual("B", result.ResolvedType.FullyQualifiedName);
Assert.IsFalse(ContainsMember(result.GetCompletionData(result.CallingClass.ProjectContent), mrr.ResolvedMember.FullyQualifiedName)); Assert.IsFalse(ContainsMember(result.GetCompletionData(result.CallingClass.ProjectContent), mrr.ResolvedMember.FullyQualifiedName));
} }
@ -1099,7 +1141,7 @@ class B {
ArrayList cd = result.GetCompletionData(lastPC); ArrayList cd = result.GetCompletionData(lastPC);
Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup"); Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup");
result = Resolve(program, "b.member", 4); 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] [Test]
@ -1120,7 +1162,7 @@ class B {
ArrayList cd = result.GetCompletionData(lastPC); ArrayList cd = result.GetCompletionData(lastPC);
Assert.IsTrue(MemberExists(cd, "member"), "member should be in completion lookup"); Assert.IsTrue(MemberExists(cd, "member"), "member should be in completion lookup");
result = Resolve(program, "a.member", 4); result = Resolve(program, "a.member", 4);
Assert.IsNotNull(result, "member should be found!"); Assert.IsTrue(result != null && result.IsValid, "member should be found!");
} }
[Test] [Test]
@ -1141,7 +1183,7 @@ class B {
ArrayList cd = result.GetCompletionData(lastPC); ArrayList cd = result.GetCompletionData(lastPC);
Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup"); Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup");
result = Resolve(program, "b.member", 4); 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] [Test]
@ -1162,7 +1204,70 @@ class B {
ArrayList cd = result.GetCompletionData(lastPC); ArrayList cd = result.GetCompletionData(lastPC);
Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup"); Assert.IsFalse(MemberExists(cd, "member"), "member should not be in completion lookup");
result = Resolve(program, "b.member", 4); 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) bool MemberExists(ArrayList members, string name)

1
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Ambience.cs

@ -125,6 +125,7 @@ namespace ICSharpCode.SharpDevelop.Dom
return conversionFlags; return conversionFlags;
} }
set { set {
CheckThread();
conversionFlags = value; conversionFlags = value;
} }
} }

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/CSharp/CSharpAmbience.cs

@ -382,7 +382,7 @@ namespace ICSharpCode.SharpDevelop.Dom.CSharp
builder.Append(GetModifier(m)); builder.Append(GetModifier(m));
} }
if (m.ReturnType != null && ShowReturnType) { if (!m.IsConstructor && m.ReturnType != null && ShowReturnType) {
builder.Append(Convert(m.ReturnType)); builder.Append(Convert(m.ReturnType));
builder.Append(' '); builder.Append(' ');
} }

5
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); AddAttributes(CompilationUnit.ProjectContent, m.Attributes, method.CustomAttributes);
if (this.ClassType == ClassType.Interface) { if (this.ClassType == ClassType.Interface) {
m.Modifiers = ModifierEnum.Public | ModifierEnum.Abstract; m.Modifiers = ModifierEnum.Public | ModifierEnum.Abstract;

5
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/AbstractReturnType.cs

@ -41,10 +41,7 @@ namespace ICSharpCode.SharpDevelop.Dom
public override int GetHashCode() public override int GetHashCode()
{ {
if (fullyQualifiedName == null) return DefaultReturnType.GetHashCode(this);
return 0;
else
return fullyQualifiedName.GetHashCode();
} }
string fullyQualifiedName = null; string fullyQualifiedName = null;

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/CombinedReturnType.cs

@ -11,7 +11,7 @@ using System.Collections.Generic;
namespace ICSharpCode.SharpDevelop.Dom namespace ICSharpCode.SharpDevelop.Dom
{ {
/// <summary> /// <summary>
/// Combines multiple return types for use in contraints. /// Combines multiple return types for use in constraints.
/// </summary> /// </summary>
public sealed class CombinedReturnType : AbstractReturnType public sealed class CombinedReturnType : AbstractReturnType
{ {

2
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/DefaultMethod.cs

@ -165,7 +165,7 @@ namespace ICSharpCode.SharpDevelop.Dom
public virtual bool IsConstructor { public virtual bool IsConstructor {
get { get {
return ReturnType == null || Name == "#ctor"; return Name == "#ctor";
} }
} }

7
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; IClass c;
public DefaultReturnType(IClass c) public DefaultReturnType(IClass c)

14
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 { public override IReturnType BaseType {
get { get {
IClass c = content.GetClass(fullName, typeArgumentCount); IClass c = content.GetClass(fullName, typeArgumentCount);

11
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) public sealed override bool Equals(object obj)
{ {
if (obj == this) return Equals(obj as IReturnType);
return true;
else
return Equals(obj as IReturnType);
} }
public virtual bool Equals(IReturnType other) 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; IReturnType baseType = BaseType;
bool tmp = (baseType != null && TryEnter()) ? baseType.Equals(other) : false; bool tmp = (baseType != null && TryEnter()) ? baseType.Equals(other) : false;
busy = false; busy = false;

29
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/Implementations/SearchClassReturnType.cs

@ -41,23 +41,6 @@ namespace ICSharpCode.SharpDevelop.Dom
shortName = name.Substring(pos + 1); 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 // we need to use a static Dictionary as cache to provide a easy was to clear all cached
// BaseTypes. // BaseTypes.
// When the cached BaseTypes could not be cleared as soon as the parse information is updated // 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 { public override IReturnType BaseType {
get { get {
if (isSearching)
return null;
IReturnType type; IReturnType type;
lock (cache) { lock (cache) {
if (isSearching)
return null;
if (cache.TryGetValue(this, out type)) if (cache.TryGetValue(this, out type))
return type; return type;
isSearching = true;
} }
try { try {
isSearching = true;
type = pc.SearchType(new SearchTypeRequest(name, typeParameterCount, declaringClass, caretLine, caretColumn)).Result; type = pc.SearchType(new SearchTypeRequest(name, typeParameterCount, declaringClass, caretLine, caretColumn)).Result;
lock (cache) { lock (cache) {
isSearching = false;
cache[this] = type; cache[this] = type;
} }
return type; return type;
} finally { } catch {
isSearching = false; isSearching = false;
throw;
} }
} }
} }

27
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/MemberLookupHelper.cs

@ -34,15 +34,17 @@ namespace ICSharpCode.SharpDevelop.Dom
public static List<IList<IMember>> LookupMember( public static List<IList<IMember>> LookupMember(
IReturnType type, string name, IClass callingClass, IReturnType type, string name, IClass callingClass,
LanguageProperties language, bool isInvocation) LanguageProperties language, bool isInvocation, bool? isClassInInheritanceTree)
{ {
if (language == null) if (language == null)
throw new ArgumentNullException("language"); throw new ArgumentNullException("language");
bool isClassInInheritanceTree = false; if (isClassInInheritanceTree == null) {
IClass underlyingClass = type.GetUnderlyingClass(); isClassInInheritanceTree = false;
if (underlyingClass != null) IClass underlyingClass = type.GetUnderlyingClass();
isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass); if (underlyingClass != null)
isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass);
}
IEnumerable<IMember> members; IEnumerable<IMember> members;
if (language == LanguageProperties.VBNet && language.NameComparer.Equals(name, "New")) { 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)); 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<IMethod> class SignatureComparer : IEqualityComparer<IMethod>
@ -180,13 +182,20 @@ namespace ICSharpCode.SharpDevelop.Dom
/// </summary> /// </summary>
public static List<IMember> GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language) public static List<IMember> GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language)
{ {
if (language == null)
throw new ArgumentNullException("language");
bool isClassInInheritanceTree = false; bool isClassInInheritanceTree = false;
IClass underlyingClass = rt.GetUnderlyingClass(); IClass underlyingClass = rt.GetUnderlyingClass();
if (underlyingClass != null) if (underlyingClass != null)
isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass); isClassInInheritanceTree = underlyingClass.IsTypeInInheritanceTree(callingClass);
return GetAccessibleMembers(rt, callingClass, language, isClassInInheritanceTree);
}
/// <summary>
/// Gets all accessible members, including indexers and constructors.
/// </summary>
public static List<IMember> GetAccessibleMembers(IReturnType rt, IClass callingClass, LanguageProperties language, bool isClassInInheritanceTree)
{
if (language == null)
throw new ArgumentNullException("language");
List<IMember> result = new List<IMember>(); List<IMember> result = new List<IMember>();
foreach (var g in GetAllMembers(rt).GroupBy(m => m.Name, language.NameComparer)) { foreach (var g in GetAllMembers(rt).GroupBy(m => m.Name, language.NameComparer)) {

8
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, ResolveResult rr = ResolveMember(tmp.DefaultReturnType, identifier,
identifierExpression.TypeArguments, identifierExpression.TypeArguments,
identifierExpression.Parent is InvocationExpression, identifierExpression.Parent is InvocationExpression,
false); false, null);
if (rr != null && rr.IsValid) if (rr != null && rr.IsValid)
return rr; return rr;
// also try to resolve the member in outer classes // also try to resolve the member in outer classes
@ -588,7 +588,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
ResolveResult rr = ResolveMember(c.DefaultReturnType, identifier, ResolveResult rr = ResolveMember(c.DefaultReturnType, identifier,
identifierExpression.TypeArguments, identifierExpression.TypeArguments,
identifierExpression.Parent is InvocationExpression, identifierExpression.Parent is InvocationExpression,
false); false, null);
if (rr != null && rr.IsValid) if (rr != null && rr.IsValid)
return rr; return rr;
} }
@ -626,9 +626,9 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
#region ResolveMember #region ResolveMember
internal ResolveResult ResolveMember(IReturnType declaringType, string memberName, internal ResolveResult ResolveMember(IReturnType declaringType, string memberName,
List<TypeReference> typeArguments, bool isInvocation, List<TypeReference> typeArguments, bool isInvocation,
bool allowExtensionMethods) bool allowExtensionMethods, bool? isClassInInheritanceTree)
{ {
List<IList<IMember>> members = MemberLookupHelper.LookupMember(declaringType, memberName, callingClass, languageProperties, isInvocation); List<IList<IMember>> members = MemberLookupHelper.LookupMember(declaringType, memberName, callingClass, languageProperties, isInvocation, isClassInInheritanceTree);
if (members != null && typeArguments != null && typeArguments.Count != 0) { if (members != null && typeArguments != null && typeArguments.Count != 0) {
List<IReturnType> typeArgs = typeArguments.ConvertAll(r => TypeVisitor.CreateReturnType(r, this)); List<IReturnType> typeArgs = typeArguments.ConvertAll(r => TypeVisitor.CreateReturnType(r, this));

32
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/NRefactoryResolver/ResolveVisitor.cs

@ -118,7 +118,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
return new VBBaseOrThisReferenceInConstructorResolveResult( return new VBBaseOrThisReferenceInConstructorResolveResult(
resolver.CallingClass, resolver.CallingMember, resolver.CallingClass.BaseType); resolver.CallingClass, resolver.CallingMember, resolver.CallingClass.BaseType);
} else { } 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) if (firstResult == null)
firstResult = result; firstResult = result;
} }
return CreateMemberResolveResult(firstResult); if (firstResult != null) {
return CreateMemberResolveResult(firstResult);
} else {
return FallbackResolveMethod(invocationExpression, mgrr, argumentTypes);
}
} else if (rr != null && rr.ResolvedType != null) { } else if (rr != null && rr.ResolvedType != null) {
IClass c = rr.ResolvedType.GetUnderlyingClass(); IClass c = rr.ResolvedType.GetUnderlyingClass();
if (c != null && c.ClassType == ClassType.Delegate) { if (c != null && c.ClassType == ClassType.Delegate) {
@ -319,6 +323,26 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
return null; 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<IMethod> 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) public override object VisitLambdaExpression(LambdaExpression lambdaExpression, object data)
{ {
return null; return null;
@ -357,7 +381,9 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
return resolver.ResolveMember(type, memberReferenceExpression.MemberName, return resolver.ResolveMember(type, memberReferenceExpression.MemberName,
memberReferenceExpression.TypeArguments, memberReferenceExpression.TypeArguments,
memberReferenceExpression.Parent is InvocationExpression, 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; return null;
} }

36
src/Main/ICSharpCode.SharpDevelop.Dom/Project/Src/ResolveResult.cs

@ -705,6 +705,42 @@ namespace ICSharpCode.SharpDevelop.Dom
} }
#endregion #endregion
#region BaseResolveResult
/// <summary>
/// Is used for "base"/"MyBase" expression.
/// The completion list always shows protected members.
/// </summary>
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 #region UnknownIdentifierResolveResult
public class UnknownIdentifierResolveResult : ResolveResult public class UnknownIdentifierResolveResult : ResolveResult
{ {

Loading…
Cancel
Save