From c6a9c223be9265f72b042dfcf41aad7006e9f9ba Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 30 Sep 2019 12:03:05 -0700 Subject: [PATCH 1/9] Remove stale reference --- .../Impl/Microsoft.Python.LanguageServer.csproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/LanguageServer/Impl/Microsoft.Python.LanguageServer.csproj b/src/LanguageServer/Impl/Microsoft.Python.LanguageServer.csproj index ca455737f..a33882e0d 100644 --- a/src/LanguageServer/Impl/Microsoft.Python.LanguageServer.csproj +++ b/src/LanguageServer/Impl/Microsoft.Python.LanguageServer.csproj @@ -33,14 +33,6 @@ - - - $(AnalysisReference)/Microsoft.Python.Analysis.Engine.dll - - - PreserveNewest - - From 6109ac761f1c2398c5ca6b4f38826cfb28051454 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Tue, 12 Nov 2019 13:55:07 -0800 Subject: [PATCH 2/9] Don't suppress LHS diagnostics on augmented assign --- .../UndefinedVariables/UndefinedVariablesWalker.cs | 2 -- src/Analysis/Ast/Test/AssignmentTests.cs | 9 +++++++++ src/Analysis/Ast/Test/LintUndefinedVarsTests.cs | 12 ++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Ast/Impl/Linting/UndefinedVariables/UndefinedVariablesWalker.cs b/src/Analysis/Ast/Impl/Linting/UndefinedVariables/UndefinedVariablesWalker.cs index 7365bf08d..42ac73bf0 100644 --- a/src/Analysis/Ast/Impl/Linting/UndefinedVariables/UndefinedVariablesWalker.cs +++ b/src/Analysis/Ast/Impl/Linting/UndefinedVariables/UndefinedVariablesWalker.cs @@ -49,9 +49,7 @@ public override bool Walk(SuiteStatement node) { HandleNonLocal(nls); break; case AugmentedAssignStatement augs: - _suppressDiagnostics = true; augs.Left?.Walk(new ExpressionWalker(this)); - _suppressDiagnostics = false; augs.Right?.Walk(new ExpressionWalker(this)); break; case AssignmentStatement asst: diff --git a/src/Analysis/Ast/Test/AssignmentTests.cs b/src/Analysis/Ast/Test/AssignmentTests.cs index cf3a54344..298454515 100644 --- a/src/Analysis/Ast/Test/AssignmentTests.cs +++ b/src/Analysis/Ast/Test/AssignmentTests.cs @@ -219,6 +219,15 @@ def __init__(self): .Which.Should().HaveMembers("abc", "y", "__class__"); } + [TestMethod, Priority(0)] + public async Task AugmentedAssignToUndefined() { + const string code = @" +x += 1 +"; + var analysis = await GetAnalysisAsync(code); + analysis.Should().NotHaveVariable("x"); + } + [TestMethod, Priority(0)] public async Task BaseInstanceVariable() { const string code = @" diff --git a/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs b/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs index cdee6b70f..dec8c849a 100644 --- a/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs +++ b/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs @@ -821,6 +821,18 @@ class Subclass(MyClass): d.Should().BeEmpty(); } + [TestMethod, Priority(0)] + public async Task AugmentedAssignToUndefined() { + const string code = @" +x += 1 +"; + var d = await LintAsync(code); + d.Should().HaveCount(1); + d[0].ErrorCode.Should().Be(ErrorCodes.UndefinedVariable); + d[0].SourceSpan.Should().Be(2, 1, 2, 2); + } + + private async Task> LintAsync(string code, InterpreterConfiguration configuration = null) { var analysis = await GetAnalysisAsync(code, configuration ?? PythonVersions.LatestAvailable3X); var a = Services.GetService(); From bcfc3b7246947674cbc18d7a76d2b90c105acf89 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Tue, 12 Nov 2019 15:30:27 -0800 Subject: [PATCH 3/9] Revert "Don't suppress LHS diagnostics on augmented assign" This reverts commit 6109ac761f1c2398c5ca6b4f38826cfb28051454. --- .../UndefinedVariables/UndefinedVariablesWalker.cs | 2 ++ src/Analysis/Ast/Test/AssignmentTests.cs | 9 --------- src/Analysis/Ast/Test/LintUndefinedVarsTests.cs | 12 ------------ 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/src/Analysis/Ast/Impl/Linting/UndefinedVariables/UndefinedVariablesWalker.cs b/src/Analysis/Ast/Impl/Linting/UndefinedVariables/UndefinedVariablesWalker.cs index 42ac73bf0..7365bf08d 100644 --- a/src/Analysis/Ast/Impl/Linting/UndefinedVariables/UndefinedVariablesWalker.cs +++ b/src/Analysis/Ast/Impl/Linting/UndefinedVariables/UndefinedVariablesWalker.cs @@ -49,7 +49,9 @@ public override bool Walk(SuiteStatement node) { HandleNonLocal(nls); break; case AugmentedAssignStatement augs: + _suppressDiagnostics = true; augs.Left?.Walk(new ExpressionWalker(this)); + _suppressDiagnostics = false; augs.Right?.Walk(new ExpressionWalker(this)); break; case AssignmentStatement asst: diff --git a/src/Analysis/Ast/Test/AssignmentTests.cs b/src/Analysis/Ast/Test/AssignmentTests.cs index 298454515..cf3a54344 100644 --- a/src/Analysis/Ast/Test/AssignmentTests.cs +++ b/src/Analysis/Ast/Test/AssignmentTests.cs @@ -219,15 +219,6 @@ def __init__(self): .Which.Should().HaveMembers("abc", "y", "__class__"); } - [TestMethod, Priority(0)] - public async Task AugmentedAssignToUndefined() { - const string code = @" -x += 1 -"; - var analysis = await GetAnalysisAsync(code); - analysis.Should().NotHaveVariable("x"); - } - [TestMethod, Priority(0)] public async Task BaseInstanceVariable() { const string code = @" diff --git a/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs b/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs index dec8c849a..cdee6b70f 100644 --- a/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs +++ b/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs @@ -821,18 +821,6 @@ class Subclass(MyClass): d.Should().BeEmpty(); } - [TestMethod, Priority(0)] - public async Task AugmentedAssignToUndefined() { - const string code = @" -x += 1 -"; - var d = await LintAsync(code); - d.Should().HaveCount(1); - d[0].ErrorCode.Should().Be(ErrorCodes.UndefinedVariable); - d[0].SourceSpan.Should().Be(2, 1, 2, 2); - } - - private async Task> LintAsync(string code, InterpreterConfiguration configuration = null) { var analysis = await GetAnalysisAsync(code, configuration ?? PythonVersions.LatestAvailable3X); var a = Services.GetService(); From c16646d97345765a93cac68179e467e9fd8ce697 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Thu, 12 Dec 2019 23:04:51 -0800 Subject: [PATCH 4/9] Escape [ and ] --- .../Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs | 5 ++--- .../Impl/Documentation/DocstringConverter.cs | 2 +- src/LanguageServer/Test/DocstringConverterTests.cs | 7 +++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs b/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs index 5348dbc2d..d4b3b79d1 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs @@ -38,10 +38,9 @@ internal sealed class FunctionEvaluator : MemberEvaluator { public FunctionEvaluator(ExpressionEval eval, PythonFunctionOverload overload) : base(eval, overload.FunctionDefinition) { _overload = overload; - _function = overload.ClassMember ?? throw new NullReferenceException(nameof(overload.ClassMember)); + _function = overload.ClassMember ?? throw new ArgumentNullException(nameof(overload)); _self = _function.DeclaringType as PythonClassType; - - FunctionDefinition = overload.FunctionDefinition; + FunctionDefinition = overload.FunctionDefinition ?? throw new ArgumentNullException(nameof(overload)); } private FunctionDefinition FunctionDefinition { get; } diff --git a/src/LanguageServer/Impl/Documentation/DocstringConverter.cs b/src/LanguageServer/Impl/Documentation/DocstringConverter.cs index 046488540..3f345a11a 100644 --- a/src/LanguageServer/Impl/Documentation/DocstringConverter.cs +++ b/src/LanguageServer/Impl/Documentation/DocstringConverter.cs @@ -176,7 +176,7 @@ private static readonly (Regex, string)[] PotentialHeaders = new[] { private static readonly Regex TildaHeaderRegex = new Regex(@"^\s*~~~+$", RegexOptions.Singleline | RegexOptions.Compiled); private static readonly Regex PlusHeaderRegex = new Regex(@"^\s*\+\+\++$", RegexOptions.Singleline | RegexOptions.Compiled); private static readonly Regex LeadingAsteriskRegex = new Regex(@"^(\s+\* )(.*)$", RegexOptions.Singleline | RegexOptions.Compiled); - private static readonly Regex UnescapedMarkdownCharsRegex = new Regex(@"(? Date: Fri, 13 Dec 2019 11:09:45 -0800 Subject: [PATCH 5/9] PR feedback --- src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs b/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs index d4b3b79d1..cba3040ca 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs @@ -38,9 +38,9 @@ internal sealed class FunctionEvaluator : MemberEvaluator { public FunctionEvaluator(ExpressionEval eval, PythonFunctionOverload overload) : base(eval, overload.FunctionDefinition) { _overload = overload; - _function = overload.ClassMember ?? throw new ArgumentNullException(nameof(overload)); + _function = overload.ClassMember ?? throw new ArgumentNullException(nameof(overload.ClassMember)); _self = _function.DeclaringType as PythonClassType; - FunctionDefinition = overload.FunctionDefinition ?? throw new ArgumentNullException(nameof(overload)); + FunctionDefinition = overload.FunctionDefinition ?? throw new ArgumentNullException(nameof(overload.FunctionDefinition)); } private FunctionDefinition FunctionDefinition { get; } From 161260432267072669167cff6dda8c151bd5717f Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 2 Jan 2020 12:02:33 -0800 Subject: [PATCH 6/9] Fix navigation to local unknown parameters --- src/LanguageServer/Impl/Sources/DefinitionSource.cs | 2 +- src/LanguageServer/Test/GoToDefinitionTests.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/LanguageServer/Impl/Sources/DefinitionSource.cs b/src/LanguageServer/Impl/Sources/DefinitionSource.cs index a91cad1fe..29cf4e99a 100644 --- a/src/LanguageServer/Impl/Sources/DefinitionSource.cs +++ b/src/LanguageServer/Impl/Sources/DefinitionSource.cs @@ -265,7 +265,7 @@ private Reference TryFromVariable(string name, IDocumentAnalysis analysis, Sourc var m = analysis.ExpressionEvaluator.LookupNameInScopes(name, out var scope, LookupOptions.All); var v = scope?.Variables[name]; - if (m == null || scope == null || scope.Module.ModuleType == ModuleType.Builtins || v.IsUnknown()) { + if (m == null || scope == null || scope.Module.ModuleType == ModuleType.Builtins || v == null) { return null; } diff --git a/src/LanguageServer/Test/GoToDefinitionTests.cs b/src/LanguageServer/Test/GoToDefinitionTests.cs index 37bcb933b..58d1b8494 100644 --- a/src/LanguageServer/Test/GoToDefinitionTests.cs +++ b/src/LanguageServer/Test/GoToDefinitionTests.cs @@ -710,5 +710,17 @@ from nonexistent import some var reference = ds.FindDefinition(analysis, new SourceLocation(2, 26), out _); reference.Should().BeNull(); } + + [TestMethod, Priority(0)] + public async Task LocalParameter() { + const string code = @" +def func(a, b): + return a+b +"; + var analysis = await GetAnalysisAsync(code); + var ds = new DefinitionSource(Services); + var reference = ds.FindDefinition(analysis, new SourceLocation(3, 12), out _); + reference.range.Should().Be(1, 9, 1, 10); + } } } From 8bfd46b903d483149f5b3dc9ff45c8cab7bb5c58 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 2 Jan 2020 14:56:39 -0800 Subject: [PATCH 7/9] Enable option for library code navigation --- .../Ast/Impl/Analyzer/AnalysisModuleKey.cs | 5 +- .../Ast/Impl/Analyzer/AnalysisWalker.cs | 24 +++++++-- .../Evaluation/ExpressionEval.Callables.cs | 3 +- .../Ast/Impl/Analyzer/PythonAnalyzer.cs | 2 +- .../Impl/Analyzer/PythonAnalyzerSession.cs | 5 ++ .../Analyzer/Symbols/FunctionEvaluator.cs | 8 +-- .../Ast/Impl/Definitions/AnalysisOptions.cs | 7 --- src/Analysis/Ast/Impl/Types/LocatedMember.cs | 4 +- .../Impl/LanguageServer.Configuration.cs | 1 - src/LanguageServer/Test/ReferencesTests.cs | 49 +++++++++++++++++++ 10 files changed, 86 insertions(+), 22 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/AnalysisModuleKey.cs b/src/Analysis/Ast/Impl/Analyzer/AnalysisModuleKey.cs index a92c02906..3de3ac411 100644 --- a/src/Analysis/Ast/Impl/Analyzer/AnalysisModuleKey.cs +++ b/src/Analysis/Ast/Impl/Analyzer/AnalysisModuleKey.cs @@ -26,7 +26,6 @@ namespace Microsoft.Python.Analysis.Analyzer { public string Name { get; } public string FilePath { get; } public bool IsTypeshed { get; } - public bool IsNonUserAsDocument { get; } public AnalysisModuleKey(IPythonModule module) : this( module.Name, @@ -41,13 +40,12 @@ private AnalysisModuleKey(string name, string filePath, bool isTypeshed, bool is Name = name; FilePath = filePath; IsTypeshed = isTypeshed; - IsNonUserAsDocument = isNonUserAsDocument; } public AnalysisModuleKey GetNonUserAsDocumentKey() => new AnalysisModuleKey(Name, FilePath, IsTypeshed, true); public bool Equals(AnalysisModuleKey other) - => Name.EqualsOrdinal(other.Name) && FilePath.PathEquals(other.FilePath) && IsTypeshed == other.IsTypeshed && IsNonUserAsDocument == other.IsNonUserAsDocument; + => Name.EqualsOrdinal(other.Name) && FilePath.PathEquals(other.FilePath) && IsTypeshed == other.IsTypeshed; public override bool Equals(object obj) => obj is AnalysisModuleKey other && Equals(other); @@ -56,7 +54,6 @@ public override int GetHashCode() { var hashCode = Name != null ? Name.GetHashCode() : 0; hashCode = (hashCode * 397) ^ (FilePath != null ? FilePath.GetPathHashCode() : 0); hashCode = (hashCode * 397) ^ IsTypeshed.GetHashCode(); - hashCode = (hashCode * 397) ^ IsNonUserAsDocument.GetHashCode(); return hashCode; } } diff --git a/src/Analysis/Ast/Impl/Analyzer/AnalysisWalker.cs b/src/Analysis/Ast/Impl/Analyzer/AnalysisWalker.cs index e733cf60e..f85643fba 100644 --- a/src/Analysis/Ast/Impl/Analyzer/AnalysisWalker.cs +++ b/src/Analysis/Ast/Impl/Analyzer/AnalysisWalker.cs @@ -18,6 +18,7 @@ using Microsoft.Python.Analysis.Analyzer.Evaluation; using Microsoft.Python.Analysis.Analyzer.Handlers; using Microsoft.Python.Analysis.Analyzer.Symbols; +using Microsoft.Python.Analysis.Modules; using Microsoft.Python.Analysis.Types; using Microsoft.Python.Parsing.Ast; @@ -61,6 +62,26 @@ public override bool Walk(NamedExpression node) { return base.Walk(node); } + public override bool Walk(CallExpression node) { + Eval.ProcessCallForReferences(node); + return base.Walk(node); + } + + public override void PostWalk(DelStatement node) { + if (Module.ModuleType != ModuleType.User && + Eval.Services.GetService()?.Options.KeepLibraryAst != true) { + return; + } + + var names = node.Expressions.OfType() + .Concat(node.Expressions.OfType().SelectMany(t => t.Items.OfType())) + .Where(x => !string.IsNullOrEmpty(x.Name)); + + foreach (var nex in names) { + Eval.LookupNameInScopes(nex.Name)?.AddReference(Eval.GetLocationOfName(nex)); + } + } + public override bool Walk(ExpressionStatement node) { switch (node.Expression) { case ExpressionWithAnnotation ea: @@ -69,9 +90,6 @@ public override bool Walk(ExpressionStatement node) { case Comprehension comp: Eval.ProcessComprehension(comp); return false; - case CallExpression callex: - Eval.ProcessCallForReferences(callex); - return true; default: return base.Walk(node); } diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs index 351a54d39..436adc1f9 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Callables.cs @@ -389,7 +389,8 @@ private void DeclareParameter(Parameter p, ParameterInfo pi) { } internal void ProcessCallForReferences(CallExpression callExpr, LookupOptions lookupOptions = LookupOptions.Normal) { - if (Module.ModuleType != ModuleType.User) { + if (Module.ModuleType != ModuleType.User && + Services.GetService()?.Options.KeepLibraryAst != true) { return; } diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs index 3f1698648..9822c74c8 100644 --- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs +++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzer.cs @@ -252,7 +252,7 @@ private void AnalyzeDocument(in AnalysisModuleKey key, in PythonAnalyzerEntry en ActivityTracker.StartTracking(); _log?.Log(TraceEventType.Verbose, $"Analysis of {entry.Module.Name} ({entry.Module.ModuleType}) queued. Dependencies: {string.Join(", ", dependencies.Select(d => d.IsTypeshed ? $"{d.Name} (stub)" : d.Name))}"); - var graphVersion = _dependencyResolver.ChangeValue(key, entry, entry.IsUserOrBuiltin || key.IsNonUserAsDocument, dependencies); + var graphVersion = _dependencyResolver.ChangeValue(key, entry, entry.IsUserOrBuiltin, dependencies); lock (_syncObj) { if (_version >= graphVersion) { return; diff --git a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzerSession.cs b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzerSession.cs index 023550a05..f532f2037 100644 --- a/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzerSession.cs +++ b/src/Analysis/Ast/Impl/Analyzer/PythonAnalyzerSession.cs @@ -512,6 +512,11 @@ private IDocumentAnalysis CreateAnalysis(IDependencyChainSingleNode(); + if (optionsProvider?.Options.KeepLibraryAst == true) { + createLibraryAnalysis = false; + } + if (!createLibraryAnalysis) { return new DocumentAnalysis(document, version, walker.GlobalScope, walker.Eval, walker.StarImportMemberNames); } diff --git a/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs b/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs index cba3040ca..39c7b128a 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Symbols/FunctionEvaluator.cs @@ -60,15 +60,15 @@ public override void Evaluate() { // Do process body of constructors since they may be declaring // variables that are later used to determine return type of other // methods and properties. + var optionsProvider = Eval.Services.GetService(); + var keepAst = optionsProvider?.Options.KeepLibraryAst == true; var ctor = _function.IsDunderInit() || _function.IsDunderNew(); - if (ctor || returnType.IsUnknown() || Module.ModuleType == ModuleType.User) { + if (ctor || returnType.IsUnknown() || Module.ModuleType == ModuleType.User || keepAst) { // Return type from the annotation is sufficient for libraries and stubs, no need to walk the body. FunctionDefinition.Body?.Walk(this); // For libraries remove declared local function variables to free up some memory // unless function has inner classes or functions. - var optionsProvider = Eval.Services.GetService(); - if (Module.ModuleType != ModuleType.User && - optionsProvider?.Options.KeepLibraryLocalVariables != true && + if (Module.ModuleType != ModuleType.User && !keepAst && Eval.CurrentScope.Variables.All( v => v.GetPythonType() == null && v.GetPythonType() == null) diff --git a/src/Analysis/Ast/Impl/Definitions/AnalysisOptions.cs b/src/Analysis/Ast/Impl/Definitions/AnalysisOptions.cs index dcf73ec35..52a8f2106 100644 --- a/src/Analysis/Ast/Impl/Definitions/AnalysisOptions.cs +++ b/src/Analysis/Ast/Impl/Definitions/AnalysisOptions.cs @@ -36,13 +36,6 @@ public enum AnalysisCachingLevel { public class AnalysisOptions { public bool LintingEnabled { get; set; } - /// - /// Keep in memory information on local variables declared in - /// functions in libraries. Provides ability to navigate to - /// symbols used in function bodies in packages and libraries. - /// - public bool KeepLibraryLocalVariables { get; set; } - /// /// Keep in memory AST of library source code. May somewhat /// improve performance when library code has to be re-analyzed. diff --git a/src/Analysis/Ast/Impl/Types/LocatedMember.cs b/src/Analysis/Ast/Impl/Types/LocatedMember.cs index 54d732663..504af4be9 100644 --- a/src/Analysis/Ast/Impl/Types/LocatedMember.cs +++ b/src/Analysis/Ast/Impl/Types/LocatedMember.cs @@ -65,8 +65,10 @@ public virtual void AddReference(Location location) { (this.DeclaringModule?.ModuleType == ModuleType.Builtins && MemberType != PythonMemberType.Function)) { return; } + var keepReferencesInLibraries = + location.Module.Analysis.ExpressionEvaluator.Services.GetService()?.Options.KeepLibraryAst == true; // Don't add references to library code. - if (location.Module?.ModuleType == ModuleType.User && !location.Equals(Location)) { + if ((location.Module?.ModuleType == ModuleType.User || keepReferencesInLibraries) && !location.Equals(Location)) { _references = _references ?? new HashSet(); _references.Add(location); } diff --git a/src/LanguageServer/Impl/LanguageServer.Configuration.cs b/src/LanguageServer/Impl/LanguageServer.Configuration.cs index a7634fb75..64651e862 100644 --- a/src/LanguageServer/Impl/LanguageServer.Configuration.cs +++ b/src/LanguageServer/Impl/LanguageServer.Configuration.cs @@ -130,7 +130,6 @@ private void HandleDiagnosticsChanges(JToken pythonSection, LanguageServerSettin var memory = analysis["memory"]; var optionsProvider = _services.GetService(); - optionsProvider.Options.KeepLibraryLocalVariables = GetSetting(memory, "keepLibraryLocalVariables", false); optionsProvider.Options.KeepLibraryAst = GetSetting(memory, "keepLibraryAst", false); optionsProvider.Options.AnalysisCachingLevel = GetAnalysisCachingLevel(analysis); diff --git a/src/LanguageServer/Test/ReferencesTests.cs b/src/LanguageServer/Test/ReferencesTests.cs index 405808b5c..7db878718 100644 --- a/src/LanguageServer/Test/ReferencesTests.cs +++ b/src/LanguageServer/Test/ReferencesTests.cs @@ -435,5 +435,54 @@ public async Task EmptyAnalysis() { var references = await rs.FindAllReferencesAsync(null, new SourceLocation(1, 1), ReferenceSearchOptions.All); references.Should().BeEmpty(); } + + [TestMethod, Priority(0)] + public async Task DelStatement1() { + const string code = @" +def func(a, b): + return a+b + +del func +"; + var analysis = await GetAnalysisAsync(code); + var rs = new ReferenceSource(Services); + var refs = await rs.FindAllReferencesAsync(analysis.Document.Uri, new SourceLocation(5, 6), ReferenceSearchOptions.All); + + refs.Should().HaveCount(2); + refs[0].range.Should().Be(1, 4, 1, 8); + refs[0].uri.Should().Be(analysis.Document.Uri); + refs[1].range.Should().Be(4, 4, 4, 8); + refs[1].uri.Should().Be(analysis.Document.Uri); + } + + [TestMethod, Priority(0)] + public async Task DelStatement2() { + const string code = @" +def func1(a, b): + return a+b + +def func2(a, b): + return a+b + +del (func1, func2) +"; + var analysis = await GetAnalysisAsync(code); + var rs = new ReferenceSource(Services); + var refs = await rs.FindAllReferencesAsync(analysis.Document.Uri, new SourceLocation(8, 6), ReferenceSearchOptions.All); + + refs.Should().HaveCount(2); + refs[0].range.Should().Be(1, 4, 1, 9); + refs[0].uri.Should().Be(analysis.Document.Uri); + refs[1].range.Should().Be(7, 5, 7, 10); + refs[1].uri.Should().Be(analysis.Document.Uri); + + refs = await rs.FindAllReferencesAsync(analysis.Document.Uri, new SourceLocation(8, 14), ReferenceSearchOptions.All); + + refs.Should().HaveCount(2); + refs[0].range.Should().Be(4, 4, 4, 9); + refs[0].uri.Should().Be(analysis.Document.Uri); + refs[1].range.Should().Be(7, 12, 7, 17); + refs[1].uri.Should().Be(analysis.Document.Uri); + } } } From 2ce2d7bd4622fd46607793d86415031134b80256 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 2 Jan 2020 15:14:39 -0800 Subject: [PATCH 8/9] Eval both sides of binary of for references --- .../Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs index c0bb0b92e..dbd3f3116 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Operators.cs @@ -68,10 +68,11 @@ private IMember GetValueFromBinaryOp(Expression expr, LookupOptions lookupOption if (expr is OrExpression orexp) { // Consider 'self.__params = types.MappingProxyType(params or {})' var leftSide = GetValueFromExpression(orexp.Left, lookupOptions); + // Do evaluate both sides in order to correctly track references + var rightSide = GetValueFromExpression(orexp.Right, lookupOptions); if (!leftSide.IsUnknown()) { return leftSide; } - var rightSide = GetValueFromExpression(orexp.Right, lookupOptions); return rightSide.IsUnknown() ? Interpreter.GetBuiltinType(BuiltinTypeId.Bool) : rightSide; } From f518221d72a6c8825f5d7f3e4a1a679ffcc3f4c2 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Thu, 2 Jan 2020 16:08:44 -0800 Subject: [PATCH 9/9] Simplify condition --- src/LanguageServer/Impl/Sources/DefinitionSource.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/LanguageServer/Impl/Sources/DefinitionSource.cs b/src/LanguageServer/Impl/Sources/DefinitionSource.cs index 29cf4e99a..f55de804c 100644 --- a/src/LanguageServer/Impl/Sources/DefinitionSource.cs +++ b/src/LanguageServer/Impl/Sources/DefinitionSource.cs @@ -264,8 +264,12 @@ private Reference TryFromVariable(string name, IDocumentAnalysis analysis, Sourc definingMember = null; var m = analysis.ExpressionEvaluator.LookupNameInScopes(name, out var scope, LookupOptions.All); - var v = scope?.Variables[name]; - if (m == null || scope == null || scope.Module.ModuleType == ModuleType.Builtins || v == null) { + if(m == null || scope == null || scope.Module.ModuleType == ModuleType.Builtins) { + return null; + } + + var v = scope.Variables[name]; + if (v == null || (v.Source == VariableSource.Import && v.IsUnknown())) { return null; }