From c6a9c223be9265f72b042dfcf41aad7006e9f9ba Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Mon, 30 Sep 2019 12:03:05 -0700 Subject: [PATCH 01/11] 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 02/11] 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 03/11] 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 04/11] 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 05/11] 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 e2d4146af63af93a30bcc59007b32d68cce3e54a Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Thu, 19 Mar 2020 18:10:51 -0700 Subject: [PATCH 06/11] Allow navigation to stubs --- src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs | 4 +++- src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs index 3b67d45d2..f55abb0f6 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.cs @@ -60,7 +60,9 @@ public ExpressionEval(IServiceContainer services, IPythonModule module, PythonAs public LocationInfo GetLocationInfo(Node node) => node?.GetLocation(this) ?? LocationInfo.Empty; public Location GetLocationOfName(Node node) { - if (node == null || Module.ModuleType != ModuleType.User && Module.ModuleType != ModuleType.Library) { + if (node == null || + Module.ModuleType == ModuleType.Specialized || Module.ModuleType == ModuleType.Compiled || + Module.ModuleType == ModuleType.CompiledBuiltin || Module.ModuleType == ModuleType.Builtins) { return DefaultLocation; } diff --git a/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs b/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs index b383758d1..3d2a725f8 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs @@ -128,7 +128,7 @@ private void AddFunction(FunctionDefinition fd, PythonType declaringType) { // if there are multiple functions with same name exist, only the very first one will be // maintained in the scope. we should improve this if possible. // https://github.com/microsoft/python-language-server/issues/1693 - _eval.DeclareVariable(fd.Name, f, VariableSource.Declaration); + _eval.DeclareVariable(fd.Name, f, VariableSource.Declaration, _eval.GetLocationOfName(fd)); _typeMap[fd] = f; declaringType?.AddMember(f.Name, f, overwrite: true); } From 481e7f510178b279b2aa00054cd12558d8424932 Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Sun, 22 Mar 2020 17:41:02 -0700 Subject: [PATCH 07/11] Better handle stubs for compiled modules --- .../Evaluation/ExpressionEval.Scopes.cs | 2 ++ src/Analysis/Ast/Impl/Analyzer/StubMerger.cs | 20 +++++++++++++++++-- src/Analysis/Ast/Impl/Values/Scope.cs | 5 +++++ .../Test/GoToDefinitionTests.cs | 14 +++++++++++++ src/LanguageServer/Test/HoverTests.cs | 12 +++++++++++ 5 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Scopes.cs b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Scopes.cs index 2a1b5787b..fbc867250 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Scopes.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Evaluation/ExpressionEval.Scopes.cs @@ -177,6 +177,8 @@ public IDisposable OpenScope(IPythonModule module, ScopeStatement node, out Scop return new ScopeTracker(this); } + internal void ReplaceVariable(IVariable v) => CurrentScope.ReplaceVariable(v); + private class ScopeTracker : IDisposable { private readonly ExpressionEval _eval; diff --git a/src/Analysis/Ast/Impl/Analyzer/StubMerger.cs b/src/Analysis/Ast/Impl/Analyzer/StubMerger.cs index 54eb2dd29..97114e3de 100644 --- a/src/Analysis/Ast/Impl/Analyzer/StubMerger.cs +++ b/src/Analysis/Ast/Impl/Analyzer/StubMerger.cs @@ -181,7 +181,17 @@ private void MergeMembers(IVariable v, IPythonType sourceType, IPythonType stubT // Replace the class entirely since stub members may use generic types // and the class definition is important. We transfer missing members // from the original class to the stub. - _eval.DeclareVariable(v.Name, v.Value, v.Source); + // + // In case module is compiled, it is already a stub and has no locations + // for code navigation.. In this case we replace the entire variable by one + // from the stub rather than just the value since stub variable has location + // and its own root definition/reference chain. + if (sourceType.DeclaringModule.ModuleType == ModuleType.Compiled || + sourceType.DeclaringModule.ModuleType == ModuleType.CompiledBuiltin) { + _eval.ReplaceVariable(v); + } else { + _eval.DeclareVariable(v.Name, v.Value, v.Source); + } // First pass: go through source class members and pick those // that are not present in the stub class. @@ -340,7 +350,13 @@ private bool IsFromThisModuleOrSubmodules(IPythonType type) { var thisModule = _eval.Module; var typeModule = type.DeclaringModule; var typeMainModuleName = typeModule.Name.Split('.').FirstOrDefault(); - return typeModule.Equals(thisModule) || typeMainModuleName == thisModule.Name; + if (typeModule.Equals(thisModule) || typeMainModuleName == thisModule.Name) { + return true; + } + // Check if module is explicitly imported by the current one. For example, 'os' + // imports 'nt' and os.pyi specifies functions from 'nt' such as mkdir and so on. + var imported = thisModule.GlobalScope.Variables[typeModule.Name]; + return imported?.Value != null && imported.Source == VariableSource.Import; } } } diff --git a/src/Analysis/Ast/Impl/Values/Scope.cs b/src/Analysis/Ast/Impl/Values/Scope.cs index 2d49f8f69..08df8a957 100644 --- a/src/Analysis/Ast/Impl/Values/Scope.cs +++ b/src/Analysis/Ast/Impl/Values/Scope.cs @@ -98,6 +98,11 @@ public void DeclareImported(string name, IMember value, Location location = defa internal void AddChildScope(Scope s) => (_childScopes ?? (_childScopes = new Dictionary()))[s.Node] = s; + internal void ReplaceVariable(IVariable v) { + VariableCollection.RemoveVariable(v.Name); + VariableCollection.DeclareVariable(v.Name, v.Value, v.Source, v.Location); + } + private VariableCollection VariableCollection => _variables ?? (_variables = new VariableCollection()); private void DeclareBuiltinVariables() { diff --git a/src/LanguageServer/Test/GoToDefinitionTests.cs b/src/LanguageServer/Test/GoToDefinitionTests.cs index 58d1b8494..fdd3f3a28 100644 --- a/src/LanguageServer/Test/GoToDefinitionTests.cs +++ b/src/LanguageServer/Test/GoToDefinitionTests.cs @@ -722,5 +722,19 @@ def func(a, b): var reference = ds.FindDefinition(analysis, new SourceLocation(3, 12), out _); reference.range.Should().Be(1, 9, 1, 10); } + + [TestMethod, Priority(0)] + public async Task CompiledCode() { + const string code = @" +import os +os.mkdir() +"; + var analysis = await GetAnalysisAsync(code); + var ds = new DefinitionSource(Services); + var reference = ds.FindDefinition(analysis, new SourceLocation(3, 6), out _); + reference.range.start.line.Should().NotBe(1); + reference.range.end.line.Should().NotBe(1); + reference.uri.AbsolutePath.Should().Contain(".pyi"); + } } } diff --git a/src/LanguageServer/Test/HoverTests.cs b/src/LanguageServer/Test/HoverTests.cs index 0a167b18b..9377e5cc0 100644 --- a/src/LanguageServer/Test/HoverTests.cs +++ b/src/LanguageServer/Test/HoverTests.cs @@ -284,6 +284,18 @@ class A: AssertHover(hs, analysis, new SourceLocation(4, 7), @"x: int", new SourceSpan(4, 7, 4, 8)); } + [TestMethod, Priority(0)] + public async Task CompiledCode() { + const string code = @" +import os +os.mkdir() +"; + var analysis = await GetAnalysisAsync(code); + var hs = new HoverSource(new PlainTextDocumentationSource()); + var hover = hs.GetHover(analysis, new SourceLocation(3, 6)); + hover.contents.value.Should().Contain("Create a directory"); + } + private static void AssertNoHover(HoverSource hs, IDocumentAnalysis analysis, SourceLocation position) { var hover = hs.GetHover(analysis, position); hover.Should().BeNull(); From 31fe80ded90069faceaf99b3279c8ca8eab7002f Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Sat, 25 Apr 2020 22:32:18 -0700 Subject: [PATCH 08/11] Fix typeshed path --- src/Analysis/Ast/Impl/Analyzer/StubMerger.cs | 6 ++++- .../Modules/Resolution/TypeshedResolution.cs | 6 ++++- .../Impl/Implementation/Server.Editor.cs | 18 ++++++++----- .../Impl/Sources/DefinitionSource.cs | 25 +++++++++++++------ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/StubMerger.cs b/src/Analysis/Ast/Impl/Analyzer/StubMerger.cs index 97114e3de..2636a5691 100644 --- a/src/Analysis/Ast/Impl/Analyzer/StubMerger.cs +++ b/src/Analysis/Ast/Impl/Analyzer/StubMerger.cs @@ -149,6 +149,10 @@ private void TryReplaceMember(IVariable v, IPythonType sourceType, IPythonType s MergeMembers(v, sourceFunction, stubType, cancellationToken); break; + case PythonPropertyType sourceProperty: + MergeMembers(v, sourceProperty, stubType, cancellationToken); + break; + case IPythonModule _: // We do not re-declare modules. break; @@ -203,7 +207,7 @@ private void MergeMembers(IVariable v, IPythonType sourceType, IPythonType stubT continue; // Do not add unknowns to the stub. } var sourceMemberType = sourceMember?.GetPythonType(); - if (sourceMemberType is IPythonClassMember cm && cm.DeclaringType != sourceType) { + if (sourceMemberType is IPythonClassMember cm && !cm.DeclaringModule.Equals(sourceType.DeclaringModule)) { continue; // Only take members from this class and not from bases. } if (!IsFromThisModuleOrSubmodules(sourceMemberType)) { diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs index a5ad74b30..cbd1c33c8 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs @@ -32,8 +32,12 @@ internal sealed class TypeshedResolution : ModuleResolutionBase, IModuleResoluti public TypeshedResolution(string root, IServiceContainer services) : base(root, services) { // TODO: merge with user-provided stub paths - var stubs = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Stubs"); + var asmLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var stubs = Path.Combine(asmLocation, "Stubs"); + var typeshed = Path.Combine(asmLocation, "Typeshed"); + _typeStubPaths = GetTypeShedPaths(Root) + .Concat(GetTypeShedPaths(typeshed)) .Concat(GetTypeShedPaths(stubs)) .Where(services.GetService().DirectoryExists) .ToImmutableArray(); diff --git a/src/LanguageServer/Impl/Implementation/Server.Editor.cs b/src/LanguageServer/Impl/Implementation/Server.Editor.cs index b6133bd84..46de921fa 100644 --- a/src/LanguageServer/Impl/Implementation/Server.Editor.cs +++ b/src/LanguageServer/Impl/Implementation/Server.Editor.cs @@ -89,8 +89,11 @@ public async Task GotoDefinition(TextDocumentPositionParams @params _log?.Log(TraceEventType.Verbose, $"Goto Definition in {uri} at {@params.position}"); var analysis = await Document.GetAnalysisAsync(uri, Services, CompletionAnalysisTimeout, cancellationToken); - var reference = new DefinitionSource(Services).FindDefinition(analysis, @params.position, out _); - return reference != null ? new[] { reference } : Array.Empty(); + var ds = new DefinitionSource(Services); + var reference = ds.FindDefinition(analysis, @params.position, out _); + return reference != null && ds.CanNavigateToModule(reference.uri) + ? new[] { reference } + : Array.Empty(); } public async Task GotoDeclaration(TextDocumentPositionParams @params, CancellationToken cancellationToken) { @@ -98,8 +101,11 @@ public async Task GotoDeclaration(TextDocumentPositionParams @params, _log?.Log(TraceEventType.Verbose, $"Goto Declaration in {uri} at {@params.position}"); var analysis = await Document.GetAnalysisAsync(uri, Services, CompletionAnalysisTimeout, cancellationToken); - var reference = new DeclarationSource(Services).FindDefinition(analysis, @params.position, out _); - return reference != null ? new Location { uri = reference.uri, range = reference.range } : null; + var ds = new DeclarationSource(Services); + var reference = ds.FindDefinition(analysis, @params.position, out _); + return reference != null && ds.CanNavigateToModule(reference.uri) + ? new Location { uri = reference.uri, range = reference.range } + : null; } public Task FindReferences(ReferencesParams @params, CancellationToken cancellationToken) { @@ -137,8 +143,8 @@ public async Task CodeAction(CodeActionParams @params, Cancellatio return codeActions.ToArray(); - static bool AskedFor(CodeActionParams @params, string codeActionKind) { - return @params.context.only == null || @params.context.only.Any(s => s.StartsWith(codeActionKind)); + bool AskedFor(CodeActionParams p, string codeActionKind) { + return p.context.only == null || p.context.only.Any(s => s.StartsWith(codeActionKind)); } } } diff --git a/src/LanguageServer/Impl/Sources/DefinitionSource.cs b/src/LanguageServer/Impl/Sources/DefinitionSource.cs index 6cacb068a..e104afba4 100644 --- a/src/LanguageServer/Impl/Sources/DefinitionSource.cs +++ b/src/LanguageServer/Impl/Sources/DefinitionSource.cs @@ -14,6 +14,7 @@ // permissions and limitations under the License. using System; +using System.IO; using System.Linq; using Microsoft.Python.Analysis; using Microsoft.Python.Analysis.Analyzer; @@ -360,10 +361,14 @@ private Reference FromMember(IMember m) { return null; } - private bool CanNavigateToModule(Uri uri) { + public bool CanNavigateToModule(Uri uri) { if (uri == null) { return false; } + + if (!CanNavigateToPath(uri.LocalPath)) { + return false; + } var rdt = _services.GetService(); var doc = rdt.GetDocument(uri); // Allow navigation to modules not in RDT - most probably @@ -371,11 +376,17 @@ private bool CanNavigateToModule(Uri uri) { return doc == null || CanNavigateToModule(doc); } - private static bool CanNavigateToModule(IPythonModule m) - => m?.ModuleType == ModuleType.User || - m?.ModuleType == ModuleType.Stub || - m?.ModuleType == ModuleType.Package || - m?.ModuleType == ModuleType.Library || - m?.ModuleType == ModuleType.Specialized; + private static bool CanNavigateToModule(IPythonModule m) { + if(m == null || !CanNavigateToPath(m.FilePath)) { + return false; + } + return m.ModuleType == ModuleType.User || + m.ModuleType == ModuleType.Stub || + m.ModuleType == ModuleType.Package || + m.ModuleType == ModuleType.Library || + m.ModuleType == ModuleType.Specialized; + } + + private static bool CanNavigateToPath(string path) => Path.GetExtension(path) != ".exe"; } } From 9b7c4ee3950753d3c8359af886a4a3cf1524a99c Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Sun, 26 Apr 2020 10:43:06 -0700 Subject: [PATCH 09/11] Partial undo --- .../Ast/Impl/Modules/Resolution/TypeshedResolution.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs index cbd1c33c8..baae903d8 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs @@ -34,10 +34,10 @@ public TypeshedResolution(string root, IServiceContainer services) : base(root, // TODO: merge with user-provided stub paths var asmLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var stubs = Path.Combine(asmLocation, "Stubs"); - var typeshed = Path.Combine(asmLocation, "Typeshed"); + var typeshedRoot = Root ?? Path.Combine(asmLocation, "Typeshed"); _typeStubPaths = GetTypeShedPaths(Root) - .Concat(GetTypeShedPaths(typeshed)) + .Concat(GetTypeShedPaths(typeshedRoot)) .Concat(GetTypeShedPaths(stubs)) .Where(services.GetService().DirectoryExists) .ToImmutableArray(); From 443c1d8e5c45d8afbe43b9b9f8de1034f64bb5fe Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Sun, 26 Apr 2020 10:44:00 -0700 Subject: [PATCH 10/11] Partial undo --- src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs b/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs index baae903d8..91576a8dc 100644 --- a/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs +++ b/src/Analysis/Ast/Impl/Modules/Resolution/TypeshedResolution.cs @@ -36,8 +36,7 @@ public TypeshedResolution(string root, IServiceContainer services) : base(root, var stubs = Path.Combine(asmLocation, "Stubs"); var typeshedRoot = Root ?? Path.Combine(asmLocation, "Typeshed"); - _typeStubPaths = GetTypeShedPaths(Root) - .Concat(GetTypeShedPaths(typeshedRoot)) + _typeStubPaths = GetTypeShedPaths(typeshedRoot) .Concat(GetTypeShedPaths(stubs)) .Where(services.GetService().DirectoryExists) .ToImmutableArray(); From 695d7150a044d548eefc6c0f717b4782b796b43c Mon Sep 17 00:00:00 2001 From: Mikhail Arkhipov Date: Thu, 30 Apr 2020 22:08:45 -0700 Subject: [PATCH 11/11] Undo accidental change --- src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs b/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs index 3d2a725f8..b383758d1 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs @@ -128,7 +128,7 @@ private void AddFunction(FunctionDefinition fd, PythonType declaringType) { // if there are multiple functions with same name exist, only the very first one will be // maintained in the scope. we should improve this if possible. // https://github.com/microsoft/python-language-server/issues/1693 - _eval.DeclareVariable(fd.Name, f, VariableSource.Declaration, _eval.GetLocationOfName(fd)); + _eval.DeclareVariable(fd.Name, f, VariableSource.Declaration); _typeMap[fd] = f; declaringType?.AddMember(f.Name, f, overwrite: true); }