Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/Analysis/Ast/Impl/Modules/BuiltinsPythonModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ private void SpecializeTypes() {
continue;
}

if (biType.IsUnknown()) {
// Under no circumstances we modify the unknown type.
continue;
}

if (biType.IsHidden) {
_hiddenNames.Add(biType.Name);
}
Expand Down Expand Up @@ -98,6 +103,8 @@ private void SpecializeTypes() {
biType.AddMember(@"__iter__", BuiltinsSpecializations.__iter__(Interpreter, typeId), true);
}
break;
case BuiltinTypeId.Unknown:
break;
default:
biType.TrySetTypeId(typeId);
switch (typeId) {
Expand Down
2 changes: 1 addition & 1 deletion src/Analysis/Ast/Impl/Types/PythonType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public PythonType(
private PythonType(string name, IPythonModule declaringModule, BuiltinTypeId typeId = BuiltinTypeId.Unknown) {
_name = name ?? throw new ArgumentNullException(nameof(name));
DeclaringModule = declaringModule;
_typeId = typeId; _typeId = typeId;
_typeId = typeId;
}

#region IPythonType
Expand Down
17 changes: 17 additions & 0 deletions src/Analysis/Ast/Test/BasicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,23 @@ import sys
.And.HaveVariable("x").OfType(BuiltinTypeId.List);
}

[DataRow(true, true)]
[DataRow(false, true)]
[DataRow(true, false)]
[DataRow(false, false)]
[DataTestMethod, Priority(0)]
public async Task UnknownType(bool isPython3X, bool isAnaconda) {
const string code = @"x = 1";

var configuration = isPython3X
? isAnaconda ? PythonVersions.LatestAnaconda3X : PythonVersions.LatestAvailable3X
: isAnaconda ? PythonVersions.LatestAnaconda2X : PythonVersions.LatestAvailable2X;
var analysis = await GetAnalysisAsync(code, configuration);

var unkType = analysis.Document.Interpreter.UnknownType;
unkType.TypeId.Should().Be(BuiltinTypeId.Unknown);
}

[DataRow(true, true)]
[DataRow(false, true)]
[DataRow(true, false)]
Expand Down
64 changes: 47 additions & 17 deletions src/LanguageServer/Impl/Sources/DefinitionSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Microsoft.Python.Analysis.Modules;
using Microsoft.Python.Analysis.Types;
using Microsoft.Python.Analysis.Values;
using Microsoft.Python.Core;
using Microsoft.Python.Core.Text;
using Microsoft.Python.LanguageServer.Completion;
using Microsoft.Python.LanguageServer.Protocol;
Expand Down Expand Up @@ -55,23 +56,10 @@ public Reference FindDefinition(IDocumentAnalysis analysis, SourceLocation locat
}

var value = eval.GetValueFromExpression(expr);
if (value.IsUnknown()) {
// If this is 'import A as B' A is not declared as a variable, so try modules.
string moduleName = null;
if (!string.IsNullOrEmpty(name)) {
switch (statement) {
case ImportStatement imp when imp.Names.Any(x => x?.MakeString() == name):
case FromImportStatement fimp when fimp.Root.Names.Any(x => x?.Name == name):
moduleName = name;
break;
}

if (moduleName != null) {
var module = analysis.Document.Interpreter.ModuleResolution.GetImportedModule(moduleName);
if (module != null && CanNavigateToModule(module, analysis)) {
return new Reference {range = default, uri = module.Uri};
}
}
if (value.IsUnknown() && !string.IsNullOrEmpty(name)) {
var reference = FromImport(statement, name, analysis, out value);
if (reference != null) {
return reference;
}
}

Expand All @@ -82,6 +70,48 @@ public Reference FindDefinition(IDocumentAnalysis analysis, SourceLocation locat
}
}

private Reference FromImport(Node statement, string name, IDocumentAnalysis analysis, out IMember value) {
value = null;
string moduleName = null;
switch (statement) {
// In 'import A as B' A is not declared as a variable, so try locating B.
case ImportStatement imp when imp.Names.Any(x => x?.MakeString() == name):
case FromImportStatement fimp when fimp.Root.Names.Any(x => x?.Name == name):
moduleName = name;
break;
}

if (moduleName != null) {
var module = analysis.Document.Interpreter.ModuleResolution.GetImportedModule(moduleName);
if (module != null && CanNavigateToModule(module, analysis)) {
return new Reference { range = default, uri = module.Uri };
}
}

// Perhaps it is a member such as A in 'from X import A as B'
switch (statement) {
case ImportStatement imp: {
// Import A as B
var index = imp.Names.IndexOf(x => x?.MakeString() == name);
if (index >= 0 && index < imp.AsNames.Count) {
value = analysis.ExpressionEvaluator.GetValueFromExpression(imp.AsNames[index]);
return null;
}
break;
}
case FromImportStatement fimp: {
// From X import A as B
var index = fimp.Names.IndexOf(x => x?.Name == name);
if (index >= 0 && index < fimp.AsNames.Count) {
value = analysis.ExpressionEvaluator.GetValueFromExpression(fimp.AsNames[index]);
return null;
}
break;
}
}
return null;
}

private Reference FromMember(IMember value, Expression expr, Node statement, IDocumentAnalysis analysis) {
Node node = null;
IPythonModule module = null;
Expand Down
13 changes: 13 additions & 0 deletions src/LanguageServer/Test/GoToDefinitionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,19 @@ public async Task GotoModuleSourceFromImport() {
reference.uri.AbsolutePath.Should().NotContain("pyi");
}

[TestMethod, Priority(0)]
public async Task GotoModuleSourceFromImportAs() {
const string code = @"from logging import RootLogger as rl";
var analysis = await GetAnalysisAsync(code, PythonVersions.LatestAvailable3X);
var ds = new DefinitionSource();

var reference = ds.FindDefinition(analysis, new SourceLocation(1, 23));
reference.Should().NotBeNull();
reference.range.start.line.Should().BeGreaterThan(500);
reference.uri.AbsolutePath.Should().Contain("logging");
reference.uri.AbsolutePath.Should().NotContain("pyi");
}

[TestMethod, Priority(0)]
public async Task GotoBuiltinObject() {
const string code = @"
Expand Down