From d992e73b07ca8f6377efca552874b2eb0088e171 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 11 Aug 2005 10:16:12 +0000 Subject: [PATCH] Fixed two small code completion bugs: - code completion does not show members of base class when some interface of the class does not exist - when referenced assemblies had inter-dependencies (Assembly A depends on B), code completion on properties in A that used a type in B would not work. ReflectionParameter: Read "ref/out/params" modifier correctly. ReflectionProjectContent: Use ReflectionLoad also for GAC assemblies specified by partial name. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@348 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../VBNetBinding/Project/Src/VBNetAmbience.cs | 9 ++- .../Project/ICSharpCode.SharpDevelop.csproj | 2 +- src/Main/Base/Project/Src/Dom/IParameter.cs | 4 + .../Src/Dom/Implementations/DefaultClass.cs | 47 ++++++------ .../Dom/Implementations/DefaultParameter.cs | 7 +- .../NRefactoryASTConvertVisitor.cs | 2 +- .../NRefactoryResolver/NRefactoryResolver.cs | 40 ++++++---- .../ReflectionLayer/ReflectionParameter.cs | 23 ++++-- .../ReflectionLayer/ReflectionReturnType.cs | 5 ++ .../ParserService/ParseProjectContent.cs | 22 ++++-- .../Services/ParserService/ParserService.cs | 2 + .../ParserService/ProjectContentRegistry.cs | 75 +++++++++++-------- .../ParserService/ReflectionProjectContent.cs | 20 ++++- .../CodeCompletionDataProvider.cs | 7 +- 14 files changed, 169 insertions(+), 96 deletions(-) diff --git a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetAmbience.cs b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetAmbience.cs index fec1f9859f..2f1944be5c 100644 --- a/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetAmbience.cs +++ b/src/AddIns/BackendBindings/VBNetBinding/Project/Src/VBNetAmbience.cs @@ -564,12 +564,13 @@ namespace VBNetBinding builder.Append(""); } + if (param.IsOptional) { + builder.Append("Optional "); + } if (param.IsRef || param.IsOut) { builder.Append("ByRef "); } else if (param.IsParams) { - builder.Append("ByVal ParamArray "); - } else { - builder.Append("ByVal "); + builder.Append("ParamArray "); } if (IncludeHTMLMarkup) { builder.Append(""); @@ -581,7 +582,7 @@ namespace VBNetBinding } builder.Append(Convert(param.ReturnType)); - + return builder.ToString(); } diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index f51d575af4..35c681b5f3 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -183,7 +183,7 @@ UserControl - Form + UserControl diff --git a/src/Main/Base/Project/Src/Dom/IParameter.cs b/src/Main/Base/Project/Src/Dom/IParameter.cs index 5a5c76cca6..5a476210b6 100644 --- a/src/Main/Base/Project/Src/Dom/IParameter.cs +++ b/src/Main/Base/Project/Src/Dom/IParameter.cs @@ -50,5 +50,9 @@ namespace ICSharpCode.SharpDevelop.Dom bool IsParams { get; } + + bool IsOptional { + get; + } } } diff --git a/src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs b/src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs index 0b5c191703..c200a6d464 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/DefaultClass.cs @@ -230,25 +230,28 @@ namespace ICSharpCode.SharpDevelop.Dom Queue typesToVisit = new Queue(); bool enqueuedLastBaseType = false; IClass currentClass = this; + IReturnType nextType; do { - if (!visitedList.Contains(currentClass)) { - visitedList.Add(currentClass); - foreach (IReturnType type in currentClass.BaseTypes) { - typesToVisit.Enqueue(type); + if (currentClass != null) { + if (!visitedList.Contains(currentClass)) { + visitedList.Add(currentClass); + foreach (IReturnType type in currentClass.BaseTypes) { + typesToVisit.Enqueue(type); + } } } - IReturnType nextType; if (typesToVisit.Count > 0) { nextType = typesToVisit.Dequeue(); } else { nextType = enqueuedLastBaseType ? null : GetBaseTypeByClassType(); enqueuedLastBaseType = true; } - currentClass = (nextType != null) ? nextType.GetUnderlyingClass() : null; - } while (currentClass != null); + if (nextType != null) { + currentClass = nextType.GetUnderlyingClass(); + } + } while (nextType != null); if (UseInheritanceCache) inheritanceTreeCache = visitedList; - currentClass = ReflectionReturnType.Object.GetUnderlyingClass(); return visitedList; } } @@ -279,20 +282,20 @@ namespace ICSharpCode.SharpDevelop.Dom IReturnType GetBaseTypeByClassType() { - switch (ClassType) { - case ClassType.Class: - if (FullyQualifiedName != "System.Object") { - return ReflectionReturnType.Object; - } - break; - case ClassType.Enum: - return ProjectContentRegistry.Mscorlib.GetClass("System.Enum").DefaultReturnType; - case ClassType.Delegate: - return ProjectContentRegistry.Mscorlib.GetClass("System.Delegate").DefaultReturnType; - case ClassType.Struct: - return ProjectContentRegistry.Mscorlib.GetClass("System.ValueType").DefaultReturnType; - } - return null; + switch (ClassType) { + case ClassType.Class: + if (FullyQualifiedName != "System.Object") { + return ReflectionReturnType.Object; + } + break; + case ClassType.Enum: + return ProjectContentRegistry.Mscorlib.GetClass("System.Enum").DefaultReturnType; + case ClassType.Delegate: + return ProjectContentRegistry.Mscorlib.GetClass("System.Delegate").DefaultReturnType; + case ClassType.Struct: + return ProjectContentRegistry.Mscorlib.GetClass("System.ValueType").DefaultReturnType; + } + return null; } public IClass BaseClass { diff --git a/src/Main/Base/Project/Src/Dom/Implementations/DefaultParameter.cs b/src/Main/Base/Project/Src/Dom/Implementations/DefaultParameter.cs index cb4d3bce72..37c2007a6b 100644 --- a/src/Main/Base/Project/Src/Dom/Implementations/DefaultParameter.cs +++ b/src/Main/Base/Project/Src/Dom/Implementations/DefaultParameter.cs @@ -64,7 +64,12 @@ namespace ICSharpCode.SharpDevelop.Dom return (modifier & ParameterModifiers.Params) == ParameterModifiers.Params; } } - + public bool IsOptional { + get { + return (modifier & ParameterModifiers.Optional) == ParameterModifiers.Optional; + } + } + public virtual string Name { get { return name; diff --git a/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryASTConvertVisitor.cs b/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryASTConvertVisitor.cs index 7960bbfd7b..f196576839 100644 --- a/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryASTConvertVisitor.cs +++ b/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryASTConvertVisitor.cs @@ -285,7 +285,7 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver } currentClass.Push(c); - if (typeDeclaration.BaseTypes != null) { + if (c.ClassType != ClassType.Enum && typeDeclaration.BaseTypes != null) { foreach (AST.TypeReference type in typeDeclaration.BaseTypes) { c.BaseTypes.Add(CreateReturnType(type)); } diff --git a/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs b/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs index b181009268..37710c3fff 100644 --- a/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs +++ b/src/Main/Base/Project/Src/Dom/NRefactoryResolver/NRefactoryResolver.cs @@ -101,16 +101,16 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver Expression ParseExpression(string expression) { - using (ICSharpCode.NRefactory.Parser.IParser p = ParserFactory.CreateParser(language, new System.IO.StringReader(expression))) { - return p.ParseExpression(); + Expression expr = SpecialConstructs(expression); + if (expr == null) { + using (ICSharpCode.NRefactory.Parser.IParser p = ParserFactory.CreateParser(language, new System.IO.StringReader(expression))) { + expr = p.ParseExpression(); + } } + return expr; } - public ResolveResult Resolve(ExpressionResult expressionResult, - int caretLineNumber, - int caretColumn, - string fileName, - string fileContent) + string GetFixedExpression(ExpressionResult expressionResult) { string expression = expressionResult.Expression; if (expression == null) { @@ -121,6 +121,16 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver if (expressionResult.Context.IsObjectCreation) { expression = "new " + expression; } + return expression; + } + + public ResolveResult Resolve(ExpressionResult expressionResult, + int caretLineNumber, + int caretColumn, + string fileName, + string fileContent) + { + string expression = GetFixedExpression(expressionResult); this.caretLine = caretLineNumber; this.caretColumn = caretColumn; @@ -147,12 +157,9 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver } } if (expr == null) { - expr = SpecialConstructs(expression); + expr = ParseExpression(expression); if (expr == null) { - expr = ParseExpression(expression); - if (expr == null) { - return null; - } + return null; } } @@ -160,6 +167,13 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver return ResolveAttribute(expr); } + RunLookupTableVisitor(fileContent); + + return ResolveInternal(expr, expressionResult.Context); + } + + void RunLookupTableVisitor(string fileContent) + { lookupTableVisitor = new LookupTableVisitor(languageProperties.NameComparer); callingMember = GetCurrentMember(); @@ -171,8 +185,6 @@ namespace ICSharpCode.SharpDevelop.Dom.NRefactoryResolver lookupTableVisitor.Visit(p.CompilationUnit, null); } } - - return ResolveInternal(expr, expressionResult.Context); } string GetAttributeName(Expression expr) diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionParameter.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionParameter.cs index 453dd9482f..6577c1b46e 100644 --- a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionParameter.cs +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionParameter.cs @@ -31,18 +31,25 @@ namespace ICSharpCode.SharpDevelop.Dom this.parameterInfo = parameterInfo; this.member = member; + Type type = parameterInfo.ParameterType; + if (parameterInfo.IsOut) { modifier = ParameterModifiers.Out; + } else if (type.Name.EndsWith("&")) { + // seems there is no other way to determine a ref parameter + modifier = ParameterModifiers.Ref; } - Type type = parameterInfo.ParameterType; - // TODO read param attribute - //if (type.IsArray && type != typeof(Array) && Attribute.IsDefined(parameterInfo, typeof(ParamArrayAttribute), true)) { - // modifier |= ParameterModifier.Params; - //} - // seems there is no other way to determine a ref parameter - if (type.Name.EndsWith("&")) { - modifier |= ParameterModifiers.Ref; + if (parameterInfo.IsOptional) { + modifier |= ParameterModifiers.Optional; + } + if (type.IsArray && type != typeof(Array)) { + foreach (CustomAttributeData data in CustomAttributeData.GetCustomAttributes(parameterInfo)) { + if (data.Constructor.DeclaringType.FullName == typeof(ParamArrayAttribute).FullName) { + modifier |= ParameterModifiers.Params; + break; + } + } } } } diff --git a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionReturnType.cs b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionReturnType.cs index 3302a8f2d2..3a45e94048 100644 --- a/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionReturnType.cs +++ b/src/Main/Base/Project/Src/Dom/ReflectionLayer/ReflectionReturnType.cs @@ -116,6 +116,11 @@ namespace ICSharpCode.SharpDevelop.Dom string name = type.FullName; if (name == null) return null; + if (name.Length > 1) { + if (name[name.Length - 1] == '&') { + name = name.Substring(0, name.Length - 1); + } + } if (name.Length > 2) { if (name[name.Length - 2] == '`') { name = name.Substring(0, name.Length - 2); diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs index eed946f3f0..d7122184be 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParseProjectContent.cs @@ -59,23 +59,33 @@ namespace ICSharpCode.Core switch (item.ItemType) { case ItemType.Reference: case ItemType.ProjectReference: - AddReference(item as ReferenceProjectItem); + AddReference(item as ReferenceProjectItem, false); break; } } + UpdateReferenceInterDependencies(); } - delegate void AddReferenceDelegate(ReferenceProjectItem reference); + void UpdateReferenceInterDependencies() + { + foreach (IProjectContent referencedContent in this.ReferencedContents) { + if (referencedContent is ReflectionProjectContent) { + ((ReflectionProjectContent)referencedContent).InitializeReferences(); + } + } + } + + delegate void AddReferenceDelegate(ReferenceProjectItem reference, bool updateInterDependencies); - void AddReference(ReferenceProjectItem reference) + void AddReference(ReferenceProjectItem reference, bool updateInterDependencies) { try { IProjectContent referencedContent = ProjectContentRegistry.GetProjectContentForReference(reference); if (referencedContent != null) { ReferencedContents.Add(referencedContent); } - if (referencedContent is ReflectionProjectContent) { - ((ReflectionProjectContent)referencedContent).InitializeReferences(); + if (updateInterDependencies) { + UpdateReferenceInterDependencies(); } } catch (Exception e) { MessageService.ShowError(e); @@ -87,7 +97,7 @@ namespace ICSharpCode.Core if (e.Project != project) return; ReferenceProjectItem reference = e.ProjectItem as ReferenceProjectItem; if (reference != null) { - new AddReferenceDelegate(AddReference).BeginInvoke(reference, null, null); + new AddReferenceDelegate(AddReference).BeginInvoke(reference, true, null, null); } if (e.ProjectItem.ItemType == ItemType.Import) { UpdateDefaultImports(project.Items.ToArray()); diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index b4b6b87149..a4d41c2d44 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -181,6 +181,7 @@ namespace ICSharpCode.Core static void ParserUpdateThread() { + LoggingService.Info("ParserUpdateThread started"); // preload mscorlib, we're going to need it anyway IProjectContent dummyVar = ProjectContentRegistry.Mscorlib; @@ -196,6 +197,7 @@ namespace ICSharpCode.Core } Thread.Sleep(2000); } + LoggingService.Info("ParserUpdateThread stopped"); } static object[] GetWorkbench() diff --git a/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs b/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs index 473cc2cce8..6048b77d72 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ProjectContentRegistry.cs @@ -81,16 +81,19 @@ namespace ICSharpCode.Core return ParserService.GetProjectContent(((ProjectReferenceProjectItem)item).ReferencedProject); } lock (contents) { - if (contents.ContainsKey(item.FileName)) { - return contents[item.FileName]; + string itemInclude = item.Include; + string itemFileName = item.FileName; + if (contents.ContainsKey(itemFileName)) { + return contents[itemFileName]; } - if (contents.ContainsKey(item.Include)) { - return contents[item.Include]; + if (contents.ContainsKey(itemInclude)) { + return contents[itemInclude]; } - string shortName = item.Include; - LoggingService.Debug("Loading PC for " + shortName); + LoggingService.Debug("Loading PC for " + itemInclude); + + string shortName = itemInclude; int pos = shortName.IndexOf(','); if (pos > 0) shortName = shortName.Substring(0, pos); @@ -101,47 +104,46 @@ namespace ICSharpCode.Core string how = "??"; #endif Assembly assembly = GetDefaultAssembly(shortName); + if (assembly != null) { + contents[item.Include] = new ReflectionProjectContent(assembly); + #if DEBUG + how = "typeof"; + #endif + return contents[itemInclude]; + } + lookupDirectory = Path.GetDirectoryName(itemFileName); + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += AssemblyResolve; try { + assembly = Assembly.ReflectionOnlyLoadFrom(itemFileName); if (assembly != null) { - contents[item.Include] = new ReflectionProjectContent(assembly); + contents[itemFileName] = new ReflectionProjectContent(assembly); + contents[assembly.FullName] = contents[itemFileName]; #if DEBUG - how = "typeof"; + how = "ReflectionOnly"; #endif - return contents[item.Include]; - } - lookupDirectory = Path.GetDirectoryName(item.FileName); - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += AssemblyResolve; - try { - assembly = Assembly.ReflectionOnlyLoadFrom(item.FileName); - if (assembly != null) { - contents[item.FileName] = new ReflectionProjectContent(assembly); - #if DEBUG - how = "ReflectionOnly"; - #endif - return contents[item.FileName]; - } - } finally { - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= AssemblyResolve; - lookupDirectory = null; + return contents[itemFileName]; } } catch (FileNotFoundException) { try { - assembly = LoadGACAssembly(item.Include, true); + assembly = LoadGACAssembly(itemInclude, true); if (assembly != null) { - contents[item.Include] = new ReflectionProjectContent(assembly); + contents[itemInclude] = new ReflectionProjectContent(assembly); + contents[assembly.FullName] = contents[itemInclude]; #if DEBUG how = "PartialName"; #endif - return contents[item.Include]; + return contents[itemInclude]; } } catch (Exception e) { - LoggingService.Debug("Can't load assembly '" + item.Include + "' : " + e.Message); + LoggingService.Debug("Can't load assembly '" + itemInclude + "' : " + e.Message); } } catch (BadImageFormatException) { - LoggingService.Warn("BadImageFormat: " + shortName); + LoggingService.Warn("BadImageFormat: " + itemInclude); } finally { + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= AssemblyResolve; + lookupDirectory = null; #if DEBUG - LoggingService.DebugFormatted("Loaded {0} with {2} in {1}ms", item.Include, Environment.TickCount - time, how); + LoggingService.DebugFormatted("Loaded {0} with {2} in {1}ms", itemInclude, Environment.TickCount - time, how); #endif StatusBarService.ProgressMonitor.Done(); } @@ -279,9 +281,16 @@ namespace ICSharpCode.Core public static Assembly LoadGACAssembly(string partialName, bool reflectionOnly) { - #pragma warning disable 618 - return Assembly.LoadWithPartialName(partialName); - #pragma warning restore 618 + if (reflectionOnly) { + AssemblyName name = FindBestMatchingAssemblyName(partialName); + if (name == null) + return null; + return Assembly.ReflectionOnlyLoad(name.FullName); + } else { + #pragma warning disable 618 + return Assembly.LoadWithPartialName(partialName); + #pragma warning restore 618 + } } } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ReflectionProjectContent.cs b/src/Main/Base/Project/Src/Services/ParserService/ReflectionProjectContent.cs index 0fad806706..bc5cbf1a82 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ReflectionProjectContent.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ReflectionProjectContent.cs @@ -57,15 +57,33 @@ namespace ICSharpCode.Core } bool initialized = false; + ArrayList missingNames; public void InitializeReferences() { - if (initialized) return; + if (initialized) { + if (missingNames != null) { + for (int i = 0; i < missingNames.Count; i++) { + IProjectContent content = ProjectContentRegistry.GetExistingProjectContent((AssemblyName)missingNames[i]); + if (content != null) { + ReferencedContents.Add(content); + missingNames.RemoveAt(i--); + } + } + if (missingNames.Count == 0) + missingNames = null; + } + return; + } initialized = true; foreach (AssemblyName name in assembly.GetReferencedAssemblies()) { IProjectContent content = ProjectContentRegistry.GetExistingProjectContent(name); if (content != null) { ReferencedContents.Add(content); + } else { + if (missingNames == null) + missingNames = new ArrayList(); + missingNames.Add(name); } } } diff --git a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CodeCompletionDataProvider.cs b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CodeCompletionDataProvider.cs index 5df4b39a96..1310760040 100644 --- a/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CodeCompletionDataProvider.cs +++ b/src/Main/Base/Project/Src/TextEditor/Gui/Editor/CompletionWindow/CodeCompletionDataProvider.cs @@ -42,16 +42,13 @@ namespace ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor else LoggingService.DebugFormatted("GenerateCompletionData for >>{0}<<, context={1}", expressionResult.Expression, expressionResult.Context); } + string textContent = textArea.Document.TextContent; #if DEBUG if (DebugMode) { Debugger.Break(); } #endif - AddResolveResults(ParserService.Resolve(expressionResult, - caretLineNumber, - caretColumn, - fileName, - textArea.Document.TextContent), + AddResolveResults(ParserService.Resolve(expressionResult, caretLineNumber, caretColumn, fileName, textContent), expressionResult.Context); } }