diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs index 2044291750..640e829325 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpCompletionBinding.cs @@ -261,10 +261,10 @@ namespace CSharpBinding new ClassFinder(ParserService.GetParseInformation(editor.FileName), editor.Caret.Line, editor.Caret.Column) ), ""); if (suggestedClassName != c.Name) { - // create an IClass instance that includes the type arguments in its name - context.SuggestedItem = new RenamedClass(c, suggestedClassName); + // create a special code completion item that completes also the type arguments + context.SuggestedItem = new SuggestedCodeCompletionItem(c, suggestedClassName); } else { - context.SuggestedItem = c; + context.SuggestedItem = new CodeCompletionItem(c); } } return context; @@ -273,27 +273,6 @@ namespace CSharpBinding return null; } - /// - /// A class that copies the properties important for the code completion display from another class, - /// but provides its own Name implementation. - /// Unlike the AbstractEntity.Name implementation, here 'Name' may include the namespace or type arguments. - /// - sealed class RenamedClass : DefaultClass, IClass - { - string newName; - - public RenamedClass(IClass c, string newName) : base(c.CompilationUnit, c.ClassType, c.Modifiers, c.Region, c.DeclaringType) - { - this.newName = newName; - CopyDocumentationFrom(c); - this.FullyQualifiedName = c.FullyQualifiedName; - } - - string ICompletionEntry.Name { - get { return newName; } - } - } - #region "case"-keyword completion bool DoCaseCompletion(ITextEditor editor) { diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 3187c651ff..b3a88d759e 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -351,6 +351,7 @@ Code + @@ -362,7 +363,6 @@ - diff --git a/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs b/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs index c91bf39aa3..0d7930e8dd 100644 --- a/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs +++ b/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs @@ -154,18 +154,13 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion if (method != null && codeItem != null) { methodItems[method.Name] = codeItem; } - if (o.Equals(context.SuggestedItem)) - result.SuggestedItem = item; } } - if (context.SuggestedItem != null) { - if (result.SuggestedItem == null) { - result.SuggestedItem = CreateCompletionItem(context.SuggestedItem, context); - if (result.SuggestedItem != null) { - result.Items.Insert(0, result.SuggestedItem); - } - } + // Suggested entry (List a = new => suggest List). + if (context.SuggestedItem is SuggestedCodeCompletionItem) { + result.SuggestedItem = (SuggestedCodeCompletionItem)context.SuggestedItem; + result.Items.Insert(0, result.SuggestedItem); } return result; } @@ -238,6 +233,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion description = ambience.Convert(entity); this.Image = ClassBrowserIconService.GetIcon(entity); this.Overloads = 1; + this.InsertGenericArguments = false; this.Priority = CodeCompletionDataUsageCache.GetPriority(entity.DotNetName, true); } @@ -252,6 +248,12 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion public IImage Image { get; set; } + /// + /// If true, will insert Text including generic arguments (e.g. List<T> or List<string>). + /// Otherwise will insert Text without generic arguments (e.g. List). + /// + public bool InsertGenericArguments { get; set; } + protected void MarkAsUsed() { CodeCompletionDataUsageCache.IncrementUsage(entity.DotNetName); @@ -288,8 +290,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion addUsing = !IsKnownName(nameResult); } - //insertedText = StripGenericArgument(insertedText, context); - InsertText(context, insertedText); + InsertTextStripGenericArguments(context, insertedText, this.InsertGenericArguments); if (addUsing && nameResult != null && nameResult.CallingClass != null) { var cu = nameResult.CallingClass.CompilationUnit; @@ -298,15 +299,28 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion } } else { // Something else than a class or Extension method is being inserted - just insert text - //insertedText = StripGenericArgument(insertedText, context); - InsertText(context, insertedText); + InsertTextStripGenericArguments(context, insertedText, this.InsertGenericArguments); + } + } + + /// + /// Inserts the given text. Strips generic arguments from it if specified. + /// + static void InsertTextStripGenericArguments(CompletionContext context, string insertedText, bool stringGenericArguments) + { + if (!stringGenericArguments) { + // FIXME CodeCompletionItem should contain IReturnType and decide whether to INCLUDE generic arguments + // or not, not strip them. + insertedText = StripGenericArguments(insertedText, context); } + context.Editor.Document.Replace(context.StartOffset, context.Length, insertedText); + context.EndOffset = context.StartOffset + insertedText.Length; } /// /// Turns e.g. "List<T>" into "List<" /// - string StripGenericArgument(string itemText, CompletionContext context) + static string StripGenericArguments(string itemText, CompletionContext context) { if (context == null || context.Editor == null || context.Editor.Language == null || context.Editor.Language.Properties != LanguageProperties.CSharp) @@ -325,23 +339,6 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion return itemText; } - bool IsReferenceTo(ResolveResult nameResult, IClass selectedClass) - { - // CC list contains RenamedClass instances which are kind of hacky: - // their name is e.g. "List" or "int[]", but they do not have any generic arguments, - // so IsReferenceTo fails bc it compares generic argument count. - // This compares just name and ignores generic arguments. - return nameResult.IsReferenceTo(selectedClass) || - (nameResult.ResolvedType.IsConstructedReturnType && - nameResult.ResolvedType.FullyQualifiedName == selectedClass.FullyQualifiedName); - } - - void InsertText(CompletionContext context, string insertedText) - { - context.Editor.Document.Replace(context.StartOffset, context.Length, insertedText); - context.EndOffset = context.StartOffset + insertedText.Length; - } - IClass GetClassOrExtensionMethodClass(IEntity selectedEntity) { var selectedClass = selectedEntity as IClass; @@ -514,4 +511,18 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion } #endregion } + + /// + /// CodeCompletionItem that inserts also generic arguments. + /// Used only when suggesting items in CC (e.g. List<int> a = new => suggest List<int>). + /// + public class SuggestedCodeCompletionItem : CodeCompletionItem + { + public SuggestedCodeCompletionItem(IEntity entity, string nameWithSpecifiedGenericArguments) + : base(entity) + { + this.Text = nameWithSpecifiedGenericArguments; + this.InsertGenericArguments = true; + } + } } diff --git a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs index a172c0f72d..433a9ab7b8 100644 --- a/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs +++ b/src/Main/Base/Project/Src/Services/ParserService/ParserService.cs @@ -276,6 +276,12 @@ namespace ICSharpCode.SharpDevelop return null; } + public static ResolveResult Resolve(int offset, IDocument document, string fileName) + { + var position = document.OffsetToPosition(offset); + return Resolve(position.Line, position.Column, document, fileName); + } + public static ExpressionResult FindFullExpression(int caretLine, int caretColumn, IDocument document, string fileName) { IExpressionFinder expressionFinder = GetExpressionFinder(fileName); @@ -285,12 +291,6 @@ namespace ICSharpCode.SharpDevelop return ExpressionResult.Empty; return expressionFinder.FindFullExpression(document.Text, document.PositionToOffset(caretLine, caretColumn)); } - - public static ResolveResult Resolve(int offset, IDocument document, string fileName) - { - var position = document.OffsetToPosition(offset); - return Resolve(position.Line, position.Column, document, fileName); - } #endregion #region GetParseableFileContent diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActionsHelper.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHelper.cs similarity index 100% rename from src/Main/Base/Project/Src/Services/RefactoringService/ContextActionsHelper.cs rename to src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionsHelper.cs diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs index 3a570c0f01..b96b6d51d3 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs @@ -181,11 +181,12 @@ namespace ICSharpCode.SharpDevelop.Refactoring ---------------------- CurrentLineAST: {2} ---------------------- - AstNodeAtCaret: {3} + CurrentASTNode: [{3}] {4} ---------------------- - CurrentMemberAST: {4} + CurrentMemberAST: {5} ----------------------", CurrentExpression, CurrentSymbol, CurrentLineAST, + CurrentElement == null ? "" : CurrentElement.GetType().ToString(), CurrentElement == null ? "" : CurrentElement.ToString().TakeStartEllipsis(400), CurrentMemberAST == null ? "" : CurrentMemberAST.ToString().TakeStartEllipsis(400))); }