public override async Task <DocumentSymbol[]> HierarchicalDocumentSymbol(DocumentSymbolParams @params, CancellationToken cancellationToken)
        {
            var opts  = GetMemberOptions.ExcludeBuiltins | GetMemberOptions.DeclaredOnly;
            var entry = ProjectFiles.GetEntry(@params.textDocument);

            var members = await GetModuleVariablesAsync(entry as ProjectEntry, opts, string.Empty, 50, cancellationToken);

            return(ToDocumentSymbols(members));
        }
        public override async Task <SymbolInformation[]> DocumentSymbol(DocumentSymbolParams @params)
        {
            var opts  = GetMemberOptions.ExcludeBuiltins | GetMemberOptions.DeclaredOnly;
            var entry = ProjectFiles.GetEntry(@params.textDocument);

            var members = await GetModuleVariablesAsync(entry as ProjectEntry, opts, string.Empty, 50);

            return(members
                   .GroupBy(mr => mr.Name)
                   .Select(g => g.First())
                   .Select(ToSymbolInformation)
                   .ToArray());
        }
Exemple #3
0
        public override Task <SymbolInformation[]> DocumentSymbol(DocumentSymbolParams @params)
        {
            var opts  = GetMemberOptions.ExcludeBuiltins | GetMemberOptions.DeclaredOnly;
            var entry = ProjectFiles.GetEntry(@params.textDocument);

            var members = GetModuleVariables(entry as IPythonProjectEntry, opts, string.Empty);

            return(Task.FromResult(members
                                   .GroupBy(mr => mr.Name)
                                   .Select(g => g.First())
                                   .Select(m => ToSymbolInformation(m))
                                   .ToArray()));
        }
Exemple #4
0
        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
            });
        }
        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);
        }
Exemple #6
0
        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));
        }
Exemple #7
0
 public OpenFile(ProjectFiles projectFiles, ILogger log)
 {
     _projectFiles = projectFiles;
     _log          = log;
 }
Exemple #8
0
        internal Task <CompletionList> Completion(CompletionParams @params, CancellationToken cancellationToken)
        {
            var uri = @params.textDocument.uri;

            ProjectFiles.GetAnalysis(@params.textDocument, @params.position, @params._version, out var entry, out var tree);
            TraceMessage($"Completions in {uri} at {@params.position}");

            tree = GetParseTree(entry, uri, cancellationToken, out var version) ?? tree;
            var analysis = entry?.Analysis;

            if (analysis == null)
            {
                TraceMessage($"No analysis found for {uri}");
                return(Task.FromResult(new CompletionList()));
            }

            var opts = GetOptions(@params.context);
            var ctxt = new CompletionAnalysis(analysis, tree, @params.position, opts, _displayTextBuilder, this,
                                              () => entry.ReadDocument(ProjectFiles.GetPart(uri), out _));
            var members = ctxt.GetCompletionsFromString(@params._expr) ?? ctxt.GetCompletions();

            if (members == null)
            {
                TraceMessage($"Do not trigger at {@params.position} in {uri}");
                return(Task.FromResult(new CompletionList()));
            }

            if (!Settings.completion.showAdvancedMembers)
            {
                members = members.Where(m => !m.label.StartsWith("__"));
            }

            var filterKind = @params.context?._filterKind;

            if (filterKind.HasValue && filterKind != CompletionItemKind.None)
            {
                TraceMessage($"Only returning {filterKind.Value} items");
                members = members.Where(m => m.kind == filterKind.Value);
            }

            var res = new CompletionList {
                items            = members.ToArray(),
                _expr            = ctxt.ParentExpression?.ToCodeString(tree, CodeFormattingOptions.Traditional),
                _commitByDefault = ctxt.ShouldCommitByDefault,
                _allowSnippet    = ctxt.ShouldAllowSnippets
            };

            SourceLocation trigger = @params.position;

            if (ctxt.ApplicableSpan.HasValue)
            {
                res._applicableSpan = ctxt.ApplicableSpan;
            }
            else if (ctxt.Node != null)
            {
                var span = ctxt.Node.GetSpan(tree);
                if (@params.context?.triggerKind == CompletionTriggerKind.TriggerCharacter)
                {
                    if (span.End > trigger)
                    {
                        span = new SourceSpan(span.Start, trigger);
                    }
                }
                if (span.End != span.Start)
                {
                    res._applicableSpan = span;
                }
            }
            else if (@params.context?.triggerKind == CompletionTriggerKind.TriggerCharacter)
            {
                var ch = @params.context?.triggerCharacter.FirstOrDefault() ?? '\0';
                res._applicableSpan = new SourceSpan(
                    trigger.Line,
                    Tokenizer.IsIdentifierStartChar(ch) ? Math.Max(1, trigger.Column - 1) : trigger.Column,
                    trigger.Line,
                    trigger.Column
                    );
            }

            LogMessage(MessageType.Info, $"Found {res.items.Length} completions for {uri} at {@params.position} after filtering");

            var evt = PostProcessCompletion;

            if (evt != null)
            {
                var e = new Extensibility.CompletionEventArgs(analysis, tree, @params.position, res);
                try {
                    evt(this, e);
                    res       = e.CompletionList;
                    res.items = res.items ?? Array.Empty <CompletionItem>();
                    LogMessage(MessageType.Info, $"Found {res.items.Length} completions after hooks");
                } catch (Exception ex) when(!ex.IsCriticalException())
                {
                    // We do not replace res in this case.
                    LogMessage(MessageType.Error, $"Error while post-processing completions: {ex}");
                }
            }
            return(Task.FromResult(res));
        }