private IEnumerable <CompletionItem> GetCompletionsFromMembers(ref GetMemberOptions opts) { var finder = new ExpressionFinder(Tree, GetExpressionOptions.EvaluateMembers); if (finder.GetExpression(Index) is Expression expr) { _log.TraceMessage($"Completing expression {expr.ToCodeString(Tree, CodeFormattingOptions.Traditional)}"); ParentExpression = expr; return(Analysis.GetMembers(expr, Position, opts, null).Select(ToCompletionItem)); } return(null); }
private IEnumerable <CompletionItem> GetCompletionsFromTopLevel(bool allowKeywords, bool allowArguments, GetMemberOptions opts) { if (Node?.EndIndex < Index) { return(Empty); } if (allowKeywords) { opts |= GetMemberOptions.IncludeExpressionKeywords; if (ShouldIncludeStatementKeywords(Statement, Index, out var span)) { opts |= GetMemberOptions.IncludeStatementKeywords; if (span.HasValue) { ApplicableSpan = new SourceSpan( Tree.IndexToLocation(span.Value.Start), Tree.IndexToLocation(span.Value.End) ); } } ShouldAllowSnippets = true; } _log.TraceMessage($"Completing all names"); var members = Analysis.GetAllAvailableMembers(Position, opts); if (allowArguments) { var finder = new ExpressionFinder(Tree, new GetExpressionOptions { Calls = true }); if (finder.GetExpression(Index) is CallExpression callExpr && callExpr.GetArgumentAtIndex(Tree, Index, out _)) { var argNames = Analysis.GetSignatures(callExpr.Target, Position) .SelectMany(o => o.Parameters).Select(p => p?.Name) .Where(n => !string.IsNullOrEmpty(n)) .Distinct() .Except(callExpr.Args.MaybeEnumerate().Select(a => a.Name).Where(n => !string.IsNullOrEmpty(n))) .Select(n => new MemberResult($"{n}=", PythonMemberType.NamedArgument)); argNames = argNames.MaybeEnumerate().ToArray(); _log.TraceMessage($"Including {argNames.Count()} named arguments"); members = members?.Concat(argNames) ?? argNames; } } return(members.Select(ToCompletionItem).Where(c => !string.IsNullOrEmpty(c.insertText))); }
public async Task <IEnumerable <CodeAction> > GetCodeActionsAsync(IDocumentAnalysis analysis, CodeActionSettings settings, DiagnosticsEntry diagnostic, CancellationToken cancellationToken) { if (!settings.GetQuickFixOption("addimports", true)) { return(Enumerable.Empty <CodeAction>()); } var finder = new ExpressionFinder(analysis.Ast, new FindExpressionOptions() { Names = true }); var node = finder.GetExpression(diagnostic.SourceSpan); if (!(node is NameExpression nex)) { return(Enumerable.Empty <CodeAction>()); } var identifier = nex.Name; if (string.IsNullOrEmpty(identifier)) { return(Enumerable.Empty <CodeAction>()); } var codeActions = new List <CodeAction>(); var diagnostics = new[] { diagnostic.ToDiagnostic() }; // see whether it is one of abbreviation we specialize foreach (var moduleFullName in WellKnownAbbreviationMap.Where(kv => kv.Value == identifier).Select(kv => kv.Key)) { var moduleName = GetModuleName(moduleFullName); await GetCodeActionsAsync(analysis, diagnostics, new Input(node, moduleName, moduleFullName), codeActions, cancellationToken); } // add then search given name as it is await GetCodeActionsAsync(analysis, diagnostics, new Input(node, identifier), codeActions, cancellationToken); return(codeActions); string GetModuleName(string moduleFullName) { var index = moduleFullName.LastIndexOf("."); return(index < 0 ? moduleFullName : moduleFullName.Substring(index + 1)); } }
public override async Task <Hover> Hover(TextDocumentPositionParams @params) { await _analyzerCreationTask; await IfTestWaitForAnalysisCompleteAsync(); var uri = @params.textDocument.uri; _projectFiles.GetAnalysis(@params.textDocument, @params.position, @params._version, out var entry, out var tree); TraceMessage($"Hover in {uri} at {@params.position}"); var analysis = entry?.Analysis; if (analysis == null) { TraceMessage($"No analysis found for {uri}"); return(EmptyHover); } tree = GetParseTree(entry, uri, CancellationToken, out var version) ?? tree; var index = tree.LocationToIndex(@params.position); var w = new ImportedModuleNameWalker(entry.ModuleName, index); tree.Walk(w); if (!string.IsNullOrEmpty(w.ImportedName) && _analyzer.Modules.TryImport(w.ImportedName, out var modRef)) { var doc = _displayTextBuilder.GetModuleDocumentation(modRef); return(new Hover { contents = doc }); } Expression expr; SourceSpan?exprSpan; Analyzer.InterpreterScope scope = null; var finder = new ExpressionFinder(tree, GetExpressionOptions.Hover); expr = finder.GetExpression(@params.position) as Expression; exprSpan = expr?.GetSpan(tree); if (expr == null) { TraceMessage($"No hover info found in {uri} at {@params.position}"); return(EmptyHover); } TraceMessage($"Getting hover for {expr.ToCodeString(tree, CodeFormattingOptions.Traditional)}"); var values = analysis.GetValues(expr, @params.position, scope).ToList(); string originalExpr; if (expr is ConstantExpression || expr is ErrorExpression) { originalExpr = null; } else { originalExpr = @params._expr?.Trim(); if (string.IsNullOrEmpty(originalExpr)) { originalExpr = expr.ToCodeString(tree, CodeFormattingOptions.Traditional); } } var names = values.Select(GetFullTypeName).Where(n => !string.IsNullOrEmpty(n)).Distinct().ToArray(); var res = new Hover { contents = GetMarkupContent( _displayTextBuilder.GetDocumentation(values, originalExpr), _clientCaps.textDocument?.hover?.contentFormat), range = exprSpan, _version = version, _typeNames = names }; return(res); }
public override async Task <SignatureHelp> SignatureHelp(TextDocumentPositionParams @params) { var uri = @params.textDocument.uri; ProjectFiles.GetAnalysis(@params.textDocument, @params.position, @params._version, out var entry, out var tree); TraceMessage($"Signatures in {uri} at {@params.position}"); var analysis = entry != null ? await entry.GetAnalysisAsync(waitingTimeout : 50) : null; if (analysis == null) { TraceMessage($"No analysis found for {uri}"); return(new SignatureHelp()); } IEnumerable <IOverloadResult> overloads; int activeSignature = -1, activeParameter = -1; if (!string.IsNullOrEmpty(@params._expr)) { TraceMessage($"Getting signatures for {@params._expr}"); overloads = analysis.GetSignatures(@params._expr, @params.position); } else { var finder = new ExpressionFinder(tree, new GetExpressionOptions { Calls = true }); var index = tree.LocationToIndex(@params.position); if (finder.GetExpression(@params.position) is CallExpression callExpr) { TraceMessage($"Getting signatures for {callExpr.ToCodeString(tree, CodeFormattingOptions.Traditional)}"); overloads = analysis.GetSignatures(callExpr.Target, @params.position); activeParameter = -1; if (callExpr.GetArgumentAtIndex(tree, index, out activeParameter) && activeParameter < 0) { // Returned 'true' and activeParameter == -1 means that we are after // the trailing comma, so assume partially typed expression such as 'pow(x, y, |) activeParameter = callExpr.Args.Count; } } else { TraceMessage($"No signatures found in {uri} at {@params.position}"); return(new SignatureHelp()); } } var sigs = overloads.Select(ToSignatureInformation).ToArray(); if (activeParameter >= 0 && activeSignature < 0) { // TODO: Better selection of active signature activeSignature = sigs .Select((s, i) => Tuple.Create(s, i)) .OrderBy(t => t.Item1.parameters.Length) .FirstOrDefault(t => t.Item1.parameters.Length > activeParameter) ?.Item2 ?? -1; } activeSignature = activeSignature >= 0 ? activeSignature : (sigs.Length > 0 ? 0 : -1); return(new SignatureHelp { signatures = sigs, activeSignature = activeSignature, activeParameter = activeParameter }); }
public static CompletionResult GetCompletions(Node statement, ScopeStatement scopeStatement, CompletionContext context) { SourceSpan?applicableSpan = null; var eval = context.Analysis.ExpressionEvaluator; var options = GetOptions(statement, context.Position, out var span); if (span.HasValue) { applicableSpan = new SourceSpan(context.IndexToLocation(span.Value.Start), context.IndexToLocation(span.Value.End)); } var scope = context.Analysis.FindScope(context.Location); IEnumerable <CompletionItem> items; using (eval.OpenScope(scope)) { // Get variables declared in the module. var variables = eval.CurrentScope.EnumerateTowardsGlobal.SelectMany(s => s.Variables).ToArray(); items = variables.Select(v => context.ItemSource.CreateCompletionItem(v.Name, v)).ToArray(); } // Get builtins var builtins = context.Analysis.Document.Interpreter.ModuleResolution.BuiltinsModule; var builtinItems = builtins.GetMemberNames() .Select(n => { var m = builtins.GetMember(n); if ((options & CompletionListOptions.ExceptionsOnly) == CompletionListOptions.ExceptionsOnly && !IsExceptionType(m.GetPythonType())) { return(null); } return(context.ItemSource.CreateCompletionItem(n, m)); }).ExcludeDefault(); items = items.Concat(builtinItems); // Add possible function arguments. var finder = new ExpressionFinder(context.Ast, new FindExpressionOptions { Calls = true }); if (finder.GetExpression(context.Position) is CallExpression callExpr && callExpr.GetArgumentAtIndex(context.Ast, context.Position, out _)) { var value = eval.GetValueFromExpression(callExpr.Target); if (value?.GetPythonType() is IPythonFunctionType ft) { var arguments = ft.Overloads.SelectMany(o => o.Parameters).Select(p => p?.Name) .Where(n => !string.IsNullOrEmpty(n)) .Distinct() .Except(callExpr.Args.MaybeEnumerate().Select(a => a.Name).Where(n => !string.IsNullOrEmpty(n))) .Select(n => CompletionItemSource.CreateCompletionItem($"{n}=", CompletionItemKind.Variable)) .ToArray(); items = items.Concat(arguments).ToArray(); } } var keywords = GetKeywordItems(context, options, scopeStatement); items = items.Concat(keywords); return(new CompletionResult(items, applicableSpan)); }
internal async Task <Reference[]> FindReferences(ReferencesParams @params, CancellationToken cancellationToken) { var uri = @params.textDocument.uri; ProjectFiles.GetAnalysis(@params.textDocument, @params.position, @params._version, out var entry, out var tree); TraceMessage($"References in {uri} at {@params.position}"); var analysis = entry != null ? await entry.GetAnalysisAsync(50, cancellationToken) : null; if (analysis == null) { TraceMessage($"No analysis found for {uri}"); return(Array.Empty <Reference>()); } tree = GetParseTree(entry, uri, cancellationToken, out var version); var extras = new List <Reference>(); if (@params.context?.includeDeclaration ?? false) { var index = tree.LocationToIndex(@params.position); var w = new ImportedModuleNameWalker(entry, index, tree); tree.Walk(w); if (w.ImportedType != null) { @params._expr = w.ImportedType.Name; } else { foreach (var n in w.ImportedModules) { if (Analyzer.Modules.TryGetImportedModule(n.Name, out var modRef) && modRef.AnalysisModule != null) { // Return a module reference extras.AddRange(modRef.AnalysisModule.Locations .Select(l => new Reference { uri = l.DocumentUri, range = l.Span, _version = version?.Version, _kind = ReferenceKind.Definition }) .ToArray()); } } } } IEnumerable <IAnalysisVariable> result; if (!string.IsNullOrEmpty(@params._expr)) { TraceMessage($"Getting references for {@params._expr}"); result = analysis.GetVariables(@params._expr, @params.position); } else { var finder = new ExpressionFinder(tree, GetExpressionOptions.FindDefinition); if (finder.GetExpression(@params.position) is Expression expr) { TraceMessage($"Getting references for {expr.ToCodeString(tree, CodeFormattingOptions.Traditional)}"); result = analysis.GetVariables(expr, @params.position); } else { TraceMessage($"No references found in {uri} at {@params.position}"); result = Enumerable.Empty <IAnalysisVariable>(); } } var filtered = result.Where(v => v.Type != VariableType.None); if (!(@params.context?.includeDeclaration ?? false)) { filtered = filtered.Where(v => v.Type != VariableType.Definition); } if (!(@params.context?._includeValues ?? false)) { filtered = filtered.Where(v => v.Type != VariableType.Value); } var res = filtered.Select(v => new Reference { uri = v.Location.DocumentUri, range = v.Location.Span, _kind = ToReferenceKind(v.Type), _version = version?.Version }) .Concat(extras) .GroupBy(r => r, ReferenceComparer.Instance) .Select(g => g.OrderByDescending(r => (SourceLocation)r.range.end).ThenBy(r => (int?)r._kind ?? int.MaxValue).First()) .ToArray(); return(res); }
internal Task <Hover> Hover(TextDocumentPositionParams @params, CancellationToken cancellationToken) { var uri = @params.textDocument.uri; ProjectFiles.GetAnalysis(@params.textDocument, @params.position, @params._version, out var entry, out var tree); TraceMessage($"Hover in {uri} at {@params.position}"); var analysis = entry?.Analysis; if (analysis == null) { TraceMessage($"No analysis found for {uri}"); return(Task.FromResult(EmptyHover)); } tree = GetParseTree(entry, uri, cancellationToken, out var version) ?? tree; Expression expr; SourceSpan?exprSpan; Analyzer.InterpreterScope scope = null; var finder = new ExpressionFinder(tree, GetExpressionOptions.Hover); expr = finder.GetExpression(@params.position) as Expression; exprSpan = expr?.GetSpan(tree); if (expr == null) { TraceMessage($"No hover info found in {uri} at {@params.position}"); return(Task.FromResult(EmptyHover)); } TraceMessage($"Getting hover for {expr.ToCodeString(tree, CodeFormattingOptions.Traditional)}"); // First try values from expression. This works for the import statement most of the time. var values = analysis.GetValues(expr, @params.position, scope).ToList(); if (values.Count == 0) { // See if this is hover over import statement var index = tree.LocationToIndex(@params.position); var w = new ImportedModuleNameWalker(entry, index, tree); tree.Walk(w); if (w.ImportedType != null) { values = analysis.GetValues(w.ImportedType.Name, @params.position).ToList(); } else { var sb = new StringBuilder(); var span = SourceSpan.Invalid; foreach (var n in w.ImportedModules) { if (Analyzer.Modules.TryGetImportedModule(n.Name, out var modRef) && modRef.AnalysisModule != null) { if (sb.Length > 0) { sb.AppendLine(); sb.AppendLine(); } sb.Append(_displayTextBuilder.GetModuleDocumentation(modRef)); span = span.IsValid ? span.Union(n.SourceSpan) : n.SourceSpan; } } if (sb.Length > 0) { return(Task.FromResult(new Hover { contents = sb.ToString(), range = span })); } } } if (values.Count > 0) { string originalExpr; if (expr is ConstantExpression || expr is ErrorExpression) { originalExpr = null; } else { originalExpr = @params._expr?.Trim(); if (string.IsNullOrEmpty(originalExpr)) { originalExpr = expr.ToCodeString(tree, CodeFormattingOptions.Traditional); } } var names = values.Select(GetFullTypeName).Where(n => !string.IsNullOrEmpty(n)).Distinct().ToArray(); var res = new Hover { contents = GetMarkupContent( _displayTextBuilder.GetDocumentation(values, originalExpr), _clientCaps.textDocument?.hover?.contentFormat), range = exprSpan, _version = version?.Version, _typeNames = names }; return(Task.FromResult(res)); } return(Task.FromResult(EmptyHover)); }
public override async Task <Reference[]> FindReferences(ReferencesParams @params, CancellationToken cancellationToken) { await WaitForCompleteAnalysisAsync(cancellationToken); var uri = @params.textDocument.uri; ProjectFiles.GetEntry(@params.textDocument, @params._version, out var entry, out var tree); TraceMessage($"References in {uri} at {@params.position}"); var analysis = entry != null ? await entry.GetAnalysisAsync(50, cancellationToken) : null; if (analysis == null) { TraceMessage($"No analysis found for {uri}"); return(Array.Empty <Reference>()); } tree = GetParseTree(entry, uri, cancellationToken, out var version); var modRefs = GetModuleReferences(entry, tree, version, @params); IEnumerable <IAnalysisVariable> result; if (!string.IsNullOrEmpty(@params._expr)) { TraceMessage($"Getting references for {@params._expr}"); result = analysis.GetVariables(@params._expr, @params.position); } else { var finder = new ExpressionFinder(tree, GetExpressionOptions.FindDefinition); if (finder.GetExpression(@params.position) is Expression expr) { TraceMessage($"Getting references for {expr.ToCodeString(tree, CodeFormattingOptions.Traditional)}"); result = analysis.GetVariables(expr, @params.position); } else { TraceMessage($"No references found in {uri} at {@params.position}"); result = Enumerable.Empty <IAnalysisVariable>(); } } var filtered = result.Where(v => v.Type != VariableType.None); if (!(@params.context?.includeDeclaration ?? false)) { filtered = filtered.Where(v => v.Type != VariableType.Definition); } if (!(@params.context?._includeValues ?? false)) { filtered = filtered.Where(v => v.Type != VariableType.Value); } var res = filtered.Select(v => new Reference { uri = v.Location.DocumentUri, range = v.Location.Span, _kind = ToReferenceKind(v.Type), _version = version?.Version }) .Concat(modRefs) .GroupBy(r => r, ReferenceComparer.Instance) .Select(g => g.OrderByDescending(r => (SourceLocation)r.range.end).ThenBy(r => (int?)r._kind ?? int.MaxValue).First()) .ToArray(); return(res); }
public override async Task <Hover> Hover(TextDocumentPositionParams @params, CancellationToken cancellationToken) { var uri = @params.textDocument.uri; ProjectFiles.GetEntry(@params.textDocument, @params._version, out var entry, out var tree); TraceMessage($"Hover in {uri} at {@params.position}"); var analysis = entry != null ? await entry.GetAnalysisAsync(50, cancellationToken) : null; if (analysis == null) { TraceMessage($"No analysis found for {uri}"); return(EmptyHover); } tree = GetParseTree(entry, uri, cancellationToken, out var version) ?? tree; Expression expr; SourceSpan?exprSpan; var finder = new ExpressionFinder(tree, GetExpressionOptions.Hover); expr = finder.GetExpression(@params.position) as Expression; exprSpan = expr?.GetSpan(tree); if (expr == null) { TraceMessage($"No hover info found in {uri} at {@params.position}"); return(EmptyHover); } TraceMessage($"Getting hover for {expr.ToCodeString(tree, CodeFormattingOptions.Traditional)}"); var hover = await GetSelfHoverAsync(expr, analysis, tree, @params.position, cancellationToken); if (hover != null && hover != EmptyHover) { return(hover); } // First try values from expression. This works for the import statement most of the time. var values = analysis.GetValues(expr, @params.position, null).ToList(); if (values.Count == 0) { values = GetImportHover(entry, analysis, tree, @params.position, out hover).ToList(); if (hover != null) { return(hover); } } if (values.Count > 0) { string originalExpr; if (expr is ConstantExpression || expr is ErrorExpression) { originalExpr = null; } else { originalExpr = @params._expr?.Trim(); if (string.IsNullOrEmpty(originalExpr)) { originalExpr = expr.ToCodeString(tree, CodeFormattingOptions.Traditional); } } var names = values.Select(GetFullTypeName).Where(n => !string.IsNullOrEmpty(n)).Distinct().ToArray(); var res = new Hover { contents = GetMarkupContent( _displayTextBuilder.GetDocumentation(values, originalExpr), _clientCaps.textDocument?.hover?.contentFormat), range = exprSpan, _version = version?.Version, _typeNames = names }; return(res); } return(EmptyHover); }