diff options
Diffstat (limited to 'main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CSharpCompletionTextEditorExtension.cs')
-rw-r--r-- | main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CSharpCompletionTextEditorExtension.cs | 1229 |
1 files changed, 393 insertions, 836 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CSharpCompletionTextEditorExtension.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CSharpCompletionTextEditorExtension.cs index 6e1134678f..2374acb902 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CSharpCompletionTextEditorExtension.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Completion/CSharpCompletionTextEditorExtension.cs @@ -26,45 +26,39 @@ using System; using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; using System.Collections.Generic; -using Mono.TextEditor; - using MonoDevelop.Core; using MonoDevelop.Debugger; -using MonoDevelop.Projects; using MonoDevelop.Ide.Gui; using MonoDevelop.CodeGeneration; -using MonoDevelop.Ide.TypeSystem; using MonoDevelop.Ide.Gui.Content; -using MonoDevelop.Ide.CodeTemplates; using MonoDevelop.Ide.CodeCompletion; using MonoDevelop.Components.Commands; -using ICSharpCode.NRefactory; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.Semantics; -using ICSharpCode.NRefactory.Completion; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.CSharp.Resolver; -using ICSharpCode.NRefactory.CSharp.Completion; -using ICSharpCode.NRefactory.CSharp.TypeSystem; -using ICSharpCode.NRefactory.CSharp.Refactoring; - -using MonoDevelop.CSharp.Project; using MonoDevelop.CSharp.Formatting; -using MonoDevelop.CSharp.Refactoring.CodeActions; -using MonoDevelop.Refactoring; + +using ICSharpCode.NRefactory6.CSharp.Completion; +using MonoDevelop.Ide.TypeSystem; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +using MonoDevelop.Ide.Editor.Extension; +using MonoDevelop.Ide.Editor; +using System.Threading.Tasks; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp; using System.Xml; +using ICSharpCode.NRefactory6.CSharp; +using MonoDevelop.Refactoring; +using System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Syntax; namespace MonoDevelop.CSharp.Completion { - public class CSharpCompletionTextEditorExtension : CompletionTextEditorExtension, IParameterCompletionDataFactory, ITextEditorMemberPositionProvider, IDebuggerExpressionResolver + sealed class CSharpCompletionTextEditorExtension : CompletionTextEditorExtension, IDebuggerExpressionResolver { - internal protected virtual Mono.TextEditor.TextEditorData TextEditorData { +/* internal protected virtual Mono.TextEditor.TextEditorData TextEditorData { get { var doc = Document; if (doc == null) @@ -76,9 +70,10 @@ namespace MonoDevelop.CSharp.Completion protected virtual IProjectContent ProjectContent { get { return Document.GetProjectContext (); } } - +*/ SyntaxTree unit; - static readonly SyntaxTree emptyUnit = new SyntaxTree (); + static readonly SyntaxTree emptyUnit = CSharpSyntaxTree.ParseText (""); + SyntaxTree Unit { get { return unit ?? emptyUnit; @@ -87,36 +82,16 @@ namespace MonoDevelop.CSharp.Completion unit = value; } } - - public new MonoDevelop.Ide.Gui.Document Document { - get { - return base.document; - } - } - public ICompilation UnresolvedFileCompilation { - get; - set; - } - - public CSharpUnresolvedFile CSharpUnresolvedFile { - get; - set; - } - public ParsedDocument ParsedDocument { get { - return document.ParsedDocument; + return DocumentContext.ParsedDocument; } } - - public virtual ICompilation Compilation { - get { return Project != null ? TypeSystemService.GetCompilation (Project) : ProjectContent.CreateCompilation (); } - } - + public MonoDevelop.Projects.Project Project { get { - return document.Project; + return DocumentContext.Project; } } @@ -125,8 +100,8 @@ namespace MonoDevelop.CSharp.Completion get { if (policy == null) { IEnumerable<string> types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain (MonoDevelop.CSharp.Formatting.CSharpFormatter.MimeType); - if (Document.Project != null && Document.Project.Policies != null) { - policy = base.Document.Project.Policies.Get<CSharpFormattingPolicy> (types); + if (DocumentContext.Project != null && DocumentContext.Project.Policies != null) { + policy = base.DocumentContext.Project.Policies.Get<CSharpFormattingPolicy> (types); } else { policy = MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<CSharpFormattingPolicy> (types); } @@ -141,12 +116,38 @@ namespace MonoDevelop.CSharp.Completion } } - internal MDRefactoringContext MDRefactoringCtx { - get; - private set; + static Func<Microsoft.CodeAnalysis.Document, CancellationToken, Task<Microsoft.CodeAnalysis.Document>> WithFrozenPartialSemanticsAsync; + static List<ICompletionData> snippets; + + static CSharpCompletionTextEditorExtension () + { + var methodInfo = typeof(Microsoft.CodeAnalysis.Document).GetMethod ("WithFrozenPartialSemanticsAsync", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod); + if (methodInfo == null) + LoggingService.LogError ("Error in completion set up: Document.WithFrozenPartialSemanticsAsync not found!"); + + WithFrozenPartialSemanticsAsync = (doc, token) => (Task<Microsoft.CodeAnalysis.Document>)methodInfo.Invoke (doc, new object[] { token }); + + + CompletionEngine.SnippetCallback = delegate(CancellationToken arg) { + if (snippets != null) + return Task.FromResult ((IEnumerable<ICompletionData>)snippets); + var newSnippets = new List<ICompletionData> (); + foreach (var ct in MonoDevelop.Ide.CodeTemplates.CodeTemplateService.GetCodeTemplates ("text/x-csharp")) { + if (string.IsNullOrEmpty (ct.Shortcut) || ct.CodeTemplateContext != MonoDevelop.Ide.CodeTemplates.CodeTemplateContext.Standard) + continue; + newSnippets.Add (new RoslynCompletionData (null) { + CompletionText = ct.Shortcut, + DisplayText = ct.Shortcut, + Description = ct.Shortcut + Environment.NewLine + GettextCatalog.GetString (ct.Description), + Icon = ct.Icon + }); + } + snippets = newSnippets; + return Task.FromResult ((IEnumerable<ICompletionData>)newSnippets); + }; + } - public CSharpCompletionTextEditorExtension () { } @@ -160,23 +161,27 @@ namespace MonoDevelop.CSharp.Completion public CSharpCompletionTextEditorExtension (MonoDevelop.Ide.Gui.Document doc, bool addEventHandlersInInitialization = true) : this () { this.addEventHandlersInInitialization = addEventHandlersInInitialization; - Initialize (doc); + Initialize (doc.Editor, doc); } - public override void Initialize () + protected override void Initialize () { base.Initialize (); - var parsedDocument = document.ParsedDocument; +// DocumentContext.DocumentParsed += HandleDocumentParsed; + additionalContextHandlers = new [] { + new ProtocolMemberContextHandler (this) + }; + + var parsedDocument = DocumentContext.ParsedDocument; if (parsedDocument != null) { - this.Unit = parsedDocument.GetAst<SyntaxTree> (); - this.UnresolvedFileCompilation = Compilation; - this.CSharpUnresolvedFile = parsedDocument.ParsedFile as CSharpUnresolvedFile; - if (addEventHandlersInInitialization) - document.Editor.Caret.PositionChanged += HandlePositionChanged; +// this.Unit = parsedDocument.GetAst<SyntaxTree> (); +// this.UnresolvedFileCompilation = DocumentContext.Compilation; +// this.CSharpUnresolvedFile = parsedDocument.ParsedFile as CSharpUnresolvedFile; +// Editor.CaretPositionChanged += HandlePositionChanged; } - + if (addEventHandlersInInitialization) - Document.DocumentParsed += HandleDocumentParsed; + DocumentContext.DocumentParsed += HandleDocumentParsed; } CancellationTokenSource src = new CancellationTokenSource (); @@ -186,46 +191,26 @@ namespace MonoDevelop.CSharp.Completion src.Cancel (); src = new CancellationTokenSource (); } - - void HandlePositionChanged (object sender, DocumentLocationEventArgs e) - { - StopPositionChangedTask (); - var doc = Document; - if (doc == null || doc.Editor == null) - return; - MDRefactoringContext.Create (doc, doc.Editor.Caret.Location, src.Token).ContinueWith (t => { - MDRefactoringCtx = t.Result; - }, TaskContinuationOptions.ExecuteSynchronously); - } - + [CommandUpdateHandler (CodeGenerationCommands.ShowCodeGenerationWindow)] public void CheckShowCodeGenerationWindow (CommandInfo info) { - info.Enabled = TextEditorData != null && Document.GetContent<ICompletionWidget> () != null; + info.Enabled = Editor != null && DocumentContext.GetContent<ICompletionWidget> () != null; } [CommandHandler (CodeGenerationCommands.ShowCodeGenerationWindow)] public void ShowCodeGenerationWindow () { - var completionWidget = Document.GetContent<ICompletionWidget> (); + var completionWidget = DocumentContext.GetContent<ICompletionWidget> (); if (completionWidget == null) return; - CodeCompletionContext completionContext = completionWidget.CreateCodeCompletionContext (TextEditorData.Caret.Offset); - GenerateCodeWindow.ShowIfValid (Document, completionContext); + CodeCompletionContext completionContext = completionWidget.CreateCodeCompletionContext (Editor.CaretOffset); + GenerateCodeWindow.ShowIfValid (Editor, DocumentContext, completionContext); } public override void Dispose () { - StopPositionChangedTask (); - unit = null; - CSharpUnresolvedFile = null; - UnresolvedFileCompilation = null; - Document.DocumentParsed -= HandleDocumentParsed; - if (unstableTypeSystemSegmentTree != null) { - unstableTypeSystemSegmentTree.RemoveListener (); - unstableTypeSystemSegmentTree = null; - } - + DocumentContext.DocumentParsed -= HandleDocumentParsed; if (validTypeSystemSegmentTree != null) { validTypeSystemSegmentTree.RemoveListener (); validTypeSystemSegmentTree = null; @@ -236,30 +221,23 @@ namespace MonoDevelop.CSharp.Completion void HandleDocumentParsed (object sender, EventArgs e) { - var newDocument = Document.ParsedDocument; - if (newDocument == null) + var parsedDocument = DocumentContext.ParsedDocument; + if (parsedDocument == null) return; - var newTree = TypeSystemSegmentTree.Create (newDocument, TextEditorData); - - if (unstableTypeSystemSegmentTree != null) - unstableTypeSystemSegmentTree.RemoveListener (); - - if (!newDocument.HasErrors) { - if (validTypeSystemSegmentTree != null) - validTypeSystemSegmentTree.RemoveListener (); - validTypeSystemSegmentTree = newTree; - unstableTypeSystemSegmentTree = null; - } else { - unstableTypeSystemSegmentTree = newTree; - } - newTree.InstallListener (document.Editor.Document); + var semanticModel = parsedDocument.GetAst<SemanticModel> (); + if (semanticModel == null) + return; + var newTree = TypeSystemSegmentTree.Create (Editor, DocumentContext, semanticModel); + + if (validTypeSystemSegmentTree != null) + validTypeSystemSegmentTree.RemoveListener (); + validTypeSystemSegmentTree = newTree; + newTree.InstallListener (Editor); - this.Unit = newDocument.GetAst<SyntaxTree> (); - this.CSharpUnresolvedFile = newDocument.ParsedFile as CSharpUnresolvedFile; - this.UnresolvedFileCompilation = Compilation; if (TypeSegmentTreeUpdated != null) TypeSegmentTreeUpdated (this, EventArgs.Empty); } + public event EventHandler TypeSegmentTreeUpdated; public void UpdateParsedDocument () @@ -267,11 +245,11 @@ namespace MonoDevelop.CSharp.Completion HandleDocumentParsed (null, null); } - public override bool KeyPress (Gdk.Key key, char keyChar, Gdk.ModifierType modifier) + public override bool KeyPress (KeyDescriptor descriptor) { - bool result = base.KeyPress (key, keyChar, modifier); + bool result = base.KeyPress (descriptor); - if (/*EnableParameterInsight &&*/ (keyChar == ',' || keyChar == ')') && CanRunParameterCompletionCommand ()) + if (/*EnableParameterInsight &&*/ (descriptor.KeyChar == ',' || descriptor.KeyChar == ')') && CanRunParameterCompletionCommand ()) base.RunParameterCompletionCommand (); // if (IsInsideComment ()) @@ -279,7 +257,7 @@ namespace MonoDevelop.CSharp.Completion return result; } - public override ICompletionDataList HandleCodeCompletion (CodeCompletionContext completionContext, char completionChar, ref int triggerWordLength) + public override Task<ICompletionDataList> HandleCodeCompletionAsync (CodeCompletionContext completionContext, char completionChar, CancellationToken token = default(CancellationToken)) { // if (!EnableCodeCompletion) // return null; @@ -288,17 +266,18 @@ namespace MonoDevelop.CSharp.Completion // var timer = Counters.ResolveTime.BeginTiming (); try { + int triggerWordLength = 0; if (char.IsLetterOrDigit (completionChar) || completionChar == '_') { - if (completionContext.TriggerOffset > 1 && char.IsLetterOrDigit (TextEditorData.GetCharAt (completionContext.TriggerOffset - 2))) + if (completionContext.TriggerOffset > 1 && char.IsLetterOrDigit (Editor.GetCharAt (completionContext.TriggerOffset - 2))) return null; triggerWordLength = 1; } - return InternalHandleCodeCompletion (completionContext, completionChar, false, ref triggerWordLength); + return InternalHandleCodeCompletion (completionContext, completionChar, false, triggerWordLength, token); } catch (Exception e) { LoggingService.LogError ("Unexpected code completion exception." + Environment.NewLine + - "FileName: " + Document.FileName + Environment.NewLine + + "FileName: " + DocumentContext.Name + Environment.NewLine + "Position: line=" + completionContext.TriggerLine + " col=" + completionContext.TriggerLineOffset + Environment.NewLine + - "Line text: " + TextEditorData.GetLineText (completionContext.TriggerLine), + "Line text: " + Editor.GetLineText (completionContext.TriggerLine), e); return null; } finally { @@ -309,10 +288,6 @@ namespace MonoDevelop.CSharp.Completion class CSharpCompletionDataList : CompletionDataList { - public CSharpResolver Resolver { - get; - set; - } } interface IListData @@ -320,120 +295,147 @@ namespace MonoDevelop.CSharp.Completion CSharpCompletionDataList List { get; set; } } - ICompletionContextProvider CreateContextProvider () - { - return new CompletionContextProvider (document.ParsedDocument, TextEditorData, validTypeSystemSegmentTree, unstableTypeSystemSegmentTree); - } - CSharpTypeResolveContext CreateTypeResolveContext () + void AddImportCompletionData (CSharpCompletionDataList result, SemanticModel semanticModel, int position, CancellationToken cancellationToken = default(CancellationToken)) { - var compilation = UnresolvedFileCompilation; - if (compilation == null) - return null; - var rctx = new CSharpTypeResolveContext (compilation.MainAssembly); - var loc = TextEditorData.Caret.Location; - rctx = rctx.WithUsingScope (CSharpUnresolvedFile.GetUsingScope (loc).Resolve (compilation)); - int offset = TextEditorData.Caret.Offset; - var curDef = GetTypeAt (offset); - if (curDef != null) { - var resolvedDef = curDef.Resolve (rctx).GetDefinition (); - if (resolvedDef == null) - return rctx; - rctx = rctx.WithCurrentTypeDefinition (resolvedDef); - var foundMember = GetMemberAt (offset); - if (foundMember != null) { - var curMember = resolvedDef.Members.FirstOrDefault (m => m.Region.FileName == foundMember.Region.FileName && m.Region.Begin == foundMember.Region.Begin); - if (curMember != null) - rctx = rctx.WithCurrentMember (curMember); + if (result.Count == 0) + return; + var root = semanticModel.SyntaxTree.GetRoot (); + var node = root.FindNode (TextSpan.FromBounds (position, position)); + var syntaxTree = root.SyntaxTree; + + if (syntaxTree.IsInNonUserCode(position, cancellationToken) || + syntaxTree.IsRightOfDotOrArrowOrColonColon(position, cancellationToken) || + syntaxTree.GetContainingTypeOrEnumDeclaration(position, cancellationToken) is EnumDeclarationSyntax || + syntaxTree.IsPreProcessorDirectiveContext(position, cancellationToken)) + return; + + var tokenLeftOfPosition = syntaxTree.FindTokenOnLeftOfPosition (position, cancellationToken); + + if (syntaxTree.IsGlobalStatementContext (position, cancellationToken) || + syntaxTree.IsExpressionContext (position, tokenLeftOfPosition, true, cancellationToken) || + syntaxTree.IsStatementContext (position, tokenLeftOfPosition, cancellationToken) || + syntaxTree.IsTypeContext (position, cancellationToken) || + syntaxTree.IsTypeDeclarationContext (position, tokenLeftOfPosition, cancellationToken) || + syntaxTree.IsNamespaceContext (position, cancellationToken) || + syntaxTree.IsMemberDeclarationContext (position, tokenLeftOfPosition, cancellationToken) || + syntaxTree.IsLabelContext (position, cancellationToken)) { + var usedNamespaces = new HashSet<string> (); + foreach (var un in semanticModel.GetUsingNamespacesInScope (node)) { + usedNamespaces.Add (un.GetFullName ()); } - } + var enclosingNamespaceName = semanticModel.GetEnclosingNamespace (position, cancellationToken).GetFullName (); - return rctx; + var stack = new Stack<INamespaceOrTypeSymbol>(); + foreach (var member in semanticModel.Compilation.GlobalNamespace.GetNamespaceMembers ()) + stack.Push (member); + + while (stack.Count > 0) { + if (cancellationToken.IsCancellationRequested) + break; + var current = stack.Pop(); + var currentNs = current as INamespaceSymbol; + if (currentNs != null) { + var currentNsName = currentNs.GetFullName (); + if (usedNamespaces.Contains (currentNsName) || + enclosingNamespaceName == currentNsName || + (enclosingNamespaceName.StartsWith (currentNsName) && + enclosingNamespaceName [currentNsName.Length] == '.')) { + foreach (var member in currentNs.GetNamespaceMembers ()) + stack.Push (member); + } else { + foreach (var member in currentNs.GetMembers()) + stack.Push (member); + } + } else { + var type = (INamedTypeSymbol)current; + if (type.IsImplicitClass || type.IsScriptClass) + continue; + if (type.DeclaredAccessibility != Accessibility.Public) { + if (type.DeclaredAccessibility != Accessibility.Internal) + continue; + if (!type.IsAccessibleWithin (semanticModel.Compilation.Assembly)) + continue; + } + result.Add (new ImportSymbolCompletionData (this, type, false)); + } + } + } } - CompletionEngineCache cache = new CompletionEngineCache (); - ICompletionDataList InternalHandleCodeCompletion (CodeCompletionContext completionContext, char completionChar, bool ctrlSpace, ref int triggerWordLength) + + IEnumerable<CompletionContextHandler> additionalContextHandlers; + + Task<ICompletionDataList> InternalHandleCodeCompletion (CodeCompletionContext completionContext, char completionChar, bool ctrlSpace, int triggerWordLength, CancellationToken token) { - var data = TextEditorData; - if (data.CurrentMode is TextLinkEditMode) { - if (((TextLinkEditMode)data.CurrentMode).TextLinkMode == TextLinkMode.EditIdentifier) - return null; - } - if (Unit == null || CSharpUnresolvedFile == null) - return null; - if(unstableTypeSystemSegmentTree == null && validTypeSystemSegmentTree == null) + if (Editor.EditMode != MonoDevelop.Ide.Editor.EditMode.Edit) return null; +// var data = Editor; +// if (data.CurrentMode is TextLinkEditMode) { +// if (((TextLinkEditMode)data.CurrentMode).TextLinkMode == TextLinkMode.EditIdentifier) +// return null; +// } + var offset = Editor.CaretOffset; var list = new CSharpCompletionDataList (); - list.Resolver = CSharpUnresolvedFile != null ? CSharpUnresolvedFile.GetResolver (UnresolvedFileCompilation, TextEditorData.Caret.Location) : new CSharpResolver (Compilation); - var ctx = CreateTypeResolveContext (); - if (ctx == null) - return null; - var completionDataFactory = new CompletionDataFactory (this, new CSharpResolver (ctx)); - if (MDRefactoringCtx == null) { - src.Cancel (); - MDRefactoringCtx = MDRefactoringContext.Create (Document, TextEditorData.Caret.Location).Result; - } + list.TriggerWordLength = triggerWordLength; + try { + var analysisDocument = DocumentContext.AnalysisDocument; + if (analysisDocument == null) + return null; + + var partialDoc = WithFrozenPartialSemanticsAsync (analysisDocument, token).Result; + var semanticModel = partialDoc.GetSemanticModelAsync ().Result; + + var engine = new CompletionEngine (TypeSystemService.Workspace, new RoslynCodeCompletionFactory (this, semanticModel)); + var ctx = new ICSharpCode.NRefactory6.CSharp.CompletionContext (partialDoc, offset, semanticModel); + ctx.AdditionalContextHandlers = additionalContextHandlers; + var triggerInfo = new CompletionTriggerInfo (ctrlSpace ? CompletionTriggerReason.CompletionCommand : CompletionTriggerReason.CharTyped, completionChar); + var completionResult = engine.GetCompletionDataAsync (ctx, triggerInfo, token).Result; + if (completionResult == CompletionResult.Empty) + return null; - var engine = new MonoCSharpCompletionEngine ( - this, - data.Document, - CreateContextProvider (), - completionDataFactory, - ProjectContent, - ctx - ); - completionDataFactory.Engine = engine; - engine.AutomaticallyAddImports = AddImportedItemsToCompletionList.Value; - engine.IncludeKeywordsInCompletionList = EnableAutoCodeCompletion || IncludeKeywordsInCompletionList.Value; - engine.CompletionEngineCache = cache; - if (FilterCompletionListByEditorBrowsable) { - engine.EditorBrowsableBehavior = IncludeEditorBrowsableAdvancedMembers ? EditorBrowsableBehavior.IncludeAdvanced : EditorBrowsableBehavior.Normal; - } else { - engine.EditorBrowsableBehavior = EditorBrowsableBehavior.Ignore; - } - if (Document.HasProject && MonoDevelop.Ide.IdeApp.IsInitialized) { - var configuration = Document.Project.GetConfiguration (MonoDevelop.Ide.IdeApp.Workspace.ActiveConfiguration) as DotNetProjectConfiguration; - var par = configuration != null ? configuration.CompilationParameters as CSharpCompilerParameters : null; - if (par != null) - engine.LanguageVersion = MonoDevelop.CSharp.Parser.TypeSystemParser.ConvertLanguageVersion (par.LangVersion); - } + foreach (var symbol in completionResult) { + list.Add ((CompletionData)symbol); + } - engine.FormattingPolicy = FormattingPolicy.CreateOptions (); - engine.EolMarker = data.EolMarker; - engine.IndentString = data.Options.IndentationString; - try { - foreach (var cd in engine.GetCompletionData (completionContext.TriggerOffset, ctrlSpace)) { - list.Add (cd); - if (cd is IListData) - ((IListData)cd).List = list; + if (AddImportedItemsToCompletionList.Value && list.OfType<RoslynSymbolCompletionData> ().Any (cd => cd.Symbol is ITypeSymbol)) { + AddImportCompletionData (list, semanticModel, offset, token); } + + list.AutoCompleteEmptyMatch = completionResult.AutoCompleteEmptyMatch; + // list.AutoCompleteEmptyMatchOnCurlyBrace = completionResult.AutoCompleteEmptyMatchOnCurlyBracket; + list.AutoSelect = completionResult.AutoSelect; + list.DefaultCompletionString = completionResult.DefaultCompletionString; + // list.CloseOnSquareBrackets = completionResult.CloseOnSquareBrackets; + if (ctrlSpace) + list.AutoCompleteUniqueMatch = true; + } catch (OperationCanceledException) { + return null; + } catch (AggregateException e) { + foreach (var inner in e.Flatten ().InnerExceptions) + LoggingService.LogError ("Error while getting C# recommendations", inner); } catch (Exception e) { - LoggingService.LogError ("Error while getting completion data.", e); + LoggingService.LogError ("Error while getting C# recommendations", e); } - list.AutoCompleteEmptyMatch = engine.AutoCompleteEmptyMatch; - list.AutoCompleteEmptyMatchOnCurlyBrace = engine.AutoCompleteEmptyMatchOnCurlyBracket; - list.AutoSelect = engine.AutoSelect; - list.DefaultCompletionString = engine.DefaultCompletionString; - list.CloseOnSquareBrackets = engine.CloseOnSquareBrackets; - if (ctrlSpace) - list.AutoCompleteUniqueMatch = true; - return list.Count > 0 ? list : null; + return Task.FromResult ((ICompletionDataList)list); } public override ICompletionDataList CodeCompletionCommand (CodeCompletionContext completionContext) { int triggerWordLength = 0; - char ch = completionContext.TriggerOffset > 0 ? TextEditorData.GetCharAt (completionContext.TriggerOffset - 1) : '\0'; - return InternalHandleCodeCompletion (completionContext, ch, true, ref triggerWordLength); + char ch = completionContext.TriggerOffset > 0 ? Editor.GetCharAt (completionContext.TriggerOffset - 1) : '\0'; + return InternalHandleCodeCompletion (completionContext, ch, true, triggerWordLength, default(CancellationToken)).Result; } - static bool HasAllUsedParameters (IParameterDataProvider provider, List<string> list, int n) + static bool HasAllUsedParameters (MonoDevelop.Ide.CodeCompletion.ParameterHintingData provider, string[] list) { - int pc = provider.GetParameterCount (n); + if (provider == null || list == null) + return true; + int pc = provider.ParameterCount; foreach (var usedParam in list) { bool found = false; for (int m = 0; m < pc; m++) { - if (usedParam == provider.GetParameterName (n, m)){ + if (usedParam == provider.GetParameterName (m)){ found = true; break; } @@ -443,29 +445,24 @@ namespace MonoDevelop.CSharp.Completion } return true; } - public override int GuessBestMethodOverload (IParameterDataProvider provider, int currentOverload) + + public override int GuessBestMethodOverload (MonoDevelop.Ide.CodeCompletion.ParameterHintingResult provider, int currentOverload) { - var ctx = CreateTypeResolveContext (); - if (ctx == null) + var analysisDocument = DocumentContext.AnalysisDocument; + if (analysisDocument == null) return -1; - var engine = new CSharpParameterCompletionEngine ( - TextEditorData.Document, - CreateContextProvider (), - this, - ProjectContent, - ctx - ); - List<string> list; - int cparam = engine.GetCurrentParameterIndex (provider.StartOffset, TextEditorData.Caret.Offset, out list); - if (cparam > provider.GetParameterCount (currentOverload) && !provider.AllowParameterList (currentOverload) || !HasAllUsedParameters (provider, list, currentOverload)) { + var result = ICSharpCode.NRefactory6.CSharp.ParameterUtil.GetCurrentParameterIndex (analysisDocument, provider.StartOffset, Editor.CaretOffset).Result; + var cparam = result.ParameterIndex; + var list = result.UsedNamespaceParameters; + if (cparam > provider[currentOverload].ParameterCount && !provider[currentOverload].IsParameterListAllowed || !HasAllUsedParameters (provider[currentOverload], list)) { // Look for an overload which has more parameters int bestOverload = -1; int bestParamCount = int.MaxValue; for (int n = 0; n < provider.Count; n++) { - int pc = provider.GetParameterCount (n); + int pc = provider[n].ParameterCount; if (pc < bestParamCount && pc >= cparam) { - if (HasAllUsedParameters (provider, list, n)) { + if (HasAllUsedParameters (provider[n], list)) { bestOverload = n; bestParamCount = pc; } @@ -475,7 +472,7 @@ namespace MonoDevelop.CSharp.Completion } if (bestOverload == -1) { for (int n=0; n<provider.Count; n++) { - if (provider.AllowParameterList (n) && HasAllUsedParameters (provider, list, n)) { + if (provider[n].IsParameterListAllowed && HasAllUsedParameters (provider[n], list)) { bestOverload = n; break; } @@ -487,12 +484,12 @@ namespace MonoDevelop.CSharp.Completion } - static bool ContainsPublicConstructors (ITypeDefinition t) - { - if (t.Methods.Count (m => m.IsConstructor) == 0) - return true; - return t.Methods.Any (m => m.IsConstructor && m.IsPublic); - } +// static bool ContainsPublicConstructors (ITypeDefinition t) +// { +// if (t.Methods.Count (m => m.IsConstructor) == 0) +// return true; +// return t.Methods.Any (m => m.IsConstructor && m.IsPublic); +// } // CompletionDataList result = new ProjectDomCompletionDataList (); @@ -600,140 +597,66 @@ namespace MonoDevelop.CSharp.Completion // } // } - public override ParameterDataProvider HandleParameterCompletion (CodeCompletionContext completionContext, char completionChar) + + public override Task<MonoDevelop.Ide.CodeCompletion.ParameterHintingResult> HandleParameterCompletionAsync (CodeCompletionContext completionContext, char completionChar, CancellationToken token = default(CancellationToken)) { -// if (!EnableCodeCompletion) -// return null; - if (Unit == null || CSharpUnresolvedFile == null) + var data = Editor; + if (completionChar != '(' && completionChar != ',') return null; - var ctx = CreateTypeResolveContext (); - if (ctx == null) + if (Editor.EditMode != MonoDevelop.Ide.Editor.EditMode.Edit) return null; + var offset = Editor.CaretOffset; if (completionChar != '(' && completionChar != ',') return null; - try { - var engine = new CSharpParameterCompletionEngine ( - TextEditorData.Document, - CreateContextProvider (), - this, - ProjectContent, - ctx - ); - return engine.GetParameterDataProvider (completionContext.TriggerOffset, completionChar) as ParameterDataProvider; + + var analysisDocument = DocumentContext.AnalysisDocument; + if (analysisDocument == null) + return null; + var partialDoc = WithFrozenPartialSemanticsAsync (analysisDocument, token).Result; + var semanticModel = partialDoc.GetSemanticModelAsync ().Result; + var engine = new ParameterHintingEngine (TypeSystemService.Workspace, new RoslynParameterHintingFactory ()); + var result = engine.GetParameterDataProviderAsync (analysisDocument, semanticModel, offset, token).Result; + return Task.FromResult (new MonoDevelop.Ide.CodeCompletion.ParameterHintingResult (result.OfType<MonoDevelop.Ide.CodeCompletion.ParameterHintingData>().ToList (), result.StartOffset)); } catch (Exception e) { LoggingService.LogError ("Unexpected parameter completion exception." + Environment.NewLine + - "FileName: " + Document.FileName + Environment.NewLine + + "FileName: " + DocumentContext.Name + Environment.NewLine + "Position: line=" + completionContext.TriggerLine + " col=" + completionContext.TriggerLineOffset + Environment.NewLine + - "Line text: " + TextEditorData.GetLineText (completionContext.TriggerLine), + "Line text: " + Editor.GetLineText (completionContext.TriggerLine), e); - return null; - } finally { - // if (timer != null) - // timer.Dispose (); } + return null; } - List<string> GetUsedNamespaces () - { - var scope = CSharpUnresolvedFile.GetUsingScope (TextEditorData.Caret.Location); - var result = new List<string> (); - while (scope != null) { - result.Add (scope.NamespaceName); - var ctx = CSharpUnresolvedFile.GetResolver (Compilation, scope.Region.Begin); - foreach (var u in scope.Usings) { - var ns = u.ResolveNamespace (ctx); - if (ns == null) - continue; - result.Add (ns.FullName); - } - scope = scope.Parent; - } - return result; - } - - public override bool GetParameterCompletionCommandOffset (out int cpos) - { - var ctx = CreateTypeResolveContext (); - if (ctx == null) { - cpos = -1; - return false; - } - - var engine = new CSharpParameterCompletionEngine ( - TextEditorData.Document, - CreateContextProvider (), - this, - ProjectContent, - ctx - ); - engine.SetOffset (TextEditorData.Caret.Offset); - return engine.GetParameterCompletionCommandOffset (out cpos); - } +// List<string> GetUsedNamespaces () +// { +// var scope = CSharpUnresolvedFile.GetUsingScope (document.Editor.Caret.Location); +// var result = new List<string> (); +// while (scope != null) { +// result.Add (scope.NamespaceName); +// var ctx = CSharpUnresolvedFile.GetResolver (Document.Compilation, scope.Region.Begin); +// foreach (var u in scope.Usings) { +// var ns = u.ResolveNamespace (ctx); +// if (ns == null) +// continue; +// result.Add (ns.FullName); +// } +// scope = scope.Parent; +// } +// return result; +// } public override int GetCurrentParameterIndex (int startOffset) { - var ctx = CreateTypeResolveContext (); - if (ctx == null) + var analysisDocument = DocumentContext.AnalysisDocument; + if (analysisDocument == null) return -1; - - var engine = new CSharpParameterCompletionEngine ( - TextEditorData.Document, - CreateContextProvider (), - this, - ProjectContent, - ctx - ); - List<string> list; - return engine.GetCurrentParameterIndex (startOffset, TextEditorData.Caret.Offset, out list); + var result = ICSharpCode.NRefactory6.CSharp.ParameterUtil.GetCurrentParameterIndex (analysisDocument, startOffset, Editor.CaretOffset).Result; + return result.ParameterIndex; } - /* - internal int GetCurrentParameterIndex (ICompletionWidget widget, int offset, int memberStart) - { - int cursor = widget.CurrentCodeCompletionContext.TriggerOffset; - int i = offset; - if (i > cursor) - return -1; - if (i == cursor) - return 1; // parameters are 1 based - var types = MonoDevelop.Ide.DesktopService.GetMimeTypeInheritanceChain (CSharpFormatter.MimeType); - var engine = new CSharpIndentEngine (MonoDevelop.Projects.Policies.PolicyService.GetDefaultPolicy<CSharpFormattingPolicy> (types)); - int index = memberStart + 1; - int parentheses = 0; - int bracket = 0; - do { - char c = widget.GetChar (i - 1); - engine.Push (c); - switch (c) { - case '{': - if (!engine.IsInsideOrdinaryCommentOrString) - bracket++; - break; - case '}': - if (!engine.IsInsideOrdinaryCommentOrString) - bracket--; - break; - case '(': - if (!engine.IsInsideOrdinaryCommentOrString) - parentheses++; - break; - case ')': - if (!engine.IsInsideOrdinaryCommentOrString) - parentheses--; - break; - case ',': - if (!engine.IsInsideOrdinaryCommentOrString && parentheses == 1 && bracket == 0) - index++; - break; - } - i++; - } while (i <= cursor && parentheses >= 0); - - return parentheses != 1 || bracket > 0 ? -1 : index; - }*/ - +/* #region ICompletionDataFactory implementation internal class CompletionDataFactory : ICompletionDataFactory { @@ -801,12 +724,12 @@ namespace MonoDevelop.CSharp.Completion return tooltipFunc != null ? tooltipFunc (List, smartWrap) : new TooltipInformation (); } - protected List<ICompletionData> overloads; + protected List<ICSharpCode.NRefactory6.CSharp.Completion.ICompletionData> overloads; public override bool HasOverloads { get { return overloads != null && overloads.Count > 0; } } - public override IEnumerable<ICompletionData> OverloadedData { + public override IEnumerable<ICSharpCode.NRefactory6.CSharp.Completion.ICompletionData> OverloadedData { get { return overloads; } @@ -821,10 +744,10 @@ namespace MonoDevelop.CSharp.Completion overloads.Add (data); } - public override void InsertCompletionText (CompletionListWindow window, ref KeyActions ka, Gdk.Key closeChar, char keyChar, Gdk.ModifierType modifier) + public override void InsertCompletionText (CompletionListWindow window, ref KeyActions ka, KeyDescriptor descriptor) { var currentWord = GetCurrentWord (window); - if (CompletionText == "new()" && keyChar == '(') { + if (CompletionText == "new()" && descriptor.KeyChar == '(') { window.CompletionWidget.SetCompletionText (window.CodeCompletionContext, currentWord, "new"); } else { window.CompletionWidget.SetCompletionText (window.CodeCompletionContext, currentWord, CompletionText); @@ -879,7 +802,7 @@ namespace MonoDevelop.CSharp.Completion public override TooltipInformation CreateTooltipInformation (bool smartWrap) { var def = type.GetDefinition (); - var result = def != null ? MemberCompletionData.CreateTooltipInformation (compilation, file, List.Resolver, ext.TextEditorData, ext.FormattingPolicy, def, smartWrap) : new TooltipInformation (); + var result = def != null ? MemberCompletionData.CreateTooltipInformation (compilation, file, List.Resolver, ext.Editor, ext.FormattingPolicy, def, smartWrap) : new TooltipInformation (); if (ConflictingTypes != null) { var conflicts = new StringBuilder (); var sig = new SignatureMarkupCreator (List.Resolver, ext.FormattingPolicy.CreateOptions ()); @@ -1024,11 +947,11 @@ namespace MonoDevelop.CSharp.Completion - public override void InsertCompletionText (CompletionListWindow window, ref KeyActions ka, Gdk.Key closeChar, char keyChar, Gdk.ModifierType modifier) + public override void InsertCompletionText (CompletionListWindow window, ref KeyActions ka, KeyDescriptor descriptor) { var currentWord = GetCurrentWord (window); var text = CompletionText; - if (keyChar != '>') + if (descriptor.KeyChar != '>') text += ">"; window.CompletionWidget.SetCompletionText (window.CodeCompletionContext, currentWord, text); } @@ -1065,7 +988,7 @@ namespace MonoDevelop.CSharp.Completion } ICompletionData ICompletionDataFactory.CreateNewPartialCompletionData (int declarationBegin, IUnresolvedTypeDefinition type, IUnresolvedMember m) { - var ctx = ext.CSharpUnresolvedFile.GetTypeResolveContext (ext.UnresolvedFileCompilation, ext.TextEditorData.Caret.Location); + var ctx = ext.CSharpUnresolvedFile.GetTypeResolveContext (ext.UnresolvedFileCompilation, ext.Editor.CaretLocation); return new NewOverrideCompletionData (ext, declarationBegin, type, m.CreateResolved (ctx)); } IEnumerable<ICompletionData> ICompletionDataFactory.CreateCodeTemplateCompletionData () @@ -1079,7 +1002,7 @@ namespace MonoDevelop.CSharp.Completion IEnumerable<ICompletionData> ICompletionDataFactory.CreatePreProcessorDefinesCompletionData () { - var project = ext.document.Project; + var project = ext.DocumentContext.Project; if (project == null) yield break; var configuration = project.GetConfiguration (MonoDevelop.Ide.IdeApp.Workspace.ActiveConfiguration) as DotNetProjectConfiguration; @@ -1148,352 +1071,16 @@ namespace MonoDevelop.CSharp.Completion } - class ImportSymbolCompletionData : CompletionData, IEntityCompletionData - { - readonly IType type; - readonly bool useFullName; - readonly CSharpCompletionTextEditorExtension ext; - public IType Type { - get { return this.type; } - } - - public ImportSymbolCompletionData (CSharpCompletionTextEditorExtension ext, bool useFullName, IType type, bool addConstructors) - { - this.ext = ext; - this.useFullName = useFullName; - this.type = type; - this.DisplayFlags |= ICSharpCode.NRefactory.Completion.DisplayFlags.IsImportCompletion; - } - - public override TooltipInformation CreateTooltipInformation (bool smartWrap) - { - return MemberCompletionData.CreateTooltipInformation (ext, null, type.GetDefinition (), smartWrap); - } - - bool initialized = false; - bool generateUsing, insertNamespace; - - void Initialize () - { - if (initialized) - return; - initialized = true; - if (string.IsNullOrEmpty (type.Namespace)) - return; - generateUsing = !useFullName; - insertNamespace = useFullName; - } - - #region IActionCompletionData implementation - public override void InsertCompletionText (CompletionListWindow window, ref KeyActions ka, Gdk.Key closeChar, char keyChar, Gdk.ModifierType modifier) - { - Initialize (); - var doc = ext.document; - using (var undo = doc.Editor.OpenUndoGroup ()) { - string text = insertNamespace ? type.Namespace + "." + type.Name : type.Name; - if (text != GetCurrentWord (window)) { - if (window.WasShiftPressed && generateUsing) - text = type.Namespace + "." + text; - window.CompletionWidget.SetCompletionText (window.CodeCompletionContext, GetCurrentWord (window), text); - } - - if (!window.WasShiftPressed && generateUsing) { - var generator = CodeGenerator.CreateGenerator (doc); - if (generator != null) { - generator.AddGlobalNamespaceImport (doc, type.Namespace); - // reparse - doc.UpdateParseDocument (); - } - } - } - ka |= KeyActions.Ignore; - } - #endregion - - #region ICompletionData implementation - public override IconId Icon { - get { - return type.GetStockIcon (); - } - } - - public override string DisplayText { - get { - return type.Name; - } - } - - static string GetDefaultDisplaySelection (string description, bool isSelected) - { - if (!isSelected) - return "<span foreground=\"darkgray\">" + description + "</span>"; - return description; - } - - string displayDescription = null; - public override string GetDisplayDescription (bool isSelected) - { - if (displayDescription == null) { - Initialize (); - if (generateUsing || insertNamespace) { - displayDescription = string.Format (GettextCatalog.GetString ("(from '{0}')"), type.Namespace); - } else { - displayDescription = ""; - } - } - return GetDefaultDisplaySelection (displayDescription, isSelected); - } - - public override string Description { - get { - return type.Namespace; - } - } - - public override string CompletionText { - get { - return type.Name; - } - } - #endregion - - - List<CompletionData> overloads; - - public override IEnumerable<ICompletionData> OverloadedData { - get { - yield return this; - if (overloads == null) - yield break; - foreach (var overload in overloads) - yield return overload; - } - } - - public override bool HasOverloads { - get { return overloads != null && overloads.Count > 0; } - } - - public override void AddOverload (ICSharpCode.NRefactory.Completion.ICompletionData data) - { - AddOverload ((ImportSymbolCompletionData)data); - } - - void AddOverload (ImportSymbolCompletionData overload) - { - if (overloads == null) - overloads = new List<CompletionData> (); - overloads.Add (overload); - } - - IEntity IEntityCompletionData.Entity { - get { - return type.GetDefinition (); - } - } - } - - - ICompletionData ICompletionDataFactory.CreateImportCompletionData(IType type, bool useFullName, bool addConstructors) - { - return new ImportSymbolCompletionData (ext, useFullName, type, addConstructors); - } - - } + #endregion - - #region IParameterCompletionDataFactory implementation - IParameterDataProvider IParameterCompletionDataFactory.CreateConstructorProvider (int startOffset, IType type) - { - return new ConstructorParameterDataProvider (startOffset, this, type); - } - - IParameterDataProvider IParameterCompletionDataFactory.CreateConstructorProvider (int startOffset, IType type, AstNode initializer) - { - return new ConstructorParameterDataProvider (startOffset, this, type, initializer); - } - - IParameterDataProvider IParameterCompletionDataFactory.CreateMethodDataProvider (int startOffset, IEnumerable<IMethod> methods) - { - return new MethodParameterDataProvider (startOffset, this, methods); - } - - IParameterDataProvider IParameterCompletionDataFactory.CreateDelegateDataProvider (int startOffset, IType type) - { - return new DelegateDataProvider (startOffset, this, type); - } +*/ - IParameterDataProvider IParameterCompletionDataFactory.CreateIndexerParameterDataProvider (int startOffset, IType type, IEnumerable<IProperty> indexers, AstNode resolvedNode) - { - var arrayType = type as ArrayType; - if (arrayType != null) - return new ArrayTypeParameterDataProvider (startOffset, this, arrayType); - return new IndexerParameterDataProvider (startOffset, this, type, indexers, resolvedNode); - } - - IParameterDataProvider IParameterCompletionDataFactory.CreateTypeParameterDataProvider (int startOffset, IEnumerable<IType> types) - { - return new TypeParameterDataProvider (startOffset, this, types); - } - - IParameterDataProvider IParameterCompletionDataFactory.CreateTypeParameterDataProvider (int startOffset, IEnumerable<IMethod> methods) - { - return new TypeParameterDataProvider (startOffset, this, methods); - } - #endregion #region IDebuggerExpressionResolver implementation - static string GetIdentifierName (TextEditorData editor, Identifier id, out int startOffset) - { - startOffset = editor.LocationToOffset (id.StartLocation.Line, id.StartLocation.Column); - - return editor.GetTextBetween (id.StartLocation, id.EndLocation); - } - - internal static string ResolveExpression (TextEditorData editor, ResolveResult result, AstNode node, out int startOffset) - { - //Console.WriteLine ("result is a {0}", result.GetType ().Name); - startOffset = -1; - - if (result is NamespaceResolveResult || - result is ConversionResolveResult || - result is ConstantResolveResult || - result is ForEachResolveResult || - result is TypeIsResolveResult || - result is TypeOfResolveResult || - result is ErrorResolveResult) - return null; - - if (result.IsCompileTimeConstant) - return null; - - startOffset = editor.LocationToOffset (node.StartLocation.Line, node.StartLocation.Column); - - if (result is InvocationResolveResult) { - var ir = (InvocationResolveResult) result; - if (ir.Member.Name == ".ctor") { - // if the user is hovering over something like "new Abc (...)", we want to show them type information for Abc - return ir.Member.DeclaringType.FullName; - } - - // do not support general method invocation for tooltips because it could cause side-effects - return null; - } else if (result is LocalResolveResult) { - if (node is ParameterDeclaration) { - // user is hovering over a method parameter, but we don't want to include the parameter type - var param = (ParameterDeclaration) node; - - return GetIdentifierName (editor, param.NameToken, out startOffset); - } - - if (node is VariableInitializer) { - // user is hovering over something like "int fubar = 5;", but we don't want the expression to include the " = 5" - var variable = (VariableInitializer) node; - - return GetIdentifierName (editor, variable.NameToken, out startOffset); - } - } else if (result is MemberResolveResult) { - var mr = (MemberResolveResult) result; - - if (node is PropertyDeclaration) { - var prop = (PropertyDeclaration) node; - var name = GetIdentifierName (editor, prop.NameToken, out startOffset); - - // if the property is static, then we want to return "Full.TypeName.Property" - if (prop.Modifiers.HasFlag (Modifiers.Static)) - return mr.Member.DeclaringType.FullName + "." + name; - - // otherwise we want to return "this.Property" so that it won't conflict with anything else in the local scope - return "this." + name; - } - - if (node is FieldDeclaration) { - var field = (FieldDeclaration) node; - var name = GetIdentifierName (editor, field.NameToken, out startOffset); - - // if the field is static, then we want to return "Full.TypeName.Field" - if (field.Modifiers.HasFlag (Modifiers.Static)) - return mr.Member.DeclaringType.FullName + "." + name; - - // otherwise we want to return "this.Field" so that it won't conflict with anything else in the local scope - return "this." + name; - } - - if (node is VariableInitializer) { - // user is hovering over a field declaration that includes initialization - var variable = (VariableInitializer) node; - var name = GetIdentifierName (editor, variable.NameToken, out startOffset); - - // walk up the AST to find the FieldDeclaration so that we can determine if it is static or not - var field = variable.GetParent<FieldDeclaration> (); - - // if the field is static, then we want to return "Full.TypeName.Field" - if (field.Modifiers.HasFlag (Modifiers.Static)) - return mr.Member.DeclaringType.FullName + "." + name; - - // otherwise we want to return "this.Field" so that it won't conflict with anything else in the local scope - return "this." + name; - } - - if (node is NamedExpression) { - // user is hovering over 'Property' in an expression like: var fubar = new Fubar () { Property = baz }; - var variable = node.GetParent<VariableInitializer> (); - if (variable != null) { - var variableName = GetIdentifierName (editor, variable.NameToken, out startOffset); - var name = GetIdentifierName (editor, ((NamedExpression) node).NameToken, out startOffset); - - return variableName + "." + name; - } - } - } else if (result is TypeResolveResult) { - return ((TypeResolveResult) result).Type.FullName; - } - - return editor.GetTextBetween (node.StartLocation, node.EndLocation); - } - - static bool TryResolveAt (Document doc, DocumentLocation loc, out ResolveResult result, out AstNode node) - { - if (doc == null) - throw new ArgumentNullException ("doc"); - - result = null; - node = null; - - var parsedDocument = doc.ParsedDocument; - if (parsedDocument == null) - return false; - - var unit = parsedDocument.GetAst<SyntaxTree> (); - var parsedFile = parsedDocument.ParsedFile as CSharpUnresolvedFile; - - if (unit == null || parsedFile == null) - return false; - - try { - result = ResolveAtLocation.Resolve (new Lazy<ICompilation> (() => doc.Compilation), parsedFile, unit, loc, out node); - if (result == null || node is Statement) - return false; - } catch { - return false; - } - - return true; - } - - string IDebuggerExpressionResolver.ResolveExpression (TextEditorData editor, Document doc, int offset, out int startOffset) + async Task<DebugDataTipInfo> IDebuggerExpressionResolver.ResolveExpressionAsync (IReadonlyTextDocument editor, DocumentContext doc, int offset, CancellationToken cancellationToken) { - ResolveResult result; - AstNode node; - - var loc = editor.OffsetToLocation (offset); - if (!TryResolveAt (doc, loc, out result, out node)) { - startOffset = -1; - return null; - } - - return ResolveExpression (editor, result, node, out startOffset); + return await Resolver.DebuggerExpressionResolver.ResolveAsync (editor, doc, offset, cancellationToken); } #endregion @@ -1501,16 +1088,15 @@ namespace MonoDevelop.CSharp.Completion #region TypeSystemSegmentTree TypeSystemSegmentTree validTypeSystemSegmentTree; - TypeSystemSegmentTree unstableTypeSystemSegmentTree; internal class TypeSystemTreeSegment : TreeSegment { - public IUnresolvedEntity Entity { + public SyntaxNode Entity { get; private set; } - public TypeSystemTreeSegment (int offset, int length, IUnresolvedEntity entity) : base (offset, length) + public TypeSystemTreeSegment (int offset, int length, SyntaxNode entity) : base (offset, length) { this.Entity = entity; } @@ -1519,8 +1105,6 @@ namespace MonoDevelop.CSharp.Completion internal TypeSystemTreeSegment GetMemberSegmentAt (int offset) { TypeSystemTreeSegment result = null; - if (unstableTypeSystemSegmentTree != null) - result = unstableTypeSystemSegmentTree.GetMemberSegmentAt (offset); if (result == null && validTypeSystemSegmentTree != null) result = validTypeSystemSegmentTree.GetMemberSegmentAt (offset); return result; @@ -1528,174 +1112,147 @@ namespace MonoDevelop.CSharp.Completion internal class TypeSystemSegmentTree : SegmentTree<TypeSystemTreeSegment> { - public IUnresolvedTypeDefinition GetTypeAt (int offset) - { - IUnresolvedTypeDefinition result = null; - foreach (var seg in GetSegmentsAt (offset).Where (s => s.Entity is IUnresolvedTypeDefinition)) { - if (result == null || result.Region.IsInside (seg.Entity.Region.Begin)) - result = (IUnresolvedTypeDefinition)seg.Entity; - } - return result; - } - - public IUnresolvedMember GetMemberAt (int offset) + public SyntaxNode GetMemberAt (int offset) { // Members don't overlap - var seg = GetSegmentsAt (offset).FirstOrDefault (s => s.Entity is IUnresolvedMember); + var seg = GetSegmentsAt (offset).FirstOrDefault (); if (seg == null) return null; - return (IUnresolvedMember)seg.Entity; + return seg.Entity; } public TypeSystemTreeSegment GetMemberSegmentAt (int offset) { - // Members don't overlap - var seg = GetSegmentsAt (offset).FirstOrDefault (s => s.Entity is IUnresolvedMember); - if (seg == null) - return null; - return seg; + return GetSegmentsAt (offset).LastOrDefault (); } - internal static TypeSystemSegmentTree Create (ParsedDocument parsedDocument, TextEditorData textEditorData) - { - TypeSystemSegmentTree result = new TypeSystemSegmentTree (); - - foreach (var type in parsedDocument.TopLevelTypeDefinitions) - AddType (textEditorData, result, type); - - return result; - } - static void AddType (TextEditorData textEditorData, TypeSystemSegmentTree result, IUnresolvedTypeDefinition type) + internal static TypeSystemSegmentTree Create (MonoDevelop.Ide.Editor.TextEditor editor, DocumentContext ctx, SemanticModel semanticModel) { - int offset = textEditorData.LocationToOffset (type.Region.Begin); - int endOffset = type.Region.End.IsEmpty ? int.MaxValue : textEditorData.LocationToOffset (type.Region.End); - if (endOffset < 0) - endOffset = int.MaxValue; - result.Add (new TypeSystemTreeSegment (offset, endOffset - offset, type)); - foreach (var entity in type.Members) { - if (entity.IsSynthetic) - continue; - offset = textEditorData.LocationToOffset (entity.Region.Begin); - endOffset = textEditorData.LocationToOffset (entity.Region.End); - if (endOffset < 0) - endOffset = int.MaxValue; - result.Add (new TypeSystemTreeSegment (offset, endOffset - offset, entity)); - } - - foreach (var nested in type.NestedTypes) - AddType (textEditorData, result, nested); + var visitor = new TreeVisitor (); + visitor.Visit (semanticModel.SyntaxTree.GetRoot ()); + return visitor.Result; } - } - - public IUnresolvedTypeDefinition GetTypeAt (int offset) - { - if (unstableTypeSystemSegmentTree == null && validTypeSystemSegmentTree == null) - return null; - IUnresolvedTypeDefinition type = null; - if (unstableTypeSystemSegmentTree != null) - type = unstableTypeSystemSegmentTree.GetTypeAt (offset); - if (type == null && validTypeSystemSegmentTree != null) - type = validTypeSystemSegmentTree.GetTypeAt (offset); - return type; - } - - public IUnresolvedMember GetMemberAt (int offset) - { - if (unstableTypeSystemSegmentTree == null && validTypeSystemSegmentTree == null) - return null; - IUnresolvedMember member = null; - if (unstableTypeSystemSegmentTree != null) - member = unstableTypeSystemSegmentTree.GetMemberAt (offset); - if (member == null && validTypeSystemSegmentTree != null) - member = validTypeSystemSegmentTree.GetMemberAt (offset); + class TreeVisitor : CSharpSyntaxWalker + { + public TypeSystemSegmentTree Result = new TypeSystemSegmentTree (); - return member; - } - #endregion + public override void VisitClassDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + base.VisitClassDeclaration (node); + } + public override void VisitStructDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + base.VisitStructDeclaration (node); + } + public override void VisitInterfaceDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.InterfaceDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + base.VisitInterfaceDeclaration (node); + } - class CompletionContextProvider : ICompletionContextProvider - { - readonly ParsedDocument parsedDocument; - readonly TextEditorData textEditorData; - readonly TypeSystemSegmentTree validTypeSystemSegmentTree; - readonly TypeSystemSegmentTree unstableTypeSystemSegmentTree; + public override void VisitEnumDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.EnumDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + } - public CompletionContextProvider (ParsedDocument parsedDocument, TextEditorData textEditorData, - TypeSystemSegmentTree validTypeSystemSegmentTree, TypeSystemSegmentTree unstableTypeSystemSegmentTree) - { - this.parsedDocument = parsedDocument; - this.textEditorData = textEditorData; - this.validTypeSystemSegmentTree = validTypeSystemSegmentTree; - this.unstableTypeSystemSegmentTree = unstableTypeSystemSegmentTree; - } + public override void VisitPropertyDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.PropertyDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + } - IList<string> ICompletionContextProvider.ConditionalSymbols { - get { - return parsedDocument.GetAst<SyntaxTree> ().ConditionalSymbols; + public override void VisitMethodDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); } - } - void ICompletionContextProvider.GetCurrentMembers (int offset, out IUnresolvedTypeDefinition currentType, out IUnresolvedMember currentMember) - { - currentType = GetTypeAt (offset); - currentMember = GetMemberAt (offset); - } + public override void VisitConstructorDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + } - public IUnresolvedTypeDefinition GetTypeAt (int offset) - { - if (unstableTypeSystemSegmentTree == null && validTypeSystemSegmentTree == null) - return null; - IUnresolvedTypeDefinition type = null; - if (unstableTypeSystemSegmentTree != null) - type = unstableTypeSystemSegmentTree.GetTypeAt (offset); - if (type == null && validTypeSystemSegmentTree != null) - type = validTypeSystemSegmentTree.GetTypeAt (offset); - return type; - } + public override void VisitDestructorDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.DestructorDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + } - public IUnresolvedMember GetMemberAt (int offset) - { - if (unstableTypeSystemSegmentTree == null && validTypeSystemSegmentTree == null) - return null; + public override void VisitIndexerDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.IndexerDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + } - IUnresolvedMember member = null; - if (unstableTypeSystemSegmentTree != null) - member = unstableTypeSystemSegmentTree.GetMemberAt (offset); - if (member == null && validTypeSystemSegmentTree != null) - member = validTypeSystemSegmentTree.GetMemberAt (offset); - return member; - } + public override void VisitDelegateDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.DelegateDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + } - Tuple<string, TextLocation> ICompletionContextProvider.GetMemberTextToCaret (int caretOffset, IUnresolvedTypeDefinition currentType, IUnresolvedMember currentMember) - { - int startOffset; - if (currentMember != null && currentType != null && currentType.Kind != TypeKind.Enum) { - startOffset = textEditorData.LocationToOffset(currentMember.Region.Begin); - } else if (currentType != null) { - startOffset = textEditorData.LocationToOffset(currentType.Region.Begin); - } else { - startOffset = 0; + public override void VisitOperatorDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.OperatorDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); } - while (startOffset > 0) { - char ch = textEditorData.GetCharAt(startOffset - 1); - if (ch != ' ' && ch != '\t') { - break; - } - --startOffset; + + public override void VisitEventDeclaration (Microsoft.CodeAnalysis.CSharp.Syntax.EventDeclarationSyntax node) + { + Result.Add (new TypeSystemTreeSegment (node.SpanStart, node.Span.Length, node)); + } + + public override void VisitBlock (Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax node) + { + // nothing } - return Tuple.Create (caretOffset > startOffset ? textEditorData.GetTextAt (startOffset, caretOffset - startOffset) : "", - (TextLocation)textEditorData.OffsetToLocation (startOffset)); } + + } + + public SyntaxNode GetMemberAt (int offset) + { + SyntaxNode member = null; + if (member == null && validTypeSystemSegmentTree != null) + member = validTypeSystemSegmentTree.GetMemberAt (offset); + return member; + } + #endregion + + - CSharpAstResolver ICompletionContextProvider.GetResolver (CSharpResolver resolver, AstNode rootNode) - { - return new CSharpAstResolver (resolver, rootNode, parsedDocument.ParsedFile as CSharpUnresolvedFile); + [CommandHandler(RefactoryCommands.ImportSymbol)] + void ImportSymbolCommand () + { + if (Editor.SelectionMode == SelectionMode.Block) + return; + var analysisDocument = DocumentContext.AnalysisDocument; + if (analysisDocument == null) + return; + var offset = Editor.CaretOffset; + + ICompletionDataList completionList = null; + int cpos, wlen; + if (!GetCompletionCommandOffset (out cpos, out wlen)) { + cpos = Editor.CaretOffset; + wlen = 0; } + currentCompletionContext = CompletionWidget.CreateCodeCompletionContext (cpos); + currentCompletionContext.TriggerWordLength = wlen; + + var list = new CSharpCompletionDataList (); + list.TriggerWordLength = wlen; + var partialDoc = WithFrozenPartialSemanticsAsync (analysisDocument, default (CancellationToken)).Result; + var semanticModel = partialDoc.GetSemanticModelAsync ().Result; + + AddImportCompletionData (list, semanticModel, offset); + + completionList = CodeCompletionCommand (currentCompletionContext); + if (completionList != null) + CompletionWindowManager.ShowWindow (this, (char)0, completionList, CompletionWidget, currentCompletionContext); + else + currentCompletionContext = null; } + } } |