diff --git a/src/Analysis/Engine/Impl/AnalysisValueSetExtensions.cs b/src/Analysis/Engine/Impl/AnalysisValueSetExtensions.cs index 3ea088976..bd7d67316 100644 --- a/src/Analysis/Engine/Impl/AnalysisValueSetExtensions.cs +++ b/src/Analysis/Engine/Impl/AnalysisValueSetExtensions.cs @@ -218,7 +218,7 @@ internal static AnalysisValue GetUnionType(this IAnalysisSet types) { /// Gets instance representations of all members of the set. /// public static IAnalysisSet GetInstanceType(this IAnalysisSet types) - => AnalysisSet.Create(types.SelectMany(ns => (ns.PythonType as IPythonType2)?.IsClass == true ? ns : ns.GetInstanceType())); + => AnalysisSet.Create(types.SelectMany(ns => ns.PythonType?.IsTypeFactory == true ? ns : ns.GetInstanceType())); public static bool IsUnknown(this IAnalysisSet res) { return res == null || diff --git a/src/Analysis/Engine/Impl/Analyzer/DDG.cs b/src/Analysis/Engine/Impl/Analyzer/DDG.cs index a579ff4c0..a8a3bca6b 100644 --- a/src/Analysis/Engine/Impl/Analyzer/DDG.cs +++ b/src/Analysis/Engine/Impl/Analyzer/DDG.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. diff --git a/src/Analysis/Engine/Impl/Definitions/IOverloadResult.cs b/src/Analysis/Engine/Impl/Definitions/IOverloadResult.cs index 7fc3cbcba..0dde5f8cf 100644 --- a/src/Analysis/Engine/Impl/Definitions/IOverloadResult.cs +++ b/src/Analysis/Engine/Impl/Definitions/IOverloadResult.cs @@ -9,21 +9,40 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; namespace Microsoft.PythonTools.Analysis { public interface IOverloadResult { + /// + /// Function name. + /// string Name { get; } + + /// + /// Function documentation. + /// string Documentation { get; } - [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", - Justification = "breaking change")] + + /// + /// First parameter if removed from the set. + /// Typically 'self' or 'cls'. + /// + ParameterResult FirstParameter { get; } + + /// + /// Function parameters. First parameter may be removed, in which case + /// it is present as . + /// ParameterResult[] Parameters { get; } + + /// + /// Possible return types. + /// IReadOnlyList ReturnType { get; } } } diff --git a/src/Analysis/Engine/Impl/EmptyBuiltinModule.cs b/src/Analysis/Engine/Impl/EmptyBuiltinModule.cs index 7e8d4b984..dab810cb8 100644 --- a/src/Analysis/Engine/Impl/EmptyBuiltinModule.cs +++ b/src/Analysis/Engine/Impl/EmptyBuiltinModule.cs @@ -16,14 +16,11 @@ using System.Collections.Generic; using Microsoft.PythonTools.Interpreter; +using Microsoft.PythonTools.Interpreter.Ast; namespace Microsoft.PythonTools.Analysis { - class EmptyBuiltinModule : IBuiltinPythonModule { - private readonly string _name; - - public EmptyBuiltinModule(string name) { - _name = name; - } + class EmptyBuiltinModule : PythonModuleType, IBuiltinPythonModule { + public EmptyBuiltinModule(string name): base(name) { } #region IBuiltinPythonModule Members @@ -35,42 +32,12 @@ public IMember GetAnyMember(string name) { #region IPythonModule Members - public string Name { - get { return _name; } - } - public IEnumerable GetChildrenModules() { yield break; } public void Imported(IModuleContext context) { } - - public string Documentation { - get { return string.Empty; } - } - - #endregion - - #region IMemberContainer Members - - public IMember GetMember(IModuleContext context, string name) { - return null; - } - - public IEnumerable GetMemberNames(IModuleContext moduleContext) { - yield break; - } - #endregion - - #region IMember Members - - public PythonMemberType MemberType { - get { return PythonMemberType.Module; } - } - - #endregion - } } diff --git a/src/Analysis/Engine/Impl/Infrastructure/Extensions/EnumerableExtensions.cs b/src/Analysis/Engine/Impl/Infrastructure/Extensions/EnumerableExtensions.cs index 0ffca1a5c..28a0337d0 100644 --- a/src/Analysis/Engine/Impl/Infrastructure/Extensions/EnumerableExtensions.cs +++ b/src/Analysis/Engine/Impl/Infrastructure/Extensions/EnumerableExtensions.cs @@ -23,31 +23,21 @@ static class EnumerableExtensions { public static bool IsNullOrEmpty(this IEnumerable source) => source == null || !source.Any(); - public static T[] MaybeEnumerate(this T[] source) { - return source ?? Array.Empty(); - } + public static T[] MaybeEnumerate(this T[] source) => source ?? Array.Empty(); - public static IEnumerable MaybeEnumerate(this IEnumerable source) { - return source ?? Enumerable.Empty(); - } + public static IEnumerable MaybeEnumerate(this IEnumerable source) => source ?? Enumerable.Empty(); - private static T Identity(T source) { - return source; - } + private static T Identity(T source) => source; - public static IEnumerable SelectMany(this IEnumerable> source) { - return source.SelectMany(Identity); - } + public static IEnumerable SelectMany(this IEnumerable> source) => source.SelectMany(Identity); - public static IEnumerable Ordered(this IEnumerable source) { - return source.OrderBy(Identity); - } + public static IEnumerable Ordered(this IEnumerable source) + => source.OrderBy(Identity); private static bool NotNull(T obj) where T : class => obj != null; - public static IEnumerable WhereNotNull(this IEnumerable source) where T : class { - return source.Where(NotNull); - } + public static IEnumerable WhereNotNull(this IEnumerable source) where T : class + => source != null ? source.Where(NotNull) : Enumerable.Empty(); public static bool SetEquals(this IEnumerable source, IEnumerable other, IEqualityComparer comparer = null) where T : class { diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstAnalysisFunctionWalker.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstAnalysisFunctionWalker.cs index 9eecd8018..7316bce0c 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstAnalysisFunctionWalker.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstAnalysisFunctionWalker.cs @@ -65,7 +65,9 @@ public void Walk() { var self = GetSelf(); _selfType = (self as AstPythonConstant)?.Type as AstPythonType; - _overload.ReturnTypes.AddRange(_scope.GetTypesFromAnnotation(Target.ReturnAnnotation).ExcludeDefault()); + var annotationTypes = _scope.GetTypesFromAnnotation(Target.ReturnAnnotation).ExcludeDefault(); + _overload.ReturnTypes.AddRange(annotationTypes); + _scope.PushScope(); // Declare self, if any @@ -84,7 +86,10 @@ public void Walk() { _scope.SetInScope(p.Name, value ?? _scope.UnknownType); } - Target.Walk(this); + // return type from the annotation always wins, no need to walk the body. + if (!annotationTypes.Any()) { + Target.Walk(this); + } _scope.PopScope(); } @@ -165,7 +170,8 @@ public override bool Walk(IfStatement node) { if (name != null && typeName != null) { var typeId = typeName.GetTypeId(); if (typeId != BuiltinTypeId.Unknown) { - _scope.SetInScope(name, new AstPythonConstant(new AstPythonBuiltinType(typeName, typeId))); + _scope.SetInScope(name, + new AstPythonConstant(new AstPythonType(typeName, typeId))); } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstAnalysisWalker.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstAnalysisWalker.cs index 42e47663d..b8d9582df 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstAnalysisWalker.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstAnalysisWalker.cs @@ -115,7 +115,7 @@ internal LocationInfo GetLoc(ClassDefinition node) { private LocationInfo GetLoc(Node node) => _scope.GetLoc(node); private IMember Clone(IMember member) => - member is IPythonMultipleMembers mm ? AstPythonMultipleMembers.Create(mm.Members) : + member is IPythonMultipleMembers mm ? AstPythonMultipleMembers.Create(mm.GetMembers()) : member; public override bool Walk(AssignmentStatement node) { @@ -423,14 +423,18 @@ public override bool Walk(FunctionDefinition node) { var dec = (node.Decorators?.Decorators).MaybeEnumerate().ExcludeDefault(); foreach (var d in dec) { var obj = _scope.GetValueFromExpression(d); + + var declaringType = obj as IPythonType; + var declaringModule = declaringType?.DeclaringModule; + if (obj == _interpreter.GetBuiltinType(BuiltinTypeId.Property)) { - AddProperty(node); + AddProperty(node, declaringModule, declaringType); return false; } - var mod = (obj as IPythonType)?.DeclaringModule ?? (obj as IPythonFunction)?.DeclaringModule; - var name = (obj as IPythonType)?.Name ?? (obj as IPythonFunction)?.Name; - if (mod?.Name == "abc" && name == "abstractproperty") { - AddProperty(node); + + var name = declaringType?.Name; + if (declaringModule?.Name == "abc" && name == "abstractproperty") { + AddProperty(node, declaringModule, declaringType); return false; } } @@ -450,10 +454,10 @@ public override bool Walk(FunctionDefinition node) { return false; } - private void AddProperty(FunctionDefinition node) { + private void AddProperty(FunctionDefinition node, IPythonModule declaringModule, IPythonType declaringType) { var existing = _scope.LookupNameInScopes(node.Name, NameLookupContext.LookupOptions.Local) as AstPythonProperty; if (existing == null) { - existing = new AstPythonProperty(_ast, node, GetLoc(node)); + existing = new AstPythonProperty(node, declaringModule, declaringType, GetLoc(node)); _scope.SetInScope(node.Name, existing); } @@ -471,8 +475,8 @@ private IPythonFunctionOverload CreateFunctionOverload(NameLookupContext funcSco .ToArray(); var overload = new AstPythonFunctionOverload( - parameters, - funcScope.GetLocOfName(node, node.NameExpression), + parameters, + funcScope.GetLocOfName(node, node.NameExpression), node.ReturnAnnotation?.ToCodeString(_ast)); _functionWalkers.Add(new AstAnalysisFunctionWalker(funcScope, node, overload)); @@ -485,14 +489,13 @@ private static string GetDoc(SuiteStatement node) { return ce?.Value as string; } - private AstPythonType CreateType(ClassDefinition node) { - if (node == null) { - throw new ArgumentNullException(nameof(node)); - } - return CreateBuiltinTypes - ? new AstPythonBuiltinType(node.Name, _module, node.StartIndex, GetDoc(node.Body as SuiteStatement), GetLoc(node)) - : new AstPythonType(node.Name, _module, node.StartIndex, GetDoc(node.Body as SuiteStatement), GetLoc(node)); + private AstPythonClass CreateClass(ClassDefinition node) { + node = node ?? throw new ArgumentNullException(nameof(node)); + return new AstPythonClass(node, _module, + GetDoc(node.Body as SuiteStatement), GetLoc(node), + CreateBuiltinTypes ? BuiltinTypeId.Unknown : BuiltinTypeId.Type); // built-ins set type later } + private void CollectTopLevelDefinitions() { var s = (_ast.Body as SuiteStatement).Statements.ToArray(); @@ -501,7 +504,7 @@ private void CollectTopLevelDefinitions() { } foreach (var node in s.OfType()) { - _members[node.Name] = CreateType(node); + _members[node.Name] = CreateClass(node); } foreach (var node in s.OfType().Where(n => n.Right is NameExpression)) { @@ -516,10 +519,12 @@ private void CollectTopLevelDefinitions() { public override bool Walk(ClassDefinition node) { var member = _scope.GetInScope(node.Name); - var t = member as AstPythonType ?? - (member as IPythonMultipleMembers)?.Members.OfType().FirstOrDefault(pt => pt.StartIndex == node.StartIndex); + var t = member as AstPythonClass; + if (t == null && member is IPythonMultipleMembers mm) { + t = mm.GetMembers().OfType().FirstOrDefault(pt => pt.ClassDefinition.StartIndex == node.StartIndex); + } if (t == null) { - t = CreateType(node); + t = CreateClass(node); _scope.SetInScope(node.Name, t); } @@ -549,7 +554,7 @@ public void ProcessFunctionDefinition(FunctionDefinition node) { var existing = _scope.LookupNameInScopes(node.Name, NameLookupContext.LookupOptions.Local) as AstPythonFunction; if (existing == null) { var cls = _scope.GetInScope("__class__") as IPythonType; - existing = new AstPythonFunction(_ast, _module, cls, node, GetLoc(node)); + existing = new AstPythonFunction(node, _module, cls, GetLoc(node)); _scope.SetInScope(node.Name, existing); } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstBuiltinsPythonModule.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstBuiltinsPythonModule.cs index 5d69d8afd..9ef20664a 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstBuiltinsPythonModule.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstBuiltinsPythonModule.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -43,8 +43,7 @@ public override IMember GetMember(IModuleContext context, string name) { public IMember GetAnyMember(string name) { lock (_members) { - IMember m; - _members.TryGetValue(name, out m); + _members.TryGetValue(name, out var m); return m; } } @@ -96,13 +95,12 @@ protected override PythonWalker PrepareWalker(AstPythonInterpreter interpreter, } protected override void PostWalk(PythonWalker walker) { - AstPythonBuiltinType boolType = null; - AstPythonBuiltinType noneType = null; + IPythonType boolType = null; + IPythonType noneType = null; foreach (BuiltinTypeId typeId in Enum.GetValues(typeof(BuiltinTypeId))) { - if (_members.TryGetValue("__{0}__".FormatInvariant(typeId), out IMember m) && m is AstPythonBuiltinType biType) { - if (typeId != BuiltinTypeId.Str && - typeId != BuiltinTypeId.StrIterator) { + if (_members.TryGetValue("__{0}__".FormatInvariant(typeId), out var m) && m is AstPythonType biType && biType.IsBuiltin) { + if (typeId != BuiltinTypeId.Str && typeId != BuiltinTypeId.StrIterator) { biType.TrySetTypeId(typeId); } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstNestedPythonModule.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstNestedPythonModule.cs index 2d0f49853..ce9297a04 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstNestedPythonModule.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstNestedPythonModule.cs @@ -22,19 +22,15 @@ using Microsoft.PythonTools.Analysis.Infrastructure; namespace Microsoft.PythonTools.Interpreter.Ast { - internal sealed class AstNestedPythonModule : IPythonModule, ILocatedMember { - private readonly string _name; + internal sealed class AstNestedPythonModule : PythonModuleType, IPythonModule, ILocatedMember { private readonly IPythonInterpreter _interpreter; private IPythonModule _module; - public AstNestedPythonModule(IPythonInterpreter interpreter, string fullName) { + public AstNestedPythonModule(IPythonInterpreter interpreter, string fullName) : base(fullName) { _interpreter = interpreter ?? throw new ArgumentNullException(nameof(interpreter)); - _name = fullName ?? throw new ArgumentNullException(nameof(fullName)); } - public string Name => MaybeModule?.Name ?? _name; - public string Documentation => MaybeModule?.Documentation ?? string.Empty; - public PythonMemberType MemberType => PythonMemberType.Module; + public override string Documentation => MaybeModule?.Documentation ?? string.Empty; public IEnumerable Locations => ((MaybeModule as ILocatedMember)?.Locations).MaybeEnumerate(); public bool IsLoaded => MaybeModule != null; @@ -46,13 +42,13 @@ private IPythonModule GetModule() { return module; } - module = _interpreter.ImportModule(_name); + module = _interpreter.ImportModule(Name); if (module != null) { Debug.Assert(!(module is AstNestedPythonModule), "ImportModule should not return nested module"); } if (module == null) { - module = new SentinelModule(_name, false); + module = new SentinelModule(Name, false); } return Interlocked.CompareExchange(ref _module, module, null) ?? module; @@ -60,9 +56,10 @@ private IPythonModule GetModule() { public IEnumerable GetChildrenModules() => GetModule().GetChildrenModules(); - public IMember GetMember(IModuleContext context, string name) => GetModule().GetMember(context, name); + public override IMember GetMember(IModuleContext context, string name) + => GetModule().GetMember(context, name); - public IEnumerable GetMemberNames(IModuleContext context) => + public override IEnumerable GetMemberNames(IModuleContext context) => // TODO: Make GetMemberNames() faster than Imported() GetModule().GetMemberNames(context); diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonBoundMethod.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonBoundMethod.cs deleted file mode 100644 index 645a6b772..000000000 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonBoundMethod.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Python Tools for Visual Studio -// 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. -// -// See the Apache Version 2.0 License for specific language governing -// permissions and limitations under the License. - -using System.Collections.Generic; -using Microsoft.PythonTools.Analysis; -using Microsoft.PythonTools.Analysis.Infrastructure; - -namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonBoundMethod : IPythonBoundFunction, ILocatedMember { - public AstPythonBoundMethod(IPythonFunction function, IPythonType selfType) { - Function = function; - SelfType = selfType; - } - - public IPythonFunction Function { get; } - public IPythonType SelfType { get; } - public PythonMemberType MemberType => PythonMemberType.Method; - public IEnumerable Locations => (Function as ILocatedMember)?.Locations.MaybeEnumerate(); - } -} diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonBuiltinType.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonBuiltinType.cs deleted file mode 100644 index 4fb6e0f17..000000000 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonBuiltinType.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Python Tools for Visual Studio -// 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.Linq; -using Microsoft.PythonTools.Analysis; - -namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonBuiltinType : AstPythonType { - private BuiltinTypeId _typeId; - - public AstPythonBuiltinType(string name, BuiltinTypeId typeId) - : base(name) { - _typeId = typeId; - } - - public AstPythonBuiltinType( - string name, - IPythonModule declModule, - int startIndex, - string doc, - LocationInfo loc, - BuiltinTypeId typeId = BuiltinTypeId.Unknown, - bool isClass = false - ) : base(name, declModule, startIndex, doc, loc, isClass) { - _typeId = typeId == BuiltinTypeId.Unknown && isClass ? BuiltinTypeId.Type : typeId; - } - - public bool TrySetTypeId(BuiltinTypeId typeId) { - if (_typeId != BuiltinTypeId.Unknown) { - return false; - } - _typeId = typeId; - return true; - } - - public override bool IsBuiltin => true; - public override BuiltinTypeId TypeId => _typeId; - - public bool IsHidden => ContainsMember("__hidden__"); - - /// - /// Clones builtin type as class. Typically used in scenarios where method - /// returns an object that acts like a class constructor, such as namedtuple. - /// - /// - public AstPythonBuiltinType AsClass() { - var clone = new AstPythonBuiltinType(Name, DeclaringModule, StartIndex, Documentation, - Locations.OfType().FirstOrDefault(), - TypeId == BuiltinTypeId.Unknown ? BuiltinTypeId.Type : TypeId, true); - clone.AddMembers(Members, true); - return clone; - } - } -} diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonClass.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonClass.cs new file mode 100644 index 000000000..111028c6b --- /dev/null +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonClass.cs @@ -0,0 +1,183 @@ +// Python Tools for Visual Studio +// 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.Linq; +using System.Threading; +using Microsoft.PythonTools.Analysis; +using Microsoft.PythonTools.Analysis.Infrastructure; +using Microsoft.PythonTools.Parsing.Ast; + +namespace Microsoft.PythonTools.Interpreter.Ast { + class AstPythonClass : AstPythonType, IPythonClass { + protected static readonly IPythonModule NoDeclModule = new AstPythonModule(); + + private readonly object _lock = new object(); + + private IReadOnlyList _mro; + private readonly AsyncLocal _isProcessing = new AsyncLocal(); + + public AstPythonClass( + ClassDefinition classDefinition, + IPythonModule declaringModule, + string doc, + ILocationInfo loc, + BuiltinTypeId builtinTypeId = BuiltinTypeId.Type + ) : base(classDefinition.Name, declaringModule, doc, loc, builtinTypeId, false) { + ClassDefinition = classDefinition; + } + + internal AstPythonClass(string name) : base(name, BuiltinTypeId.Type) { } + + #region IPythonType + public override PythonMemberType MemberType => PythonMemberType.Class; + + public override IMember GetMember(IModuleContext context, string name) { + IMember member; + lock (_lock) { + if (Members.TryGetValue(name, out member)) { + return member; + } + + // Special case names that we want to add to our own Members dict + switch (name) { + case "__mro__": + member = AddMember(name, new AstPythonSequence( + (context as IPythonInterpreter)?.GetBuiltinType(BuiltinTypeId.Tuple), + DeclaringModule, + Mro, + (context as IPythonInterpreter)?.GetBuiltinType(BuiltinTypeId.TupleIterator) + ), true); + return member; + } + } + if (Push()) { + try { + foreach (var m in Mro.Reverse()) { + if (m == this) { + return member; + } + member = member ?? m.GetMember(context, name); + } + } finally { + Pop(); + } + } + return null; + } + #endregion + + #region IPythonClass + public ClassDefinition ClassDefinition { get; } + public IReadOnlyList Bases { get; private set; } + + public IReadOnlyList Mro { + get { + lock (_lock) { + if (_mro != null) { + return _mro; + } + if (Bases == null) { + //Debug.Fail("Accessing Mro before SetBases has been called"); + return new IPythonType[] { this }; + } + _mro = new IPythonType[] { this }; + _mro = CalculateMro(this); + return _mro; + } + } + } + #endregion + + internal void SetBases(IPythonInterpreter interpreter, IEnumerable bases) { + lock (_lock) { + if (Bases != null) { + return; // Already set + } + + Bases = bases.MaybeEnumerate().ToArray(); + if (Bases.Count > 0) { + AddMember("__base__", Bases[0], true); + } + + AddMember("__bases__", new AstPythonSequence( + interpreter?.GetBuiltinType(BuiltinTypeId.Tuple), + DeclaringModule, + Bases, + interpreter?.GetBuiltinType(BuiltinTypeId.TupleIterator) + ), true); + } + } + + internal static IReadOnlyList CalculateMro(IPythonType cls, HashSet recursionProtection = null) { + if (cls == null) { + return Array.Empty(); + } + if (recursionProtection == null) { + recursionProtection = new HashSet(); + } + if (!recursionProtection.Add(cls)) { + return Array.Empty(); + } + try { + var mergeList = new List> { new List() }; + var finalMro = new List { cls }; + + var bases = (cls as AstPythonClass)?.Bases ?? + (cls.GetMember(null, "__bases__") as IPythonSequenceType)?.IndexTypes ?? + Array.Empty(); + + foreach (var b in bases) { + var b_mro = new List(); + b_mro.AddRange(CalculateMro(b, recursionProtection)); + mergeList.Add(b_mro); + } + + while (mergeList.Any()) { + // Next candidate is the first head that does not appear in + // any other tails. + var nextInMro = mergeList.FirstOrDefault(mro => { + var m = mro.FirstOrDefault(); + return m != null && !mergeList.Any(m2 => m2.Skip(1).Contains(m)); + })?.FirstOrDefault(); + + if (nextInMro == null) { + // MRO is invalid, so return just this class + return new IPythonType[] { cls }; + } + + finalMro.Add(nextInMro); + + // Remove all instances of that class from potentially being returned again + foreach (var mro in mergeList) { + mro.RemoveAll(ns => ns == nextInMro); + } + + // Remove all lists that are now empty. + mergeList.RemoveAll(mro => !mro.Any()); + } + + return finalMro; + } finally { + recursionProtection.Remove(cls); + } + } + + private bool Push() => _isProcessing.Value ? false : (_isProcessing.Value = true); + private void Pop() => _isProcessing.Value = false; + } +} diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonConstant.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonConstant.cs index 42e8009ee..d7b8b05e8 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonConstant.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonConstant.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -20,37 +20,14 @@ using Microsoft.PythonTools.Analysis; namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonConstant : IPythonConstant, IMemberContainer, ILocatedMember { - private readonly Dictionary _cachedMembers = new Dictionary(); - - public AstPythonConstant(IPythonType type, params ILocationInfo[] locations) { + class AstPythonConstant : AstPythonTypeWrapper, IPythonConstant { + public AstPythonConstant(IPythonType type, params ILocationInfo[] locations): base(type, type.DeclaringModule) { Type = type ?? throw new ArgumentNullException(nameof(type)); Locations = locations.ToArray(); } - public IEnumerable Locations { get; } - public PythonMemberType MemberType => PythonMemberType.Constant; + public override IEnumerable Locations { get; } + public override PythonMemberType MemberType => PythonMemberType.Constant; public IPythonType Type { get; } - - public IMember GetMember(IModuleContext context, string name) { - IMember m; - lock (_cachedMembers) { - if (_cachedMembers.TryGetValue(name, out m)) { - return m; - } - } - - m = Type?.GetMember(context, name); - if (m is IPythonFunction f && !f.IsStatic) { - m = new AstPythonBoundMethod(f, Type); - lock (_cachedMembers) { - _cachedMembers[name] = m; - } - } - return m; - } - - public IEnumerable GetMemberNames(IModuleContext moduleContext) - => Type?.GetMemberNames(moduleContext); } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonFunction.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonFunction.cs index f9c210a39..cf79624e2 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonFunction.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonFunction.cs @@ -9,12 +9,11 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// 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.Linq; using Microsoft.PythonTools.Analysis; @@ -22,24 +21,24 @@ using Microsoft.PythonTools.Parsing.Ast; namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonFunction : IPythonFunction2, ILocatedMember, IHasQualifiedName { - private readonly List _overloads; + class AstPythonFunction : AstPythonType, IPythonFunction { + private readonly List _overloads = new List(); private readonly string _doc; + private readonly object _lock = new object(); public AstPythonFunction( - PythonAst ast, - IPythonModule declModule, - IPythonType declType, - FunctionDefinition def, + FunctionDefinition fd, + IPythonModule declaringModule, + IPythonType declaringType, ILocationInfo loc - ) { - DeclaringModule = declModule ?? throw new ArgumentNullException(nameof(declModule)); - DeclaringType = declType; - FunctionDefinition = def; + ) : base(fd.Name, declaringModule, fd.Documentation, loc, + declaringType != null ? BuiltinTypeId.Method : BuiltinTypeId.Function, true) { + + FunctionDefinition = fd; + DeclaringType = declaringType; - Name = FunctionDefinition.Name; if (Name == "__init__") { - _doc = declType?.Documentation; + _doc = declaringType?.Documentation; } foreach (var dec in (FunctionDefinition.Decorators?.Decorators).MaybeEnumerate().ExcludeDefault().OfType()) { @@ -49,33 +48,53 @@ ILocationInfo loc IsStatic = true; } } - - _overloads = new List(); - - Locations = loc != null ? new[] { loc } : Array.Empty(); } - public FunctionDefinition FunctionDefinition { get; } + #region IMember + public override PythonMemberType MemberType + => TypeId == BuiltinTypeId.Function ? PythonMemberType.Function : PythonMemberType.Method; + #endregion - internal void AddOverload(IPythonFunctionOverload overload) => _overloads.Add(overload); + #region IPythonFunction + public FunctionDefinition FunctionDefinition { get; } + public IPythonType DeclaringType { get; } + public override string Documentation => _doc ?? _overloads.FirstOrDefault()?.Documentation; + public virtual bool IsClassMethod { get; } + public virtual bool IsStatic { get; } + public IReadOnlyList Overloads => _overloads.ToArray(); + #endregion - public IPythonModule DeclaringModule {get;} - public IPythonType DeclaringType {get;} - public string Name { get; } - public string Documentation => _doc ?? _overloads.FirstOrDefault()?.Documentation; - public bool IsBuiltin => true; + #region IHasQualifiedName + public override string FullyQualifiedName => FullyQualifiedNamePair.CombineNames(); + public override KeyValuePair FullyQualifiedNamePair => + new KeyValuePair((DeclaringType as IHasQualifiedName)?.FullyQualifiedName ?? DeclaringType?.Name ?? DeclaringModule?.Name, Name); + #endregion - public bool IsClassMethod { get; } - public bool IsStatic { get; } + internal virtual void AddOverload(IPythonFunctionOverload overload) { + lock (_lock) { + _overloads.Add(overload); + } + } - public PythonMemberType MemberType => DeclaringType == null ? PythonMemberType.Function : PythonMemberType.Method; + internal IPythonFunction ToUnbound() => new AstPythonUnboundMethod(this); - public IReadOnlyList Overloads => _overloads.ToArray(); + /// + /// Represents unbound method, such in C.f where C is class rather than the instance. + /// + class AstPythonUnboundMethod : AstPythonTypeWrapper, IPythonFunction { + private readonly IPythonFunction _pf; - public IEnumerable Locations { get; } + public AstPythonUnboundMethod(IPythonFunction function) : base(function, function.DeclaringModule) { + _pf = function; + } - public string FullyQualifiedName => FullyQualifiedNamePair.CombineNames(); - public KeyValuePair FullyQualifiedNamePair => - new KeyValuePair((DeclaringType as IHasQualifiedName)?.FullyQualifiedName ?? DeclaringType?.Name ?? DeclaringModule?.Name, Name); + public FunctionDefinition FunctionDefinition => _pf.FunctionDefinition; + public IPythonType DeclaringType => _pf.DeclaringType; + public bool IsStatic => _pf.IsStatic; + public bool IsClassMethod => _pf.IsClassMethod; + public IReadOnlyList Overloads => _pf.Overloads; + public override BuiltinTypeId TypeId => BuiltinTypeId.Function; + public override PythonMemberType MemberType => PythonMemberType.Function; + } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonInterpreter.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonInterpreter.cs index 1fc27c250..ef4ec8ce6 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonInterpreter.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonInterpreter.cs @@ -31,8 +31,8 @@ namespace Microsoft.PythonTools.Interpreter.Ast { internal class AstPythonInterpreter : IPythonInterpreter2, IModuleContext { private readonly ConcurrentDictionary _modules = new ConcurrentDictionary(); private readonly Dictionary _builtinTypes = new Dictionary() { - { BuiltinTypeId.NoneType, new AstPythonBuiltinType("NoneType", BuiltinTypeId.NoneType) }, - { BuiltinTypeId.Unknown, new AstPythonBuiltinType("Unknown", BuiltinTypeId.Unknown) } + { BuiltinTypeId.NoneType, new AstPythonType("NoneType", BuiltinTypeId.NoneType) }, + { BuiltinTypeId.Unknown, new AstPythonType("Unknown", BuiltinTypeId.Unknown) } }; private readonly AstPythonInterpreterFactory _factory; @@ -88,10 +88,10 @@ public IPythonType GetBuiltinType(BuiltinTypeId id) { if (string.IsNullOrEmpty(name)) { Debug.Assert(id == BuiltinTypeId.Unknown, $"no name for {id}"); if (!_builtinTypes.TryGetValue(BuiltinTypeId.Unknown, out res)) { - _builtinTypes[BuiltinTypeId.Unknown] = res = new AstPythonType(""); + _builtinTypes[BuiltinTypeId.Unknown] = res = new AstPythonType("", bm, null, null, BuiltinTypeId.Unknown); } } else { - res = new AstPythonType(name); + res = new AstPythonType(name, bm, null, null, id); } } _builtinTypes[id] = res; diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonIterables.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonIterables.cs index bdce104d4..331ad60ad 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonIterables.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonIterables.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -18,66 +18,29 @@ using System.Linq; namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonIterable : IPythonIterableType { - private readonly IPythonType _type; - + class AstPythonIterable : AstPythonTypeWrapper, IPythonIterableType { public AstPythonIterable( IPythonType iterableType, IEnumerable types, IPythonType iteratorBase, - IPythonModule declModule - ) { - _type = iterableType; - IteratorType = new AstPythonIterator(iteratorBase, types, declModule); - DeclaringModule = declModule; - } - - public AstPythonIterable( - IPythonType iterableType, - IEnumerable types, - IPythonIteratorType iteratorType, - IPythonModule declModule - ) { - _type = iterableType; - IteratorType = iteratorType; - DeclaringModule = declModule; + IPythonModule declaringModule + ) : base(iterableType, declaringModule) { + IteratorType = new AstPythonIterator(iteratorBase, types, declaringModule); } public IPythonIteratorType IteratorType { get; } - public IPythonModule DeclaringModule { get; } - - public string Name => _type.Name; - public string Documentation => _type.Documentation; - public BuiltinTypeId TypeId => _type.TypeId; - public IReadOnlyList Mro => _type.Mro; - public bool IsBuiltin => _type.IsBuiltin; - public PythonMemberType MemberType => _type.MemberType; - public IPythonFunction GetConstructors() => _type.GetConstructors(); - public IMember GetMember(IModuleContext context, string name) => _type.GetMember(context, name); - public IEnumerable GetMemberNames(IModuleContext moduleContext) => _type.GetMemberNames(moduleContext); } - class AstPythonIterator : IPythonIteratorType, IPythonIterableType { + class AstPythonIterator : AstPythonTypeWrapper, IPythonIteratorType, IPythonIterableType { private readonly IPythonType _type; - public AstPythonIterator(IPythonType iterableType, IEnumerable nextType, IPythonModule declModule) { + public AstPythonIterator(IPythonType iterableType, IEnumerable nextType, IPythonModule declaringModule): + base(iterableType, declaringModule) { _type = iterableType; NextType = nextType.ToArray(); - DeclaringModule = declModule; } public IPythonIteratorType IteratorType => this; public IEnumerable NextType { get; } - public IPythonModule DeclaringModule { get; } - - public string Name => _type.Name; - public string Documentation => _type.Documentation; - public BuiltinTypeId TypeId => _type.TypeId; - public IReadOnlyList Mro => _type.Mro; - public bool IsBuiltin => _type.IsBuiltin; - public PythonMemberType MemberType => _type.MemberType; - public IPythonFunction GetConstructors() => _type.GetConstructors(); - public IMember GetMember(IModuleContext context, string name) => _type.GetMember(context, name); - public IEnumerable GetMemberNames(IModuleContext moduleContext) => _type.GetMemberNames(moduleContext); } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonLookup.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonLookup.cs index b4e470834..0aae6ccc2 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonLookup.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonLookup.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -19,8 +19,7 @@ using System.Linq; namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonLookup : IPythonLookupType, IPythonIterableType { - private readonly IPythonType _lookupType; + class AstPythonLookup : AstPythonTypeWrapper, IPythonLookupType, IPythonIterableType { private readonly IReadOnlyDictionary> _mapping; public AstPythonLookup( @@ -30,12 +29,10 @@ public AstPythonLookup( IEnumerable values, IEnumerable>> mapping, IPythonIteratorType iterator - ) { - _lookupType = lookupType; + ): base(lookupType, declaringModule) { KeyTypes = (keys ?? throw new ArgumentNullException(nameof(keys))).ToArray(); ValueTypes = (values ?? throw new ArgumentNullException(nameof(values))).ToArray(); _mapping = mapping?.ToDictionary(k => k.Key, k => (IReadOnlyList)k.Value.ToArray()); - DeclaringModule = declaringModule; IteratorType = iterator; } @@ -50,16 +47,8 @@ public IEnumerable GetIndex(IPythonType key) { public IPythonIteratorType IteratorType { get; } - public IPythonModule DeclaringModule { get; } - - public string Name => _lookupType?.Name ?? "tuple"; - public string Documentation => _lookupType?.Documentation ?? string.Empty; - public BuiltinTypeId TypeId => _lookupType?.TypeId ?? BuiltinTypeId.Tuple; - public IReadOnlyList Mro => _lookupType?.Mro ?? Array.Empty(); - public bool IsBuiltin => _lookupType?.IsBuiltin ?? true; - public PythonMemberType MemberType => _lookupType?.MemberType ?? PythonMemberType.Class; - public IPythonFunction GetConstructors() => _lookupType?.GetConstructors(); - public IMember GetMember(IModuleContext context, string name) => _lookupType?.GetMember(context, name) ?? null; - public IEnumerable GetMemberNames(IModuleContext moduleContext) => _lookupType?.GetMemberNames(moduleContext) ?? Enumerable.Empty(); + public override string Name => InnerType?.Name ?? "tuple"; + public override BuiltinTypeId TypeId => InnerType?.TypeId ?? BuiltinTypeId.Tuple; + public override PythonMemberType MemberType => InnerType?.MemberType ?? PythonMemberType.Class; } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonModule.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonModule.cs index 36865cd46..0c4d509d1 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonModule.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonModule.cs @@ -26,21 +26,20 @@ using Microsoft.PythonTools.Parsing.Ast; namespace Microsoft.PythonTools.Interpreter.Ast { - sealed class AstPythonModule : IPythonModule, IProjectEntry, ILocatedMember { + sealed class AstPythonModule : PythonModuleType, IPythonModule, IProjectEntry, ILocatedMember { private readonly IPythonInterpreter _interpreter; private readonly List _childModules = new List(); private readonly Dictionary _members = new Dictionary(); private bool _foundChildModules; private string _documentation = string.Empty; - internal AstPythonModule() { - Name = string.Empty; - FilePath = string.Empty; + internal AstPythonModule(): base(string.Empty) { + FilePath = string.Empty; _foundChildModules = true; } - internal AstPythonModule(string moduleName, IPythonInterpreter interpreter, string documentation, string filePath, IEnumerable parseErrors) { - Name = moduleName; + internal AstPythonModule(string moduleName, IPythonInterpreter interpreter, string documentation, string filePath, IEnumerable parseErrors): + base(moduleName) { _documentation = documentation; FilePath = filePath; DocumentUri = ProjectEntry.MakeDocumentUri(FilePath); @@ -65,8 +64,7 @@ internal void Analyze(PythonAst ast, PathResolverSnapshot currentPathResolver) { public void Dispose() { } - public string Name { get; } - public string Documentation { + public override string Documentation { get { if (_documentation == null) { _members.TryGetValue("__doc__", out var m); @@ -84,7 +82,6 @@ public string Documentation { } public string FilePath { get; } public Uri DocumentUri { get; } - public PythonMemberType MemberType => PythonMemberType.Module; public Dictionary Properties { get; } = new Dictionary(); public IEnumerable Locations { get; } = Enumerable.Empty(); @@ -128,7 +125,7 @@ public IEnumerable GetChildrenModules() { } } - public IMember GetMember(IModuleContext context, string name) { + public override IMember GetMember(IModuleContext context, string name) { IMember member = null; lock (_members) { _members.TryGetValue(name, out member); @@ -142,7 +139,7 @@ public IMember GetMember(IModuleContext context, string name) { return member; } - public IEnumerable GetMemberNames(IModuleContext moduleContext) { + public override IEnumerable GetMemberNames(IModuleContext moduleContext) { lock (_members) { return _members.Keys.ToArray(); } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonMultipleMembers.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonMultipleMembers.cs index 3bb35a244..d130703e0 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonMultipleMembers.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonMultipleMembers.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -19,49 +19,16 @@ using System.Linq; using Microsoft.PythonTools.Analysis; using Microsoft.PythonTools.Analysis.Infrastructure; +using Microsoft.PythonTools.Parsing.Ast; namespace Microsoft.PythonTools.Interpreter.Ast { class AstPythonMultipleMembers : IPythonMultipleMembers, ILocatedMember { private readonly IMember[] _members; private IReadOnlyList _resolvedMembers; - - public AstPythonMultipleMembers() { - _members = Array.Empty(); - } + private readonly object _lock = new object(); private AstPythonMultipleMembers(IMember[] members) { - _members = members; - } - - private void EnsureMembers() { - if (_resolvedMembers != null) { - return; - } - lock (_members) { - if (_resolvedMembers != null) { - return; - } - - var unresolved = _members.OfType().ToArray(); - - if (unresolved.Any()) { - // Publish non-lazy members immediately. This will prevent recursion - // into EnsureMembers while we are resolving lazy values. - var resolved = _members.Where(m => !(m is ILazyMember)).ToList(); - _resolvedMembers = resolved.ToArray(); - - foreach (var lm in unresolved) { - var m = lm.Get(); - if (m != null) { - resolved.Add(m); - } - } - - _resolvedMembers = resolved; - } else { - _resolvedMembers = _members; - } - } + _members = members ?? Array.Empty(); } public static IMember Create(IEnumerable members) => Create(members.Where(m => m != null).Distinct().ToArray(), null); @@ -73,19 +40,20 @@ private static IMember Create(IMember[] members, IMember single) { if (members.Length == 1) { return members[0]; - } else if (members.Length == 0) { + } + if (members.Length == 0) { return null; } if (members.All(m => m is IPythonFunction)) { return new MultipleFunctionMembers(members); } - if (members.All(m => m is IPythonType)) { - return new MultipleTypeMembers(members); - } if (members.All(m => m is IPythonModule)) { return new MultipleModuleMembers(members); } + if (members.All(m => m is IPythonType)) { + return new MultipleTypeMembers(members); + } return new AstPythonMultipleMembers(members); } @@ -93,11 +61,14 @@ private static IMember Create(IMember[] members, IMember single) { public static IMember Combine(IMember x, IMember y) { if (x == null && y == null) { throw new InvalidOperationException("Cannot add two null members"); - } else if (x == null || (x.MemberType == PythonMemberType.Unknown && !(x is ILazyMember))) { + } + if (x == null || (x.MemberType == PythonMemberType.Unknown && !(x is ILazyMember))) { return y; - } else if (y == null || (y.MemberType == PythonMemberType.Unknown && !(y is ILazyMember))) { + } + if (y == null || (y.MemberType == PythonMemberType.Unknown && !(y is ILazyMember))) { return x; - } else if (x == y) { + } + if (x == y) { return x; } @@ -106,13 +77,14 @@ public static IMember Combine(IMember x, IMember y) { if (mmx != null && mmy == null) { return Create(mmx._members, y); - } else if (mmy != null && mmx == null) { + } + if (mmy != null && mmx == null) { return Create(mmy._members, x); - } else if (mmx != null && mmy != null) { + } + if (mmx != null && mmy != null) { return Create(mmx._members.Union(mmy._members).ToArray(), null); - } else { - return Create(new[] { x }, y); } + return Create(new[] { x }, y); } public static T CreateAs(IEnumerable members) => As(Create(members)); @@ -122,7 +94,7 @@ public static T As(IMember member) { if (member is T t) { return t; } - var members = (member as IPythonMultipleMembers)?.Members; + var members = (member as IPythonMultipleMembers)?.GetMembers(); if (members != null) { member = Create(members.Where(m => m is T)); if (member is T t2) { @@ -134,19 +106,47 @@ public static T As(IMember member) { return default(T); } - public IReadOnlyList Members { - get { - EnsureMembers(); + #region IMemberContainer + public IReadOnlyList GetMembers() { + lock (_lock) { + if (_resolvedMembers != null) { + return _resolvedMembers; + } + + var unresolved = _members.OfType().ToArray(); + if (unresolved.Length > 0) { + // Publish non-lazy members immediately. This will prevent recursion + // into EnsureMembers while we are resolving lazy values. + var resolved = _members.Where(m => !(m is ILazyMember)).ToList(); + _resolvedMembers = resolved.ToArray(); + + foreach (var lm in unresolved) { + var m = lm.Get(); + if (m != null) { + resolved.Add(m); + } + } + + _resolvedMembers = resolved; + } else { + _resolvedMembers = _members; + } return _resolvedMembers; } } public virtual PythonMemberType MemberType => PythonMemberType.Multiple; - public IEnumerable Locations => Members.OfType().SelectMany(m => m.Locations.MaybeEnumerate()); + #endregion + + #region ILocatedMember + public IEnumerable Locations => GetMembers().OfType().SelectMany(m => m.Locations.MaybeEnumerate()); + #endregion + #region Comparison // Equality deliberately uses unresolved members public override bool Equals(object obj) => GetType() == obj?.GetType() && obj is AstPythonMultipleMembers mm && new HashSet(_members).SetEquals(mm._members); public override int GetHashCode() => _members.Aggregate(GetType().GetHashCode(), (hc, m) => hc ^ (m?.GetHashCode() ?? 0)); + #endregion protected static string ChooseName(IEnumerable names) => names.FirstOrDefault(n => !string.IsNullOrEmpty(n)); protected static string ChooseDocumentation(IEnumerable docs) { @@ -154,36 +154,54 @@ protected static string ChooseDocumentation(IEnumerable docs) { return docs.FirstOrDefault(d => !string.IsNullOrEmpty(d)); } + /// + /// Represent multiple functions that effectively represent a single function + /// or method, such as when some definitions come from code and some from stubs. + /// class MultipleFunctionMembers : AstPythonMultipleMembers, IPythonFunction { public MultipleFunctionMembers(IMember[] members) : base(members) { } - private IEnumerable Functions => Members.OfType(); + private IEnumerable Functions => GetMembers().OfType(); + #region IMember + public override PythonMemberType MemberType => PythonMemberType.Function; + #endregion + + #region IPythonType public string Name => ChooseName(Functions.Select(f => f.Name)) ?? ""; public string Documentation => ChooseDocumentation(Functions.Select(f => f.Documentation)); public bool IsBuiltin => Functions.Any(f => f.IsBuiltin); + public IPythonModule DeclaringModule => CreateAs(Functions.Select(f => f.DeclaringModule)); + public BuiltinTypeId TypeId { + get { + if (IsClassMethod) { + return BuiltinTypeId.ClassMethod; + } + if (IsStatic) { + return BuiltinTypeId.StaticMethod; + } + return DeclaringType != null ? BuiltinTypeId.Method : BuiltinTypeId.Function; + } + } + public bool IsTypeFactory => false; + public IPythonFunction GetConstructor() => null; + #endregion + + #region IPythonFunction public bool IsStatic => Functions.Any(f => f.IsStatic); public bool IsClassMethod => Functions.Any(f => f.IsClassMethod); - public IReadOnlyList Overloads => Functions.SelectMany(f => f.Overloads).ToArray(); public IPythonType DeclaringType => CreateAs(Functions.Select(f => f.DeclaringType)); - public IPythonModule DeclaringModule => CreateAs(Functions.Select(f => f.DeclaringModule)); - public override PythonMemberType MemberType => PythonMemberType.Function; - } - - class MultipleMethodMembers : AstPythonMultipleMembers, IPythonMethodDescriptor { - public MultipleMethodMembers(IMember[] members) : base(members) { } - - private IEnumerable Methods => Members.OfType(); - - public IPythonFunction Function => CreateAs(Methods.Select(m => m.Function)); - public bool IsBound => Methods.Any(m => m.IsBound); - public override PythonMemberType MemberType => PythonMemberType.Method; + public IReadOnlyList Overloads => Functions.SelectMany(f => f.Overloads).ToArray(); + public FunctionDefinition FunctionDefinition => Functions.FirstOrDefault(f => f.FunctionDefinition != null)?.FunctionDefinition; + public IMember GetMember(IModuleContext context, string name) => null; + public IEnumerable GetMemberNames(IModuleContext moduleContext) => Enumerable.Empty(); + #endregion } class MultipleModuleMembers : AstPythonMultipleMembers, IPythonModule { public MultipleModuleMembers(IMember[] members) : base(members) { } - private IEnumerable Modules => Members.OfType(); + private IEnumerable Modules => GetMembers().OfType(); public string Name => ChooseName(Modules.Select(m => m.Name)) ?? ""; public string Documentation => ChooseDocumentation(Modules.Select(m => m.Documentation)); @@ -192,6 +210,12 @@ public MultipleModuleMembers(IMember[] members) : base(members) { } public IEnumerable GetMemberNames(IModuleContext moduleContext) => Modules.SelectMany(m => m.GetMemberNames(moduleContext)).Distinct(); public override PythonMemberType MemberType => PythonMemberType.Module; + public IPythonModule DeclaringModule => null; + public BuiltinTypeId TypeId => BuiltinTypeId.Module; + public bool IsBuiltin => true; + public bool IsTypeFactory => false; + public IPythonFunction GetConstructor() => null; + public void Imported(IModuleContext context) { List exceptions = null; foreach (var m in Modules) { @@ -211,18 +235,18 @@ public void Imported(IModuleContext context) { class MultipleTypeMembers : AstPythonMultipleMembers, IPythonType { public MultipleTypeMembers(IMember[] members) : base(members) { } - private IEnumerable Types => Members.OfType(); + private IEnumerable Types => GetMembers().OfType(); public string Name => ChooseName(Types.Select(t => t.Name)) ?? ""; public string Documentation => ChooseDocumentation(Types.Select(t => t.Documentation)); public BuiltinTypeId TypeId => Types.GroupBy(t => t.TypeId).OrderByDescending(g => g.Count()).FirstOrDefault()?.Key ?? BuiltinTypeId.Unknown; public IPythonModule DeclaringModule => CreateAs(Types.Select(t => t.DeclaringModule)); - public IReadOnlyList Mro => Types.Select(t => t.Mro).OrderByDescending(m => m.Count).FirstOrDefault() ?? new[] { this }; public bool IsBuiltin => Types.All(t => t.IsBuiltin); - public IPythonFunction GetConstructors() => CreateAs(Types.Select(t => t.GetConstructors())); + public bool IsTypeFactory => Types.All(t => t.IsTypeFactory); public IMember GetMember(IModuleContext context, string name) => Create(Types.Select(t => t.GetMember(context, name))); public IEnumerable GetMemberNames(IModuleContext moduleContext) => Types.SelectMany(t => t.GetMemberNames(moduleContext)).Distinct(); public override PythonMemberType MemberType => PythonMemberType.Class; + public IPythonFunction GetConstructor() => CreateAs(Types.Select(t => t.GetConstructor())); } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonProperty.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonProperty.cs index ef1271188..0c46ee251 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonProperty.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonProperty.cs @@ -5,38 +5,33 @@ using Microsoft.PythonTools.Parsing.Ast; namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonProperty : IBuiltinProperty2, ILocatedMember { + class AstPythonProperty : AstPythonType, IPythonProperty { private IPythonFunctionOverload _getter; - public AstPythonProperty( - PythonAst ast, - FunctionDefinition definition, - ILocationInfo location - ) { - IsReadOnly = true; - Locations = location != null ? new[] { location } : Enumerable.Empty(); - FunctionDefinition = definition; + public AstPythonProperty(FunctionDefinition fd, IPythonModule declaringModule, IPythonType declaringType, ILocationInfo location) + : base(fd.Name, declaringModule, null, location) { + FunctionDefinition = fd; + DeclaringType = declaringType; } + #region IMember + public override PythonMemberType MemberType => PythonMemberType.Property; + #endregion + + #region IPythonProperty + public bool IsStatic => false; + public IPythonType DeclaringType { get; } + public string Description + => Type == null ? Resources.PropertyOfUnknownType : Resources.PropertyOfType.FormatUI(Type.Name); public FunctionDefinition FunctionDefinition { get; } + #endregion - public void AddOverload(IPythonFunctionOverload overload) - => _getter = _getter ?? overload; + internal void AddOverload(IPythonFunctionOverload overload) => _getter = _getter ?? overload; public void MakeSettable() => IsReadOnly = false; public IPythonType Type => _getter?.ReturnType.FirstOrDefault(); - public bool IsStatic => false; - - public string Documentation => FunctionDefinition.Documentation; - - public string Description => Type == null ? "property of unknown type" : "property of type {0}".FormatUI(Type.Name); - - public PythonMemberType MemberType => PythonMemberType.Property; - - public bool IsReadOnly { get; private set; } - - public IEnumerable Locations { get; } + public bool IsReadOnly { get; private set; } = true; } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonSequence.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonSequence.cs index 453aaef57..f15511b0d 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonSequence.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonSequence.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -19,34 +19,22 @@ using System.Linq; namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonSequence : IPythonSequenceType, IPythonIterableType { - private readonly IPythonType _sequenceType; - + class AstPythonSequence : AstPythonTypeWrapper, IPythonSequenceType, IPythonIterableType { public AstPythonSequence( IPythonType sequenceType, IPythonModule declaringModule, IEnumerable contents, IPythonType iteratorBase - ) { - _sequenceType = sequenceType; + ): base(sequenceType, declaringModule) { IndexTypes = (contents ?? throw new ArgumentNullException(nameof(contents))).ToArray(); - DeclaringModule = declaringModule; IteratorType = new AstPythonIterator(iteratorBase, IndexTypes, declaringModule); } public IEnumerable IndexTypes { get; } public IPythonIteratorType IteratorType { get; } - public IPythonModule DeclaringModule { get; } - - public string Name => _sequenceType?.Name ?? "tuple"; - public string Documentation => _sequenceType?.Documentation ?? string.Empty; - public BuiltinTypeId TypeId => _sequenceType?.TypeId ?? BuiltinTypeId.Tuple; - public IReadOnlyList Mro => _sequenceType?.Mro ?? Array.Empty(); - public bool IsBuiltin => _sequenceType?.IsBuiltin ?? true; - public PythonMemberType MemberType => _sequenceType?.MemberType ?? PythonMemberType.Class; - public IPythonFunction GetConstructors() => _sequenceType?.GetConstructors(); - public IMember GetMember(IModuleContext context, string name) => _sequenceType?.GetMember(context, name) ?? null; - public IEnumerable GetMemberNames(IModuleContext moduleContext) - => _sequenceType?.GetMemberNames(moduleContext) ?? Enumerable.Empty(); + + public override string Name => InnerType?.Name ?? "tuple"; + public override BuiltinTypeId TypeId => InnerType?.TypeId ?? BuiltinTypeId.Tuple; + public override PythonMemberType MemberType => InnerType?.MemberType ?? PythonMemberType.Class; } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonType.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonType.cs index ddb3b19ad..001fb7ff5 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonType.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonType.cs @@ -17,238 +17,113 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; using Microsoft.PythonTools.Analysis; -using Microsoft.PythonTools.Analysis.Infrastructure; namespace Microsoft.PythonTools.Interpreter.Ast { - class AstPythonType : IPythonType2, IMemberContainer, ILocatedMember, IHasQualifiedName { - private static readonly IPythonModule NoDeclModule = new AstPythonModule(); - + class AstPythonType : IPythonType, ILocatedMember, IHasQualifiedName { private readonly string _name; private readonly object _lock = new object(); - private Dictionary _members; - private IReadOnlyList _mro; - private AsyncLocal _isProcessing = new AsyncLocal(); + private BuiltinTypeId _typeId; - protected Dictionary Members => - _members ?? (_members = new Dictionary()); + protected IReadOnlyDictionary Members => WritableMembers; - public AstPythonType(string name): this(name, new Dictionary(), Array.Empty()) { } + private Dictionary WritableMembers => + _members ?? (_members = new Dictionary()); public AstPythonType( string name, - IPythonModule declModule, - int startIndex, + IPythonModule declaringModule, string doc, ILocationInfo loc, - bool isClass = false - ) { - _name = name ?? throw new ArgumentNullException(nameof(name)); + BuiltinTypeId typeId = BuiltinTypeId.Unknown, + bool isTypeFactory = false + ) : this(name, typeId, isTypeFactory) { Documentation = doc; - DeclaringModule = declModule ?? throw new ArgumentNullException(nameof(declModule)); + DeclaringModule = declaringModule; Locations = loc != null ? new[] { loc } : Array.Empty(); - StartIndex = startIndex; - IsClass = isClass; + IsTypeFactory = isTypeFactory; } - private AstPythonType(string name, Dictionary members, IEnumerable locations) { + public AstPythonType(string name, BuiltinTypeId typeId, bool isTypeFactory = false) { _name = name ?? throw new ArgumentNullException(nameof(name)); - _members = members; - _mro = Array.Empty(); - DeclaringModule = NoDeclModule; - Locations = locations ?? Enumerable.Empty(); - } - - internal void AddMembers(IEnumerable> members, bool overwrite) { - lock (_lock) { - foreach (var kv in members) { - if (!overwrite) { - if (Members.TryGetValue(kv.Key, out var existing)) { - continue; - } - } - Members[kv.Key] = kv.Value; - } - } - } - - internal void SetBases(IPythonInterpreter interpreter, IEnumerable bases) { - lock (_lock) { - if (Bases != null) { - return; // Already set - } - - Bases = bases.MaybeEnumerate().ToArray(); - if (Bases.Count > 0) { - Members["__base__"] = Bases[0]; - } - - Members["__bases__"] = new AstPythonSequence( - interpreter?.GetBuiltinType(BuiltinTypeId.Tuple), - DeclaringModule, - Bases, - interpreter?.GetBuiltinType(BuiltinTypeId.TupleIterator) - ); - } + _typeId = typeId == BuiltinTypeId.Unknown && isTypeFactory ? BuiltinTypeId.Type : typeId; } - public IReadOnlyList Mro { + #region IPythonType + public virtual string Name { get { lock (_lock) { - if (_mro != null) { - return _mro; - } - if (Bases == null) { - //Debug.Fail("Accessing Mro before SetBases has been called"); - return new IPythonType[] { this }; - } - _mro = new IPythonType[] { this }; - _mro = CalculateMro(this); - return _mro; + return Members.TryGetValue("__name__", out var nameMember) && nameMember is AstPythonStringLiteral lit ? lit.Value : _name; } } } - internal static IReadOnlyList CalculateMro(IPythonType cls, HashSet recursionProtection = null) { - if (cls == null) { - return Array.Empty(); - } - if (recursionProtection == null) { - recursionProtection = new HashSet(); - } - if (!recursionProtection.Add(cls)) { - return Array.Empty(); - } - try { - var mergeList = new List> { new List() }; - var finalMro = new List { cls }; - - var bases = (cls as AstPythonType)?.Bases ?? - (cls.GetMember(null, "__bases__") as IPythonSequenceType)?.IndexTypes ?? - Array.Empty(); - - foreach (var b in bases) { - var b_mro = new List(); - b_mro.AddRange(CalculateMro(b, recursionProtection)); - mergeList.Add(b_mro); - } - - while (mergeList.Any()) { - // Next candidate is the first head that does not appear in - // any other tails. - var nextInMro = mergeList.FirstOrDefault(mro => { - var m = mro.FirstOrDefault(); - return m != null && !mergeList.Any(m2 => m2.Skip(1).Contains(m)); - })?.FirstOrDefault(); - - if (nextInMro == null) { - // MRO is invalid, so return just this class - return new IPythonType[] { cls }; - } - - finalMro.Add(nextInMro); - - // Remove all instances of that class from potentially being returned again - foreach (var mro in mergeList) { - mro.RemoveAll(ns => ns == nextInMro); - } - - // Remove all lists that are now empty. - mergeList.RemoveAll(mro => !mro.Any()); - } - - return finalMro; - } finally { - recursionProtection.Remove(cls); + public virtual string Documentation { get; } + public IPythonModule DeclaringModule { get; } + public virtual PythonMemberType MemberType => _typeId.GetMemberId(); + public virtual BuiltinTypeId TypeId => _typeId; + public bool IsBuiltin => DeclaringModule == null || DeclaringModule is IBuiltinPythonModule; + public bool IsTypeFactory { get; } + public IPythonFunction GetConstructor() => GetMember(null, "__init__") as IPythonFunction; + #endregion + + #region ILocatedMember + public virtual IEnumerable Locations { get; } = Array.Empty(); + #endregion + + #region IHasQualifiedName + public virtual string FullyQualifiedName => FullyQualifiedNamePair.CombineNames(); + public virtual KeyValuePair FullyQualifiedNamePair => new KeyValuePair(DeclaringModule.Name, Name); + #endregion + + #region IMemberContainer + public virtual IMember GetMember(IModuleContext context, string name) => Members.TryGetValue(name, out var member) ? member : null; + public virtual IEnumerable GetMemberNames(IModuleContext moduleContext) => Members.Keys; + #endregion + + internal bool TrySetTypeId(BuiltinTypeId typeId) { + if (_typeId != BuiltinTypeId.Unknown) { + return false; } + _typeId = typeId; + return true; } - public string Name { - get { - lock (_lock) { - if (Members.TryGetValue("__name__", out var nameMember) && nameMember is AstPythonStringLiteral lit) { - return lit.Value; - } + internal void AddMembers(IEnumerable> members, bool overwrite) { + lock (_lock) { + foreach (var kv in members.Where(m => overwrite || !Members.ContainsKey(m.Key))) { + WritableMembers[kv.Key] = kv.Value; } - return _name; } } - public string Documentation { get; } - public IPythonModule DeclaringModule { get; } - public IReadOnlyList Bases { get; private set; } - public virtual bool IsBuiltin => false; - public PythonMemberType MemberType => PythonMemberType.Class; - public virtual BuiltinTypeId TypeId => BuiltinTypeId.Type; - public virtual bool IsClass { get; } - - /// - /// The start index of this class. Used to disambiguate multiple - /// class definitions with the same name in the same file. - /// - public int StartIndex { get; } - public IEnumerable Locations { get; } - - public string FullyQualifiedName => FullyQualifiedNamePair.CombineNames(); - public KeyValuePair FullyQualifiedNamePair => new KeyValuePair(DeclaringModule.Name, Name); - - public IMember GetMember(IModuleContext context, string name) { - IMember member; + internal IMember AddMember(string name, IMember member, bool overwrite) { lock (_lock) { - if (Members.TryGetValue(name, out member)) { - return member; - } - - // Special case names that we want to add to our own Members dict - switch (name) { - case "__mro__": - member = Members[name] = new AstPythonSequence( - (context as IPythonInterpreter)?.GetBuiltinType(BuiltinTypeId.Tuple), - DeclaringModule, - Mro, - (context as IPythonInterpreter)?.GetBuiltinType(BuiltinTypeId.TupleIterator) - ); - return member; - } - } - if (Push()) { - try { - foreach (var m in Mro.Reverse()) { - if (m == this) { - return member; - } - member = member ?? m.GetMember(context, name); - } - } finally { - Pop(); + if (overwrite || !Members.ContainsKey(name)) { + WritableMembers[name] = member; } + return member; } - return null; } - private bool Push() => _isProcessing.Value ? false : (_isProcessing.Value = true); - private void Pop() => _isProcessing.Value = false; - - public IPythonFunction GetConstructors() => GetMember(null, "__init__") as IPythonFunction; - - public IEnumerable GetMemberNames(IModuleContext moduleContext) { - var names = new HashSet(); - lock (_lock) { - names.UnionWith(Members.Keys); - } + internal bool IsHidden => ContainsMember("__hidden__"); - foreach (var m in Mro.Skip(1)) { - names.UnionWith(m.GetMemberNames(moduleContext)); - } - return names; + /// + /// Provides type factory. Similar to __metaclass__ but does not expose full + /// metaclass functionality. Used in cases when function has to return a class + /// rather than the class instance. Example: function annotated as '-> Type[T]' + /// can be called as a T constructor so func() constructs class instance rather than invoking + /// call on an existing instance. See also collections/namedtuple typing in the Typeshed. + /// + internal AstPythonType GetTypeFactory() { + var clone = new AstPythonType(Name, DeclaringModule, Documentation, + Locations.OfType().FirstOrDefault(), + TypeId == BuiltinTypeId.Unknown ? BuiltinTypeId.Type : TypeId, true); + clone.AddMembers(Members, true); + return clone; } - protected bool ContainsMember(string name) { - lock (_lock) { - return Members.ContainsKey(name); - } - } + protected bool ContainsMember(string name) => Members.ContainsKey(name); } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonTypeWrapper.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonTypeWrapper.cs new file mode 100644 index 000000000..097a2a6f5 --- /dev/null +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstPythonTypeWrapper.cs @@ -0,0 +1,43 @@ +// Python Tools for Visual Studio +// 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.Collections.Generic; +using System.Linq; +using Microsoft.PythonTools.Analysis.Infrastructure; + +namespace Microsoft.PythonTools.Interpreter.Ast { + /// + /// Delegates most of the methods to the wrapped/inner class. + /// + class AstPythonTypeWrapper : AstPythonType { + protected IPythonType InnerType { get; } + + public AstPythonTypeWrapper(IPythonType type) + : this(type, type.DeclaringModule) { } + + public AstPythonTypeWrapper(IPythonType type, IPythonModule declaringModule) + : base(type?.Name ?? "", declaringModule, type?.Documentation, + (type as ILocatedMember)?.Locations.MaybeEnumerate().FirstOrDefault()) { + InnerType = type; + } + + public override BuiltinTypeId TypeId => InnerType?.TypeId ?? BuiltinTypeId.Unknown; + public override PythonMemberType MemberType => InnerType?.MemberType ?? PythonMemberType.Unknown; + public override IMember GetMember(IModuleContext context, string name) => InnerType?.GetMember(context, name); + public override IEnumerable GetMemberNames(IModuleContext moduleContext) => InnerType?.GetMemberNames(moduleContext); + + } +} diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstScrapedPythonModule.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstScrapedPythonModule.cs index 5abb4cc71..d874eb88d 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstScrapedPythonModule.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstScrapedPythonModule.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -27,7 +27,7 @@ using Microsoft.PythonTools.Parsing.Ast; namespace Microsoft.PythonTools.Interpreter.Ast { - class AstScrapedPythonModule : IPythonModule + class AstScrapedPythonModule : PythonModuleType, IPythonModule #if DEBUG // In debug builds we let you F12 to the scraped file , ILocatedMember @@ -37,28 +37,23 @@ class AstScrapedPythonModule : IPythonModule protected readonly Dictionary _members; private bool _scraped; - public AstScrapedPythonModule(string name, string filePath) { - Name = name ?? throw new ArgumentNullException(nameof(name)); + public AstScrapedPythonModule(string name, string filePath): base(name) { ParseErrors = Enumerable.Empty(); _filePath = filePath; _members = new Dictionary(); _scraped = false; } - public string Name { get; } - - public string Documentation { + public override string Documentation { get { var m = GetMember(null, "__doc__") as AstPythonStringLiteral; return m != null ? m.Value : string.Empty; } } - public PythonMemberType MemberType => PythonMemberType.Module; - public IEnumerable GetChildrenModules() => Enumerable.Empty(); - public virtual IMember GetMember(IModuleContext context, string name) { + public override IMember GetMember(IModuleContext context, string name) { IMember m; if (!_scraped) { Imported(context); @@ -75,7 +70,7 @@ public virtual IMember GetMember(IModuleContext context, string name) { return m; } - public virtual IEnumerable GetMemberNames(IModuleContext moduleContext) { + public override IEnumerable GetMemberNames(IModuleContext moduleContext) { if (!_scraped) { Imported(moduleContext); } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstTypeAnnotationConverter.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstTypeAnnotationConverter.cs index e57f9d699..979a8163a 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstTypeAnnotationConverter.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstTypeAnnotationConverter.cs @@ -39,7 +39,7 @@ private static IPythonType AsIPythonType(IMember m) { } if (m is IPythonMultipleMembers mm) { - return AstPythonMultipleMembers.CreateAs(mm.Members); + return AstPythonMultipleMembers.CreateAs(mm.GetMembers()); } return null; @@ -76,8 +76,8 @@ private IEnumerable FinalizeList(IPythonType type) { public override IPythonType LookupName(string name) { var m = _scope.LookupNameInScopes(name, NameLookupContext.LookupOptions.Global | NameLookupContext.LookupOptions.Builtins); if (m is IPythonMultipleMembers mm) { - m = (IMember)AstPythonMultipleMembers.CreateAs(mm.Members) ?? - AstPythonMultipleMembers.CreateAs(mm.Members); + m = (IMember)AstPythonMultipleMembers.CreateAs(mm.GetMembers()) ?? + AstPythonMultipleMembers.CreateAs(mm.GetMembers()); } if (m is IPythonModule mod) { // Wrap the module in an IPythonType interface @@ -98,7 +98,7 @@ public override IReadOnlyList GetUnionTypes(IPythonType type) => type is UnionType unionType ? unionType.Types : type is IPythonMultipleMembers multipleMembers - ? multipleMembers.Members.OfType().ToArray() + ? multipleMembers.GetMembers().OfType().ToArray() : null; public override IPythonType MakeGeneric(IPythonType baseType, IReadOnlyList args) { @@ -197,75 +197,46 @@ private IPythonType MakeLookupType(BuiltinTypeId typeId, IReadOnlyList DeclaringModule.Name; - public string Documentation => DeclaringModule.Documentation; - public BuiltinTypeId TypeId => BuiltinTypeId.Module; - public IReadOnlyList Mro => new[] { this }; - public bool IsBuiltin => true; - public PythonMemberType MemberType => PythonMemberType.Module; - public IPythonFunction GetConstructors() => null; + public override BuiltinTypeId TypeId => BuiltinTypeId.Module; + public override PythonMemberType MemberType => PythonMemberType.Module; - public IMember GetMember(IModuleContext context, string name) => DeclaringModule.GetMember(context, name); - public IEnumerable GetMemberNames(IModuleContext moduleContext) => DeclaringModule.GetMemberNames(moduleContext); + public override IMember GetMember(IModuleContext context, string name) => DeclaringModule.GetMember(context, name); + public override IEnumerable GetMemberNames(IModuleContext moduleContext) => DeclaringModule.GetMemberNames(moduleContext); } - private class UnionType : IPythonMultipleMembers, IPythonType { - public UnionType(IReadOnlyList types) { + private class UnionType : AstPythonType, IPythonMultipleMembers { + public UnionType(IReadOnlyList types): + base("Any", types.Select(t => t.DeclaringModule).ExcludeDefault().FirstOrDefault(), null, null) { Types = types; } public IReadOnlyList Types { get; } - public IReadOnlyList Members => Types.OfType().ToArray(); + public IReadOnlyList GetMembers() => Types.OfType().ToArray(); - public PythonMemberType MemberType => PythonMemberType.Unknown; - public string Name => "Any"; - public string Documentation => null; - public BuiltinTypeId TypeId => BuiltinTypeId.Unknown; - public IPythonModule DeclaringModule => null; - public IReadOnlyList Mro => null; - public bool IsBuiltin => false; - public IPythonFunction GetConstructors() => null; - - public IMember GetMember(IModuleContext context, string name) => new UnionType( + public override IMember GetMember(IModuleContext context, string name) => new UnionType( Types.Select(t => t.GetMember(context, name)).OfType().ToArray() ); - public IEnumerable GetMemberNames(IModuleContext moduleContext) => Types.SelectMany(t => t.GetMemberNames(moduleContext)); + public override IEnumerable GetMemberNames(IModuleContext moduleContext) => Types.SelectMany(t => t.GetMemberNames(moduleContext)); } - private class NameType : IPythonType { - public NameType(string name) { - Name = name; - } - - public IPythonModule DeclaringModule => null; - - public string Name { get; } - public string Documentation => null; - public BuiltinTypeId TypeId => BuiltinTypeId.Unknown; - public IReadOnlyList Mro => null; - public bool IsBuiltin => true; - public PythonMemberType MemberType => PythonMemberType.Unknown; - public IPythonFunction GetConstructors() => null; - - public IMember GetMember(IModuleContext context, string name) => null; - public IEnumerable GetMemberNames(IModuleContext moduleContext) => null; - } + private class NameType : AstPythonType { + public NameType(string name): base(name, BuiltinTypeId.Unknown) { } + } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/AstTypingModule.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/AstTypingModule.cs index a3b396b7f..ecb1c385e 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/AstTypingModule.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/AstTypingModule.cs @@ -35,7 +35,7 @@ public static bool IsTypingType(IMember type) { } if (type is IPythonMultipleMembers mm) { - return mm.Members.Any(IsTypingType); + return mm.GetMembers().Any(IsTypingType); } return false; diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/NameLookupContext.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/NameLookupContext.cs index 86254ef1d..b7d04a427 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Ast/NameLookupContext.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/NameLookupContext.cs @@ -157,7 +157,7 @@ public IEnumerable GetTypesFromAnnotation(Expression expr) { var ann = new TypeAnnotation(Ast.LanguageVersion, expr); var m = ann.GetValue(new AstTypeAnnotationConverter(this)); if (m is IPythonMultipleMembers mm) { - return mm.Members.OfType(); + return mm.GetMembers().OfType(); } else if (m is IPythonType type) { return Enumerable.Repeat(type, 1); } @@ -233,9 +233,11 @@ private IMember GetValueFromMember(MemberExpression expr, LookupOptions options) switch (e) { case IMemberContainer mc: value = mc.GetMember(Context, expr.Name); + // If container is class rather than the instance, then method is an unbound function. + value = mc is IPythonClass c && value is AstPythonFunction f && !f.IsStatic ? f.ToUnbound() : value; break; case IPythonMultipleMembers mm: - value = mm.Members.OfType() + value = mm.GetMembers().OfType() .Select(x => x.GetMember(Context, expr.Name)) .ExcludeDefault() .FirstOrDefault(); @@ -245,7 +247,7 @@ private IMember GetValueFromMember(MemberExpression expr, LookupOptions options) break; } - if (value is IBuiltinProperty2 p) { + if (value is IPythonProperty p) { value = GetPropertyReturnType(p, expr); } else if (value == null) { _log?.Log(TraceLevel.Verbose, "UnknownMember", expr.ToCodeString(Ast).Trim()); @@ -358,6 +360,9 @@ private IMember GetValueFromCallable(CallExpression expr, LookupOptions options) var m = GetValueFromExpression(expr.Target); IMember value = null; switch (m) { + case IPythonFunction pf: + value = GetValueFromPropertyOrFunction(pf, expr); + break; case IPythonType type when type == Interpreter.GetBuiltinType(BuiltinTypeId.Type) && expr.Args.Count >= 1: value = GetTypeFromValue(GetValueFromExpression(expr.Args[0].Expression, options)); break; @@ -365,7 +370,6 @@ private IMember GetValueFromCallable(CallExpression expr, LookupOptions options) value = new AstPythonConstant(type, GetLoc(expr)); break; default: - value = GetValueFromPropertyOrFunction(m, expr); break; } @@ -377,19 +381,17 @@ private IMember GetValueFromCallable(CallExpression expr, LookupOptions options) private IMember GetValueFromPropertyOrFunction(IMember fn, Expression expr) { switch (fn) { - case IPythonBoundFunction bf when bf.Function is IPythonFunction2 f: - return GetValueFromFunction(f, expr); - case IPythonFunction2 f: - return GetValueFromFunction(f, expr); - case IBuiltinProperty2 p: + case IPythonProperty p: return GetPropertyReturnType(p, expr); + case IPythonFunction f: + return GetValueFromFunction(f, expr); case IPythonConstant c when c.Type?.MemberType == PythonMemberType.Class: return c.Type; // typically cls() } return null; } - private IMember GetValueFromFunction(IPythonFunction2 fn, Expression expr) { + private IMember GetValueFromFunction(IPythonFunction fn, Expression expr) { var returnType = GetFunctionReturnType(fn.Overloads.FirstOrDefault()); if (IsUnknown(returnType)) { // Function may not have been walked yet. Do it now. @@ -402,7 +404,7 @@ private IMember GetValueFromFunction(IPythonFunction2 fn, Expression expr) { private IPythonType GetFunctionReturnType(IPythonFunctionOverload o) => o != null && o.ReturnType.Count > 0 ? o.ReturnType[0] : UnknownType; - private IMember GetPropertyReturnType(IBuiltinProperty2 p, Expression expr) { + private IMember GetPropertyReturnType(IPythonProperty p, Expression expr) { if (IsUnknown(p.Type)) { // Function may not have been walked yet. Do it now. _functionWalkers.ProcessFunction(p.FunctionDefinition); @@ -425,7 +427,7 @@ public IPythonConstant GetConstantFromLiteral(Expression expr, LookupOptions opt public IEnumerable GetTypesFromValue(IMember value) { if (value is IPythonMultipleMembers mm) { - return mm.Members.Select(GetTypeFromValue).Distinct(); + return mm.GetMembers().Select(GetTypeFromValue).Distinct(); } else { var t = GetTypeFromValue(value); if (t != null) { @@ -448,45 +450,38 @@ public IPythonType GetTypeFromValue(IMember value) { switch (value.MemberType) { case PythonMemberType.Class: return Interpreter.GetBuiltinType(BuiltinTypeId.Type); - case PythonMemberType.Delegate: - case PythonMemberType.DelegateInstance: case PythonMemberType.Function: return Interpreter.GetBuiltinType(BuiltinTypeId.Function); case PythonMemberType.Method: - return Interpreter.GetBuiltinType(BuiltinTypeId.BuiltinMethodDescriptor); + return Interpreter.GetBuiltinType(BuiltinTypeId.Method); case PythonMemberType.Enum: case PythonMemberType.EnumInstance: break; case PythonMemberType.Module: return Interpreter.GetBuiltinType(BuiltinTypeId.Module); - case PythonMemberType.Namespace: - return Interpreter.GetBuiltinType(BuiltinTypeId.Object); case PythonMemberType.Event: break; } - IPythonFunction f; - if ((f = value as IPythonFunction ?? (value as IPythonBoundFunction)?.Function) != null) { + if (value is IPythonFunction f) { if (f.IsStatic) { return Interpreter.GetBuiltinType(BuiltinTypeId.StaticMethod); } else if (f.IsClassMethod) { return Interpreter.GetBuiltinType(BuiltinTypeId.ClassMethod); } - return Interpreter.GetBuiltinType(BuiltinTypeId.Function); + return f.DeclaringType == null + ? Interpreter.GetBuiltinType(BuiltinTypeId.Function) + : Interpreter.GetBuiltinType(BuiltinTypeId.Method); } - if (value is IBuiltinProperty prop) { + if (value is IPythonProperty prop) { return prop.Type ?? Interpreter.GetBuiltinType(BuiltinTypeId.Property); } else if (value.MemberType == PythonMemberType.Property) { return Interpreter.GetBuiltinType(BuiltinTypeId.Property); } - if (value is IPythonMethodDescriptor) { - return Interpreter.GetBuiltinType(BuiltinTypeId.BuiltinMethodDescriptor); - } - if (value is IPythonMultipleMembers mm) { - return AstPythonMultipleMembers.CreateAs(mm.Members); + return AstPythonMultipleMembers.CreateAs(mm.GetMembers()); } if (value is IPythonType) { diff --git a/src/Analysis/Engine/Impl/Interpreter/Ast/PythonModuleType.cs b/src/Analysis/Engine/Impl/Interpreter/Ast/PythonModuleType.cs new file mode 100644 index 000000000..d1c4f4243 --- /dev/null +++ b/src/Analysis/Engine/Impl/Interpreter/Ast/PythonModuleType.cs @@ -0,0 +1,47 @@ +// Python Tools for Visual Studio +// 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.Linq; + +namespace Microsoft.PythonTools.Interpreter.Ast { + class PythonModuleType: IPythonType { + public PythonModuleType(string name) { + Name = name ?? throw new ArgumentNullException(nameof(name)); + } + + #region IPythonType + public string Name { get; } + public virtual string Documentation { get; } = string.Empty; + + public virtual IPythonModule DeclaringModule => null; + public BuiltinTypeId TypeId => BuiltinTypeId.Module; + public bool IsBuiltin => true; + public bool IsTypeFactory => false; + public IPythonFunction GetConstructor() => null; + #endregion + + #region IMember + public PythonMemberType MemberType => PythonMemberType.Module; + #endregion + + #region IMemberContainer + public virtual IMember GetMember(IModuleContext context, string name) => null; + public virtual IEnumerable GetMemberNames(IModuleContext moduleContext) => Enumerable.Empty(); + #endregion + } +} diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/BuiltinTypeId.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/BuiltinTypeId.cs index d11640f3b..4abd2e27b 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/BuiltinTypeId.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/BuiltinTypeId.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -22,7 +22,7 @@ namespace Microsoft.PythonTools.Interpreter { /// /// Well known built-in types that the analysis engine needs for doing interpretation. /// - public enum BuiltinTypeId : int { + public enum BuiltinTypeId { Unknown, Object, Type, @@ -83,8 +83,7 @@ public enum BuiltinTypeId : int { Module, Function, - BuiltinMethodDescriptor, - BuiltinFunction, + Method, Generator, Property, @@ -109,40 +108,33 @@ public enum BuiltinTypeId : int { /// DictItems, SetIterator, - CallableIterator, + CallableIterator } public static class BuiltinTypeIdExtensions { /// /// Indicates whether an ID should be remapped by an interpreter. /// - public static bool IsVirtualId(this BuiltinTypeId id) { - return id == BuiltinTypeId.Str || + public static bool IsVirtualId(this BuiltinTypeId id) => id == BuiltinTypeId.Str || id == BuiltinTypeId.StrIterator || (int)id > (int)LastTypeId; - } public static BuiltinTypeId LastTypeId => BuiltinTypeId.CallableIterator; - public static string GetModuleName(this BuiltinTypeId id, Version version) { - return id.GetModuleName(version.Major == 3); - } + public static string GetModuleName(this BuiltinTypeId id, Version version) + => id.GetModuleName(version.Major == 3); - public static string GetModuleName(this BuiltinTypeId id, PythonLanguageVersion languageVersion) { - return id.GetModuleName(languageVersion.IsNone() || languageVersion.Is3x()); - } + public static string GetModuleName(this BuiltinTypeId id, PythonLanguageVersion languageVersion) + => id.GetModuleName(languageVersion.IsNone() || languageVersion.Is3x()); - private static string GetModuleName(this BuiltinTypeId id, bool is3x) { - return is3x ? "builtins" : "__builtin__"; - } + private static string GetModuleName(this BuiltinTypeId id, bool is3x) + => is3x ? "builtins" : "__builtin__"; - public static string GetTypeName(this BuiltinTypeId id, Version version) { - return id.GetTypeName(version.Major == 3); - } + public static string GetTypeName(this BuiltinTypeId id, Version version) + => id.GetTypeName(version.Major == 3); - public static string GetTypeName(this BuiltinTypeId id, PythonLanguageVersion languageVersion) { - return id.GetTypeName(languageVersion.IsNone() || languageVersion.Is3x()); - } + public static string GetTypeName(this BuiltinTypeId id, PythonLanguageVersion languageVersion) + => id.GetTypeName(languageVersion.IsNone() || languageVersion.Is3x()); private static string GetTypeName(this BuiltinTypeId id, bool is3x) { string name; @@ -162,8 +154,6 @@ private static string GetTypeName(this BuiltinTypeId id, bool is3x) { case BuiltinTypeId.Tuple: name = "tuple"; break; case BuiltinTypeId.Type: name = "type"; break; - case BuiltinTypeId.BuiltinFunction: name = "builtin_function"; break; - case BuiltinTypeId.BuiltinMethodDescriptor: name = "builtin_method_descriptor"; break; case BuiltinTypeId.DictKeys: name = "dict_keys"; break; case BuiltinTypeId.DictValues: name = "dict_values"; break; case BuiltinTypeId.DictItems: name = "dict_items"; break; @@ -181,6 +171,7 @@ private static string GetTypeName(this BuiltinTypeId id, bool is3x) { case BuiltinTypeId.CallableIterator: name = "callable_iterator"; break; case BuiltinTypeId.Property: name = "property"; break; + case BuiltinTypeId.Method: name = "method"; break; case BuiltinTypeId.ClassMethod: name = "classmethod"; break; case BuiltinTypeId.StaticMethod: name = "staticmethod"; break; case BuiltinTypeId.FrozenSet: name = "frozenset"; break; @@ -211,8 +202,6 @@ public static BuiltinTypeId GetTypeId(this string name) { case "type": return BuiltinTypeId.Type; case "frozenset": return BuiltinTypeId.FrozenSet; - case "builtin_function": return BuiltinTypeId.BuiltinFunction; - case "builtin_method_descriptor": return BuiltinTypeId.BuiltinMethodDescriptor; case "dict_keys": return BuiltinTypeId.DictKeys; case "dict_values": return BuiltinTypeId.DictValues; case "dict_items": return BuiltinTypeId.DictItems; @@ -232,11 +221,64 @@ public static BuiltinTypeId GetTypeId(this string name) { case "callable_iterator": return BuiltinTypeId.CallableIterator; case "property": return BuiltinTypeId.Property; + case "method": return BuiltinTypeId.Method; case "classmethod": return BuiltinTypeId.ClassMethod; case "staticmethod": return BuiltinTypeId.StaticMethod; } return BuiltinTypeId.Unknown; } + internal static PythonMemberType GetMemberId(this BuiltinTypeId id) { + switch (id) { + case BuiltinTypeId.Bool: + case BuiltinTypeId.Complex: + case BuiltinTypeId.Float: + case BuiltinTypeId.Int: + case BuiltinTypeId.Long: + case BuiltinTypeId.Str: + case BuiltinTypeId.Unicode: + case BuiltinTypeId.NoneType: + case BuiltinTypeId.Ellipsis: + return PythonMemberType.Constant; + + case BuiltinTypeId.Dict: + case BuiltinTypeId.List: + case BuiltinTypeId.Object: + case BuiltinTypeId.Set: + case BuiltinTypeId.Bytes: + case BuiltinTypeId.Tuple: + case BuiltinTypeId.DictKeys: + case BuiltinTypeId.DictValues: + case BuiltinTypeId.DictItems: + case BuiltinTypeId.Generator: + case BuiltinTypeId.FrozenSet: + case BuiltinTypeId.ListIterator: + case BuiltinTypeId.TupleIterator: + case BuiltinTypeId.SetIterator: + case BuiltinTypeId.StrIterator: + case BuiltinTypeId.UnicodeIterator: + case BuiltinTypeId.BytesIterator: + case BuiltinTypeId.CallableIterator: + return PythonMemberType.Instance; + + case BuiltinTypeId.Type: + return PythonMemberType.Class; + + case BuiltinTypeId.Module: + return PythonMemberType.Module; + + case BuiltinTypeId.Function: + case BuiltinTypeId.ClassMethod: + case BuiltinTypeId.StaticMethod: + return PythonMemberType.Function; + + case BuiltinTypeId.Property: + return PythonMemberType.Property; + + case BuiltinTypeId.Method: + return PythonMemberType.Method; + } + return PythonMemberType.Unknown; + } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/IMember.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/IMember.cs index 595b94c8a..8d05d2a9a 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/IMember.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/IMember.cs @@ -20,8 +20,6 @@ namespace Microsoft.PythonTools.Interpreter { /// Represents a member that appears in a module, type, etc... /// public interface IMember { - PythonMemberType MemberType { - get; - } + PythonMemberType MemberType { get; } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonMethodDescriptor.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonClass.cs similarity index 60% rename from src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonMethodDescriptor.cs rename to src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonClass.cs index 5c556ff6a..2a454c334 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonMethodDescriptor.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonClass.cs @@ -9,29 +9,22 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. +using System.Collections.Generic; +using Microsoft.PythonTools.Parsing.Ast; namespace Microsoft.PythonTools.Interpreter { /// - /// Represents a method descriptor for an instance of a function. + /// Represents Python tclass - typically a type that has + /// __bases__ and the method resolution order. /// - public interface IPythonMethodDescriptor : IMember { - /// - /// The built-in function that the method descriptor wraps. - /// - IPythonFunction Function { - get; - } - - /// - /// True if the method is already bound to an instance. - /// - bool IsBound { - get; - } + public interface IPythonClass : IPythonType { + ClassDefinition ClassDefinition { get; } + IReadOnlyList Mro { get; } + IReadOnlyList Bases { get; } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonFunction.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonFunction.cs index 69036e271..d310ce766 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonFunction.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonFunction.cs @@ -19,34 +19,16 @@ namespace Microsoft.PythonTools.Interpreter { /// - /// Represents an object which is a function. Provides documentation for signature help. + /// Represents a function. /// - public interface IPythonFunction : IMember { - string Name { get; } - string Documentation { get; } - bool IsBuiltin { get; } - + public interface IPythonFunction : IPythonType { + FunctionDefinition FunctionDefinition { get; } + IPythonType DeclaringType { get; } /// /// False if binds instance when in a class, true if always static. /// bool IsStatic { get; } bool IsClassMethod { get; } IReadOnlyList Overloads { get; } - IPythonType DeclaringType { get; } - IPythonModule DeclaringModule { get; } - } - - public interface IPythonFunction2 : IPythonFunction { - FunctionDefinition FunctionDefinition { get; } - } - - /// - /// Represents a bound function. Similar to , - /// but uses Python 3.x semantics where the first argument of Function is - /// assumed to be filled with an instance of SelfType. - /// - public interface IPythonBoundFunction : IMember { - IPythonType SelfType { get; } - IPythonFunction Function { get; } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonModule.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonModule.cs index 917dd51c5..177af8490 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonModule.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonModule.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -20,22 +20,9 @@ namespace Microsoft.PythonTools.Interpreter { /// /// Represents a Python module which members can be imported from. /// - public interface IPythonModule : IMemberContainer, IMember { - string Name { - get; - } - + public interface IPythonModule : IPythonType { IEnumerable GetChildrenModules(); void Imported(IModuleContext context); - - /// - /// The documentation of the module - /// - /// New in 1.1. - /// - string Documentation { - get; - } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonMultipleMembers.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonMultipleMembers.cs index 6d0aa8218..bb4bc6d70 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonMultipleMembers.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonMultipleMembers.cs @@ -21,8 +21,6 @@ namespace Microsoft.PythonTools.Interpreter { /// Represents a collection of multiple members which can appear under a single name. /// public interface IPythonMultipleMembers : IMember { - IReadOnlyList Members { - get; - } + IReadOnlyList GetMembers(); } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/IBuiltinProperty.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonProperty.cs similarity index 85% rename from src/Analysis/Engine/Impl/Interpreter/Definitions/IBuiltinProperty.cs rename to src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonProperty.cs index e9cc0ab1f..7cca5d0b7 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/IBuiltinProperty.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonProperty.cs @@ -20,29 +20,24 @@ namespace Microsoft.PythonTools.Interpreter { /// /// Represents a built-in property which has a getter/setter. /// - public interface IBuiltinProperty : IMember { + public interface IPythonProperty : IPythonType { /// /// The type of the value the property gets/sets. /// IPythonType Type { get; } /// - /// True if the property is static (declared on the class) not the instance. + /// A user readable description of the property. /// - bool IsStatic { get; } + string Description { get; } /// - /// Documentation for the property. + /// True if the property is static (declared on the class) not the instance. /// - string Documentation { get; } + bool IsStatic { get; } - /// - /// A user readable description of the property. - /// - string Description { get; } - } + IPythonType DeclaringType { get; } - public interface IBuiltinProperty2: IBuiltinProperty { FunctionDefinition FunctionDefinition { get; } } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonType.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonType.cs index a3f64a0e7..d3d9f6a76 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonType.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/IPythonType.cs @@ -15,35 +15,43 @@ // permissions and limitations under the License. using System.Collections.Generic; +using Microsoft.PythonTools.Parsing.Ast; namespace Microsoft.PythonTools.Interpreter { public interface IPythonType : IMemberContainer, IMember { - IPythonFunction GetConstructors(); - - // PythonType.Get__name__(this); + // Python __name__. string Name { get; } /// - /// Human-readable documentation that may be displayed in the editor hover tooltip. + /// Module the type is declared in. /// - string Documentation { get; } + IPythonModule DeclaringModule { get; } + /// + /// Indicates built-in type id such as 'int' or 'str' + /// or 'type' for user-defined entities. + /// BuiltinTypeId TypeId { get; } - IPythonModule DeclaringModule { get; } - - IReadOnlyList Mro { get; } + /// + /// Human-readable documentation that may be displayed in the editor hover tooltip. + /// + string Documentation { get; } + /// + /// Indicates if type is a built-in type. + /// bool IsBuiltin { get; } - } - public interface IPythonType2 : IPythonType { /// - /// Indicates that type is a class. Used in cases when function has to return - /// a class rather than the class instance. Example: function annotated as '-> Type[T]' - /// can be called as a T constructor so func() constructs class instance rather than invoking - /// // call on an existing instance. See also collections/namedtuple typing in the Typeshed. + /// Type is a type class factory. + /// + bool IsTypeFactory { get; } + + /// + /// Returns constructors of the type, if any. /// - bool IsClass { get; } + /// + IPythonFunction GetConstructor(); } } diff --git a/src/Analysis/Engine/Impl/Interpreter/Definitions/PythonMemberType.cs b/src/Analysis/Engine/Impl/Interpreter/Definitions/PythonMemberType.cs index 6b464037a..db1e4bbeb 100644 --- a/src/Analysis/Engine/Impl/Interpreter/Definitions/PythonMemberType.cs +++ b/src/Analysis/Engine/Impl/Interpreter/Definitions/PythonMemberType.cs @@ -33,14 +33,6 @@ public enum PythonMemberType { /// Instance, /// - /// The result is a delegate type. - /// - Delegate, - /// - /// The result is an instance of a delegate. - /// - DelegateInstance, - /// /// The result is an enum type. /// Enum, @@ -60,16 +52,10 @@ public enum PythonMemberType { /// An instance of a built-in or user defined module. /// Module, - /// - /// An instance of a namespace object that was imported from .NET. - /// - Namespace, - /// /// A constant defined in source code. /// Constant, - /// /// A .NET event object that is exposed to Python. /// @@ -82,22 +68,18 @@ public enum PythonMemberType { /// A .NET property object that is exposed to Python. /// Property, - /// /// A merge of multiple types. /// Multiple, - /// /// The member represents a keyword /// Keyword, - /// /// The member represents a code snippet /// CodeSnippet, - /// /// The member represents a named argument /// diff --git a/src/Analysis/Engine/Impl/Interpreter/SentinelModule.cs b/src/Analysis/Engine/Impl/Interpreter/SentinelModule.cs index e6f37103b..fd94d42b3 100644 --- a/src/Analysis/Engine/Impl/Interpreter/SentinelModule.cs +++ b/src/Analysis/Engine/Impl/Interpreter/SentinelModule.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -20,16 +20,16 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.PythonTools.Intellisense; +using Microsoft.PythonTools.Interpreter.Ast; namespace Microsoft.PythonTools.Interpreter { - sealed class SentinelModule : IPythonModule { + sealed class SentinelModule : PythonModuleType, IPythonModule { private readonly AnalysisQueue _scope; private readonly SemaphoreSlim _semaphore; private volatile IPythonModule _realModule; - public SentinelModule(string name, bool importing) { + public SentinelModule(string name, bool importing): base(name) { _scope = AnalysisQueue.Current; - Name = name; if (importing) { _semaphore = new SemaphoreSlim(0, 1000); } else { @@ -68,12 +68,7 @@ public void Complete(IPythonModule module) { } } - public string Name { get; } - public string Documentation => null; - public PythonMemberType MemberType => PythonMemberType.Module; - public IEnumerable GetChildrenModules() => Enumerable.Empty(); - public IMember GetMember(IModuleContext context, string name) => null; - public IEnumerable GetMemberNames(IModuleContext moduleContext) => Enumerable.Empty(); public void Imported(IModuleContext context) { } + public IEnumerable GetChildrenModules() => Enumerable.Empty(); } } diff --git a/src/Analysis/Engine/Impl/KnownTypes.cs b/src/Analysis/Engine/Impl/KnownTypes.cs index 94971c36f..a2600e494 100644 --- a/src/Analysis/Engine/Impl/KnownTypes.cs +++ b/src/Analysis/Engine/Impl/KnownTypes.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -18,9 +18,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using Microsoft.PythonTools.Analysis; using Microsoft.PythonTools.Analysis.Values; using Microsoft.PythonTools.Interpreter; +using Microsoft.PythonTools.Interpreter.Ast; using Microsoft.PythonTools.Parsing; namespace Microsoft.PythonTools.Analysis { @@ -39,7 +39,7 @@ internal class KnownTypes : IKnownPythonTypes, IKnownClasses { public static KnownTypes CreateDefault(PythonAnalyzer state, IBuiltinPythonModule fallback) { var res = new KnownTypes(); - for (int value = 0; value < res._types.Length; ++value) { + for (var value = 0; value < res._types.Length; ++value) { res._types[value] = (IPythonType)fallback.GetAnyMember( ((BuiltinTypeId)value).GetTypeName(state.LanguageVersion) ); @@ -55,7 +55,7 @@ public static KnownTypes Create(PythonAnalyzer state, IBuiltinPythonModule fallb var interpreter = state.Interpreter; - for (int value = 0; value < res._types.Length; ++value) { + for (var value = 0; value < res._types.Length; ++value) { IPythonType type; try { type = interpreter.GetBuiltinType((BuiltinTypeId)value); @@ -74,40 +74,32 @@ public static KnownTypes Create(PythonAnalyzer state, IBuiltinPythonModule fallb } private KnownTypes() { - int count = (int)BuiltinTypeIdExtensions.LastTypeId + 1; + var count = (int)BuiltinTypeIdExtensions.LastTypeId + 1; _types = new IPythonType[count]; _classInfos = new BuiltinClassInfo[count]; } private void SetClassInfo(PythonAnalyzer state) { - for (int value = 0; value < _types.Length; ++value) { + for (var value = 0; value < _types.Length; ++value) { if (_types[value] != null) { _classInfos[value] = state.GetBuiltinType(_types[value]); } } } - IPythonType IKnownPythonTypes.this[BuiltinTypeId id] { - get { - return _types[(int)id]; - } - } + IPythonType IKnownPythonTypes.this[BuiltinTypeId id] => _types[(int)id]; - BuiltinClassInfo IKnownClasses.this[BuiltinTypeId id] { - get { - return _classInfos[(int)id]; - } - } + BuiltinClassInfo IKnownClasses.this[BuiltinTypeId id] => _classInfos[(int)id]; } - class FallbackBuiltinModule : IBuiltinPythonModule, IPythonModule { + class FallbackBuiltinModule : PythonModuleType, IBuiltinPythonModule { public readonly PythonLanguageVersion LanguageVersion; private readonly Dictionary _cachedInstances; - public FallbackBuiltinModule(PythonLanguageVersion version) { + public FallbackBuiltinModule(PythonLanguageVersion version) + : base(BuiltinTypeId.Unknown.GetModuleName(version)) { LanguageVersion = version; _cachedInstances = new Dictionary(); - Name = BuiltinTypeId.Unknown.GetModuleName(version); } private IMember GetOrCreate(BuiltinTypeId typeId) { @@ -133,10 +125,6 @@ private IMember GetOrCreate(BuiltinTypeId typeId) { } } - public string Documentation => string.Empty; - public PythonMemberType MemberType => PythonMemberType.Module; - public string Name { get; } - public IMember GetAnyMember(string name) { foreach (BuiltinTypeId typeId in Enum.GetValues(typeof(BuiltinTypeId))) { if (typeId.GetTypeName(LanguageVersion) == name) { @@ -147,27 +135,16 @@ public IMember GetAnyMember(string name) { } public IEnumerable GetChildrenModules() => Enumerable.Empty(); - public IMember GetMember(IModuleContext context, string name) => null; - public IEnumerable GetMemberNames(IModuleContext moduleContext) => Enumerable.Empty(); public void Imported(IModuleContext context) { } } - class FallbackBuiltinPythonType : IPythonType { - public FallbackBuiltinPythonType(IBuiltinPythonModule module, BuiltinTypeId typeId, string name = null) { - DeclaringModule = module; - Name = name ?? typeId.GetModuleName((DeclaringModule as FallbackBuiltinModule)?.LanguageVersion ?? PythonLanguageVersion.None); + class FallbackBuiltinPythonType : AstPythonType { + public FallbackBuiltinPythonType(FallbackBuiltinModule declaringModule, BuiltinTypeId typeId) : + base(typeId.GetModuleName(declaringModule.LanguageVersion), declaringModule, declaringModule.Documentation, null) { TypeId = typeId; } - public IPythonModule DeclaringModule { get; } - public string Documentation => string.Empty; - public bool IsBuiltin => true; - public PythonMemberType MemberType => PythonMemberType.Class; - public IReadOnlyList Mro => new[] { (IPythonType)this }; - public string Name { get; } - public BuiltinTypeId TypeId {get;} - public IPythonFunction GetConstructors() => null; - public IMember GetMember(IModuleContext context, string name) => null; - public IEnumerable GetMemberNames(IModuleContext moduleContext) => Enumerable.Empty(); + public override PythonMemberType MemberType => PythonMemberType.Class; + public override BuiltinTypeId TypeId { get; } } } diff --git a/src/Analysis/Engine/Impl/ModuleTable.cs b/src/Analysis/Engine/Impl/ModuleTable.cs index 66ebc5c32..dcc106928 100644 --- a/src/Analysis/Engine/Impl/ModuleTable.cs +++ b/src/Analysis/Engine/Impl/ModuleTable.cs @@ -403,7 +403,7 @@ private static bool BuiltinModuleContainsMember(IModuleContext context, string n // if something non-excludable aliased w/ something excludable we probably only care about the excludable // (for example a module and None - timeit.py does this in the std lib) if (member is IPythonMultipleMembers multipleMembers) { - foreach (var innerMember in multipleMembers.Members) { + foreach (var innerMember in multipleMembers.GetMembers()) { if (IsExcludedBuiltin(module, innerMember)) { return false; } diff --git a/src/Analysis/Engine/Impl/OverloadResult.cs b/src/Analysis/Engine/Impl/OverloadResult.cs index f6191eab3..b7f9f2a1e 100644 --- a/src/Analysis/Engine/Impl/OverloadResult.cs +++ b/src/Analysis/Engine/Impl/OverloadResult.cs @@ -38,6 +38,7 @@ public OverloadResult(ParameterResult[] parameters, string name, string document public virtual IReadOnlyList ReturnType => _returnType; public virtual string Documentation { get; } = string.Empty; public virtual ParameterResult[] Parameters => _parameters; + public virtual ParameterResult FirstParameter => null; internal virtual OverloadResult WithNewParameters(ParameterResult[] newParameters) => new OverloadResult(newParameters, Name, Documentation, _returnType); @@ -241,6 +242,7 @@ public OverloadResult ToOverloadResult() { class BuiltinFunctionOverloadResult : OverloadResult { private readonly IPythonFunctionOverload _overload; + private ParameterResult _selfParameter; private ParameterResult[] _parameters; private readonly ParameterResult[] _extraParameters; private readonly int _removedParams; @@ -333,43 +335,55 @@ private void DocCalculator() { } } + public override ParameterResult FirstParameter { + get { + EnsureParameters(); + return _selfParameter; + } + } + public override ParameterResult[] Parameters { get { - if (_parameters == null) { - if (_overload != null) { - var target = _overload; - - var pinfo = _overload.GetParameters(); - var result = new List(pinfo.Length + _extraParameters.Length); - var ignored = 0; - ParameterResult kwDict = null; - foreach (var param in pinfo) { - if (ignored < _removedParams) { - ignored++; - } else { - var paramResult = GetParameterResultFromParameterInfo(param); - if (param.IsKeywordDict) { - kwDict = paramResult; - } else { - result.Add(paramResult); - } - } - } + EnsureParameters(); + return _parameters; + } + } - result.InsertRange(0, _extraParameters); + private void EnsureParameters() { + if (_parameters != null) { + return; + } - // always add kw dict last. When defined in C# and combined w/ params - // it has to come earlier than it's legally allowed in Python so we - // move it to the end for intellisense purposes here. - if (kwDict != null) { - result.Add(kwDict); - } - _parameters = result.ToArray(); + if (_overload != null) { + var pinfo = _overload.GetParameters(); + var result = new List(pinfo.Length + _extraParameters.Length); + var ignored = 0; + ParameterResult kwDict = null; + foreach (var param in pinfo) { + if (ignored < _removedParams) { + _selfParameter = GetParameterResultFromParameterInfo(param); + ignored++; } else { - _parameters = new ParameterResult[0]; + var paramResult = GetParameterResultFromParameterInfo(param); + if (param.IsKeywordDict) { + kwDict = paramResult; + } else { + result.Add(paramResult); + } } } - return _parameters; + + result.InsertRange(0, _extraParameters); + + // always add kw dict last. When defined in C# and combined w/ params + // it has to come earlier than it's legally allowed in Python so we + // move it to the end for intellisense purposes here. + if (kwDict != null) { + result.Add(kwDict); + } + _parameters = result.ToArray(); + } else { + _parameters = Array.Empty(); } } diff --git a/src/Analysis/Engine/Impl/PythonAnalyzer.cs b/src/Analysis/Engine/Impl/PythonAnalyzer.cs index 14a4a8ec0..0a66db8a8 100644 --- a/src/Analysis/Engine/Impl/PythonAnalyzer.cs +++ b/src/Analysis/Engine/Impl/PythonAnalyzer.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -638,43 +638,50 @@ public AnalysisValue GetAnalysisValueFromObjects(object attr) { } var attrType = attr.GetType(); - if (attr is IPythonType pt) { - return GetBuiltinType(pt); - } else if (attr is IPythonFunction pf) { - return GetCached(attr, () => new BuiltinFunctionInfo(pf, this)) ?? _noneInst; - } else if (attr is IPythonMethodDescriptor md) { - return GetCached(attr, () => { - if (md.IsBound) { - return new BuiltinFunctionInfo(md.Function, this); - } else { - return new BuiltinMethodInfo(md, this); - } - }) ?? _noneInst; - } else if (attr is IPythonBoundFunction pbf) { - return GetCached(attr, () => new BoundBuiltinMethodInfo(pbf, this)) ?? _noneInst; - } else if (attr is IBuiltinProperty bp) { + if (attr is IPythonFunction pf) { + if (pf.MemberType == PythonMemberType.Function) { + return GetCached(attr, () => new BuiltinFunctionInfo(pf, this)) ?? _noneInst; + } + return GetCached(attr, () => new BoundBuiltinMethodInfo(pf, this)) ?? _noneInst; + } + + if (attr is IPythonProperty bp) { return GetCached(attr, () => new BuiltinPropertyInfo(bp, this)) ?? _noneInst; - } else if (attr is IPythonModule pm) { + } + + if (attr is IPythonModule pm) { return Modules.GetBuiltinModule(pm); - } else if (attr is IPythonEvent pe) { + } + + if (attr is IPythonEvent pe) { return GetCached(attr, () => new BuiltinEventInfo(pe, this)) ?? _noneInst; - } else if (attr is IPythonConstant || + } + + if (attr is IPythonConstant || attrType == typeof(bool) || attrType == typeof(int) || attrType == typeof(Complex) || attrType == typeof(string) || attrType == typeof(long) || attrType == typeof(double)) { return GetConstant(attr).First(); - } else if (attr is IMemberContainer mc) { - return GetCached(attr, () => new ReflectedNamespace(mc, this)); - } else if (attr is IPythonMultipleMembers mm) { - var members = mm.Members; + } + + if (attr is IPythonMultipleMembers mm) { + if(attr is IPythonType t && mm.GetMembers().OfType().Any()) { + // Class info will merge multiple into a single unit. + return GetBuiltinType(t); + } + var members = mm.GetMembers(); return GetCached(attr, () => MultipleMemberInfo.Create(members.Select(GetAnalysisValueFromObjects)).FirstOrDefault() ?? ClassInfos[BuiltinTypeId.NoneType].Instance ); - } else { - var pyAttrType = GetTypeFromObject(attr); - Debug.Assert(pyAttrType != null); - return GetBuiltinType(pyAttrType).Instance; } + + if (attr is IPythonType pt) { + return GetBuiltinType(pt); + } + + var pyAttrType = GetTypeFromObject(attr); + Debug.Assert(pyAttrType != null); + return GetBuiltinType(pyAttrType).Instance; } internal IDictionary GetAllMembers(IMemberContainer container, IModuleContext moduleContext) { @@ -876,7 +883,7 @@ internal AggregateProjectEntry GetAggregate(params IProjectEntry[] aggregating) return GetAggregateWorker(aggregating); } - private static void SortAggregates(IProjectEntry[] aggregating) + private static void SortAggregates(IProjectEntry[] aggregating) => Array.Sort(aggregating, (x, y) => x.GetHashCode() - y.GetHashCode()); internal AggregateProjectEntry GetAggregate(HashSet from, IProjectEntry with) { diff --git a/src/Analysis/Engine/Impl/QualifiedFunctionNameWalker.cs b/src/Analysis/Engine/Impl/QualifiedFunctionNameWalker.cs deleted file mode 100644 index a402599b9..000000000 --- a/src/Analysis/Engine/Impl/QualifiedFunctionNameWalker.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Python Tools for Visual Studio -// 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, -// MERCHANTABLITY 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.IO; -using System.Linq; -using Microsoft.PythonTools.Parsing.Ast; - -namespace Microsoft.PythonTools.Analysis { - /// - /// Computes the fully qualified function name, including name of the enclosing class for methods, - /// and, recursively, names of any outer functions. - /// - /// - /// Given this code: - /// - /// class A: - /// def b(self): - /// def c(): - /// class D: - /// def e(self): - /// pass - /// - /// And with the current statement being pass, the qualified name is "D.e in c in A.b". - /// - class QualifiedFunctionNameWalker : PythonWalker { - private readonly PythonAst _ast; - private readonly int _lineNumber; - private readonly List _names = new List(); - private readonly string _expectedFuncName; - - public QualifiedFunctionNameWalker(PythonAst ast, int lineNumber, string expectedFuncName) { - _ast = ast; - _lineNumber = lineNumber; - _expectedFuncName = expectedFuncName; - } - - public IEnumerable Name => _names.AsEnumerable().Reverse(); - - public static string GetDisplayName(int lineNo, string functionName, PythonAst ast, Func nameAggregator) { - var walker = new QualifiedFunctionNameWalker(ast, lineNo, functionName); - try { - ast.Walk(walker); - } catch (InvalidDataException) { - // Walker ran into a mismatch between expected function name and AST, so we cannot - // rely on AST to construct an accurate qualified name. Just return what we have. - return functionName; - } - - var names = walker.Name; - if (names.Any()) { - string qualName = names.Aggregate(nameAggregator); - if (!string.IsNullOrEmpty(qualName)) { - return qualName; - } - } - - return functionName; - } - - public override void PostWalk(FunctionDefinition node) { - int start = node.GetStart(_ast).Line; - int end = node.Body.GetEnd(_ast).Line + 1; - if (_lineNumber < start || _lineNumber >= end) { - return; - } - - string funcName = node.Name; - if (_names.Count == 0 && funcName != _expectedFuncName) { - // The innermost function name must match the one that we've got from the code object. - // If it doesn't, the source code that we're parsing is out of sync with the running program, - // and cannot be used to compute the fully qualified name. - throw new InvalidDataException(); - } - - for (var classDef = node.Parent as ClassDefinition; classDef != null; classDef = classDef.Parent as ClassDefinition) { - funcName = classDef.Name + "." + funcName; - } - - _names.Add(funcName); - } - } -} diff --git a/src/Analysis/Engine/Impl/ReadOnlyWrapper.cs b/src/Analysis/Engine/Impl/ReadOnlyWrapper.cs deleted file mode 100644 index 37018cd33..000000000 --- a/src/Analysis/Engine/Impl/ReadOnlyWrapper.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Python Tools for Visual Studio -// 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. -// -// See the Apache Version 2.0 License for specific language governing -// permissions and limitations under the License. - -using System.Collections.Generic; -using System.Diagnostics; - -namespace Microsoft.PythonTools.Analysis { - // Very light wrappers that are intended to discourage direct modification - // of the wrapped collections. They do not enforce thread-safety or prevent - // the underlying collection from being modified. Hopefully the JIT - // optimizer will learn how to completely bypass the wrappers one day. - - [DebuggerDisplay("Count = {Count}")] - struct ReadOnlyDictionary : IEnumerable> { - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - private readonly IDictionary dictionary; - - public ReadOnlyDictionary(IDictionary obj) { - dictionary = obj; - } - - public TValue this[TKey key] { - get { - return dictionary[key]; - } - } - - public bool TryGetValue(TKey key, out TValue value) { - return dictionary.TryGetValue(key, out value); - } - - public int Count { - get { - return dictionary.Count; - } - } - - public ICollection Keys { - get { - return dictionary.Keys; - } - } - - public ICollection Values { - get { - return dictionary.Values; - } - } - - public IEnumerator> GetEnumerator() { - return dictionary.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return dictionary.GetEnumerator(); - } - - public bool ContainsKey(TKey key) { - return dictionary.ContainsKey(key); - } - } - - [DebuggerDisplay("Count = {Count}")] - struct ReadOnlyList : IEnumerable { - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - private readonly IList list; - - public ReadOnlyList(IList obj) { - list = obj; - } - - public T this[int index] { - get { - return list[index]; - } - } - - public int Count { - get { - return list.Count; - } - } - - public IEnumerator GetEnumerator() { - return list.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return list.GetEnumerator(); - } - } - - [DebuggerDisplay("Count = {Count}")] - struct ReadOnlySet : IEnumerable { - [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] - private readonly ISet set; - - public ReadOnlySet(ISet obj) { - set = obj; - } - - public bool Contains(T item) { - return set.Contains(item); - } - - public int Count { - get { - return set.Count; - } - } - - public IEnumerator GetEnumerator() { - return set.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { - return set.GetEnumerator(); - } - } -} diff --git a/src/Analysis/Engine/Impl/Resources.Designer.cs b/src/Analysis/Engine/Impl/Resources.Designer.cs index 87df9a494..f74238ffc 100644 --- a/src/Analysis/Engine/Impl/Resources.Designer.cs +++ b/src/Analysis/Engine/Impl/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace Microsoft.PythonTools.Analysis { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -159,6 +159,24 @@ internal static string LinesBetweenMethodsInClassShort { } } + /// + /// Looks up a localized string similar to property of type {0}. + /// + internal static string PropertyOfType { + get { + return ResourceManager.GetString("PropertyOfType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to property of unknown type. + /// + internal static string PropertyOfUnknownType { + get { + return ResourceManager.GetString("PropertyOfUnknownType", resourceCulture); + } + } + /// /// Looks up a localized string similar to If checked, removes blank lines between methods and inserts the number specified below. Otherwise, lines between methods are not modified.. /// diff --git a/src/Analysis/Engine/Impl/Resources.resx b/src/Analysis/Engine/Impl/Resources.resx index c67372ff4..da96f9470 100644 --- a/src/Analysis/Engine/Impl/Resources.resx +++ b/src/Analysis/Engine/Impl/Resources.resx @@ -315,4 +315,10 @@ '{0}' used before definition + + property of type {0} + + + property of unknown type + \ No newline at end of file diff --git a/src/Analysis/Engine/Impl/Values/BoundBuiltinMethodInfo.cs b/src/Analysis/Engine/Impl/Values/BoundBuiltinMethodInfo.cs index 7049805a0..97b79969a 100644 --- a/src/Analysis/Engine/Impl/Values/BoundBuiltinMethodInfo.cs +++ b/src/Analysis/Engine/Impl/Values/BoundBuiltinMethodInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -20,32 +20,33 @@ namespace Microsoft.PythonTools.Analysis.Values { class BoundBuiltinMethodInfo : BuiltinNamespace { - private readonly BuiltinMethodInfo _method; private OverloadResult[] _overloads; public BoundBuiltinMethodInfo(BuiltinMethodInfo method) : base(method.PythonType, method.ProjectState) { - _method = method; + Method = method; } - public BoundBuiltinMethodInfo(IPythonBoundFunction function, PythonAnalyzer projectState) - : this(new BuiltinMethodInfo(function.Function, PythonMemberType.Method, projectState)) { + public BoundBuiltinMethodInfo(IPythonFunction function, PythonAnalyzer projectState) + : this(new BuiltinMethodInfo(function, PythonMemberType.Method, projectState)) { } - public override PythonMemberType MemberType => _method.MemberType; + public override PythonMemberType MemberType => Method.MemberType; - public override IPythonType PythonType => base._type; + public override BuiltinTypeId TypeId => Method.TypeId; - public BuiltinMethodInfo Method => _method; + public override IPythonType PythonType => Type; - public override string Documentation => _method.Documentation; + public BuiltinMethodInfo Method { get; } - public override string Description => $"bound method {_method.Name}"; + public override string Documentation => Method.Documentation; + + public override string Description => Method.Description; public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) { // Check if method returns self - var returnType = _method.ReturnTypes.GetInstanceType(); - if (args.Length > 0 && returnType.Split(v => v is BuiltinInstanceInfo biif && biif.PythonType == _method.Function?.DeclaringType, out _, out _)) { + var returnType = Method.ReturnTypes.GetInstanceType(); + if (args.Length > 0 && returnType.Split(v => v is BuiltinInstanceInfo biif && biif.PythonType == Method.Function?.DeclaringType, out _, out _)) { return args[0]; // Return actual self (i.e. derived class) } return returnType; @@ -54,10 +55,10 @@ public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] a public override IEnumerable Overloads { get { if (_overloads == null) { - var overloads = _method.Function.Overloads; + var overloads = Method.Function.Overloads; var result = new OverloadResult[overloads.Count]; - for (int i = 0; i < result.Length; i++) { - result[i] = new BuiltinFunctionOverloadResult(_method.ProjectState, _method.Name, overloads[i], _method._fromFunction ? 1 : 0); + for (var i = 0; i < result.Length; i++) { + result[i] = new BuiltinFunctionOverloadResult(Method.ProjectState, Method.Name, overloads[i], 1); } _overloads = result; } diff --git a/src/Analysis/Engine/Impl/Values/BuiltinClassInfo.cs b/src/Analysis/Engine/Impl/Values/BuiltinClassInfo.cs index c9f837950..43e850013 100644 --- a/src/Analysis/Engine/Impl/Values/BuiltinClassInfo.cs +++ b/src/Analysis/Engine/Impl/Values/BuiltinClassInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -19,7 +19,6 @@ using System.Diagnostics; using System.Linq; using Microsoft.PythonTools.Analysis.Analyzer; -using Microsoft.PythonTools.Analysis.Infrastructure; using Microsoft.PythonTools.Interpreter; using Microsoft.PythonTools.Parsing.Ast; @@ -39,16 +38,15 @@ public BuiltinClassInfo(IPythonType classObj, PythonAnalyzer projectState) _doc = null; } - public override IPythonType PythonType => _type; - public override bool IsOfType(IAnalysisSet klass) { - return klass.Contains(ProjectState.ClassInfos[BuiltinTypeId.Type]); - } + public override IPythonType PythonType => Type; + public override bool IsOfType(IAnalysisSet klass) + => klass.Contains(ProjectState.ClassInfos[BuiltinTypeId.Type]); - public override BuiltinTypeId TypeId => _type.TypeId; + public override BuiltinTypeId TypeId => Type.TypeId; public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) { // TODO: More Type propagation - IAdvancedPythonType advType = _type as IAdvancedPythonType; + IAdvancedPythonType advType = Type as IAdvancedPythonType; if (advType != null) { var types = advType.GetTypesPropagatedOnCall(); if (types != null) { @@ -65,14 +63,14 @@ public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] a return Instance.SelfSet; } - public override string Name => _type.Name; + public override string Name => Type?.Name; public string InstanceDescription { get { switch (TypeId) { case BuiltinTypeId.NoneType: return "None"; } - return _type?.Name ?? ""; + return Type?.Name ?? ""; } } @@ -80,11 +78,11 @@ public string InstanceDescription { public string FullyQualifiedName { get { - if (_type != null) { - if (_type.IsBuiltin) { - return _type.Name; + if (Type != null) { + if (Type.IsBuiltin) { + return Type.Name; } - return _type.DeclaringModule.Name + "." + _type.Name; + return Type.DeclaringModule.Name + "." + Type.Name; } return null; } @@ -92,8 +90,8 @@ public string FullyQualifiedName { public KeyValuePair FullyQualifiedNamePair { get { - if (_type != null) { - return new KeyValuePair(_type.DeclaringModule.Name, _type.Name); + if (Type != null) { + return new KeyValuePair(Type.DeclaringModule.Name, Type.Name); } throw new NotSupportedException(); } @@ -101,7 +99,7 @@ public KeyValuePair FullyQualifiedNamePair { public override IMro Mro { get { - var mro = _type.Mro; + var mro = (Type as IPythonClass)?.Mro; if (mro != null) { return new Mro(mro.Where(t => t != null).Select(t => ProjectState.GetBuiltinType(t))); } @@ -114,11 +112,11 @@ public override IMro Mro { public override IAnalysisSet GetInstanceType() => Instance; protected virtual BuiltinInstanceInfo MakeInstance() { - if (_type.TypeId == BuiltinTypeId.Int || _type.TypeId == BuiltinTypeId.Long || _type.TypeId == BuiltinTypeId.Float || _type.TypeId == BuiltinTypeId.Complex) { + if (Type.TypeId == BuiltinTypeId.Int || Type.TypeId == BuiltinTypeId.Long || Type.TypeId == BuiltinTypeId.Float || Type.TypeId == BuiltinTypeId.Complex) { return new NumericInstanceInfo(this); - } else if (_type.TypeId == BuiltinTypeId.Str || _type.TypeId == BuiltinTypeId.Unicode || _type.TypeId == BuiltinTypeId.Bytes) { + } else if (Type.TypeId == BuiltinTypeId.Str || Type.TypeId == BuiltinTypeId.Unicode || Type.TypeId == BuiltinTypeId.Bytes) { return new SequenceBuiltinInstanceInfo(this, true, true); - } else if (_type.TypeId == BuiltinTypeId.Tuple || _type.TypeId == BuiltinTypeId.List) { + } else if (Type.TypeId == BuiltinTypeId.Tuple || Type.TypeId == BuiltinTypeId.List) { Debug.Fail("Overloads should have been called here"); // But we fall back to the old type anyway return new SequenceBuiltinInstanceInfo(this, false, false); @@ -127,19 +125,14 @@ protected virtual BuiltinInstanceInfo MakeInstance() { return new BuiltinInstanceInfo(this); } - /// - /// Returns the overloads available for calling the constructor of the type. - /// public override IEnumerable Overloads { get { // TODO: sometimes might have a specialized __init__. // This just covers typical .NET types - var ctors = _type.GetConstructors(); - - if (ctors != null) { - return ctors.Overloads.Select(ctor => new BuiltinFunctionOverloadResult(ProjectState, _type.Name, ctor, 1, () => Documentation)); - } - return new OverloadResult[0]; + var ctors = Type.GetConstructor(); + return ctors != null + ? ctors.Overloads.Select(ctor => new BuiltinFunctionOverloadResult(ProjectState, Type.Name, ctor, 1, () => Documentation)) + : Enumerable.Empty(); } } @@ -159,7 +152,7 @@ public override void SetMember(Node node, AnalysisUnit unit, string name, IAnaly } public override IAnalysisSet GetIndex(Node node, AnalysisUnit unit, IAnalysisSet index) { - var clrType = _type as IAdvancedPythonType; + var clrType = Type as IAdvancedPythonType; if (clrType == null || !clrType.IsGenericTypeDefinition) { return AnalysisSet.Empty; } @@ -241,16 +234,16 @@ private static bool MissingType(List[] types) { } public virtual IEnumerable> GetRichDescription() { - yield return new KeyValuePair(WellKnownRichDescriptionKinds.Misc, _type.IsBuiltin ? "type " : "class "); + yield return new KeyValuePair(WellKnownRichDescriptionKinds.Misc, Type.IsBuiltin ? "type " : "class "); yield return new KeyValuePair(WellKnownRichDescriptionKinds.Name, FullName); yield return new KeyValuePair(WellKnownRichDescriptionKinds.EndOfDeclaration, string.Empty); } private string FullName { get { - var name = _type.Name; - if (!_type.IsBuiltin && !string.IsNullOrEmpty(_type.DeclaringModule?.Name)) { - name = _type.DeclaringModule.Name + "." + name; + var name = Type.Name; + if (!Type.IsBuiltin && !string.IsNullOrEmpty(Type.DeclaringModule?.Name)) { + name = Type.DeclaringModule.Name + "." + name; } return name; } @@ -260,7 +253,7 @@ public override string Documentation { get { if (_doc == null) { try { - var doc = _type.Documentation ?? string.Empty; + var doc = Type.Documentation ?? string.Empty; _doc = Utils.StripDocumentation(doc.ToString()); } catch { _doc = String.Empty; @@ -270,8 +263,8 @@ public override string Documentation { } } - public override PythonMemberType MemberType => _type.MemberType; - public override string ToString() => "Class " + _type.Name; + public override PythonMemberType MemberType => Type.MemberType; + public override string ToString() => "Class " + Type.Name; internal override AnalysisValue UnionMergeTypes(AnalysisValue ns, int strength) { if (strength >= MergeStrength.ToObject) { @@ -335,6 +328,6 @@ internal override void AddReference(Node node, AnalysisUnit unit) { } internal override IEnumerable References => _references?.AllReferences ?? new LocationInfo[0]; - public override ILocatedMember GetLocatedMember() => _type as ILocatedMember; + public override ILocatedMember GetLocatedMember() => Type as ILocatedMember; } } diff --git a/src/Analysis/Engine/Impl/Values/BuiltinFunctionInfo.cs b/src/Analysis/Engine/Impl/Values/BuiltinFunctionInfo.cs index b29f3c3cd..cf9c1743f 100644 --- a/src/Analysis/Engine/Impl/Values/BuiltinFunctionInfo.cs +++ b/src/Analysis/Engine/Impl/Values/BuiltinFunctionInfo.cs @@ -28,20 +28,20 @@ internal class BuiltinFunctionInfo : BuiltinNamespace, IHasRichDesc private BuiltinMethodInfo _method; public BuiltinFunctionInfo(IPythonFunction function, PythonAnalyzer projectState) - : base(projectState.Types[BuiltinTypeId.BuiltinFunction], projectState) { + : base(projectState.Types[BuiltinTypeId.Function], projectState) { Function = function; } - public override IPythonType PythonType => _type; + public override IPythonType PythonType => Type; public override bool IsOfType(IAnalysisSet klass) - => klass.Contains(ProjectState.ClassInfos[BuiltinTypeId.Function]) || klass.Contains(ProjectState.ClassInfos[BuiltinTypeId.BuiltinFunction]); + => klass.Contains(ProjectState.ClassInfos[BuiltinTypeId.Function]); public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) { var returnTypes = GetFunctionOverloads().Where(o => o.ReturnType != null).SelectMany(o => o.ReturnType); var types = returnTypes.Select(t => { var av = ProjectState.GetAnalysisValueFromObjects(t); - return t is IPythonType2 pt2 && pt2.IsClass + return t.IsTypeFactory ? AnalysisSet.Create(av) : ProjectState.GetAnalysisValueFromObjects(t).GetInstanceType(); }); diff --git a/src/Analysis/Engine/Impl/Values/BuiltinInstanceInfo.cs b/src/Analysis/Engine/Impl/Values/BuiltinInstanceInfo.cs index 4f2474514..d9c1b8df2 100644 --- a/src/Analysis/Engine/Impl/Values/BuiltinInstanceInfo.cs +++ b/src/Analysis/Engine/Impl/Values/BuiltinInstanceInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -23,35 +23,32 @@ namespace Microsoft.PythonTools.Analysis.Values { internal class BuiltinInstanceInfo : BuiltinNamespace, IBuiltinInstanceInfo { - private readonly BuiltinClassInfo _klass; - - public BuiltinInstanceInfo(BuiltinClassInfo klass) - : base(klass?._type, klass?.ProjectState) { - _klass = klass; + public BuiltinInstanceInfo(BuiltinClassInfo classInfo) + : base(classInfo.Type, classInfo.ProjectState) { + ClassInfo = classInfo; } IBuiltinClassInfo IBuiltinInstanceInfo.ClassInfo => ClassInfo; - public BuiltinClassInfo ClassInfo => _klass; + public BuiltinClassInfo ClassInfo { get; } - public override string Name => _klass.Name; - public override IPythonType PythonType => _type; + public override string Name => ClassInfo.Name; + public override IPythonType PythonType => Type; public override IAnalysisSet GetInstanceType() { - if (_klass.TypeId == BuiltinTypeId.Type) { + if (ClassInfo.TypeId == BuiltinTypeId.Type) { return ProjectState.ClassInfos[BuiltinTypeId.Object].Instance; } return base.GetInstanceType(); } - public override string Description => _klass.InstanceDescription; - public override string ShortDescription => _klass.ShortInstanceDescription; - public override string Documentation => _klass.Documentation; + public override string Description => ClassInfo.InstanceDescription; + public override string ShortDescription => ClassInfo.ShortInstanceDescription; + public override string Documentation => ClassInfo.Documentation; public override PythonMemberType MemberType { get { - switch (_klass.MemberType) { + switch (ClassInfo.MemberType) { case PythonMemberType.Enum: return PythonMemberType.EnumInstance; - case PythonMemberType.Delegate: return PythonMemberType.DelegateInstance; default: return PythonMemberType.Instance; } @@ -61,8 +58,8 @@ public override PythonMemberType MemberType { public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) { var res = base.GetTypeMember(node, unit, name); if (res.Count > 0) { - _klass.AddMemberReference(node, unit, name); - return res.GetDescriptor(node, this, _klass, unit); + ClassInfo.AddMemberReference(node, unit, name); + return res.GetDescriptor(node, this, ClassInfo, unit); } return res; } @@ -70,7 +67,7 @@ public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string public override void SetMember(Node node, AnalysisUnit unit, string name, IAnalysisSet value) { var res = base.GetMember(node, unit, name); if (res.Count > 0) { - _klass.AddMemberReference(node, unit, name); + ClassInfo.AddMemberReference(node, unit, name); } } @@ -100,7 +97,7 @@ public override IAnalysisSet BinaryOperation(Node node, AnalysisUnit unit, Pytho return ConstantInfo.NumericOp(node, this, unit, operation, rhs) ?? NumericOp(node, unit, operation, rhs) ?? AnalysisSet.Empty; } - private IAnalysisSet NumericOp(Node node, AnalysisUnit unit, Parsing.PythonOperator operation, IAnalysisSet rhs) { + private IAnalysisSet NumericOp(Node node, AnalysisUnit unit, PythonOperator operation, IAnalysisSet rhs) { string methodName = InstanceInfo.BinaryOpToString(operation); if (methodName != null) { var method = GetMember(node, unit, methodName); @@ -140,8 +137,7 @@ public override IAnalysisSet GetIndex(Node node, AnalysisUnit unit, IAnalysisSet public override IEnumerable Overloads { get { - IAnalysisSet callRes; - if (_klass.GetAllMembers(ProjectState._defaultContext).TryGetValue("__call__", out callRes)) { + if (ClassInfo.GetAllMembers(ProjectState._defaultContext).TryGetValue("__call__", out var callRes)) { foreach (var overload in callRes.SelectMany(av => av.Overloads)) { yield return overload.WithoutLeadingParameters(1); } @@ -205,26 +201,21 @@ public override IAnalysisSet GetAsyncEnumeratorTypes(Node node, AnalysisUnit uni return base.GetAsyncEnumeratorTypes(node, unit); } - public override bool IsOfType(IAnalysisSet klass) { - if (klass.Contains(this.ClassInfo)) { + public override bool IsOfType(IAnalysisSet classes) { + if (classes.Contains(ClassInfo)) { return true; } if (TypeId != BuiltinTypeId.NoneType && TypeId != BuiltinTypeId.Type && - TypeId != BuiltinTypeId.Function && - TypeId != BuiltinTypeId.BuiltinFunction) { - return klass.Contains(ProjectState.ClassInfos[BuiltinTypeId.Object]); + TypeId != BuiltinTypeId.Function) { + return classes.Contains(ProjectState.ClassInfos[BuiltinTypeId.Object]); } return false; } - public override BuiltinTypeId TypeId { - get { - return _klass?.PythonType.TypeId ?? BuiltinTypeId.Unknown; - } - } + public override BuiltinTypeId TypeId => ClassInfo?.PythonType.TypeId ?? BuiltinTypeId.Unknown; internal override bool UnionEquals(AnalysisValue ns, int strength) { var dict = ProjectState.ClassInfos[BuiltinTypeId.Dict]; @@ -232,8 +223,8 @@ internal override bool UnionEquals(AnalysisValue ns, int strength) { if (ns is DictionaryInfo || ns == dict.Instance) { return true; } - var ci = ns as ConstantInfo; - if (ci != null && ci.ClassInfo == dict) { + + if (ns is ConstantInfo ci && ci.ClassInfo == dict) { return true; } return false; @@ -261,7 +252,8 @@ internal override bool UnionEquals(AnalysisValue ns, int strength) { // FI + BII(function) => BII(function) return ns is FunctionInfo || ns is BuiltinFunctionInfo || (ns is BuiltinInstanceInfo && ns.TypeId == BuiltinTypeId.Function); - } else if (ns.TypeId == BuiltinTypeId.Function) { + } + if (ns.TypeId == BuiltinTypeId.Function) { return false; } @@ -270,19 +262,19 @@ internal override bool UnionEquals(AnalysisValue ns, int strength) { return ns is InstanceInfo || (ns is BuiltinInstanceInfo && ns.TypeId != BuiltinTypeId.Function); - } else if (strength >= MergeStrength.ToBaseClass) { - var bii = ns as BuiltinInstanceInfo; - if (bii != null) { - return _klass != null && _klass.UnionEquals(bii.ClassInfo, strength); + } + + if (strength >= MergeStrength.ToBaseClass) { + if (ns is BuiltinInstanceInfo bii) { + return ClassInfo.UnionEquals(bii.ClassInfo, strength); } - var ii = ns as InstanceInfo; - if (ii != null) { - return _klass != null && _klass.UnionEquals(ii.ClassInfo, strength); + + if (ns is InstanceInfo ii) { + return ClassInfo.UnionEquals(ii.ClassInfo, strength); } - } else if (ns is BuiltinInstanceInfo) { + } else if (ns is BuiltinInstanceInfo bii) { // ConI + BII => BII if CIs match - var bii = ns as BuiltinInstanceInfo; - return bii != null && _klass != null && _klass.Equals(bii.ClassInfo); + return ClassInfo.Equals(bii.ClassInfo); } return base.UnionEquals(ns, strength); @@ -330,7 +322,9 @@ internal override AnalysisValue UnionMergeTypes(AnalysisValue ns, int strength) /// BII + BII => BII(object) return ProjectState.ClassInfos[BuiltinTypeId.Object].Instance; - } else if (strength >= MergeStrength.ToBaseClass) { + } + + if (strength >= MergeStrength.ToBaseClass) { if (ns is BuiltinInstanceInfo bii) { return ClassInfo.UnionMergeTypes(bii.ClassInfo, strength).GetInstanceType().Single(); } @@ -346,7 +340,7 @@ internal override AnalysisValue UnionMergeTypes(AnalysisValue ns, int strength) #region IReferenceableContainer Members public IEnumerable GetDefinitions(string name) { - return _klass.GetDefinitions(name); + return ClassInfo.GetDefinitions(name); } #endregion diff --git a/src/Analysis/Engine/Impl/Values/BuiltinMethodInfo.cs b/src/Analysis/Engine/Impl/Values/BuiltinMethodInfo.cs index f8978533e..835c7bebf 100644 --- a/src/Analysis/Engine/Impl/Values/BuiltinMethodInfo.cs +++ b/src/Analysis/Engine/Impl/Values/BuiltinMethodInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -22,66 +22,48 @@ namespace Microsoft.PythonTools.Analysis.Values { internal class BuiltinMethodInfo : BuiltinNamespace, IHasRichDescription { - private readonly IPythonFunction _function; - private readonly PythonMemberType _memberType; - internal readonly bool _fromFunction; private string _doc; - private readonly IAnalysisSet _returnTypes; private BoundBuiltinMethodInfo _boundMethod; - public BuiltinMethodInfo(IPythonMethodDescriptor method, PythonAnalyzer projectState) - : base(projectState.Types[BuiltinTypeId.BuiltinMethodDescriptor], projectState) { - var function = method.Function; - _memberType = method.MemberType; - _function = function; - _returnTypes = GetReturnTypes(function, projectState); - } - public BuiltinMethodInfo(IPythonFunction function, PythonMemberType memType, PythonAnalyzer projectState) - : base(projectState.Types[BuiltinTypeId.BuiltinMethodDescriptor], projectState) { - _memberType = memType; - _function = function; - _returnTypes = GetReturnTypes(function, projectState); - _fromFunction = true; + : base(projectState.Types[ + memType == PythonMemberType.Function ? BuiltinTypeId.Function : BuiltinTypeId.Method + ], projectState) { + MemberType = memType; + Function = function; + ReturnTypes = GetReturnTypes(function, projectState); } - public override IPythonType PythonType => _type; + public override IPythonType PythonType => Type; - public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) { - return _returnTypes.GetInstanceType(); - } + public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) + => ReturnTypes.GetInstanceType(); public override IAnalysisSet GetDescriptor(Node node, AnalysisValue instance, AnalysisValue context, AnalysisUnit unit) { if (instance == ProjectState._noneInst) { return base.GetDescriptor(node, instance, context, unit); } - if (_boundMethod == null) { - _boundMethod = new BoundBuiltinMethodInfo(this); - } - + _boundMethod = _boundMethod ?? new BoundBuiltinMethodInfo(this); return _boundMethod.SelfSet; } public IEnumerable> GetRichDescription() - => BuiltinFunctionInfo.GetRichDescription(string.Empty, _function); + => BuiltinFunctionInfo.GetRichDescription(string.Empty, Function); - public IAnalysisSet ReturnTypes => _returnTypes; - public IPythonFunction Function => _function; + public IAnalysisSet ReturnTypes { get; } + public IPythonFunction Function { get; } - public override IEnumerable Overloads { - get { - return Function.Overloads.Select(overload => + public override IEnumerable Overloads + => Function.Overloads.Select(overload => new BuiltinFunctionOverloadResult( ProjectState, - _function.Name, + Function.Name, overload, 0, new ParameterResult("self") ) ); - } - } public override string Documentation { get { @@ -98,18 +80,17 @@ public override string Documentation { return _doc; } } - public override BuiltinTypeId TypeId => BuiltinTypeId.BuiltinFunction; - public override PythonMemberType MemberType => _memberType; - public override string Name => _function.Name; - public override ILocatedMember GetLocatedMember() => _function as ILocatedMember; + public override BuiltinTypeId TypeId => BuiltinTypeId.Function; + public override PythonMemberType MemberType { get; } + public override string Name => Function.Name; + public override ILocatedMember GetLocatedMember() => Function as ILocatedMember; - public override int GetHashCode() => new { hc1 = base.GetHashCode(), hc2 = _function.GetHashCode() }.GetHashCode(); - public override bool Equals(object obj) => base.Equals(obj) && obj is BuiltinMethodInfo bmi && _function.Equals(bmi._function); + public override int GetHashCode() => new { hc1 = base.GetHashCode(), hc2 = Function.GetHashCode() }.GetHashCode(); + public override bool Equals(object obj) => base.Equals(obj) && obj is BuiltinMethodInfo bmi && Function.Equals(bmi.Function); - private IAnalysisSet GetReturnTypes(IPythonFunction func, PythonAnalyzer projectState) { - return AnalysisSet.UnionAll(func.Overloads + private IAnalysisSet GetReturnTypes(IPythonFunction func, PythonAnalyzer projectState) + => AnalysisSet.UnionAll(func.Overloads .Where(fn => fn.ReturnType != null) .Select(fn => projectState.GetAnalysisSetFromObjects(fn.ReturnType))); - } } } diff --git a/src/Analysis/Engine/Impl/Values/BuiltinModule.cs b/src/Analysis/Engine/Impl/Values/BuiltinModule.cs index 7a92e5b35..6560ffff6 100644 --- a/src/Analysis/Engine/Impl/Values/BuiltinModule.cs +++ b/src/Analysis/Engine/Impl/Values/BuiltinModule.cs @@ -55,7 +55,7 @@ public override IDictionary GetAllMembers(IModuleContext m return res; } - public override string Documentation => _type.Documentation; + public override string Documentation => Type.Documentation; public override string Description => InterpreterModule.Name; public override string Name => InterpreterModule.Name; public override IPythonType PythonType => ProjectState.Types[BuiltinTypeId.Module]; @@ -74,12 +74,12 @@ public IEnumerable GetDefinitions(string name) { #endregion internal IEnumerable GetMemberNames(IModuleContext moduleContext) { - return _type.GetMemberNames(moduleContext) + return Type.GetMemberNames(moduleContext) .Union(_specializedValues.MaybeEnumerate().Keys()); } public IModule GetChildPackage(IModuleContext context, string name) { - var mem = _type.GetMember(context, name); + var mem = Type.GetMember(context, name); if (mem != null) { return ProjectState.GetAnalysisValueFromObjects(mem) as IModule; } @@ -87,8 +87,8 @@ public IModule GetChildPackage(IModuleContext context, string name) { } public IEnumerable> GetChildrenPackages(IModuleContext context) { - return _type.GetChildrenModules() - .Select(name => new KeyValuePair(name, ProjectState.GetAnalysisValueFromObjects(_type.GetMember(context, name)))); + return Type.GetChildrenModules() + .Select(name => new KeyValuePair(name, ProjectState.GetAnalysisValueFromObjects(Type.GetMember(context, name)))); } public void SpecializeFunction(string name, CallDelegate callable, bool mergeOriginalAnalysis) { diff --git a/src/Analysis/Engine/Impl/Values/BuiltinNamespace.cs b/src/Analysis/Engine/Impl/Values/BuiltinNamespace.cs index 8c5bb60fb..6d3101ca9 100644 --- a/src/Analysis/Engine/Impl/Values/BuiltinNamespace.cs +++ b/src/Analysis/Engine/Impl/Values/BuiltinNamespace.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -24,17 +24,19 @@ namespace Microsoft.PythonTools.Analysis.Values { /// /// Base class for things which get their members primarily via a built-in .NET type. /// - class BuiltinNamespace : AnalysisValue where TMemberContainer : IMemberContainer { - internal readonly TMemberContainer _type; + class BuiltinNamespace : AnalysisValue where TMemberContainer : IPythonType { internal Dictionary _specializedValues; public BuiltinNamespace(TMemberContainer pythonType, PythonAnalyzer projectState) { - ProjectState = projectState ?? throw new ArgumentNullException(nameof(projectState)); ; - _type = pythonType; + ProjectState = projectState ?? throw new ArgumentNullException(nameof(projectState)); + Type = pythonType; // Ideally we'd assert here whenever pythonType is null, but that // makes debug builds unusable because it happens so often. } + public override BuiltinTypeId TypeId => Type?.TypeId ?? BuiltinTypeId.Unknown; + public override PythonMemberType MemberType => Type?.MemberType ?? PythonMemberType.Unknown; + public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string name) { var res = AnalysisSet.Empty; @@ -42,11 +44,11 @@ public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string return specializedRes; } - if (_type == null) { + if (Type == null) { return unit.State.ClassInfos[BuiltinTypeId.NoneType].Instance; } - var member = _type.GetMember(unit.DeclaringModule.InterpreterContext, name); + var member = Type.GetMember(unit.DeclaringModule.InterpreterContext, name); if (member != null) { res = ProjectState.GetAnalysisValueFromObjects(member); } @@ -54,16 +56,15 @@ public override IAnalysisSet GetTypeMember(Node node, AnalysisUnit unit, string } public override IDictionary GetAllMembers(IModuleContext moduleContext, GetMemberOptions options = GetMemberOptions.None) { - if (_type == null) { + if (Type == null) { return new Dictionary(); } - return ProjectState.GetAllMembers(_type, moduleContext); + return ProjectState.GetAllMembers(Type, moduleContext); } public IAnalysisSet this[string name] { get { - IAnalysisSet value; - if (TryGetMember(name, out value)) { + if (TryGetMember(name, out var value)) { return value; } throw new KeyNotFoundException("Key {0} not found".FormatInvariant(name)); @@ -77,16 +78,15 @@ public IAnalysisSet this[string name] { } public bool TryGetMember(string name, out IAnalysisSet value) { - IAnalysisSet res; - if (_specializedValues != null && _specializedValues.TryGetValue(name, out res)) { + if (_specializedValues != null && _specializedValues.TryGetValue(name, out var res)) { value = res; return true; } - if (_type == null) { + if (Type == null) { value = null; return false; } - var member = _type.GetMember(ProjectState._defaultContext, name); + var member = Type.GetMember(ProjectState._defaultContext, name); if (member != null) { value = ProjectState.GetAnalysisValueFromObjects(member); return true; @@ -97,11 +97,7 @@ public bool TryGetMember(string name, out IAnalysisSet value) { public PythonAnalyzer ProjectState { get; } - public TMemberContainer ContainedValue { - get { - return _type; - } - } + public TMemberContainer Type { get; } public virtual ILocatedMember GetLocatedMember() => null; @@ -109,14 +105,11 @@ public TMemberContainer ContainedValue { public override bool Equals(object obj) { if (obj is BuiltinNamespace bn && GetType() == bn.GetType()) { - if (_type != null) { - return _type.Equals(bn._type); - } - return bn._type == null; + return Type != null ? Type.Equals(bn.Type) : bn.Type == null; } return false; } - public override int GetHashCode() => new { hc1 = GetType().GetHashCode(), hc2 = _type?.GetHashCode() }.GetHashCode(); + public override int GetHashCode() => new { hc1 = GetType().GetHashCode(), hc2 = Type?.GetHashCode() }.GetHashCode(); } } diff --git a/src/Analysis/Engine/Impl/Values/BuiltinPropertyInfo.cs b/src/Analysis/Engine/Impl/Values/BuiltinPropertyInfo.cs index f00872503..fcfea0d8e 100644 --- a/src/Analysis/Engine/Impl/Values/BuiltinPropertyInfo.cs +++ b/src/Analysis/Engine/Impl/Values/BuiltinPropertyInfo.cs @@ -19,18 +19,16 @@ namespace Microsoft.PythonTools.Analysis.Values { internal class BuiltinPropertyInfo : BuiltinNamespace { - private readonly IBuiltinProperty _value; + private readonly IPythonProperty _value; private string _doc; - public BuiltinPropertyInfo(IBuiltinProperty value, PythonAnalyzer projectState) + public BuiltinPropertyInfo(IPythonProperty value, PythonAnalyzer projectState) : base(value.Type, projectState) { _value = value; _doc = null; } - public override IPythonType PythonType { - get { return _type; } - } + public override IPythonType PythonType => Type; public override IAnalysisSet GetDescriptor(Node node, AnalysisValue instance, AnalysisValue context, AnalysisUnit unit) { if (instance == ProjectState._noneInst) { diff --git a/src/Analysis/Engine/Impl/Values/ConstantInfo.cs b/src/Analysis/Engine/Impl/Values/ConstantInfo.cs index 52a7b9f4d..73afb3214 100644 --- a/src/Analysis/Engine/Impl/Values/ConstantInfo.cs +++ b/src/Analysis/Engine/Impl/Values/ConstantInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -27,11 +27,11 @@ internal class ConstantInfo : BuiltinInstanceInfo { private readonly PythonMemberType _memberType; private string _doc; - internal ConstantInfo(BuiltinClassInfo klass, object value, PythonMemberType memberType) - : base(klass) { + internal ConstantInfo(BuiltinClassInfo classInfo, object value, PythonMemberType memberType) + : base(classInfo) { _value = value; _memberType = memberType; - _builtinInfo = klass.Instance; + _builtinInfo = classInfo.Instance; } public override IAnalysisSet BinaryOperation(Node node, AnalysisUnit unit, PythonOperator operation, IAnalysisSet rhs) { @@ -163,7 +163,7 @@ public override string Description { return "None"; } - return _type.Name; + return Type.Name; //return PythonOps.Repr(ProjectState.CodeContext, _value); } } @@ -171,7 +171,7 @@ public override string Description { public override string Documentation { get { if (_doc == null) { - object docObj = _type.Documentation; + object docObj = Type.Documentation; _doc = docObj == null ? "" : Utils.StripDocumentation(docObj.ToString()); } return _doc; diff --git a/src/Analysis/Engine/Impl/Values/DictBuiltinClassInfo.cs b/src/Analysis/Engine/Impl/Values/DictBuiltinClassInfo.cs index e6ca59ac0..663f74317 100644 --- a/src/Analysis/Engine/Impl/Values/DictBuiltinClassInfo.cs +++ b/src/Analysis/Engine/Impl/Values/DictBuiltinClassInfo.cs @@ -24,7 +24,10 @@ public DictBuiltinClassInfo(IPythonType classObj, PythonAnalyzer projectState) : base(classObj, projectState) { } - protected override BuiltinInstanceInfo MakeInstance() => PythonType is IPythonLookupType lt ? new DictBuiltinInstanceInfo(this, lt) : new BuiltinInstanceInfo(this); + protected override BuiltinInstanceInfo MakeInstance() + => PythonType is IPythonLookupType lt + ? new DictBuiltinInstanceInfo(this, lt) + : new BuiltinInstanceInfo(this); public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] args, NameExpression[] keywordArgNames) { var res = (DictionaryInfo)unit.InterpreterScope.GetOrMakeNodeValue( diff --git a/src/Analysis/Engine/Impl/Values/DictBuiltinInstanceInfo.cs b/src/Analysis/Engine/Impl/Values/DictBuiltinInstanceInfo.cs index 139515424..03be82bd9 100644 --- a/src/Analysis/Engine/Impl/Values/DictBuiltinInstanceInfo.cs +++ b/src/Analysis/Engine/Impl/Values/DictBuiltinInstanceInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -24,11 +24,11 @@ namespace Microsoft.PythonTools.Analysis.Values { class DictBuiltinInstanceInfo : BuiltinInstanceInfo, IHasRichDescription { private readonly IPythonLookupType _dict; - public DictBuiltinInstanceInfo(DictBuiltinClassInfo klass, IPythonLookupType dict) - : base(klass) { + public DictBuiltinInstanceInfo(DictBuiltinClassInfo classInfo, IPythonLookupType dict) + : base(classInfo) { _dict = dict; - KeyType = klass.ProjectState.GetAnalysisSetFromObjects(dict.KeyTypes); - ValueType = klass.ProjectState.GetAnalysisSetFromObjects(dict.ValueTypes); + KeyType = classInfo.ProjectState.GetAnalysisSetFromObjects(dict.KeyTypes); + ValueType = classInfo.ProjectState.GetAnalysisSetFromObjects(dict.ValueTypes); } protected IAnalysisSet KeyType { get; } diff --git a/src/Analysis/Engine/Impl/Values/DictionaryInfo.cs b/src/Analysis/Engine/Impl/Values/DictionaryInfo.cs index f572a35a8..037d98dee 100644 --- a/src/Analysis/Engine/Impl/Values/DictionaryInfo.cs +++ b/src/Analysis/Engine/Impl/Values/DictionaryInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. diff --git a/src/Analysis/Engine/Impl/Values/GeneratorInfo.cs b/src/Analysis/Engine/Impl/Values/GeneratorInfo.cs index 4d2192323..56fe48a84 100644 --- a/src/Analysis/Engine/Impl/Values/GeneratorInfo.cs +++ b/src/Analysis/Engine/Impl/Values/GeneratorInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. diff --git a/src/Analysis/Engine/Impl/Values/IterableInfo.cs b/src/Analysis/Engine/Impl/Values/IterableInfo.cs index 31d2c1f8a..ac8465d32 100644 --- a/src/Analysis/Engine/Impl/Values/IterableInfo.cs +++ b/src/Analysis/Engine/Impl/Values/IterableInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -34,8 +34,8 @@ internal abstract class BaseIterableValue : BuiltinInstanceInfo, IHasRichDescrip protected IAnalysisSet _unionType; // all types that have been seen private AnalysisValue _iterMethod; - public BaseIterableValue(BuiltinClassInfo seqType) - : base(seqType) { + public BaseIterableValue(BuiltinClassInfo classInfo) + : base(classInfo) { } public IAnalysisSet UnionType { @@ -43,11 +43,11 @@ public IAnalysisSet UnionType { EnsureUnionType(); return _unionType; } - set { _unionType = value; } + set => _unionType = value; } protected abstract void EnsureUnionType(); - protected virtual string TypeName => _type?.Name ?? "iterable"; + protected virtual string TypeName => Type?.Name ?? "iterable"; protected abstract IAnalysisSet MakeIteratorInfo(Node n, AnalysisUnit unit); public override IAnalysisSet GetEnumeratorTypes(Node node, AnalysisUnit unit) { diff --git a/src/Analysis/Engine/Impl/Values/ListBuiltinClassInfo.cs b/src/Analysis/Engine/Impl/Values/ListBuiltinClassInfo.cs index b9daa170e..1d427ac89 100644 --- a/src/Analysis/Engine/Impl/Values/ListBuiltinClassInfo.cs +++ b/src/Analysis/Engine/Impl/Values/ListBuiltinClassInfo.cs @@ -39,7 +39,7 @@ internal override SequenceInfo MakeFromIndexes(Node node, IPythonProjectEntry en } public override IEnumerable> GetRichDescription() { - yield return new KeyValuePair(WellKnownRichDescriptionKinds.Type, _type.Name); + yield return new KeyValuePair(WellKnownRichDescriptionKinds.Type, Type.Name); if (_indexTypes == null || _indexTypes.Length == 0) { yield break; } diff --git a/src/Analysis/Engine/Impl/Values/NumericInstanceInfo.cs b/src/Analysis/Engine/Impl/Values/NumericInstanceInfo.cs index 118426ef9..7aae7707c 100644 --- a/src/Analysis/Engine/Impl/Values/NumericInstanceInfo.cs +++ b/src/Analysis/Engine/Impl/Values/NumericInstanceInfo.cs @@ -9,7 +9,7 @@ // 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. +// MERCHANTABILITY OR NON-INFRINGEMENT. // // See the Apache Version 2.0 License for specific language governing // permissions and limitations under the License. @@ -20,8 +20,8 @@ namespace Microsoft.PythonTools.Analysis.Values { class NumericInstanceInfo : BuiltinInstanceInfo { - public NumericInstanceInfo(BuiltinClassInfo klass) - : base(klass) { + public NumericInstanceInfo(BuiltinClassInfo classInfo) + : base(classInfo) { } public override IAnalysisSet BinaryOperation(Node node, AnalysisUnit unit, PythonOperator operation, IAnalysisSet rhs) { diff --git a/src/Analysis/Engine/Impl/Values/Protocols.cs b/src/Analysis/Engine/Impl/Values/Protocols.cs index 5bbdf69e0..b1406765a 100644 --- a/src/Analysis/Engine/Impl/Values/Protocols.cs +++ b/src/Analysis/Engine/Impl/Values/Protocols.cs @@ -71,7 +71,7 @@ protected IAnalysisSet MakeMethod(string qualname, IReadOnlyList a public override IAnalysisSet GetDescriptor(PythonAnalyzer projectState, AnalysisValue instance, AnalysisValue context) => AnalysisSet.Empty; public override IAnalysisSet GetEnumeratorTypes(Node node, AnalysisUnit unit) => AnalysisSet.Empty; public override IAnalysisSet GetIndex(Node node, AnalysisUnit unit, IAnalysisSet index) => AnalysisSet.Empty; - public override IAnalysisSet GetInstanceType() => AnalysisSet.Empty; + public override IAnalysisSet GetInstanceType() => null; public override IEnumerable> GetItems() => Enumerable.Empty< KeyValuePair>(); public override IAnalysisSet GetIterator(Node node, AnalysisUnit unit) => AnalysisSet.Empty; public override IAnalysisSet GetReturnForYieldFrom(Node node, AnalysisUnit unit) => AnalysisSet.Empty; diff --git a/src/Analysis/Engine/Impl/Values/ReflectedNamespace.cs b/src/Analysis/Engine/Impl/Values/ReflectedNamespace.cs deleted file mode 100644 index e3f740877..000000000 --- a/src/Analysis/Engine/Impl/Values/ReflectedNamespace.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Python Tools for Visual Studio -// 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, -// MERCHANTABLITY OR NON-INFRINGEMENT. -// -// See the Apache Version 2.0 License for specific language governing -// permissions and limitations under the License. - -using System.Collections.Generic; -using Microsoft.PythonTools.Analysis.Analyzer; -using Microsoft.PythonTools.Interpreter; -using Microsoft.PythonTools.Parsing.Ast; - -namespace Microsoft.PythonTools.Analysis.Values { - /// - /// Represents a .NET namespace as exposed to Python - /// - internal class ReflectedNamespace : BuiltinNamespace, IReferenceableContainer { - private readonly MemberReferences _references = new MemberReferences(); - private readonly IMemberContainer _container; - - public ReflectedNamespace(IMemberContainer member, PythonAnalyzer projectState) - : base(member, projectState) { - _container = member; - } - - public override IAnalysisSet GetMember(Node node, AnalysisUnit unit, string name) { - // Must unconditionally call the base implementation of GetMember - var res = base.GetMember(node, unit, name); - if (res.Count > 0) { - _references.AddReference(node, unit, name); - } - return res; - } - - public override IDictionary GetAllMembers(IModuleContext moduleContext, GetMemberOptions options = GetMemberOptions.None) { - return ProjectState.GetAllMembers(_container, moduleContext); - } - - public override PythonMemberType MemberType { - get { - if (_container is IMember) { - return ((IMember)_container).MemberType; - } - return PythonMemberType.Namespace; - } - } - - #region IReferenceableContainer Members - - public IEnumerable GetDefinitions(string name) { - return _references.GetDefinitions(name, _container, ProjectState._defaultContext); - } - - #endregion - } -} diff --git a/src/Analysis/Engine/Impl/Values/SequenceBuiltinClassInfo.cs b/src/Analysis/Engine/Impl/Values/SequenceBuiltinClassInfo.cs index a9a777598..d2dad8d7b 100644 --- a/src/Analysis/Engine/Impl/Values/SequenceBuiltinClassInfo.cs +++ b/src/Analysis/Engine/Impl/Values/SequenceBuiltinClassInfo.cs @@ -30,8 +30,7 @@ abstract class SequenceBuiltinClassInfo : BuiltinClassInfo, IBuiltinSequenceClas public SequenceBuiltinClassInfo(IPythonType classObj, PythonAnalyzer projectState) : base(classObj, projectState) { - var seqType = classObj as IPythonSequenceType; - if (seqType != null && seqType.IndexTypes != null) { + if (classObj is IPythonSequenceType seqType && seqType.IndexTypes != null) { _indexTypes = seqType.IndexTypes.Select(projectState.GetAnalysisValueFromObjects).Select(AnalysisValueSetExtensions.GetInstanceType).ToArray(); } else { _indexTypes = Array.Empty(); @@ -84,7 +83,7 @@ public override IAnalysisSet GetIndex(Node node, AnalysisUnit unit, IAnalysisSet } public override IEnumerable> GetRichDescription() { - yield return new KeyValuePair(WellKnownRichDescriptionKinds.Type, _type.Name); + yield return new KeyValuePair(WellKnownRichDescriptionKinds.Type, Type.Name); if (_indexTypes == null || _indexTypes.Length == 0) { yield break; } diff --git a/src/Analysis/Engine/Impl/Values/SequenceBuiltinInstanceInfo.cs b/src/Analysis/Engine/Impl/Values/SequenceBuiltinInstanceInfo.cs index 5a3386dd7..777d8865b 100644 --- a/src/Analysis/Engine/Impl/Values/SequenceBuiltinInstanceInfo.cs +++ b/src/Analysis/Engine/Impl/Values/SequenceBuiltinInstanceInfo.cs @@ -26,12 +26,11 @@ namespace Microsoft.PythonTools.Analysis.Values { class SequenceBuiltinInstanceInfo : BaseIterableValue { private readonly bool _supportsMod; - public SequenceBuiltinInstanceInfo(BuiltinClassInfo klass, bool sequenceOfSelf, bool supportsMod) - : base(klass) { + public SequenceBuiltinInstanceInfo(BuiltinClassInfo classInfo, bool sequenceOfSelf, bool supportsMod) + : base(classInfo) { _supportsMod = supportsMod; - var seqInfo = klass as SequenceBuiltinClassInfo; - if (seqInfo != null) { + if (classInfo is SequenceBuiltinClassInfo seqInfo) { UnionType = AnalysisSet.UnionAll(seqInfo.IndexTypes); } else if (sequenceOfSelf) { UnionType = SelfSet; @@ -113,7 +112,7 @@ public override IAnalysisSet BinaryOperation(Node node, AnalysisUnit unit, Parsi public override IEnumerable> GetRichDescription() { if (UnionType == this) { return new[] { - new KeyValuePair(WellKnownRichDescriptionKinds.Type, _type.Name) + new KeyValuePair(WellKnownRichDescriptionKinds.Type, Type.Name) }; } return base.GetRichDescription(); diff --git a/src/Analysis/Engine/Impl/Values/TupleBuiltinClassInfo.cs b/src/Analysis/Engine/Impl/Values/TupleBuiltinClassInfo.cs index bf5eea8de..7c72615f9 100644 --- a/src/Analysis/Engine/Impl/Values/TupleBuiltinClassInfo.cs +++ b/src/Analysis/Engine/Impl/Values/TupleBuiltinClassInfo.cs @@ -60,8 +60,8 @@ internal override SequenceInfo MakeFromIndexes(Node node, IPythonProjectEntry en } class TupleBuiltinInstanceInfo : SequenceBuiltinInstanceInfo { - public TupleBuiltinInstanceInfo(BuiltinClassInfo classObj) - : base(classObj, false, false) { } + public TupleBuiltinInstanceInfo(BuiltinClassInfo classInfo) + : base(classInfo, false, false) { } public override IEnumerable> GetRichDescription() { if (ClassInfo is TupleBuiltinClassInfo tuple && tuple.IndexTypes.Count > 0) { diff --git a/src/Analysis/Engine/Test/AnalysisTest.cs b/src/Analysis/Engine/Test/AnalysisTest.cs index 54d6917ed..0d2eab2ab 100644 --- a/src/Analysis/Engine/Test/AnalysisTest.cs +++ b/src/Analysis/Engine/Test/AnalysisTest.cs @@ -588,6 +588,7 @@ public async Task RecursiveDictionaryKeyValues() { } [TestMethod, Priority(0)] + [Ignore("https://github.com/Microsoft/python-language-server/issues/425")] public async Task RecursiveTuples() { var code = @"class A(object): @@ -2629,7 +2630,7 @@ public async Task GetVariablesDictionaryGet() { var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(@"x = {42:'abc'}"); analysis.Should().HaveVariable("x").WithValue() .Which.Should().HaveMember("get") - .Which.Should().HaveDescription("bound method get"); + .Which.Should().HaveDescription("dict.get(self, key, d = None)"); } } diff --git a/src/Analysis/Engine/Test/AstAnalysisTests.cs b/src/Analysis/Engine/Test/AstAnalysisTests.cs index b9a470ba2..400d0cc78 100644 --- a/src/Analysis/Engine/Test/AstAnalysisTests.cs +++ b/src/Analysis/Engine/Test/AstAnalysisTests.cs @@ -101,24 +101,24 @@ public void AstClasses() { "f" ); - mod.GetMember(null, "C1").Should().BeOfType() + mod.GetMember(null, "C1").Should().BeOfType() .Which.Documentation.Should().Be("C1"); - mod.GetMember(null, "C2").Should().BeOfType(); - mod.GetMember(null, "C3").Should().BeOfType(); - mod.GetMember(null, "C4").Should().BeOfType(); - mod.GetMember(null, "C5").Should().BeOfType() + mod.GetMember(null, "C2").Should().BeOfType(); + mod.GetMember(null, "C3").Should().BeOfType(); + mod.GetMember(null, "C4").Should().BeOfType(); + mod.GetMember(null, "C5").Should().BeOfType() .Which.Documentation.Should().Be("C1"); - mod.GetMember(null, "D").Should().BeOfType(); - mod.GetMember(null, "E").Should().BeOfType(); + mod.GetMember(null, "D").Should().BeOfType(); + mod.GetMember(null, "E").Should().BeOfType(); mod.GetMember(null, "f").Should().BeOfType(); - var f1 = mod.GetMember(null, "F1").Should().BeOfType().Which; + var f1 = mod.GetMember(null, "F1").Should().BeOfType().Which; f1.GetMemberNames(null).Should().OnlyContain("F2", "F3", "F6", "__class__", "__bases__"); - f1.GetMember(null, "F6").Should().BeOfType() + f1.GetMember(null, "F6").Should().BeOfType() .Which.Documentation.Should().Be("C1"); - f1.GetMember(null, "F2").Should().BeOfType(); - f1.GetMember(null, "F3").Should().BeOfType(); - f1.GetMember(null, "__class__").Should().BeOfType(); + f1.GetMember(null, "F2").Should().BeOfType(); + f1.GetMember(null, "F3").Should().BeOfType(); + f1.GetMember(null, "__class__").Should().BeOfType(); f1.GetMember(null, "__bases__").Should().BeOfType(); } @@ -136,17 +136,17 @@ public void AstFunctions() { mod.GetMember(null, "g").Should().BeOfType(); mod.GetMember(null, "h").Should().BeOfType(); - var c = mod.GetMember(null, "C").Should().BeOfType().Which; + var c = mod.GetMember(null, "C").Should().BeOfType().Which; c.GetMemberNames(null).Should().OnlyContain("i", "j", "C2", "__class__", "__bases__"); c.GetMember(null, "i").Should().BeOfType(); c.GetMember(null, "j").Should().BeOfType(); - c.GetMember(null, "__class__").Should().BeOfType(); + c.GetMember(null, "__class__").Should().BeOfType(); c.GetMember(null, "__bases__").Should().BeOfType(); - var c2 = c.GetMember(null, "C2").Should().BeOfType().Which; + var c2 = c.GetMember(null, "C2").Should().BeOfType().Which; c2.GetMemberNames(null).Should().OnlyContain("k", "__class__", "__bases__"); c2.GetMember(null, "k").Should().BeOfType(); - c2.GetMember(null, "__class__").Should().BeOfType(); + c2.GetMember(null, "__class__").Should().BeOfType(); c2.GetMember(null, "__bases__").Should().BeOfType(); } @@ -270,8 +270,9 @@ public async Task AstInstanceMembers() { using (var server = await CreateServerAsync()) { var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync("from InstanceMethod import f1, f2"); - analysis.Should().HaveVariable("f1").OfType(BuiltinTypeId.BuiltinFunction).WithValue() - .And.HaveVariable("f2").OfType(BuiltinTypeId.BuiltinMethodDescriptor).WithValue(); + analysis.Should() + .HaveVariable("f1").OfType(BuiltinTypeId.Function).WithValue().And + .HaveVariable("f2").OfType(BuiltinTypeId.Method).WithValue(); } } @@ -282,7 +283,7 @@ public async Task AstInstanceMembers_Random() { foreach (var fnName in new[] { "seed", "randrange", "gauss" }) { analysis.Should().HaveVariable(fnName) - .OfType(BuiltinTypeId.BuiltinMethodDescriptor) + .OfType(BuiltinTypeId.Method) .WithValue() .Which.Should().HaveOverloadWithParametersAt(0); } @@ -440,13 +441,13 @@ public async Task AstTypeStubPaths_ExclusiveStubs() { [TestMethod, Priority(0)] public void AstMro() { - var O = new AstPythonType("O"); - var A = new AstPythonType("A"); - var B = new AstPythonType("B"); - var C = new AstPythonType("C"); - var D = new AstPythonType("D"); - var E = new AstPythonType("E"); - var F = new AstPythonType("F"); + var O = new AstPythonClass("O"); + var A = new AstPythonClass("A"); + var B = new AstPythonClass("B"); + var C = new AstPythonClass("C"); + var D = new AstPythonClass("D"); + var E = new AstPythonClass("E"); + var F = new AstPythonClass("F"); F.SetBases(null, new[] { O }); E.SetBases(null, new[] { O }); @@ -455,9 +456,9 @@ public void AstMro() { B.SetBases(null, new[] { D, E }); A.SetBases(null, new[] { B, C }); - AstPythonType.CalculateMro(A).Should().Equal(new[] { "A", "B", "C", "D", "E", "F", "O" }, (p, n) => p.Name == n); - AstPythonType.CalculateMro(B).Should().Equal(new[] { "B", "D", "E", "O" }, (p, n) => p.Name == n); - AstPythonType.CalculateMro(C).Should().Equal(new[] { "C", "D", "F", "O" }, (p, n) => p.Name == n); + AstPythonClass.CalculateMro(A).Should().Equal(new[] { "A", "B", "C", "D", "E", "F", "O" }, (p, n) => p.Name == n); + AstPythonClass.CalculateMro(B).Should().Equal(new[] { "B", "D", "E", "O" }, (p, n) => p.Name == n); + AstPythonClass.CalculateMro(C).Should().Equal(new[] { "C", "D", "F", "O" }, (p, n) => p.Name == n); } private static IPythonModule Parse(string path, PythonLanguageVersion version) { @@ -555,7 +556,8 @@ private async Task AstBuiltinScrape(InterpreterConfiguration configuration) { // Ensure we can get all the builtin types foreach (BuiltinTypeId v in Enum.GetValues(typeof(BuiltinTypeId))) { var type = interp.GetBuiltinType(v); - type.Should().NotBeNull().And.BeOfType($"Did not find {v}"); + type.Should().NotBeNull().And.BeAssignableTo($"Did not find {v}"); + type.IsBuiltin.Should().BeTrue(); } // Ensure we cannot see or get builtin types directly @@ -843,6 +845,7 @@ public async Task AstTypeAnnotationConversion() { [TestMethod, Priority(0)] public async Task TypeShedElementTree() { using (var server = await CreateServerAsync()) { + server.Analyzer.SetTypeStubPaths(new[] { TestData.GetDefaultTypeshedPath() }); var code = @"import xml.etree.ElementTree as ET e = ET.Element() @@ -904,11 +907,11 @@ public async Task TypeShedSysExcInfo() { // sys.exc_info() -> (exception_type, exception_value, traceback) analysis.Should().HaveVariable("e1").OfTypes(BuiltinTypeId.Type) .And.HaveVariable("e2").OfTypes("BaseException") - .And.HaveVariable("e3").OfTypes(BuiltinTypeId.NoneType) + .And.HaveVariable("e3").OfTypes(BuiltinTypeId.Unknown) .And.HaveVariable("sys").WithValue() .Which.Should().HaveMember("exc_info") .Which.Should().HaveSingleOverload() - .WithSingleReturnType("tuple[type, BaseException, None]"); + .WithSingleReturnType("tuple[type, BaseException, Unknown]"); } } @@ -922,19 +925,13 @@ public async Task TypeShedJsonMakeScanner() { var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code); var v0 = analysis.Should().HaveVariable("scanner").WithValueAt(0); - var v1 = analysis.Should().HaveVariable("scanner").WithValueAt(1); v0.Which.Should().HaveSingleOverload() .Which.Should().HaveName("__call__") .And.HaveParameters("string", "index") .And.HaveParameterAt(0).WithName("string").WithType("str").WithNoDefaultValue() .And.HaveParameterAt(1).WithName("index").WithType("int").WithNoDefaultValue() - .And.HaveSingleReturnType("tuple[None, int]"); - - v1.Which.Should().HaveSingleOverload() - .Which.Should().HaveName("__call__") - .And.HaveParameters("*args", "**kwargs") - .And.HaveSingleReturnType("type"); + .And.HaveSingleReturnType("tuple[object, int]"); } } @@ -967,8 +964,8 @@ public async Task TypeShedSysInfo() { .And.HaveVariable("s_1").OfTypes(BuiltinTypeId.Str) .And.HaveVariable("s_2").OfTypes(BuiltinTypeId.Str) .And.HaveVariable("s_3").OfTypes(BuiltinTypeId.Str) - .And.HaveVariable("f_1").OfTypes(BuiltinTypeId.BuiltinMethodDescriptor) - .And.HaveVariable("f_2").OfTypes(BuiltinTypeId.BuiltinMethodDescriptor) + .And.HaveVariable("f_1").OfTypes(BuiltinTypeId.Method) + .And.HaveVariable("f_2").OfTypes(BuiltinTypeId.Method) .And.HaveVariable("i_1").OfTypes(BuiltinTypeId.Int) .And.HaveVariable("i_2").OfTypes(BuiltinTypeId.Int) .And.HaveVariable("i_3").OfTypes(BuiltinTypeId.Int) diff --git a/src/Analysis/Engine/Test/FluentAssertions/MemberContainerAssertionsExtensions.cs b/src/Analysis/Engine/Test/FluentAssertions/MemberContainerAssertionsExtensions.cs index df7ac3eea..55e8f69de 100644 --- a/src/Analysis/Engine/Test/FluentAssertions/MemberContainerAssertionsExtensions.cs +++ b/src/Analysis/Engine/Test/FluentAssertions/MemberContainerAssertionsExtensions.cs @@ -27,9 +27,9 @@ public static AndWhichConstraint OfMemberType(constraint.And, constraint.Which); } } -} \ No newline at end of file +} diff --git a/src/Analysis/Engine/Test/HoverTests.cs b/src/Analysis/Engine/Test/HoverTests.cs index 364dfb023..c38d180f9 100644 --- a/src/Analysis/Engine/Test/HoverTests.cs +++ b/src/Analysis/Engine/Test/HoverTests.cs @@ -84,7 +84,7 @@ import datetime "); await AssertHover(server, mod, new SourceLocation(3, 1), "module datetime*", new[] { "datetime" }, new SourceSpan(3, 1, 3, 9)); await AssertHover(server, mod, new SourceLocation(3, 11), "class datetime.datetime*", new[] { "datetime.datetime" }, new SourceSpan(3, 1, 3, 18)); - await AssertHover(server, mod, new SourceLocation(3, 20), "datetime.datetime.now: bound method now*", null, new SourceSpan(3, 1, 3, 22)); + await AssertHover(server, mod, new SourceLocation(3, 20), "datetime.datetime.now: datetime.datetime.now(cls)*", null, new SourceSpan(3, 1, 3, 22)); } [ServerTestMethod(LatestAvailable3X = true), Priority(0)] @@ -95,7 +95,7 @@ import datetime "); await AssertHover(server, mod, new SourceLocation(3, 1), "module datetime*", new[] { "datetime" }, new SourceSpan(3, 1, 3, 9)); await AssertHover(server, mod, new SourceLocation(3, 11), "class datetime.datetime*", new[] { "datetime.datetime" }, new SourceSpan(3, 1, 3, 18)); - await AssertHover(server, mod, new SourceLocation(3, 20), "datetime.datetime.now: bound method now*", null, new SourceSpan(3, 1, 3, 22)); + await AssertHover(server, mod, new SourceLocation(3, 20), "datetime.datetime.now: datetime.datetime.now(cls*", null, new SourceSpan(3, 1, 3, 22)); await AssertHover(server, mod, new SourceLocation(3, 28), "datetime.datetime.now().day: int*", new[] { "int" }, new SourceSpan(3, 1, 3, 28)); } diff --git a/src/Analysis/Engine/Test/TypeAnnotationTests.cs b/src/Analysis/Engine/Test/TypeAnnotationTests.cs index b04bf7111..41435c759 100644 --- a/src/Analysis/Engine/Test/TypeAnnotationTests.cs +++ b/src/Analysis/Engine/Test/TypeAnnotationTests.cs @@ -477,7 +477,7 @@ def async_query(on_success: Callable[[int], None], ", new[] { "feeder:feeder(get_next_item:function() -> str) -> None", - "async_query:async_query(on_success:function(int), on_error:function(int, Exception)) -> None" + "async_query:async_query(on_success:function(int) -> None, on_error:function(int, Exception) -> None) -> None" } ); } diff --git a/src/LanguageServer/Impl/Implementation/CompletionAnalysis.cs b/src/LanguageServer/Impl/Implementation/CompletionAnalysis.cs index 95252a161..065576264 100644 --- a/src/LanguageServer/Impl/Implementation/CompletionAnalysis.cs +++ b/src/LanguageServer/Impl/Implementation/CompletionAnalysis.cs @@ -865,14 +865,11 @@ private static CompletionItemKind ToCompletionItemKind(PythonMemberType memberTy case PythonMemberType.Unknown: return CompletionItemKind.None; case PythonMemberType.Class: return CompletionItemKind.Class; case PythonMemberType.Instance: return CompletionItemKind.Value; - case PythonMemberType.Delegate: return CompletionItemKind.Class; - case PythonMemberType.DelegateInstance: return CompletionItemKind.Function; case PythonMemberType.Enum: return CompletionItemKind.Enum; case PythonMemberType.EnumInstance: return CompletionItemKind.EnumMember; case PythonMemberType.Function: return CompletionItemKind.Function; case PythonMemberType.Method: return CompletionItemKind.Method; case PythonMemberType.Module: return CompletionItemKind.Module; - case PythonMemberType.Namespace: return CompletionItemKind.Module; case PythonMemberType.Constant: return CompletionItemKind.Constant; case PythonMemberType.Event: return CompletionItemKind.Event; case PythonMemberType.Field: return CompletionItemKind.Field; @@ -886,7 +883,7 @@ private static CompletionItemKind ToCompletionItemKind(PythonMemberType memberTy } } - private static string MakeOverrideDefParamater(ParameterResult result) { + private static string MakeOverrideDefParameter(ParameterResult result) { if (!string.IsNullOrEmpty(result.DefaultValue)) { return result.Name + "=" + result.DefaultValue; } @@ -909,11 +906,24 @@ private static string MakeOverrideCallParameter(ParameterResult result) { private string MakeOverrideCompletionString(string indentation, IOverloadResult result, string className) { var sb = new StringBuilder(); - sb.AppendLine(result.Name + "(" + string.Join(", ", result.Parameters.Select(MakeOverrideDefParamater)) + "):"); + ParameterResult first; + ParameterResult[] skipFirstParameters; + ParameterResult[] allParameters; + if (result.FirstParameter != null) { + first = result.FirstParameter; + skipFirstParameters = result.Parameters; + allParameters = new[] {first}.Concat(skipFirstParameters).ToArray(); + } else { + first = result.Parameters.FirstOrDefault(); + skipFirstParameters = result.Parameters.Skip(1).ToArray(); + allParameters = result.Parameters; + } + + sb.AppendLine(result.Name + "(" + string.Join(", ", allParameters.Select(MakeOverrideDefParameter)) + "):"); sb.Append(indentation); - if (result.Parameters.Length > 0) { - var parameterString = string.Join(", ", result.Parameters.Skip(1).Select(MakeOverrideCallParameter)); + if (allParameters.Length > 0) { + var parameterString = string.Join(", ", skipFirstParameters.Select(MakeOverrideCallParameter)); if (Tree.LanguageVersion.Is3x()) { sb.AppendFormat("return super().{0}({1})", @@ -922,7 +932,7 @@ private string MakeOverrideCompletionString(string indentation, IOverloadResult } else if (!string.IsNullOrEmpty(className)) { sb.AppendFormat("return super({0}, {1}).{2}({3})", className, - result.Parameters.First().Name, + first?.Name ?? string.Empty, result.Name, parameterString); } else { diff --git a/src/LanguageServer/Impl/Implementation/Server.WorkspaceSymbols.cs b/src/LanguageServer/Impl/Implementation/Server.WorkspaceSymbols.cs index 285f1a99d..98bb72841 100644 --- a/src/LanguageServer/Impl/Implementation/Server.WorkspaceSymbols.cs +++ b/src/LanguageServer/Impl/Implementation/Server.WorkspaceSymbols.cs @@ -191,14 +191,11 @@ private static SymbolKind ToSymbolKind(PythonMemberType memberType) { case PythonMemberType.Unknown: return SymbolKind.None; case PythonMemberType.Class: return SymbolKind.Class; case PythonMemberType.Instance: return SymbolKind.Variable; - case PythonMemberType.Delegate: return SymbolKind.Function; - case PythonMemberType.DelegateInstance: return SymbolKind.Function; case PythonMemberType.Enum: return SymbolKind.Enum; case PythonMemberType.EnumInstance: return SymbolKind.EnumMember; case PythonMemberType.Function: return SymbolKind.Function; case PythonMemberType.Method: return SymbolKind.Method; case PythonMemberType.Module: return SymbolKind.Module; - case PythonMemberType.Namespace: return SymbolKind.Namespace; case PythonMemberType.Constant: return SymbolKind.Constant; case PythonMemberType.Event: return SymbolKind.Event; case PythonMemberType.Field: return SymbolKind.Field;