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 }); }
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) { }
private bool IsAnalyzedLibraryInLoop(IDependencyChainNode <PythonAnalyzerEntry> node, IDocumentAnalysis currentAnalysis) => !node.HasMissingDependencies && currentAnalysis is LibraryAnalysis && node.IsWalkedWithDependencies && node.IsValidVersion;
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; }
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; }
public AnalysisClassifier(IDocumentAnalysis documentAnalysis) { _analysisResult = documentAnalysis.CurrentResult; _documentAnalysis = documentAnalysis; _documentAnalysis.AnalysisUpdated += AnalysisUpdated; }
/// <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);
protected LinterWalker(IDocumentAnalysis analysis, IServiceContainer services) { Analysis = analysis; Services = services; }
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)); }
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 }); }
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);
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); } }
public ModuleInfo(IDocumentAnalysis document) : this(document, module : null, new List <string>(), moduleImported : false) { }
public static string Generate(IDocumentAnalysis analysis, string name) { var generator = new UniqueNameGenerator(analysis, position: -1); return(generator.Generate(name)); }
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();
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 }); }