public static ResolveResult Resolve(Lazy <ICompilation> compilation, CSharpUnresolvedFile unresolvedFile, SyntaxTree syntaxTree, TextLocation location, out AstNode node, CancellationToken cancellationToken = default(CancellationToken)) { node = syntaxTree.GetNodeAt(location); if (node == null || node is ArrayInitializerExpression) { return(null); } if (node.Parent is UsingAliasDeclaration && node.Role == UsingAliasDeclaration.AliasRole) { var r = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile); return(r.Resolve(((UsingAliasDeclaration)node.Parent).Import, cancellationToken)); } if (CSharpAstResolver.IsUnresolvableNode(node)) { if (node is Identifier) { node = node.Parent; } else if (node.NodeType == NodeType.Token) { if (node.Parent is IndexerExpression || node.Parent is ConstructorInitializer) { // There's no other place where one could hover to see the indexer's tooltip, // so we need to resolve it when hovering over the '[' or ']'. // For constructor initializer, the same applies to the 'base'/'this' token. node = node.Parent; } else { return(null); } } else { // don't resolve arbitrary nodes - we don't want to show tooltips for everything return(null); } } else { // It's a resolvable node. // However, we usually don't want to show the tooltip everywhere // For example, hovering with the mouse over an empty line between two methods causes // node==TypeDeclaration, but we don't want to show any tooltip. if (!node.GetChildByRole(Roles.Identifier).IsNull) { // We'll suppress the tooltip for resolvable nodes if there is an identifier that // could be hovered over instead: return(null); } } if (node == null) { return(null); } if (node.Parent is ObjectCreateExpression && node.Role == Roles.Type) { node = node.Parent; } InvocationExpression parentInvocation = null; if ((node is IdentifierExpression || node is MemberReferenceExpression || node is PointerReferenceExpression) && node.Role != Roles.Argument) { // we also need to resolve the invocation parentInvocation = node.Parent as InvocationExpression; } // TODO: I think we should provide an overload so that an existing CSharpAstResolver can be reused CSharpAstResolver resolver = new CSharpAstResolver(compilation.Value, syntaxTree, unresolvedFile); ResolveResult rr = resolver.Resolve(node, cancellationToken); MethodGroupResolveResult mgrr = rr as MethodGroupResolveResult; if (mgrr != null) { // For method groups, resolve the parent invocation instead. if (parentInvocation != null) { return(resolver.Resolve(parentInvocation)); } if (node is Expression) { // If it's not an invocation, try if it's a conversion to a delegate type: Conversion c = resolver.GetConversion((Expression)node, cancellationToken); if (c.IsMethodGroupConversion) { return(new MemberResolveResult(mgrr.TargetResult, c.Method)); } } } return(rr); }