Browse Source

Fixed SD2-797: Code-completion for nested classes is broken

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/2.0@1379 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 20 years ago
parent
commit
16d87fd62e
  1. 2
      data/templates/file/CSharp/CSharp.Web.WebControl.xft
  2. 2
      data/templates/file/CSharp/CSharp.Web.WebService.xft
  3. 9
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/BooProject.cs
  4. 18
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs
  5. 13
      src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs
  6. 92
      src/AddIns/BackendBindings/Boo/BooBinding/Test/ResolverTests.cs
  7. 5
      src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs
  8. 4
      src/Main/Base/Project/Src/Dom/ResolveResult.cs
  9. 4
      src/Main/Base/Project/Src/Services/ParserService/DefaultProjectContent.cs
  10. 7
      src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs
  11. 19
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
  12. 15
      src/Main/Base/Test/InnerClassesResolverTests.cs

2
data/templates/file/CSharp/CSharp.Web.WebControl.xft

@ -6,7 +6,7 @@
icon = "C#.File.NewClass" icon = "C#.File.NewClass"
category = "C#" category = "C#"
subcategory = "ASP.NET" subcategory = "ASP.NET"
defaultname = "WebControl" defaultname = "WebControl${Number}"
language = "C#" language = "C#"
/> />

2
data/templates/file/CSharp/CSharp.Web.WebService.xft

@ -6,7 +6,7 @@
icon = "C#.File.NewClass" icon = "C#.File.NewClass"
category = "C#" category = "C#"
subcategory = "ASP.NET" subcategory = "ASP.NET"
defaultname = "WebService.asmx" defaultname = "WebService${Number}.asmx"
language = "C#" language = "C#"
/> />

9
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/BooProject.cs

@ -109,5 +109,14 @@ namespace Grunwald.BooBinding
return GetProperty("Ducky", false); return GetProperty("Ducky", false);
} }
} }
public override void SetProperty<T>(string configurationName, string platform, string property, T value, PropertyStorageLocations location)
{
bool oldDucky = Ducky;
base.SetProperty(configurationName, platform, property, value, location);
if (Ducky != oldDucky) {
ParserService.Reparse(this);
}
}
} }
} }

18
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ConvertVisitor.cs

@ -213,18 +213,24 @@ namespace Grunwald.BooBinding.CodeCompletion
return CreateReturnType(reference, c, method, c.Region.BeginLine + 1, 1, _cu.ProjectContent); return CreateReturnType(reference, c, method, c.Region.BeginLine + 1, 1, _cu.ProjectContent);
} }
} }
public static IReturnType CreateReturnType(AST.TypeReference reference, IClass callingClass,
IMethodOrProperty callingMember, int caretLine, int caretColumn, internal static IReturnType GetDefaultReturnType(IProjectContent projectContent)
IProjectContent projectContent)
{ {
System.Diagnostics.Debug.Assert(projectContent != null);
if (reference == null) {
BooProject project = projectContent.Project as BooProject; BooProject project = projectContent.Project as BooProject;
if (project != null && project.Ducky) if (project != null && project.Ducky)
return new BooResolver.DuckClass(new DefaultCompilationUnit(projectContent)).DefaultReturnType; return new BooResolver.DuckClass(new DefaultCompilationUnit(projectContent)).DefaultReturnType;
else else
return ReflectionReturnType.Object; return ReflectionReturnType.Object;
} }
public static IReturnType CreateReturnType(AST.TypeReference reference, IClass callingClass,
IMethodOrProperty callingMember, int caretLine, int caretColumn,
IProjectContent projectContent)
{
System.Diagnostics.Debug.Assert(projectContent != null);
if (reference == null) {
return GetDefaultReturnType(projectContent);
}
if (reference is AST.ArrayTypeReference) { if (reference is AST.ArrayTypeReference) {
AST.ArrayTypeReference arr = (AST.ArrayTypeReference)reference; AST.ArrayTypeReference arr = (AST.ArrayTypeReference)reference;
return new ArrayReturnType(CreateReturnType(arr.ElementType, callingClass, callingMember, return new ArrayReturnType(CreateReturnType(arr.ElementType, callingClass, callingMember,
@ -278,7 +284,7 @@ namespace Grunwald.BooBinding.CodeCompletion
if (field.Initializer != null) if (field.Initializer != null)
return new InferredReturnType(field.Initializer, OuterClass); return new InferredReturnType(field.Initializer, OuterClass);
else else
return ReflectionReturnType.Object; return GetDefaultReturnType(_cu.ProjectContent);
} else { } else {
return CreateReturnType(field.Type); return CreateReturnType(field.Type);
} }

13
src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/CodeCompletion/ResolveVisitor.cs

@ -168,9 +168,14 @@ namespace Grunwald.BooBinding.CodeCompletion
} }
} }
} }
if (callingClass != null) {
if (ResolveMember(callingClass.DefaultReturnType, identifier)) { // Find members of this class or enclosing classes
IClass tmp = callingClass;
while (tmp != null) {
if (ResolveMember(tmp.DefaultReturnType, identifier))
return true; return true;
tmp = tmp.DeclaringType;
}
} }
string namespaceName = projectContent.SearchNamespace(identifier, callingClass, cu, resolver.CaretLine, resolver.CaretColumn); string namespaceName = projectContent.SearchNamespace(identifier, callingClass, cu, resolver.CaretLine, resolver.CaretColumn);
@ -294,7 +299,8 @@ namespace Grunwald.BooBinding.CodeCompletion
if (resolveResult is TypeResolveResult) { if (resolveResult is TypeResolveResult) {
IClass rClass = (resolveResult as TypeResolveResult).ResolvedClass; IClass rClass = (resolveResult as TypeResolveResult).ResolvedClass;
if (rClass != null) { if (rClass != null) {
foreach (IClass innerClass in rClass.InnerClasses) { foreach (IClass baseClass in rClass.ClassInheritanceTree) {
foreach (IClass innerClass in baseClass.InnerClasses) {
if (IsSameName(innerClass.Name, node.Name)) { if (IsSameName(innerClass.Name, node.Name)) {
MakeTypeResult(innerClass); MakeTypeResult(innerClass);
return; return;
@ -302,6 +308,7 @@ namespace Grunwald.BooBinding.CodeCompletion
} }
} }
} }
}
ResolveMember(resolveResult.ResolvedType, node.Name); ResolveMember(resolveResult.ResolvedType, node.Name);
} }
} }

92
src/AddIns/BackendBindings/Boo/BooBinding/Test/ResolverTests.cs

@ -29,16 +29,6 @@ namespace Grunwald.BooBinding.Tests
return Resolve<T>(normalProg, code, marker); return Resolve<T>(normalProg, code, marker);
} }
T ResolveReg<T>(string code) where T : ResolveResult
{
return ResolveReg<T>(code, "/*1*/");
}
T ResolveReg<T>(string code, string marker) where T : ResolveResult
{
return Resolve<T>(regressionProg, code, marker);
}
T Resolve<T>(string prog, string code, string marker) where T : ResolveResult T Resolve<T>(string prog, string code, string marker) where T : ResolveResult
{ {
ResolveResult rr = Resolve(prog, new ExpressionResult(code), marker); ResolveResult rr = Resolve(prog, new ExpressionResult(code), marker);
@ -55,10 +45,12 @@ namespace Grunwald.BooBinding.Tests
} }
const string fileName = "tempFile.boo"; const string fileName = "tempFile.boo";
DefaultProjectContent lastPC;
void Register(string prog) void Register(string prog)
{ {
DefaultProjectContent pc = new DefaultProjectContent(); DefaultProjectContent pc = new DefaultProjectContent();
lastPC = pc;
ParserService.ForceProjectContent(pc); ParserService.ForceProjectContent(pc);
pc.ReferencedContents.Add(ProjectContentRegistry.Mscorlib); pc.ReferencedContents.Add(ProjectContentRegistry.Mscorlib);
pc.ReferencedContents.Add(ProjectContentRegistry.WinForms); pc.ReferencedContents.Add(ProjectContentRegistry.WinForms);
@ -230,16 +222,16 @@ namespace Grunwald.BooBinding.Tests
[Test] [Test]
public void Boo629VariableScope() public void Boo629VariableScope()
{ {
LocalResolveResult rr = ResolveReg<LocalResolveResult>("boo629"); LocalResolveResult rr = Resolve<LocalResolveResult>(regressionProg, "boo629", "/*1*/");
Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName); Assert.AreEqual("System.String", rr.ResolvedType.FullyQualifiedName);
} }
[Test] [Test]
public void Boo640ConditionalAssignment() public void Boo640ConditionalAssignment()
{ {
LocalResolveResult rr = ResolveReg<LocalResolveResult>("boo640b"); LocalResolveResult rr = Resolve<LocalResolveResult>(regressionProg, "boo640b", "/*1*/");
Assert.AreEqual("System.Reflection.FieldInfo", rr.ResolvedType.FullyQualifiedName); Assert.AreEqual("System.Reflection.FieldInfo", rr.ResolvedType.FullyQualifiedName);
rr = ResolveReg<LocalResolveResult>("boo640a", "/*640*/"); rr = Resolve<LocalResolveResult>(regressionProg, "boo640a", "/*640*/");
Assert.AreEqual("System.Object", rr.ResolvedType.FullyQualifiedName); Assert.AreEqual("System.Object", rr.ResolvedType.FullyQualifiedName);
Assert.IsNull(Resolve(regressionProg, new ExpressionResult("boo640a"), "/*1*/")); Assert.IsNull(Resolve(regressionProg, new ExpressionResult("boo640a"), "/*1*/"));
} }
@ -264,6 +256,80 @@ namespace Grunwald.BooBinding.Tests
} }
#endregion #endregion
#region Nested Classes
const string nestedClassProg =
"class Outer:\n" +
"\tpublic static outerField = 1\n" +
"\tpublic class Inner:\n/*inner*/" +
"\t\tpublic innerField = 2\n" +
"class Derived(Outer):\n/*derived*/" +
"\tpublic static derivedField = 3\n" +
"def Method():\n" +
"\ti as Outer.Inner\n" +
"\ti2 as Derived.Inner\n" +
"\t/*1*/";
[Test]
public void NestedClassTypeResolution()
{
TypeResolveResult trr;
trr = Resolve<TypeResolveResult>(nestedClassProg, "Outer.Inner", "/*1*/");
Assert.AreEqual("Outer.Inner", trr.ResolvedClass.FullyQualifiedName);
trr = Resolve<TypeResolveResult>(nestedClassProg, "Inner", "/*inner*/");
Assert.AreEqual("Outer.Inner", trr.ResolvedClass.FullyQualifiedName);
trr = Resolve<TypeResolveResult>(nestedClassProg, "Inner", "/*derived*/");
Assert.AreEqual("Outer.Inner", trr.ResolvedClass.FullyQualifiedName);
trr = Resolve<TypeResolveResult>(nestedClassProg, "Derived.Inner", "/*1*/");
Assert.AreEqual("Outer.Inner", trr.ResolvedClass.FullyQualifiedName);
}
[Test]
public void NestedClassCtrlSpace()
{
CtrlSpace(nestedClassProg.Replace("/*inner*/", "/*mark*/"), "outerField", "innerField", "Inner", "Outer", "Derived");
CtrlSpace(nestedClassProg.Replace("/*derived*/", "/*mark*/"), "outerField", "derivedField", "Inner", "Outer", "Derived");
}
[Test]
public void NestedClassParentStaticField()
{
MemberResolveResult mrr = Resolve<MemberResolveResult>(nestedClassProg, "outerField", "/*inner*/");
Assert.AreEqual("Outer.outerField", mrr.ResolvedMember.FullyQualifiedName);
}
[Test]
public void NestedClassCC()
{
LocalResolveResult rr = Resolve<LocalResolveResult>(nestedClassProg, "i", "/*1*/");
Assert.AreEqual("Outer.Inner", rr.ResolvedType.FullyQualifiedName);
bool ok = false;
foreach (object o in rr.GetCompletionData(lastPC)) {
IMember m = o as IMember;
if (m != null && m.Name == "innerField")
ok = true;
}
Assert.IsTrue(ok);
MemberResolveResult mrr = Resolve<MemberResolveResult>(nestedClassProg, "i.innerField", "/*1*/");
Assert.AreEqual("Outer.Inner.innerField", mrr.ResolvedMember.FullyQualifiedName);
}
[Test]
public void NestedClassCC2()
{
LocalResolveResult rr = Resolve<LocalResolveResult>(nestedClassProg, "i2", "/*1*/");
Assert.AreEqual("Outer.Inner", rr.ResolvedType.FullyQualifiedName);
bool ok = false;
foreach (object o in rr.GetCompletionData(lastPC)) {
IMember m = o as IMember;
if (m != null && m.Name == "innerField")
ok = true;
}
Assert.IsTrue(ok);
MemberResolveResult mrr = Resolve<MemberResolveResult>(nestedClassProg, "i2.innerField", "/*1*/");
Assert.AreEqual("Outer.Inner.innerField", mrr.ResolvedMember.FullyQualifiedName);
}
#endregion
#region CtrlSpace #region CtrlSpace
void CtrlSpace(string prog, params string[] expected) void CtrlSpace(string prog, params string[] expected)
{ {

5
src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs

@ -447,7 +447,8 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
return CreateMemberResolveResult(member); return CreateMemberResolveResult(member);
c = type.GetUnderlyingClass(); c = type.GetUnderlyingClass();
if (c != null) { if (c != null) {
List<IClass> innerClasses = c.InnerClasses; foreach (IClass baseClass in c.ClassInheritanceTree) {
List<IClass> innerClasses = baseClass.InnerClasses;
if (innerClasses != null) { if (innerClasses != null) {
foreach (IClass innerClass in innerClasses) { foreach (IClass innerClass in innerClasses) {
if (IsSameName(innerClass.Name, fieldReferenceExpression.FieldName)) { if (IsSameName(innerClass.Name, fieldReferenceExpression.FieldName)) {
@ -456,6 +457,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
} }
} }
} }
}
return ResolveMethod(type, fieldReferenceExpression.FieldName); return ResolveMethod(type, fieldReferenceExpression.FieldName);
} }
@ -1051,7 +1053,6 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver
members.Clear(); members.Clear();
IClass c = callingClass.DeclaringType; IClass c = callingClass.DeclaringType;
while (c != null) { while (c != null) {
result.Add(c);
t = c.DefaultReturnType; t = c.DefaultReturnType;
members.AddRange(t.GetMethods()); members.AddRange(t.GetMethods());
members.AddRange(t.GetFields()); members.AddRange(t.GetFields());

4
src/Main/Base/Project/Src/Dom/ResolveResult.cs

@ -430,7 +430,9 @@ namespace ICSharpCode.SharpDevelop.Dom
{ {
ArrayList ar = GetCompletionData(projectContent.Language, true); ArrayList ar = GetCompletionData(projectContent.Language, true);
if (resolvedClass != null) { if (resolvedClass != null) {
ar.AddRange(resolvedClass.InnerClasses); foreach (IClass baseClass in resolvedClass.ClassInheritanceTree) {
ar.AddRange(baseClass.InnerClasses);
}
} }
return ar; return ar;
} }

4
src/Main/Base/Project/Src/Services/ParserService/DefaultProjectContent.cs

@ -565,7 +565,8 @@ namespace ICSharpCode.Core
string outerName = typeName.Substring(0, lastIndex); string outerName = typeName.Substring(0, lastIndex);
IClass upperClass = GetClassInternal(outerName, typeParameterCount, language); IClass upperClass = GetClassInternal(outerName, typeParameterCount, language);
if (upperClass != null) { if (upperClass != null) {
List<IClass> innerClasses = upperClass.InnerClasses; foreach (IClass upperBaseClass in upperClass.ClassInheritanceTree) {
List<IClass> innerClasses = upperBaseClass.InnerClasses;
if (innerClasses != null) { if (innerClasses != null) {
string innerName = typeName.Substring(lastIndex + 1); string innerName = typeName.Substring(lastIndex + 1);
foreach (IClass innerClass in innerClasses) { foreach (IClass innerClass in innerClasses) {
@ -576,6 +577,7 @@ namespace ICSharpCode.Core
} }
} }
} }
}
return null; return null;
} }

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

@ -177,6 +177,13 @@ namespace ICSharpCode.Core
return project.Items.Count; return project.Items.Count;
} }
internal void ReInitialize2()
{
if (initializing) return;
initializing = true;
Initialize2();
}
internal void Initialize2() internal void Initialize2()
{ {
if (!initializing) return; if (!initializing) return;

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

@ -182,10 +182,27 @@ namespace ICSharpCode.Core
{ {
ParseProjectContent newContent = (ParseProjectContent)state; ParseProjectContent newContent = (ParseProjectContent)state;
newContent.Initialize1(); newContent.Initialize1();
StatusBarService.ProgressMonitor.BeginTask("Parsing...", newContent.GetInitializationWorkAmount());
newContent.Initialize2(); newContent.Initialize2();
StatusBarService.ProgressMonitor.Done(); StatusBarService.ProgressMonitor.Done();
} }
static void ReparseProject(object state)
{
ParseProjectContent newContent = (ParseProjectContent)state;
StatusBarService.ProgressMonitor.BeginTask("Parsing...", newContent.GetInitializationWorkAmount());
newContent.ReInitialize2();
StatusBarService.ProgressMonitor.Done();
}
public static void Reparse(IProject project)
{
ParseProjectContent pc = GetProjectContent(project) as ParseProjectContent;
if (pc != null) {
ThreadPool.QueueUserWorkItem(ReparseProject, pc);
}
}
internal static IProjectContent CreateProjectContentForAddedProject(IProject project) internal static IProjectContent CreateProjectContentForAddedProject(IProject project)
{ {
lock (projectContents) { lock (projectContents) {
@ -198,9 +215,11 @@ namespace ICSharpCode.Core
public static IProjectContent GetProjectContent(IProject project) public static IProjectContent GetProjectContent(IProject project)
{ {
lock (projectContents) {
if (projectContents.ContainsKey(project)) { if (projectContents.ContainsKey(project)) {
return projectContents[project]; return projectContents[project];
} }
}
return null; return null;
} }

15
src/Main/Base/Test/InnerClassesResolverTests.cs

@ -106,6 +106,21 @@ class C : A {
ResolveResult result = Resolve(program, "B", 6); ResolveResult result = Resolve(program, "B", 6);
Assert.IsTrue(result is TypeResolveResult); Assert.IsTrue(result is TypeResolveResult);
Assert.AreEqual("A.B", result.ResolvedType.FullyQualifiedName); Assert.AreEqual("A.B", result.ResolvedType.FullyQualifiedName);
result = Resolve(program, "C.B", 6);
Assert.IsTrue(result is TypeResolveResult);
Assert.AreEqual("A.B", result.ResolvedType.FullyQualifiedName);
result = Resolve(program, "C", 6);
Assert.IsTrue(result is TypeResolveResult);
Assert.AreEqual("C", result.ResolvedType.FullyQualifiedName);
foreach (object o in result.GetCompletionData(nrrt.lastPC)) {
if (o is IClass) {
Assert.AreEqual("A.B", ((IClass)o).FullyQualifiedName);
return;
}
}
Assert.Fail("Inherited inner class not visible.");
} }
} }
} }

Loading…
Cancel
Save