diff --git a/src/Analysis/Ast/Impl/Modules/PythonModule.cs b/src/Analysis/Ast/Impl/Modules/PythonModule.cs index df6e06112..af808c869 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonModule.cs @@ -71,8 +71,7 @@ private enum State { private object AnalysisLock { get; } = new object(); private State ContentState { get; set; } = State.None; - protected PythonModule(string name, ModuleType moduleType, IServiceContainer services) - : base(PythonMemberType.Module) { + protected PythonModule(string name, ModuleType moduleType, IServiceContainer services) : base(null) { Name = name ?? throw new ArgumentNullException(nameof(name)); Services = services ?? throw new ArgumentNullException(nameof(services)); ModuleType = moduleType; diff --git a/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs b/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs index d28233904..471c25e45 100644 --- a/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs +++ b/src/Analysis/Ast/Impl/Modules/PythonVariableModule.cs @@ -47,15 +47,15 @@ internal sealed class PythonVariableModule : LocatedMember, IPythonModule, IEqua public IGlobalScope GlobalScope => Module?.GlobalScope; public BuiltinTypeId TypeId => BuiltinTypeId.Module; public Uri Uri => Module?.Uri; + public override PythonMemberType MemberType => PythonMemberType.Module; - public PythonVariableModule(string name, IPythonInterpreter interpreter) - : base(PythonMemberType.Module) { + public PythonVariableModule(string name, IPythonInterpreter interpreter): base(null) { Name = name; Interpreter = interpreter; SetDeclaringModule(this); } - public PythonVariableModule(IPythonModule module): base(PythonMemberType.Module, module) { + public PythonVariableModule(IPythonModule module): base(module) { Name = module.Name; Interpreter = module.Interpreter; Module = module; diff --git a/src/Analysis/Ast/Impl/Specializations/Typing/Types/AnyType.cs b/src/Analysis/Ast/Impl/Specializations/Typing/Types/AnyType.cs index 091fa6659..d1e5f9e0e 100644 --- a/src/Analysis/Ast/Impl/Specializations/Typing/Types/AnyType.cs +++ b/src/Analysis/Ast/Impl/Specializations/Typing/Types/AnyType.cs @@ -20,9 +20,9 @@ namespace Microsoft.Python.Analysis.Specializations.Typing.Types { internal sealed class AnyType : LocatedMember, IPythonType { - public AnyType(IPythonModule declaringModule) - : base(PythonMemberType.Class, declaringModule) { } + public AnyType(IPythonModule declaringModule) : base(declaringModule) { } + public override PythonMemberType MemberType => PythonMemberType.Class; public string Name => "Any"; public BuiltinTypeId TypeId => BuiltinTypeId.Type; public string Documentation => Name; diff --git a/src/Analysis/Ast/Impl/Specializations/Typing/Types/GenericType.cs b/src/Analysis/Ast/Impl/Specializations/Typing/Types/GenericType.cs index f211139f8..df9d14a97 100644 --- a/src/Analysis/Ast/Impl/Specializations/Typing/Types/GenericType.cs +++ b/src/Analysis/Ast/Impl/Specializations/Typing/Types/GenericType.cs @@ -59,11 +59,12 @@ public GenericType( Parameters = parameters ?? Array.Empty(); } - private GenericType(string name, IPythonModule declaringModule) - : base(PythonMemberType.Generic, declaringModule) { + private GenericType(string name, IPythonModule declaringModule) : base(declaringModule) { Name = name ?? throw new ArgumentNullException(nameof(name)); } + public override PythonMemberType MemberType => PythonMemberType.Generic; + /// /// Type parameters such as in Tuple[T1, T2. ...] or /// Generic[_T1, _T2, ...] as returned by TypeVar. diff --git a/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingType.cs b/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingType.cs index 572a17ca5..387dcdbd2 100644 --- a/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingType.cs +++ b/src/Analysis/Ast/Impl/Specializations/Typing/Values/TypingType.cs @@ -25,12 +25,12 @@ namespace Microsoft.Python.Analysis.Specializations.Typing.Values { internal sealed class TypingType : LocatedMember, IPythonType { private readonly IPythonType _type; - public TypingType(IPythonModule declaringModule, IPythonType type) - : base(PythonMemberType.Class, declaringModule) { + public TypingType(IPythonModule declaringModule, IPythonType type): base(declaringModule) { _type = type ?? throw new ArgumentNullException(nameof(type)); Name = $"Type[{_type.Name}]"; } + public override PythonMemberType MemberType => PythonMemberType.Class; public string Name { get; } public BuiltinTypeId TypeId => BuiltinTypeId.Type; public string Documentation => Name; diff --git a/src/Analysis/Ast/Impl/Types/Definitions/IImportedMember.cs b/src/Analysis/Ast/Impl/Types/Definitions/IImportedMember.cs new file mode 100644 index 000000000..962859f78 --- /dev/null +++ b/src/Analysis/Ast/Impl/Types/Definitions/IImportedMember.cs @@ -0,0 +1,26 @@ +// Copyright(c) Microsoft Corporation +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the License); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABILITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +namespace Microsoft.Python.Analysis.Types { + /// + /// Imported member that has link to its parent in another module. + /// + public interface IImportedMember : ILocatedMember { + /// + /// Link to the primary definition such as when variable is imported from another file. + /// + ILocatedMember Parent { get; } + } +} diff --git a/src/Analysis/Ast/Impl/Types/Definitions/ILocatedMember.cs b/src/Analysis/Ast/Impl/Types/Definitions/ILocatedMember.cs index e585c4092..c1cceb88c 100644 --- a/src/Analysis/Ast/Impl/Types/Definitions/ILocatedMember.cs +++ b/src/Analysis/Ast/Impl/Types/Definitions/ILocatedMember.cs @@ -37,11 +37,6 @@ public interface ILocatedMember: IMember { /// LocationInfo Definition { get; } - /// - /// Link to the primary definition such as when variable is imported from another file. - /// - ILocatedMember Parent { get; } - /// /// List of references to the member. /// diff --git a/src/Analysis/Ast/Impl/Types/LocatedMember.cs b/src/Analysis/Ast/Impl/Types/LocatedMember.cs index 1d319be96..d752e3f4f 100644 --- a/src/Analysis/Ast/Impl/Types/LocatedMember.cs +++ b/src/Analysis/Ast/Impl/Types/LocatedMember.cs @@ -23,31 +23,18 @@ namespace Microsoft.Python.Analysis.Types { internal abstract class LocatedMember : ILocatedMember { private HashSet _references; - protected LocatedMember(PythonMemberType memberType) { - MemberType = memberType; - } - - protected LocatedMember(PythonMemberType memberType, IPythonModule module) - : this(memberType, new Location(module, default)) { } - - protected LocatedMember(PythonMemberType memberType, Location location, ILocatedMember parent = null) - : this(location, parent) { - MemberType = memberType; - } + protected LocatedMember(IPythonModule module) : this(new Location(module, default)) { } - private LocatedMember(Location location, ILocatedMember parent = null) { - Parent = parent; - Parent?.AddReference(location); + protected LocatedMember(Location location) { Location = location; } - public virtual PythonMemberType MemberType { get; } = PythonMemberType.Unknown; + public abstract PythonMemberType MemberType { get; } public virtual IPythonModule DeclaringModule => Location.Module; public virtual LocationInfo Definition => Location.LocationInfo; - public ILocatedMember Parent { get; } public virtual IReadOnlyList References { get { @@ -98,7 +85,6 @@ protected EmptyLocatedMember(PythonMemberType memberType) { public PythonMemberType MemberType { get; } public IPythonModule DeclaringModule => null; public LocationInfo Definition => LocationInfo.Empty; - public ILocatedMember Parent => null; public IReadOnlyList References => Array.Empty(); public void AddReference(Location location) { } public void RemoveReferences(IPythonModule module) { } diff --git a/src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs b/src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs index 78fc487a9..6215512ad 100644 --- a/src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs +++ b/src/Analysis/Ast/Impl/Types/PythonFunctionOverload.cs @@ -58,11 +58,14 @@ public PythonFunctionOverload(FunctionDefinition fd, IPythonClassMember classMem _returnDocumentation = ast != null ? fd.ReturnAnnotation?.ToCodeString(ast) : null; } - public PythonFunctionOverload(string name, Location location) - : base(PythonMemberType.Function, location) { + public PythonFunctionOverload(string name, Location location) : base(location) { Name = name ?? throw new ArgumentNullException(nameof(name)); } + #region ILocatedMember + public override PythonMemberType MemberType => PythonMemberType.Function; + #endregion + internal void SetParameters(IReadOnlyList parameters) => Parameters = parameters; internal void SetDocumentationProvider(Func documentationProvider) @@ -147,7 +150,6 @@ public string GetReturnDocumentation(IPythonType self = null) { } public IReadOnlyList Parameters { get; private set; } = Array.Empty(); - public override PythonMemberType MemberType => PythonMemberType.Function; public IMember StaticReturnValue { get; private set; } public IMember Call(IArgumentSet args, IPythonType self, Node callLocation = null) { diff --git a/src/Analysis/Ast/Impl/Types/PythonType.cs b/src/Analysis/Ast/Impl/Types/PythonType.cs index 252165952..41e9bda1c 100644 --- a/src/Analysis/Ast/Impl/Types/PythonType.cs +++ b/src/Analysis/Ast/Impl/Types/PythonType.cs @@ -54,13 +54,16 @@ public PythonType( _documentationProvider = documentationProvider; } - private PythonType(string name, Location location, BuiltinTypeId typeId) - : base(typeId.GetMemberId(), location) { + private PythonType(string name, Location location, BuiltinTypeId typeId) : base(location) { Check.ArgumentNotNull(nameof(location), location.Module); _name = name ?? throw new ArgumentNullException(nameof(name)); _typeId = typeId; } + #region ILocatedMember + public override PythonMemberType MemberType => _typeId.GetMemberId(); + #endregion + #region IPythonType public virtual string Name => TypeId == BuiltinTypeId.Ellipsis ? "..." : _name; diff --git a/src/Analysis/Ast/Impl/Types/PythonTypeWrapper.cs b/src/Analysis/Ast/Impl/Types/PythonTypeWrapper.cs index 9ba61a893..5201297b1 100644 --- a/src/Analysis/Ast/Impl/Types/PythonTypeWrapper.cs +++ b/src/Analysis/Ast/Impl/Types/PythonTypeWrapper.cs @@ -76,7 +76,6 @@ public virtual IMember Index(IPythonInstance instance, object index) #region ILocatedMember public Location Location => InnerType?.Location ?? default; public LocationInfo Definition => InnerType?.Definition ?? LocationInfo.Empty; - public ILocatedMember Parent => InnerType?.Parent; public IReadOnlyList References => InnerType?.References ?? Array.Empty(); public void AddReference(Location location) => InnerType?.AddReference(location); public void RemoveReferences(IPythonModule module) => InnerType?.RemoveReferences(module); diff --git a/src/Analysis/Ast/Impl/Types/PythonUnionType.cs b/src/Analysis/Ast/Impl/Types/PythonUnionType.cs index 2e7c69865..c5f83c75f 100644 --- a/src/Analysis/Ast/Impl/Types/PythonUnionType.cs +++ b/src/Analysis/Ast/Impl/Types/PythonUnionType.cs @@ -26,19 +26,19 @@ internal sealed class PythonUnionType : LocatedMember, IPythonUnionType { private readonly HashSet _types = new HashSet(PythonTypeComparer.Instance); private readonly object _lock = new object(); - public PythonUnionType(IEnumerable types, IPythonModule declaringModule) - : base(PythonMemberType.Union, declaringModule) { + public PythonUnionType(IEnumerable types, IPythonModule declaringModule) : base(declaringModule) { _types.UnionWith(types); } - private PythonUnionType(IPythonType x, IPythonType y) - : base(PythonMemberType.Union, x.DeclaringModule) { + private PythonUnionType(IPythonType x, IPythonType y) : base(x.DeclaringModule) { Check.Argument(nameof(x), () => !(x is IPythonUnionType)); Check.Argument(nameof(y), () => !(y is IPythonUnionType)); _types.Add(x); _types.Add(y); } + public override PythonMemberType MemberType => PythonMemberType.Union; + #region IPythonType public string Name { diff --git a/src/Analysis/Ast/Impl/Values/GlobalScope.cs b/src/Analysis/Ast/Impl/Values/GlobalScope.cs index df375b923..42e42e41d 100644 --- a/src/Analysis/Ast/Impl/Values/GlobalScope.cs +++ b/src/Analysis/Ast/Impl/Values/GlobalScope.cs @@ -35,13 +35,13 @@ private void DeclareBuiltinVariables() { var listType = Module.Interpreter.GetBuiltinType(BuiltinTypeId.List); var dictType = Module.Interpreter.GetBuiltinType(BuiltinTypeId.Dict); - VariableCollection.DeclareVariable("__debug__", boolType, VariableSource.Builtin); - VariableCollection.DeclareVariable("__doc__", strType, VariableSource.Builtin); - VariableCollection.DeclareVariable("__file__", strType, VariableSource.Builtin); - VariableCollection.DeclareVariable("__name__", strType, VariableSource.Builtin); - VariableCollection.DeclareVariable("__package__", strType, VariableSource.Builtin); - VariableCollection.DeclareVariable("__path__", listType, VariableSource.Builtin); - VariableCollection.DeclareVariable("__dict__", dictType, VariableSource.Builtin); + DeclareVariable("__debug__", boolType, VariableSource.Builtin); + DeclareVariable("__doc__", strType, VariableSource.Builtin); + DeclareVariable("__file__", strType, VariableSource.Builtin); + DeclareVariable("__name__", strType, VariableSource.Builtin); + DeclareVariable("__package__", strType, VariableSource.Builtin); + DeclareVariable("__path__", listType, VariableSource.Builtin); + DeclareVariable("__dict__", dictType, VariableSource.Builtin); } } } diff --git a/src/Analysis/Ast/Impl/Values/ImportedVariable.cs b/src/Analysis/Ast/Impl/Values/ImportedVariable.cs new file mode 100644 index 000000000..46a22fefe --- /dev/null +++ b/src/Analysis/Ast/Impl/Values/ImportedVariable.cs @@ -0,0 +1,102 @@ +// Copyright(c) Microsoft Corporation +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the License); you may not use +// this file except in compliance with the License. You may obtain a copy of the +// License at http://www.apache.org/licenses/LICENSE-2.0 +// +// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS +// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY +// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, +// MERCHANTABILITY OR NON-INFRINGEMENT. +// +// See the Apache Version 2.0 License for specific language governing +// permissions and limitations under the License. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.Python.Analysis.Types; +using Microsoft.Python.Core; + +namespace Microsoft.Python.Analysis.Values { + [DebuggerDisplay("{DebuggerDisplay}")] + internal sealed class ImportedVariable : Variable, IImportedMember { + public ImportedVariable(string name, IVariable parent, Location location) + : base(name, parent.Value, VariableSource.Import, location) { + Parent = parent; + Parent?.AddReference(location); + } + + #region IImportedMember + public ILocatedMember Parent { get; } + #endregion + + #region ILocatedMember + public override LocationInfo Definition { + get { + if (!Location.IsValid && Parent != null) { + return Parent?.Definition ?? LocationInfo.Empty; + } + return base.Definition; + } + } + + public override IReadOnlyList References { + get { + if (!Location.IsValid && Parent != null) { + return Parent?.References ?? Array.Empty(); + } + return base.References; + } + } + + protected override bool AddOrRemoveReference(Action action) { + // Variable can be + // a) Declared locally in the module. In this case it has non-default + // definition location and no parent (link). + // b) Imported from another module via 'from module import X'. + // In this case it has non-default definition location and non-null parent (link). + // c) Imported from another module via 'from module import *'. + // In this case it has default location (which means it is not explicitly declared) + // and the non-null parent (link). + var explicitlyDeclared = Location.IsValid; + if (!explicitlyDeclared && Parent != null) { + action(Parent); + return true; + } + // Explicitly declared. + // Values: + // a) If value is not a located member, then add reference to the variable. + // b) If variable name is the same as the value member name, then the variable + // is implicit declaration (like declared function or a class) and we need + // to add reference to the actual type instead. + var lmv = GetImplicitlyDeclaredValue(); + if (lmv != null) { + // Variable is not user-declared and rather is holder of a function or class definition. + action(lmv); + return true; + } + action(Parent); + return false; + } + + #endregion + + private ILocatedMember GetImplicitlyDeclaredValue() + => Value is ILocatedMember lm && Name.EqualsOrdinal(lm.GetPythonType()?.Name) && !Location.IsValid ? lm : null; + + private string DebuggerDisplay { + get { + switch (Value) { + case IPythonInstance pi: + return $"{Name} : instance of {pi.Type.Name}"; + case IPythonType pt: + return $"{Name} : typeInfo of {pt.Name}"; + default: + return $"{Name} : member {Value?.MemberType}"; + } + } + } + } +} diff --git a/src/Analysis/Ast/Impl/Values/Scope.cs b/src/Analysis/Ast/Impl/Values/Scope.cs index fc3933ede..c62e93d58 100644 --- a/src/Analysis/Ast/Impl/Values/Scope.cs +++ b/src/Analysis/Ast/Impl/Values/Scope.cs @@ -26,12 +26,11 @@ namespace Microsoft.Python.Analysis.Values { /// Represents scope where variables can be declared. /// internal class Scope : IScope { + private VariableCollection _variables; private VariableCollection _nonLocals; private VariableCollection _globals; private List _childScopes; - protected VariableCollection VariableCollection { get; } = new VariableCollection(); - public Scope(ScopeStatement node, IScope outerScope, IPythonModule module) { Node = node; OuterScope = outerScope; @@ -47,7 +46,7 @@ public Scope(ScopeStatement node, IScope outerScope, IPythonModule module) { public IPythonModule Module { get; } public IReadOnlyList Children => _childScopes?.ToArray() ?? Array.Empty(); - public IVariableCollection Variables => VariableCollection; + public IVariableCollection Variables => _variables ?? VariableCollection.Empty; public IVariableCollection NonLocals => _nonLocals ?? VariableCollection.Empty; public IVariableCollection Globals => _globals ?? VariableCollection.Empty; @@ -89,6 +88,8 @@ public void DeclareGlobal(string name, Location location) internal void AddChildScope(Scope s) => (_childScopes ?? (_childScopes = new List())).Add(s); + private VariableCollection VariableCollection => _variables ?? (_variables = new VariableCollection()); + private void DeclareBuiltinVariables() { if (Node == null || Module.ModuleType != ModuleType.User || this is IGlobalScope) { return; diff --git a/src/Analysis/Ast/Impl/Values/Variable.cs b/src/Analysis/Ast/Impl/Values/Variable.cs index cc01e5a9d..41e3d9d57 100644 --- a/src/Analysis/Ast/Impl/Values/Variable.cs +++ b/src/Analysis/Ast/Impl/Values/Variable.cs @@ -21,21 +21,13 @@ namespace Microsoft.Python.Analysis.Values { [DebuggerDisplay("{DebuggerDisplay}")] - internal sealed class Variable : LocatedMember, IVariable { - public Variable(string name, IMember value, VariableSource source, Location location) - : base(PythonMemberType.Variable, location) { + internal class Variable : LocatedMember, IVariable { + public Variable(string name, IMember value, VariableSource source, Location location) : base(location) { Name = name ?? throw new ArgumentNullException(nameof(name)); Value = value is IVariable v ? v.Value : value; Source = source; } - public Variable(string name, IVariable parent, Location location) - : base(PythonMemberType.Variable, location, parent) { - Name = name ?? throw new ArgumentNullException(nameof(name)); - Value = parent.Value; - Source = VariableSource.Import; - } - #region IVariable public string Name { get; } public VariableSource Source { get; } @@ -54,12 +46,11 @@ public void Assign(IMember value, Location location) { #endregion #region ILocatedMember + public override PythonMemberType MemberType => PythonMemberType.Variable; + public override LocationInfo Definition { get { if (!Location.IsValid) { - if (Parent != null) { - return Parent?.Definition ?? LocationInfo.Empty; - } var lmv = GetImplicitlyDeclaredValue(); if (lmv != null) { return lmv.Definition; @@ -72,9 +63,6 @@ public override LocationInfo Definition { public override IReadOnlyList References { get { if (!Location.IsValid) { - if (Parent != null) { - return Parent?.References ?? Array.Empty(); - } var lmv = GetImplicitlyDeclaredValue(); if (lmv != null) { return lmv.References; @@ -101,21 +89,7 @@ public override void RemoveReferences(IPythonModule module) { } } - private bool AddOrRemoveReference(Action action) { - // Variable can be - // a) Declared locally in the module. In this case it has non-default - // definition location and no parent (link). - // b) Imported from another module via 'from module import X'. - // In this case it has non-default definition location and non-null parent (link). - // c) Imported from another module via 'from module import *'. - // In this case it has default location (which means it is not explicitly declared) - // and the non-null parent (link). - var explicitlyDeclared = Location.IsValid; - if (!explicitlyDeclared && Parent != null) { - action(Parent); - return true; - } - // Explicitly declared. + protected virtual bool AddOrRemoveReference(Action action) { // Values: // a) If value is not a located member, then add reference to the variable. // b) If variable name is the same as the value member name, then the variable @@ -127,7 +101,6 @@ private bool AddOrRemoveReference(Action action) { action(lmv); return true; } - action(Parent); return false; } diff --git a/src/Analysis/Ast/Impl/Values/VariableCollection.cs b/src/Analysis/Ast/Impl/Values/VariableCollection.cs index 308b3493d..893358d73 100644 --- a/src/Analysis/Ast/Impl/Values/VariableCollection.cs +++ b/src/Analysis/Ast/Impl/Values/VariableCollection.cs @@ -111,7 +111,7 @@ internal void DeclareVariable(string name, IMember value, VariableSource source, internal void LinkVariable(string name, IVariable v, Location location) { name = !string.IsNullOrWhiteSpace(name) ? name : throw new ArgumentException(nameof(name)); - var variable = new Variable(name, v, location); + var variable = new ImportedVariable(name, v, location); lock (_syncObj) { _variables[name] = variable; } diff --git a/src/Analysis/Ast/Test/ReferencesTests.cs b/src/Analysis/Ast/Test/ReferencesTests.cs index 936f9dc7b..3301048ec 100644 --- a/src/Analysis/Ast/Test/ReferencesTests.cs +++ b/src/Analysis/Ast/Test/ReferencesTests.cs @@ -318,7 +318,8 @@ from MultiValues import t x = t "; var analysis = await GetAnalysisAsync(code); - var t = analysis.Should().HaveVariable("t").Which; + var t = analysis.Should().HaveVariable("t").Which as IImportedMember; + t.Should().NotBeNull(); t.Definition.Span.Should().Be(2, 25, 2, 26); t.Definition.DocumentUri.AbsolutePath.Should().Contain("module.py"); t.References.Should().HaveCount(2); diff --git a/src/LanguageServer/Impl/Sources/DefinitionSource.cs b/src/LanguageServer/Impl/Sources/DefinitionSource.cs index 89b85b743..27e82157a 100644 --- a/src/LanguageServer/Impl/Sources/DefinitionSource.cs +++ b/src/LanguageServer/Impl/Sources/DefinitionSource.cs @@ -82,7 +82,7 @@ public Reference FindDefinition(IDocumentAnalysis analysis, SourceLocation locat private Reference HandleFromImport(IDocumentAnalysis analysis, SourceLocation location, FromImportStatement statement, Node expr, out ILocatedMember definingMember) { definingMember = null; - + // Are in the dotted name? var locationIndex = location.ToIndex(analysis.Ast); if (statement.Root.StartIndex <= locationIndex && locationIndex <= statement.Root.EndIndex) { @@ -175,7 +175,8 @@ private Reference TryFromVariable(string name, IDocumentAnalysis analysis, Sourc var indexSpan = v.Definition.Span.ToIndexSpan(analysis.Ast); var index = location.ToIndex(analysis.Ast); if (indexSpan.Start <= index && index < indexSpan.End) { - var definition = v.Parent != null ? v.Parent.Definition : (v.Value as ILocatedMember)?.Definition; + var parent = (v as IImportedMember)?.Parent; + var definition = parent?.Definition ?? (v.Value as ILocatedMember)?.Definition; if (definition != null && CanNavigateToModule(definition.DocumentUri)) { return new Reference { range = definition.Span, uri = definition.DocumentUri }; } diff --git a/src/LanguageServer/Impl/Sources/ReferenceSource.cs b/src/LanguageServer/Impl/Sources/ReferenceSource.cs index 7b34d859f..c302d91f3 100644 --- a/src/LanguageServer/Impl/Sources/ReferenceSource.cs +++ b/src/LanguageServer/Impl/Sources/ReferenceSource.cs @@ -136,7 +136,7 @@ private static async Task AnalyzeFiles(IModuleManagement moduleManagement, var module = moduleManagement.GetOrLoadModule(fullName); if (module is IDocument document) { analysisTasks.Add(document.GetAnalysisAsync(cancellationToken: cancellationToken)); - } + } } } @@ -146,10 +146,20 @@ private static async Task AnalyzeFiles(IModuleManagement moduleManagement, return analysisTasks.Count > 0; } - + private ILocatedMember GetRootDefinition(ILocatedMember lm) { - for (; lm.Parent != null; lm = lm.Parent) { } - return lm; + if (!(lm is IImportedMember im) || im.Parent == null) { + return lm; + } + + var parent = im.Parent; + for (; parent != null;) { + if (!(parent is IImportedMember im1) || im1.Parent == null) { + break; + } + parent = im1.Parent; + } + return parent; } } }