public SignatureHelp GetSignature(IDocumentAnalysis analysis, SourceLocation location)
        {
            if (analysis is EmptyAnalysis)
            {
                return(null);
            }

            ExpressionLocator.FindExpression(analysis.Ast, location,
                                             FindExpressionOptions.Hover, out var node, out var statement, out var scope);

            IMember     value    = null;
            IPythonType selfType = null;
            var         call     = node as CallExpression;

            if (call != null)
            {
                using (analysis.ExpressionEvaluator.OpenScope(analysis.Document, scope)) {
                    if (call.Target is MemberExpression mex)
                    {
                        var v = analysis.ExpressionEvaluator.GetValueFromExpression(mex.Target);
                        selfType = v?.GetPythonType();
                    }
                    value = analysis.ExpressionEvaluator.GetValueFromExpression(call.Target);
                }
            }

            var ft = value?.GetPythonType <IPythonFunctionType>();

            if (ft == null)
            {
                return(null);
            }

            var skip = ft.IsStatic || ft.IsUnbound ? 0 : 1;

            var signatures = new SignatureInformation[ft.Overloads.Count];

            for (var i = 0; i < ft.Overloads.Count; i++)
            {
                var o = ft.Overloads[i];

                var parameters = o.Parameters.Skip(skip).Select(p => new ParameterInformation {
                    label         = p.Name,
                    documentation = _docSource.FormatParameterDocumentation(p)
                }).ToArray();

                signatures[i] = new SignatureInformation {
                    label         = _docSource.GetSignatureString(ft, selfType, i),
                    documentation = _docSource.FormatDocumentation(ft.Documentation),
                    parameters    = parameters
                };
            }

            var index = location.ToIndex(analysis.Ast);

            if (call.GetArgumentAtIndex(analysis.Ast, index, out var 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 = call.Args.Count;
            }

            var activeSignature = -1;

            if (activeParameter >= 0)
            {
                // TODO: Better selection of active signature by argument set
                activeSignature = signatures
                                  .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
                : (signatures.Length > 0 ? 0 : -1);

            return(new SignatureHelp {
                signatures = signatures.ToArray(),
                activeSignature = activeSignature,
                activeParameter = activeParameter
            });
        }
Пример #2
0
        private MarkupContent HandleFromImport(FromImportStatement fi, SourceLocation location, ScopeStatement scope, IDocumentAnalysis analysis)
        {
            var eval     = analysis.ExpressionEvaluator;
            var position = location.ToIndex(analysis.Ast);

            // 'from A.B import C as D'
            if (fi.Root.StartIndex <= position && position < fi.Root.EndIndex)
            {
                // We are over A.B
                var module = GetModule(fi.Root.MakeString(), fi.Root.Names, position, analysis);
                module = module ?? GetModuleFromDottedName(fi.Root.Names, position, eval);
                return(module != null?_docSource.GetHover(module.Name, module) : null);
            }
            // Are we over 'C'?
            var nameIndex = fi.Names.ExcludeDefault().IndexOf(n => n.StartIndex <= position && position < n.EndIndex);

            if (nameIndex >= 0)
            {
                var module = eval.Interpreter.ModuleResolution.GetImportedModule(fi.Root.MakeString());
                module = module ?? GetModuleFromDottedName(fi.Root.Names, -1, eval);
                if (module != null)
                {
                    var memberName = fi.Names[nameIndex].Name;
                    var m          = module.GetMember(memberName);
                    return(m != null?_docSource.GetHover(memberName, m) : null);
                }
            }
            // Are we over 'D'?
            nameIndex = fi.AsNames.ExcludeDefault().IndexOf(n => n.StartIndex <= position && position < n.EndIndex);
            if (nameIndex >= 0)
            {
                using (eval.OpenScope(analysis.Document, scope)) {
                    var variableName = fi.AsNames[nameIndex].Name;
                    var m            = eval.LookupNameInScopes(variableName, out _);
                    return(m != null?_docSource.GetHover(variableName, m) : null);
                }
            }
            return(null);
        }
 public UndefinedVariablesWalker(IDocumentAnalysis analysis, IServiceContainer services)
     : base(analysis, services)
 {
 }
Пример #4
0
 private bool IsAnalyzedLibraryInLoop(IDependencyChainNode <PythonAnalyzerEntry> node, IDocumentAnalysis currentAnalysis)
 => !node.HasMissingDependencies && currentAnalysis is LibraryAnalysis && node.IsWalkedWithDependencies && node.IsValidVersion;
Пример #5
0
        private static async Task AddCandidatesFromIndexAsync(IDocumentAnalysis analysis,
                                                              string name,
                                                              Dictionary <string, ImportInfo> importFullNameMap,
                                                              CancellationToken cancellationToken)
        {
            var indexManager = analysis.ExpressionEvaluator.Services.GetService <IIndexManager>();

            if (indexManager == null)
            {
                // indexing is not supported
                return;
            }

            var symbolsIncludingName = await indexManager.WorkspaceSymbolsAsync(name, maxLength : int.MaxValue, includeLibraries : true, cancellationToken);

            // we only consider exact matches rather than partial matches
            var symbolsWithName = symbolsIncludingName.Where(Include);

            var analyzer     = analysis.ExpressionEvaluator.Services.GetService <IPythonAnalyzer>();
            var pathResolver = analysis.Document.Interpreter.ModuleResolution.CurrentPathResolver;

            var modules = ImmutableArray <IPythonModule> .Empty;

            foreach (var symbolAndModuleName in symbolsWithName.Select(s => (symbol: s, moduleName: pathResolver.GetModuleNameByPath(s.DocumentPath))))
            {
                cancellationToken.ThrowIfCancellationRequested();

                var key    = $"{symbolAndModuleName.moduleName}.{symbolAndModuleName.symbol.Name}";
                var symbol = symbolAndModuleName.symbol;

                importFullNameMap.TryGetValue(key, out var existing);

                // we don't actually know whether this is a module. all we know is it appeared at
                // Import statement. but most likely module, so we mark it as module for now.
                // later when we check loaded module, if this happen to be loaded, this will get
                // updated with more accurate data.
                // if there happen to be multiple symbols with same name, we refer to mark it as module
                var isModule = symbol.Kind == Indexing.SymbolKind.Module || existing.IsModule;

                // any symbol marked "Module" by indexer is imported.
                importFullNameMap[key] = new ImportInfo(
                    moduleImported: isModule,
                    memberImported: isModule,
                    isModule);
            }

            bool Include(FlatSymbol symbol)
            {
                // we only suggest symbols that exist in __all__
                // otherwise, we show gigantic list from index
                return(symbol._existInAllVariable &&
                       symbol.ContainerName == null &&
                       CheckKind(symbol.Kind) &&
                       symbol.Name == name);
            }

            bool CheckKind(Indexing.SymbolKind kind)
            {
                switch (kind)
                {
                case Indexing.SymbolKind.Module:
                case Indexing.SymbolKind.Namespace:
                case Indexing.SymbolKind.Package:
                case Indexing.SymbolKind.Class:
                case Indexing.SymbolKind.Enum:
                case Indexing.SymbolKind.Interface:
                case Indexing.SymbolKind.Function:
                case Indexing.SymbolKind.Constant:
                case Indexing.SymbolKind.Struct:
                    return(true);

                default:
                    return(false);
                }
            }
        }
        public ModuleWalker(ExpressionEval eval, IImportedVariableHandler importedVariableHandler) : base(eval, importedVariableHandler)
        {
            _stubAnalysis = Module.Stub is IDocument doc?doc.GetAnyAnalysis() : null;

            _cancellationToken = CancellationToken.None;
        }
Пример #7
0
        public static ModuleModel FromAnalysis(IDocumentAnalysis analysis, IServiceContainer services, AnalysisCachingLevel options)
        {
            var uniqueId = analysis.Document.GetUniqueId(services, options);

            if (uniqueId == null)
            {
                // Caching level setting does not permit this module to be persisted.
                return(null);
            }

            var variables   = new Dictionary <string, VariableModel>();
            var functions   = new Dictionary <string, FunctionModel>();
            var classes     = new Dictionary <string, ClassModel>();
            var typeVars    = new Dictionary <string, TypeVarModel>();
            var namedTuples = new Dictionary <string, NamedTupleModel>();

            // Go directly through variables which names are listed in GetMemberNames
            // as well as variables that are declarations.
            var exportedNames = new HashSet <string>(analysis.Document.GetMemberNames());

            foreach (var v in analysis.GlobalScope.Variables
                     .Where(v => exportedNames.Contains(v.Name) ||
                            v.Source == VariableSource.Declaration ||
                            v.Source == VariableSource.Builtin ||
                            v.Source == VariableSource.Generic))
            {
                if (v.Value is IGenericTypeParameter && !typeVars.ContainsKey(v.Name))
                {
                    typeVars[v.Name] = TypeVarModel.FromGeneric(v);
                    continue;
                }

                switch (v.Value)
                {
                case ITypingNamedTupleType nt:
                    namedTuples[nt.Name] = new NamedTupleModel(nt);
                    continue;

                case IPythonFunctionType ft when ft.IsLambda():
                    // No need to persist lambdas.
                    continue;

                case IPythonFunctionType ft when v.Name != ft.Name:
                    // Variable assigned to type info of the function like
                    //    def func(): ...
                    //    x = type(func)
                    break;

                case IPythonFunctionType ft:
                    var fm = GetFunctionModel(analysis, v, ft);
                    if (fm != null && !functions.ContainsKey(ft.Name))
                    {
                        functions[ft.Name] = fm;
                        continue;
                    }
                    break;

                case IPythonClassType cls when v.Name != cls.Name:
                    // Variable assigned to type info of the class.
                    break;

                case IPythonClassType cls
                    when cls.DeclaringModule.Equals(analysis.Document) || cls.DeclaringModule.Equals(analysis.Document.Stub):
                    if (!classes.ContainsKey(cls.Name))
                    {
                        classes[cls.Name] = new ClassModel(cls);
                        continue;
                    }

                    break;
                }

                // Do not re-declare classes and functions as variables in the model.
                if (!variables.ContainsKey(v.Name))
                {
                    variables[v.Name] = VariableModel.FromVariable(v);
                }
            }

            // Take dependencies from imports. If module has stub we should also take
            // dependencies from there since persistent state is based on types that
            // are combination of stub and the module. Sometimes stub may import more
            // and we must make sure dependencies are restored before the module.
            var primaryDependencyWalker = new DependencyWalker(analysis.Ast);
            var stubDependencyWalker    = analysis.Document.Stub != null ? new DependencyWalker(analysis.Document.Stub.Analysis.Ast) : null;
            var stubImports             = stubDependencyWalker?.Imports ?? Enumerable.Empty <ImportModel>();
            var stubFromImports         = stubDependencyWalker?.FromImports ?? Enumerable.Empty <FromImportModel>();

            return(new ModuleModel {
                Id = uniqueId.GetStableHash(),
                UniqueId = uniqueId,
                Name = analysis.Document.Name,
                QualifiedName = analysis.Document.QualifiedName,
                Documentation = analysis.Document.Documentation,
                Functions = functions.Values.ToArray(),
                Variables = variables.Values.ToArray(),
                Classes = classes.Values.ToArray(),
                TypeVars = typeVars.Values.ToArray(),
                NamedTuples = namedTuples.Values.ToArray(),
                NewLines = analysis.Ast.NewLineLocations.Select(l => new NewLineModel {
                    EndIndex = l.EndIndex,
                    Kind = l.Kind
                }).ToArray(),
                FileSize = analysis.Ast.EndIndex,
                Imports = primaryDependencyWalker.Imports.ToArray(),
                FromImports = primaryDependencyWalker.FromImports.ToArray(),
                StubImports = stubImports.ToArray(),
                StubFromImports = stubFromImports.ToArray()
            });
        }
 public ModuleWalker(IServiceContainer services, IPythonModule module, PythonAst ast)
     : base(new ExpressionEval(services, module, ast))
 {
     _stubAnalysis = Module.Stub is IDocument doc?doc.GetAnyAnalysis() : null;
 }
Пример #9
0
 public AnalysisClassifier(IDocumentAnalysis documentAnalysis)
 {
     _analysisResult   = documentAnalysis.CurrentResult;
     _documentAnalysis = documentAnalysis;
     _documentAnalysis.AnalysisUpdated += AnalysisUpdated;
 }
Пример #10
0
        /// <summary>
        /// Transfers types from stub to source while preserving documentation and location.
        /// </summary>
        /// <remarks>
        /// Stub is the primary information source. Take types from the stub
        /// and replace source types by stub types. Transfer location and documentation
        /// from source members to the stub types.
        /// </remarks>
        private void TransferTypesFromStub(IDocumentAnalysis stubAnalysis, CancellationToken cancellationToken)
        {
            foreach (var v in stubAnalysis.GlobalScope.Variables.ToArray())
            {
                cancellationToken.ThrowIfCancellationRequested();

                var stubType = v.Value.GetPythonType();
                if (stubType.IsUnknown())
                {
                    continue;
                }
                // If stub says 'Any' but we have better type, keep the current type.
                if (stubType.DeclaringModule is TypingModule && stubType.Name == "Any")
                {
                    continue;
                }

                var sourceVar  = _eval.GlobalScope.Variables[v.Name];
                var sourceType = sourceVar?.Value.GetPythonType();

                if (sourceVar?.Source == VariableSource.Import &&
                    sourceVar.GetPythonType()?.DeclaringModule.Stub != null)
                {
                    // Keep imported types as they are defined in the library. For example,
                    // 'requests' imports NullHandler as 'from logging import NullHandler'.
                    // But 'requests' also declares NullHandler in its stub (but not in the main code)
                    // and that declaration does not have documentation or location. Therefore avoid
                    // taking types that are stub-only when similar type is imported from another
                    // module that also has a stub.
                    continue;
                }

                var stubPrimaryModule = stubType.DeclaringModule.PrimaryModule;

                // If type comes from another module and stub type comes from that module stub, skip it.
                // For example, 'sqlite3.dbapi2' has Date variable with value from 'datetime' module.
                // Stub of 'sqlite3.dbapi2' also has Date from 'datetime (stub)'. We want to use
                // type from the primary 'datetime' since it already merged its stub and updated
                // type location and documentation while 'datetime' stub does not have documentation
                // and its location is irrelevant since we don't navigate to stub source.
                if (!_eval.Module.Equals(sourceType?.DeclaringModule) &&
                    sourceType?.DeclaringModule.Stub != null &&
                    sourceType.DeclaringModule.Equals(stubPrimaryModule))
                {
                    continue;
                }

                // If stub type is not from this module stub, redirect type to primary since primary has locations and documentation.
                if (sourceType == null && stubPrimaryModule != null && !stubPrimaryModule.Equals(_eval.Module))
                {
                    Debug.Assert(stubType.DeclaringModule.ModuleType == ModuleType.Stub);
                    switch (stubType)
                    {
                    case PythonVariableModule vm:
                        stubType = vm.Module.PrimaryModule ?? stubType;
                        break;

                    case IPythonModule mod:
                        stubType = mod.PrimaryModule ?? stubType;
                        break;

                    default:
                        stubType = stubPrimaryModule.GetMember(v.Name)?.GetPythonType() ?? stubType;
                        break;
                    }
                }

                TryReplaceMember(v, sourceType, stubType, cancellationToken);
            }
        }
        public SignatureHelp GetSignature(IDocumentAnalysis analysis, SourceLocation location)
        {
            if (analysis is EmptyAnalysis)
            {
                return(null);
            }

            ExpressionLocator.FindExpression(analysis.Ast, location,
                                             FindExpressionOptions.Hover, out var node, out var statement, out var scope);

            IMember     value    = null;
            IPythonType selfType = null;
            string      name     = null;
            var         call     = node as CallExpression;

            if (call != null)
            {
                using (analysis.ExpressionEvaluator.OpenScope(analysis.Document, scope)) {
                    switch (call.Target)
                    {
                    case MemberExpression mex:
                        var v = analysis.ExpressionEvaluator.GetValueFromExpression(mex.Target);
                        selfType = v?.GetPythonType();
                        name     = mex.Name;
                        break;

                    case NameExpression ne:
                        name = ne.Name;
                        break;
                    }

                    value = analysis.ExpressionEvaluator.GetValueFromExpression(call.Target);
                }
            }

            var ft = value.TryGetFunctionType();

            if (ft == null)
            {
                return(null);
            }

            var signatures = new SignatureInformation[ft.Overloads.Count];

            for (var i = 0; i < ft.Overloads.Count; i++)
            {
                var o = ft.Overloads[i];

                var signatureLabel = _docSource.GetSignatureString(ft, selfType, out var parameterSpans, i, name);

                var parameterInfo = new ParameterInformation[parameterSpans.Length];
                for (var j = 0; j < parameterSpans.Length; j++)
                {
                    var(ps, p) = parameterSpans[j];

                    parameterInfo[j] = new ParameterInformation {
                        label         = _labelOffsetSupport ? new[] { ps.Start, ps.End } : (object)p.Name,
                        documentation = _docSource.FormatParameterDocumentation(p)
                    };
                }

                signatures[i] = new SignatureInformation {
                    label         = signatureLabel,
                    documentation = _docSource.FormatDocumentation(ft.Documentation),
                    parameters    = parameterInfo
                };
            }

            var index = location.ToIndex(analysis.Ast);

            if (call.GetArgumentAtIndex(analysis.Ast, index, out var 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 = call.Args.Count;
            }

            var activeSignature = -1;

            if (activeParameter >= 0)
            {
                // TODO: Better selection of active signature by argument set
                activeSignature = signatures
                                  .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
                : (signatures.Length > 0 ? 0 : -1);

            return(new SignatureHelp {
                signatures = signatures.ToArray(),
                activeSignature = activeSignature,
                activeParameter = activeParameter
            });
        }
 public static DocumentAnalysisAssertions Should(this IDocumentAnalysis analysis) => new DocumentAnalysisAssertions(analysis);
Пример #13
0
 protected LinterWalker(IDocumentAnalysis analysis, IServiceContainer services)
 {
     Analysis = analysis;
     Services = services;
 }
Пример #14
0
        private static IPythonModule GetModule(string moduleName, ImmutableArray <NameExpression> names, int position, IDocumentAnalysis analysis)
        {
            IPythonModule module    = null;
            var           eval      = analysis.ExpressionEvaluator;
            var           nameIndex = names.IndexOf(n => n.StartIndex <= position && position < n.EndIndex);

            if (nameIndex == 0)
            {
                module = eval.Interpreter.ModuleResolution.GetImportedModule(names[nameIndex].Name);
            }
            return(module ?? eval.Interpreter.ModuleResolution.GetImportedModule(moduleName));
        }
Пример #15
0
        public Hover GetHover(IDocumentAnalysis analysis, SourceLocation location)
        {
            if (analysis is EmptyAnalysis)
            {
                return(new Hover {
                    contents = Resources.AnalysisIsInProgressHover
                });
            }

            ExpressionLocator.FindExpression(analysis.Ast, location,
                                             FindExpressionOptions.Hover, out var node, out var statement, out var hoverScopeStatement);

            if (!HasHover(node) || !(node is Expression expr))
            {
                return(null);
            }

            var range = new Range {
                start = expr.GetStart(analysis.Ast),
                end   = expr.GetEnd(analysis.Ast)
            };

            var eval = analysis.ExpressionEvaluator;

            switch (statement)
            {
            case FromImportStatement fi when node is NameExpression nex: {
                var contents = HandleFromImport(fi, location, hoverScopeStatement, analysis);
                if (contents != null)
                {
                    return(new Hover {
                            contents = contents,
                            range = range
                        });
                }

                break;
            }

            case ImportStatement imp: {
                var contents = HandleImport(imp, location, hoverScopeStatement, analysis);
                if (contents != null)
                {
                    return(new Hover {
                            contents = contents,
                            range = range
                        });
                }

                break;
            }
            }

            IMember     value;
            IPythonType type;

            using (eval.OpenScope(analysis.Document, hoverScopeStatement)) {
                // Here we can be hovering over a class member. Class members are declared
                // as members as well as special variables in the class scope. If this is
                // a name expression (rather than a member expression) and it is a class
                // variable NOT in the immediate class scope, filter it out. Consider:
                //   class A:
                //     x = 1
                //     y = x
                // hover over 'x' in 'y = x' should produce proper tooltip. However, in
                //   class A:
                //     x = 1
                //     def func(self):
                //       y = x
                // hover over 'x' in 'y = x' should not produce tooltip.

                IVariable variable = null;
                if (expr is NameExpression nex)
                {
                    analysis.ExpressionEvaluator.LookupNameInScopes(nex.Name, out _, out variable, LookupOptions.All);
                    if (IsInvalidClassMember(variable, hoverScopeStatement, location.ToIndex(analysis.Ast)))
                    {
                        return(null);
                    }
                }

                value = variable?.Value ?? analysis.ExpressionEvaluator.GetValueFromExpression(expr, LookupOptions.All);
                type  = value?.GetPythonType();
                if (type == null)
                {
                    return(null);
                }
            }

            IPythonType self = null;
            string      name = null;

            // If expression is A.B, trim applicable span to 'B'.
            if (expr is MemberExpression mex)
            {
                name  = mex.Name;
                range = new Range {
                    start = mex.Target.GetEnd(analysis.Ast),
                    end   = range.end
                };

                // In case of a member expression get the target since if we end up with method
                // of a generic class, the function will need specific type to determine its return
                // value correctly. I.e. in x.func() we need to determine type of x (self for func).
                var v = analysis.ExpressionEvaluator.GetValueFromExpression(mex.Target);
                self = v?.GetPythonType();
            }

            // Figure out name, if any
            name = name ?? (node as NameExpression)?.Name;

            // Special case hovering over self or cls
            if ((name.EqualsOrdinal("self") || name.EqualsOrdinal("cls")) && type is IPythonClassType)
            {
                return(new Hover {
                    contents = _docSource.GetHover(null, type),
                    range = range
                });
            }

            name = name == null && statement is ClassDefinition cd ? cd.Name : name;
            name = name == null && statement is FunctionDefinition fd ? fd.Name : name;

            return(new Hover {
                contents = _docSource.GetHover(name, value, self),
                range = range
            });
        }
Пример #16
0
        public Hover GetHover(IDocumentAnalysis analysis, SourceLocation location)
        {
            if (analysis is EmptyAnalysis)
            {
                return(new Hover {
                    contents = Resources.AnalysisIsInProgressHover
                });
            }

            ExpressionLocator.FindExpression(analysis.Ast, location,
                                             FindExpressionOptions.Hover, out var node, out var statement, out var scope);

            if (!HasHover(node) || !(node is Expression expr))
            {
                return(null);
            }

            var range = new Range {
                start = expr.GetStart(analysis.Ast),
                end   = expr.GetEnd(analysis.Ast)
            };

            var eval = analysis.ExpressionEvaluator;

            switch (statement)
            {
            case FromImportStatement fi when node is NameExpression nex: {
                var contents = HandleFromImport(fi, location, scope, analysis);
                if (contents != null)
                {
                    return(new Hover {
                            contents = contents,
                            range = range
                        });
                }

                break;
            }

            case ImportStatement imp: {
                var contents = HandleImport(imp, location, scope, analysis);
                if (contents != null)
                {
                    return(new Hover {
                            contents = contents,
                            range = range
                        });
                }

                break;
            }
            }

            IMember     value;
            IPythonType type;

            using (eval.OpenScope(analysis.Document, scope)) {
                value = analysis.ExpressionEvaluator.GetValueFromExpression(expr);
                type  = value?.GetPythonType();
                if (type == null)
                {
                    return(null);
                }
            }

            IPythonType self = null;
            string      name = null;

            // If expression is A.B, trim applicable span to 'B'.
            if (expr is MemberExpression mex)
            {
                name  = mex.Name;
                range = new Range {
                    start = mex.Target.GetEnd(analysis.Ast),
                    end   = range.end
                };

                // In case of a member expression get the target since if we end up with method
                // of a generic class, the function will need specific type to determine its return
                // value correctly. I.e. in x.func() we need to determine type of x (self for func).
                var v = analysis.ExpressionEvaluator.GetValueFromExpression(mex.Target);
                self = v?.GetPythonType();
            }

            // Figure out name, if any
            name = name ?? (node as NameExpression)?.Name;

            // Special case hovering over self or cls
            if ((name.EqualsOrdinal("self") || name.EqualsOrdinal("cls")) && type is IPythonClassType)
            {
                return(new Hover {
                    contents = _docSource.GetHover(null, type),
                    range = range
                });
            }

            name = name == null && statement is ClassDefinition cd ? cd.Name : name;
            name = name == null && statement is FunctionDefinition fd ? fd.Name : name;

            return(new Hover {
                contents = _docSource.GetHover(name, value, self),
                range = range
            });
        }
 /// <summary>
 /// Writes module data to the database.
 /// </summary>
 public Task StoreModuleAnalysisAsync(IDocumentAnalysis analysis, CancellationToken cancellationToken = default)
 => Task.Run(() => StoreModuleAnalysis(analysis, cancellationToken), cancellationToken);
Пример #18
0
        private static void AssertNoHover(HoverSource hs, IDocumentAnalysis analysis, SourceLocation position)
        {
            var hover = hs.GetHover(analysis, position);

            hover.Should().BeNull();
        }
        public bool CanUpdateAnalysis(int version, out IPythonModule module, out PythonAst ast, out IDocumentAnalysis currentAnalysis)
        {
            lock (_syncObj) {
                module          = _module;
                ast             = _ast;
                currentAnalysis = _analysisTcs.Task.Status == TaskStatus.RanToCompletion ? _analysisTcs.Task.Result : default;

                if (module == null || ast == null)
                {
                    return(false);
                }

                if (_previousAnalysis is EmptyAnalysis || _moduleType == ModuleType.User)
                {
                    return(true);
                }

                return(_analysisVersion <= version);
            }
        }
Пример #20
0
 public ModuleInfo(IDocumentAnalysis document) :
     this(document, module : null, new List <string>(), moduleImported : false)
 {
 }
Пример #21
0
        public static string Generate(IDocumentAnalysis analysis, string name)
        {
            var generator = new UniqueNameGenerator(analysis, position: -1);

            return(generator.Generate(name));
        }
Пример #22
0
 public static IScope FindScope(this IDocumentAnalysis analysis, SourceLocation location)
 => analysis.GlobalScope.FindScope(analysis.Document, location);
        public CompletionResult GetCompletions(IDocumentAnalysis analysis, SourceLocation location)
        {
            var context = new CompletionContext(analysis, location, _itemSource);

            ExpressionLocator.FindExpression(analysis.Ast, location,
                                             FindExpressionOptions.Complete, out var expression, out var statement, out var scope);

            switch (expression)
            {
            case MemberExpression me when me.Target != null && me.DotIndex > me.StartIndex && context.Position > me.DotIndex:
                return(new CompletionResult(ExpressionCompletion.GetCompletionsFromMembers(me.Target, scope, context)));

            case ConstantExpression ce1 when ce1.Value is double || ce1.Value is float:
                // no completions on integer ., the user is typing a float
                return(CompletionResult.Empty);

            case ConstantExpression ce2 when ce2.Value is string:
            case ConstantExpression ce3 when ce3.Value is AsciiString:
            // no completions in strings
            case null when context.Ast.IsInsideComment(context.Location):
            case null when context.Ast.IsInsideString(context.Location):
                return(CompletionResult.Empty);
            }

            if (statement is ImportStatement import)
            {
                var result = ImportCompletion.TryGetCompletions(import, context);
                if (result != null)
                {
                    return(result);
                }
            }
            if (statement is FromImportStatement fromImport)
            {
                var result = ImportCompletion.GetCompletionsInFromImport(fromImport, context);
                if (result != null)
                {
                    return(result);
                }
            }

            switch (statement)
            {
            case FunctionDefinition fd when FunctionDefinitionCompletion.TryGetCompletionsForOverride(fd, context, null, out var result):
                return(result);

            case FunctionDefinition fd when FunctionDefinitionCompletion.NoCompletions(fd, context.Position, context.Ast):
                return(CompletionResult.Empty);

            case ClassDefinition cd:
                if (!ClassDefinitionCompletion.NoCompletions(cd, context, out var addMetadataArg))
                {
                    var result = TopLevelCompletion.GetCompletions(statement, scope, context);
                    return(addMetadataArg
                            ? new CompletionResult(result.Completions.Append(CompletionItemSource.MetadataArg), result.ApplicableSpan)
                            : result);
                }
                return(CompletionResult.Empty);

            case ForStatement forStatement when ForCompletion.TryGetCompletions(forStatement, context, out var result):
                return(result);

            case WithStatement withStatement when WithCompletion.TryGetCompletions(withStatement, context, out var result):
                return(result);

            case RaiseStatement raiseStatement when RaiseCompletion.TryGetCompletions(raiseStatement, context, out var result):
                return(result);

            case TryStatementHandler tryStatement when ExceptCompletion.TryGetCompletions(tryStatement, context, out var result):
                return(result);

            default: {
                var result = ErrorExpressionCompletion.GetCompletions(scope, statement, expression, context);
                if (result == null)
                {
                    return(CompletionResult.Empty);
                }
                return(result == CompletionResult.Empty ? TopLevelCompletion.GetCompletions(statement, scope, context) : result);
            }
            }
        }
 public IReadOnlyList <DiagnosticsEntry> Lint(IDocumentAnalysis analysis, IServiceContainer services)
 => _linters.SelectMany(l => l.Lint(analysis, services)).ToArray();
Пример #25
0
        private MarkupContent HandleImport(ImportStatement imp, SourceLocation location, ScopeStatement scope, IDocumentAnalysis analysis)
        {
            // 'import A.B, B.C, D.E as F, G, H'
            var eval            = analysis.ExpressionEvaluator;
            var position        = location.ToIndex(analysis.Ast);
            var dottedNameIndex = imp.Names.IndexOf(n => n.StartIndex <= position && position < n.EndIndex);

            if (dottedNameIndex >= 0)
            {
                var dottedName = imp.Names[dottedNameIndex];
                var module     = GetModule(dottedName.MakeString(), dottedName.Names, position, analysis);
                module = module ?? GetModuleFromDottedName(dottedName.Names, position, eval);
                return(module != null?_docSource.GetHover(module.Name, module) : null);
            }
            // Are we over 'D'?
            var nameIndex = imp.AsNames.ExcludeDefault().IndexOf(n => n.StartIndex <= position && position < n.EndIndex);

            if (nameIndex >= 0)
            {
                using (eval.OpenScope(analysis.Document, scope)) {
                    var variableName = imp.AsNames[nameIndex].Name;
                    var m            = eval.LookupNameInScopes(variableName, out _);
                    if (m != null)
                    {
                        return(_docSource.GetHover(variableName, m));
                    }
                }
            }
            return(null);
        }
        private static void Test(IDocumentAnalysis analysis, int position, string name, string expected)
        {
            var actual = UniqueNameGenerator.Generate(analysis, position, name);

            actual.Should().Be(expected);
        }
        /// <summary>
        /// Constructs module persistent model from analysis.
        /// </summary>
        public static ModuleModel FromAnalysis(IDocumentAnalysis analysis, IServiceContainer services, AnalysisCachingLevel options)
        {
            var uniqueId = analysis.Document.GetUniqueId(services, options);

            if (uniqueId == null)
            {
                // Caching level setting does not permit this module to be persisted.
                return(null);
            }

            var variables   = new Dictionary <string, VariableModel>();
            var functions   = new Dictionary <string, FunctionModel>();
            var classes     = new Dictionary <string, ClassModel>();
            var typeVars    = new Dictionary <string, TypeVarModel>();
            var namedTuples = new Dictionary <string, NamedTupleModel>();

            //var subModules = new Dictionary<string, SubmoduleModel>();

            foreach (var v in analysis.Document.GetMemberNames()
                     .Select(x => analysis.GlobalScope.Variables[x]).ExcludeDefault())
            {
                if (v.Value is IGenericTypeParameter && !typeVars.ContainsKey(v.Name))
                {
                    typeVars[v.Name] = TypeVarModel.FromGeneric(v, services);
                    continue;
                }

                switch (v.Value)
                {
                case ITypingNamedTupleType nt:
                    namedTuples[v.Name] = new NamedTupleModel(nt, services);
                    continue;

                case IPythonFunctionType ft when ft.IsLambda():
                    // No need to persist lambdas.
                    continue;

                case IPythonFunctionType ft when v.Name != ft.Name:
                    // Variable assigned to type info of the function like
                    //    def func(): ...
                    //    x = type(func)
                    break;

                case IPythonFunctionType ft:
                    var fm = GetFunctionModel(analysis, v, ft, services);
                    if (fm != null && !functions.ContainsKey(ft.Name))
                    {
                        functions[ft.Name] = fm;
                        continue;
                    }
                    break;

                case IPythonClassType cls when v.Name != cls.Name:
                    // Variable assigned to type info of the class.
                    break;

                case IPythonClassType cls
                    when cls.DeclaringModule.Equals(analysis.Document) || cls.DeclaringModule.Equals(analysis.Document.Stub):
                    if (!classes.ContainsKey(cls.Name))
                    {
                        classes[cls.Name] = new ClassModel(cls, services);
                        continue;
                    }

                    break;
                }

                // Do not re-declare classes and functions as variables in the model.
                if (!variables.ContainsKey(v.Name))
                {
                    variables[v.Name] = VariableModel.FromVariable(v, services);
                }
            }

            return(new ModuleModel {
                Id = uniqueId.GetStableHash(),
                UniqueId = uniqueId,
                Name = analysis.Document.Name,
                QualifiedName = analysis.Document.QualifiedName,
                FilePath = analysis.Document.FilePath,
                Documentation = analysis.Document.Documentation,
                Functions = functions.Values.ToArray(),
                Variables = variables.Values.ToArray(),
                Classes = classes.Values.ToArray(),
                TypeVars = typeVars.Values.ToArray(),
                NamedTuples = namedTuples.Values.ToArray(),
                //SubModules = subModules.Values.ToArray(),
                NewLines = analysis.Ast.NewLineLocations.Select(l => new NewLineModel {
                    EndIndex = l.EndIndex,
                    Kind = l.Kind
                }).ToArray(),
                FileSize = analysis.Ast.EndIndex
            });
        }