diff options
Diffstat (limited to 'main/src/addins/CSharpBinding/MonoDevelop.CSharp.Tooltips/LanguageItemTooltipProvider.cs')
-rw-r--r-- | main/src/addins/CSharpBinding/MonoDevelop.CSharp.Tooltips/LanguageItemTooltipProvider.cs | 508 |
1 files changed, 208 insertions, 300 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Tooltips/LanguageItemTooltipProvider.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Tooltips/LanguageItemTooltipProvider.cs index 619cb802d0..6dc8705134 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Tooltips/LanguageItemTooltipProvider.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Tooltips/LanguageItemTooltipProvider.cs @@ -25,94 +25,70 @@ // // using System; -using Mono.TextEditor; using MonoDevelop.Ide.TypeSystem; -using ICSharpCode.NRefactory.Semantics; using MonoDevelop.Ide; -using ICSharpCode.NRefactory.CSharp; using MonoDevelop.CSharp; -using ICSharpCode.NRefactory.TypeSystem; -using Gtk; -using ICSharpCode.NRefactory.CSharp.Resolver; -using ICSharpCode.NRefactory.CSharp.TypeSystem; -using System.Threading; -using System.Text; using MonoDevelop.Core; -using System.Collections.Generic; -using System.Linq; -using MonoDevelop.CSharp.Resolver; using MonoDevelop.Ide.CodeCompletion; using MonoDevelop.CSharp.Completion; using MonoDevelop.Components; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp; using MonoDevelop.Projects; using Mono.Cecil.Cil; +using MonoDevelop.Ide.Editor; +using MonoDevelop.Core.Text; +using Gtk; namespace MonoDevelop.SourceEditor { class LanguageItemTooltipProvider: TooltipProvider, IDisposable { - public LanguageItemTooltipProvider () - { - } - class ToolTipData { - public SyntaxTree Unit; - public ResolveResult Result; - public AstNode Node; - public CSharpAstResolver Resolver; + public readonly SymbolInfo SymbolInfo; + public ISymbol Symbol { get { return SymbolInfo.Symbol; } } + public readonly SyntaxToken Token; - public ToolTipData (ICSharpCode.NRefactory.CSharp.SyntaxTree unit, ICSharpCode.NRefactory.Semantics.ResolveResult result, ICSharpCode.NRefactory.CSharp.AstNode node, CSharpAstResolver file) + public ToolTipData (SymbolInfo symbol, SyntaxToken token) { - this.Unit = unit; - this.Result = result; - this.Node = node; - this.Resolver = file; + Token = token; + SymbolInfo = symbol; + } + + public override string ToString () + { + return string.Format ("[ToolTipData: Symbol={0}, Token={1}]", Symbol, Token); } } #region ITooltipProvider implementation - - public override TooltipItem GetItem (Mono.TextEditor.TextEditor editor, int offset) + public override TooltipItem GetItem (TextEditor editor, DocumentContext ctx, int offset) { - var doc = IdeApp.Workbench.ActiveDocument; - if (doc == null || doc.ParsedDocument == null) + if (ctx == null) return null; - var unit = doc.ParsedDocument.GetAst<SyntaxTree> (); - if (unit == null) + var analysisDocument = ctx.ParsedDocument; + if (analysisDocument == null) return null; - - var file = doc.ParsedDocument.ParsedFile as CSharpUnresolvedFile; - if (file == null) + var unit = analysisDocument.GetAst<SemanticModel> (); + if (unit == null) return null; - ResolveResult result; - AstNode node; - var loc = editor.OffsetToLocation (offset); - if (!doc.TryResolveAt (loc, out result, out node)) { - if (node is CSharpTokenNode) { - int startOffset2 = editor.LocationToOffset (node.StartLocation); - int endOffset2 = editor.LocationToOffset (node.EndLocation); - - return new TooltipItem (new ToolTipData (unit, result, node, null), startOffset2, endOffset2 - startOffset2); - } + var root = unit.SyntaxTree.GetRoot (); + SyntaxToken token; + try { + token = root.FindToken (offset); + } catch (ArgumentOutOfRangeException) { return null; } - if (node == lastNode) - return lastResult; - var resolver = new CSharpAstResolver (doc.Compilation, unit, file); - resolver.ApplyNavigator (new NodeListResolveVisitorNavigator (node), CancellationToken.None); - - var hoverNode = node.GetNodeAt (loc) ?? node; - - int startOffset = editor.LocationToOffset (hoverNode.StartLocation); - int endOffset = editor.LocationToOffset (hoverNode.EndLocation); - return lastResult = new TooltipItem (new ToolTipData (unit, result, node, resolver), startOffset, endOffset - startOffset); + if (!token.Span.IntersectsWith (offset)) + return null; + var symbolInfo = unit.GetSymbolInfo (token.Parent); + return new TooltipItem (new ToolTipData (symbolInfo, token), token.Span.Start, token.Span.Length); } - AstNode lastNode = null; static TooltipInformationWindow lastWindow = null; - TooltipItem lastResult; static void DestroyLastTooltipWindow () { @@ -127,21 +103,20 @@ namespace MonoDevelop.SourceEditor public void Dispose () { DestroyLastTooltipWindow (); - lastNode = null; - lastResult = null; } #endregion - protected override Gtk.Window CreateTooltipWindow (Mono.TextEditor.TextEditor editor, int offset, Gdk.ModifierType modifierState, TooltipItem item) + + public override Control CreateTooltipWindow (TextEditor editor, DocumentContext ctx, TooltipItem item, int offset, Gdk.ModifierType modifierState) { - var doc = IdeApp.Workbench.ActiveDocument; + var doc = ctx; if (doc == null) return null; var titem = (ToolTipData)item.Item; - var tooltipInformation = CreateTooltip (titem, offset, null, modifierState); + var tooltipInformation = CreateTooltip (titem, editor, ctx, offset, modifierState); if (tooltipInformation == null || string.IsNullOrEmpty (tooltipInformation.SignatureMarkup)) return null; @@ -152,259 +127,192 @@ namespace MonoDevelop.SourceEditor return result; } - public override Gtk.Window ShowTooltipWindow (TextEditor editor, int offset, Gdk.ModifierType modifierState, int mouseX, int mouseY, TooltipItem item) + TooltipInformation CreateTooltip (ToolTipData data, TextEditor editor, DocumentContext doc, int offset, Gdk.ModifierType modifierState) { - var titem = (ToolTipData)item.Item; - if (lastNode != null && lastWindow != null && lastWindow.IsRealized && titem.Node != null && lastNode == titem.Node) - return lastWindow; - - DestroyLastTooltipWindow (); - - var tipWindow = CreateTooltipWindow (editor, offset, modifierState, item) as TooltipInformationWindow; - if (tipWindow == null) - return null; - - var hoverNode = titem.Node.GetNodeAt (editor.OffsetToLocation (offset)) ?? titem.Node; - var p1 = editor.LocationToPoint (hoverNode.StartLocation); - var p2 = editor.LocationToPoint (hoverNode.EndLocation); - var positionWidget = editor.TextArea; - var caret = new Gdk.Rectangle ((int)p1.X - positionWidget.Allocation.X, (int)p2.Y - positionWidget.Allocation.Y, (int)(p2.X - p1.X), (int)editor.LineHeight); - - tipWindow.ShowPopup (positionWidget, caret, PopupPosition.Top); - tipWindow.EnterNotifyEvent += delegate { - editor.HideTooltip (false); - }; - lastWindow = tipWindow; - lastNode = titem.Node; - return tipWindow; - } - - TooltipInformation CreateTooltip (ToolTipData data, int offset, Ambience ambience, Gdk.ModifierType modifierState) - { - ResolveResult result = data.Result; - var doc = IdeApp.Workbench.ActiveDocument; - if (doc == null) - return null; bool createFooter = (modifierState & Gdk.ModifierType.Mod1Mask) != 0; - var file = doc.ParsedDocument.ParsedFile as CSharpUnresolvedFile; - if (file == null) - return null; try { - - if (result is AliasNamespaceResolveResult) { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - return sig.GetAliasedNamespaceTooltip ((AliasNamespaceResolveResult)result); - } + TooltipInformation result; + var sig = new SignatureMarkupCreator (doc, offset); + sig.BreakLineAfterReturnType = false; - if (result is AliasTypeResolveResult) { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - return sig.GetAliasedTypeTooltip ((AliasTypeResolveResult)result); - } + var typeOfExpression = data.Token.Parent as TypeOfExpressionSyntax; + if (typeOfExpression != null && data.Symbol is ITypeSymbol) + return sig.GetTypeOfTooltip (typeOfExpression, (ITypeSymbol)data.Symbol); - if (data.Node is ThisReferenceExpression && result is ThisResolveResult) { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - - return sig.GetKeywordTooltip ("this", data.Node); - } +// var parentKind = data.Token.Parent != null ? data.Token.Parent.Kind () : SyntaxKind.None; +// switch (parentKind) { +// case SyntaxKind.ConstructorConstraint: +// case SyntaxKind.ClassConstraint: +// case SyntaxKind.StructConstraint: +// return sig.GetConstraintTooltip (data.Token); +// } +// +// if (data.Node is ThisReferenceExpression && result is ThisResolveResult) { +// var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); +// var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); +// sig.BreakLineAfterReturnType = false; +// +// return sig.GetKeywordTooltip ("this", data.Node); +// } +// +// if (data.Node is TypeOfExpression) { +// var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); +// var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); +// sig.BreakLineAfterReturnType = false; +// return sig.GetTypeOfTooltip ((TypeOfExpression)data.Node, result as TypeOfResolveResult); +// } +// if (data.Node is PrimitiveType && data.Node.Parent is Constraint) { +// var t = (PrimitiveType)data.Node; +// if (t.Keyword == "class" || t.Keyword == "new" || t.Keyword == "struct") { +// var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); +// var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); +// sig.BreakLineAfterReturnType = false; +// return sig.GetConstraintTooltip (t.Keyword); +// } +// return null; +// } + result = sig.GetKeywordTooltip (data.Token); + if (result != null) + return result; - if (data.Node is TypeOfExpression) { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - return sig.GetTypeOfTooltip ((TypeOfExpression)data.Node, result as TypeOfResolveResult); - } - if (data.Node is PrimitiveType && data.Node.Parent is Constraint) { - var t = (PrimitiveType)data.Node; - if (t.Keyword == "class" || t.Keyword == "new" || t.Keyword == "struct") { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - return sig.GetConstraintTooltip (t.Keyword); - } - return null; - } - if (data.Node is ExternAliasDeclaration) { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - return sig.GetExternAliasTooltip ((ExternAliasDeclaration)data.Node, doc.Project as DotNetProject); - } - if (result == null && data.Node is CSharpTokenNode) { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - return sig.GetKeywordTooltip (data.Node); - } - if (data.Node is PrimitiveType && ((PrimitiveType)data.Node).KnownTypeCode == KnownTypeCode.Void) { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - return sig.GetKeywordTooltip ("void", null); - } - if (data.Node is NullReferenceExpression) { - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - return sig.GetKeywordTooltip ("null", null); - } - - if (result is UnknownIdentifierResolveResult) { - return new TooltipInformation () { - SignatureMarkup = string.Format ("error CS0103: The name `{0}' does not exist in the current context", ((UnknownIdentifierResolveResult)result).Identifier) - }; - } else if (result is UnknownMemberResolveResult) { - var ur = (UnknownMemberResolveResult)result; - if (ur.TargetType.Kind != TypeKind.Unknown) { - return new TooltipInformation () { - SignatureMarkup = string.Format ("error CS0117: `{0}' does not contain a definition for `{1}'", ur.TargetType.FullName, ur.MemberName) - }; - } - } else if (result.IsError) { - return new TooltipInformation () { - SignatureMarkup = "Unknown resolve error." - }; + if (data.Symbol != null) { + result = RoslynSymbolCompletionData.CreateTooltipInformation (editor, doc, data.Symbol, false, createFooter); } - if (result is LocalResolveResult) { - var lr = (LocalResolveResult)result; - var tooltipInfo = new TooltipInformation (); - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - tooltipInfo.SignatureMarkup = sig.GetLocalVariableMarkup (lr.Variable); - return tooltipInfo; - } else if (result is MethodGroupResolveResult) { - var mrr = (MethodGroupResolveResult)result; - var allMethods = new List<IMethod> (mrr.Methods); - foreach (var l in mrr.GetExtensionMethods ()) { - allMethods.AddRange (l); - } - var method = allMethods.FirstOrDefault (); - if (method != null) { - return MemberCompletionData.CreateTooltipInformation ( - doc.Compilation, - file, - doc.Editor, - doc.GetFormattingPolicy (), - method, - false, - createFooter); - } - } else if (result is CSharpInvocationResolveResult) { - var invocationResult = (CSharpInvocationResolveResult)result; - var member = (IMember)invocationResult.ReducedMethod ?? invocationResult.Member; - return MemberCompletionData.CreateTooltipInformation ( - doc.Compilation, - file, - doc.Editor, - doc.GetFormattingPolicy (), - member, - false, - createFooter); - } else if (result is MemberResolveResult) { - var member = ((MemberResolveResult)result).Member; - return MemberCompletionData.CreateTooltipInformation ( - doc.Compilation, - file, - doc.Editor, - doc.GetFormattingPolicy (), - member, - false, - createFooter); - } else if (result is NamespaceResolveResult) { - var tooltipInfo = new TooltipInformation (); - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - try { - tooltipInfo.SignatureMarkup = sig.GetMarkup (((NamespaceResolveResult)result).Namespace); - } catch (Exception e) { - LoggingService.LogError ("Got exception while creating markup for :" + ((NamespaceResolveResult)result).Namespace, e); - return new TooltipInformation (); - } - return tooltipInfo; - } else if (result is OperatorResolveResult) { - var or = result as OperatorResolveResult; - var tooltipInfo = new TooltipInformation (); - var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); - var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); - sig.BreakLineAfterReturnType = false; - try { - var method = or.UserDefinedOperatorMethod; - if (method == null) - return null; - tooltipInfo.SignatureMarkup = sig.GetMarkup (method); - } catch (Exception e) { - LoggingService.LogError ("Got exception while creating markup for :" + result, e); - return new TooltipInformation (); - } - return tooltipInfo; - } else { - return MemberCompletionData.CreateTooltipInformation ( - doc.Compilation, - file, - doc.Editor, - doc.GetFormattingPolicy (), - result.Type, - false, - createFooter); - } +// if (result == null && parentKind == SyntaxKind.IdentifierName) { +// if (data.SymbolInfo.CandidateReason == CandidateReason.None) { +// if (data.Token.Parent.Parent.Kind () == SyntaxKind.SimpleMemberAccessExpression || +// data.Token.Parent.Parent.Kind () == SyntaxKind.PointerMemberAccessExpression) { +// var ma = (MemberAccessExpressionSyntax)data.Token.Parent.Parent; +// return new TooltipInformation { +// SignatureMarkup = string.Format ("error CS0117: `{0}' does not contain a definition for `{1}'", ma.Expression, ma.Name) +// }; +// } +// return new TooltipInformation { +// SignatureMarkup = string.Format ("error CS0103: The name `{0}' does not exist in the current context", data.Token) +// }; +// } +// } + + return result; + +// if (result is AliasNamespaceResolveResult) { +// var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); +// var sig = new SignatureMarkupCreator (doc); +// sig.BreakLineAfterReturnType = false; +// return sig.GetAliasedNamespaceTooltip ((AliasNamespaceResolveResult)result); +// } +// +// if (result is AliasTypeResolveResult) { +// var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); +// var sig = new SignatureMarkupCreator (doc); +// sig.BreakLineAfterReturnType = false; +// return sig.GetAliasedTypeTooltip ((AliasTypeResolveResult)result); +// } +// +// +// if (data.Node is ExternAliasDeclaration) { +// var resolver = file.GetResolver (doc.Compilation, doc.Editor.Caret.Location); +// var sig = new SignatureMarkupCreator (resolver, doc.GetFormattingPolicy ().CreateOptions ()); +// sig.BreakLineAfterReturnType = false; +// return sig.GetExternAliasTooltip ((ExternAliasDeclaration)data.Node, doc.Project as DotNetProject); +// } +// if (result is MethodGroupResolveResult) { +// var mrr = (MethodGroupResolveResult)result; +// var allMethods = new List<IMethod> (mrr.Methods); +// foreach (var l in mrr.GetExtensionMethods ()) { +// allMethods.AddRange (l); +// } +// +// var method = allMethods.FirstOrDefault (); +// if (method != null) { +//// return MemberCompletionData.CreateTooltipInformation ( +//// doc.Compilation, +//// file, +//// doc.Editor, +//// doc.GetFormattingPolicy (), +//// method, +//// false, +//// createFooter); +// } +// } else if (result is CSharpInvocationResolveResult) { +// var invocationResult = (CSharpInvocationResolveResult)result; +// var member = (IMember)invocationResult.ReducedMethod ?? invocationResult.Member; +//// return MemberCompletionData.CreateTooltipInformation ( +//// doc.Compilation, +//// file, +//// doc.Editor, +//// doc.GetFormattingPolicy (), +//// member, +//// false, +//// createFooter); +// } else if (result is MemberResolveResult) { +// var member = ((MemberResolveResult)result).Member; +//// return MemberCompletionData.CreateTooltipInformation ( +//// doc.Compilation, +//// file, +//// doc.Editor, +//// doc.GetFormattingPolicy (), +//// member, +//// false, +//// createFooter); +// } else { +// return MemberCompletionData.CreateTooltipInformation ( +// doc.Compilation, +// file, +// doc.Editor, +// doc.GetFormattingPolicy (), +// result.Type, +// false, +// createFooter); +// } } catch (Exception e) { LoggingService.LogError ("Error while creating tooltip.", e); return null; } - - return null; - } - class ErrorVisitor : DepthFirstAstVisitor - { - readonly CSharpAstResolver resolver; - readonly CancellationToken cancellationToken; - ResolveResult errorResolveResult; - - public ResolveResult ErrorResolveResult { - get { - return errorResolveResult; - } - } - - AstNode errorNode; - - public AstNode ErrorNode { - get { - return errorNode; - } - } - - public ErrorVisitor (CSharpAstResolver resolver, CancellationToken cancellationToken = default(CancellationToken)) - { - this.resolver = resolver; - this.cancellationToken = cancellationToken; - } - - protected override void VisitChildren (AstNode node) - { - if (ErrorResolveResult != null || cancellationToken.IsCancellationRequested) - return; - if (node is Expression) { - var rr = resolver.Resolve (node, cancellationToken); - if (rr.IsError) { - errorResolveResult = rr; - errorNode = node; - } - } - base.VisitChildren (node); - } } - - protected override void GetRequiredPosition (Mono.TextEditor.TextEditor editor, Gtk.Window tipWindow, out int requiredWidth, out double xalign) +// class ErrorVisitor : DepthFirstAstVisitor +// { +// readonly CSharpAstResolver resolver; +// readonly CancellationToken cancellationToken; +// ResolveResult errorResolveResult; +// +// public ResolveResult ErrorResolveResult { +// get { +// return errorResolveResult; +// } +// } +// +// AstNode errorNode; +// +// public AstNode ErrorNode { +// get { +// return errorNode; +// } +// } +// +// public ErrorVisitor (CSharpAstResolver resolver, CancellationToken cancellationToken = default(CancellationToken)) +// { +// this.resolver = resolver; +// this.cancellationToken = cancellationToken; +// } +// +// protected override void VisitChildren (AstNode node) +// { +// if (ErrorResolveResult != null || cancellationToken.IsCancellationRequested) +// return; +// if (node is Expression) { +// var rr = resolver.Resolve (node, cancellationToken); +// if (rr.IsError) { +// errorResolveResult = rr; +// errorNode = node; +// } +// } +// base.VisitChildren (node); +// } +// } + public override void GetRequiredPosition (TextEditor editor, Control tipWindow, out int requiredWidth, out double xalign) { var win = (TooltipInformationWindow)tipWindow; requiredWidth = win.Allocation.Width; |