diff --git a/src/.editorconfig b/src/.editorconfig index d2a6ae077..5c12421ba 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -76,3 +76,7 @@ csharp_new_line_before_finally = false csharp_new_line_before_members_in_anonymous_types = false csharp_new_line_before_members_in_object_initializers = false + +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:none +dotnet_style_qualification_for_method = false:none diff --git a/src/Analysis/Engine/Impl/Analyzer/DDG.cs b/src/Analysis/Engine/Impl/Analyzer/DDG.cs index ed840aa19..c4200e5c2 100644 --- a/src/Analysis/Engine/Impl/Analyzer/DDG.cs +++ b/src/Analysis/Engine/Impl/Analyzer/DDG.cs @@ -474,7 +474,7 @@ public override bool Walk(FunctionDefinition node) { InterpreterScope funcScope; if (_unit.InterpreterScope.TryGetNodeScope(node, out funcScope)) { var function = ((FunctionScope)funcScope).Function; - var analysisUnit = (FunctionAnalysisUnit)((FunctionScope)funcScope).Function.AnalysisUnit; + var analysisUnit = (FunctionAnalysisUnit)function.AnalysisUnit; var curClass = Scope as ClassScope; if (curClass != null) { @@ -489,6 +489,10 @@ public override bool Walk(FunctionDefinition node) { function.UpdateDefaultParameters(_unit, overload.GetParameters()); } } + + foreach (var @base in bases.OfType()) { + @base.AddDerived(function); + } } } diff --git a/src/Analysis/Engine/Impl/Values/FunctionInfo.cs b/src/Analysis/Engine/Impl/Values/FunctionInfo.cs index 723b36294..7fadf73d1 100644 --- a/src/Analysis/Engine/Impl/Values/FunctionInfo.cs +++ b/src/Analysis/Engine/Impl/Values/FunctionInfo.cs @@ -27,6 +27,7 @@ namespace Microsoft.PythonTools.Analysis.Values { internal class FunctionInfo : AnalysisValue, IFunctionInfo, IHasRichDescription, IHasQualifiedName { private Dictionary _methods; + private HashSet _derived; private Dictionary _functionAttrs; private readonly FunctionAnalysisUnit _analysisUnit; private ReferenceDict _references; @@ -94,6 +95,12 @@ public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] a } var res = DoCall(node, unit, _analysisUnit, callArgs); + if (_derived != null) { + foreach (FunctionInfo derived in _derived) { + var derivedResult = derived.DoCall(node, unit, derived._analysisUnit, callArgs); + res = res.Union(derivedResult); + } + } if (_callsWithClosure != null) { var chain = new CallChain(node, unit, _callDepthLimit); @@ -158,6 +165,16 @@ private IVersioned GetAggregate(AnalysisUnit unit) { return agg; } + internal bool AddDerived(FunctionInfo derived) { + if (derived == null) throw new ArgumentNullException(nameof(derived)); + + _derived = _derived ?? new HashSet(); + + bool @new = _derived.Add(derived); + // TODO: do we need to re-queue this function analysis if a new derived was added? + return @new; + } + internal void AddParameterReference(Node node, AnalysisUnit unit, string name) { var vd = (_analysisUnit.Scope as FunctionScope)?.GetParameter(name); vd?.AddReference(node, unit); diff --git a/src/Analysis/Engine/Test/InheritanceTests.cs b/src/Analysis/Engine/Test/InheritanceTests.cs index 2f0dab6ec..38af6b43c 100644 --- a/src/Analysis/Engine/Test/InheritanceTests.cs +++ b/src/Analysis/Engine/Test/InheritanceTests.cs @@ -64,5 +64,31 @@ def virt(): analysis.Should().HaveVariable("b").OfTypes(BuiltinTypeId.Int, BuiltinTypeId.Function); } } + + [TestMethod] + public async Task ParameterTypesPropagateToDerivedFunctions() { + var code = @" +class Baze: + def foo(self, x): + pass + +class Derived(Baze): + def foo(self, x): + pass + +Baze().foo(42) +"; + + using (var server = await new Server().InitializeAsync(PythonVersions.Required_Python36X)) { + var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code); + + // the class, for which we know parameter type initially + analysis.Should().HaveClass("Baze").WithFunction("foo") + .WithParameter("x").OfType(BuiltinTypeId.Int); + // its derived class + analysis.Should().HaveClass("Derived").WithFunction("foo") + .WithParameter("x").OfType(BuiltinTypeId.Int); + } + } } }