Skip to content
This repository was archived by the owner on Nov 4, 2024. It is now read-only.

Commit 83704c0

Browse files
author
Mikhail Arkhipov
authored
Merge pull request microsoft#200 from losttech/features/FunctionParameterTypePropagation
Propagate known parameter types to derived functions
2 parents ffd9847 + 1a3ade9 commit 83704c0

File tree

4 files changed

+52
-1
lines changed

4 files changed

+52
-1
lines changed

src/.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ csharp_new_line_before_finally = false
7676
csharp_new_line_before_members_in_anonymous_types = false
7777

7878
csharp_new_line_before_members_in_object_initializers = false
79+
80+
dotnet_style_qualification_for_field = false:suggestion
81+
dotnet_style_qualification_for_property = false:none
82+
dotnet_style_qualification_for_method = false:none

src/Analysis/Engine/Impl/Analyzer/DDG.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ public override bool Walk(FunctionDefinition node) {
474474
InterpreterScope funcScope;
475475
if (_unit.InterpreterScope.TryGetNodeScope(node, out funcScope)) {
476476
var function = ((FunctionScope)funcScope).Function;
477-
var analysisUnit = (FunctionAnalysisUnit)((FunctionScope)funcScope).Function.AnalysisUnit;
477+
var analysisUnit = (FunctionAnalysisUnit)function.AnalysisUnit;
478478

479479
var curClass = Scope as ClassScope;
480480
if (curClass != null) {
@@ -489,6 +489,10 @@ public override bool Walk(FunctionDefinition node) {
489489
function.UpdateDefaultParameters(_unit, overload.GetParameters());
490490
}
491491
}
492+
493+
foreach (var @base in bases.OfType<FunctionInfo>()) {
494+
@base.AddDerived(function);
495+
}
492496
}
493497
}
494498

src/Analysis/Engine/Impl/Values/FunctionInfo.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
namespace Microsoft.PythonTools.Analysis.Values {
2828
internal class FunctionInfo : AnalysisValue, IFunctionInfo2, IHasRichDescription, IHasQualifiedName {
2929
private Dictionary<AnalysisValue, IAnalysisSet> _methods;
30+
private HashSet<FunctionInfo> _derived;
3031
private Dictionary<string, VariableDef> _functionAttrs;
3132
private readonly FunctionAnalysisUnit _analysisUnit;
3233
private ReferenceDict _references;
@@ -95,6 +96,12 @@ public override IAnalysisSet Call(Node node, AnalysisUnit unit, IAnalysisSet[] a
9596
}
9697

9798
var res = DoCall(node, unit, _analysisUnit, callArgs);
99+
if (_derived != null) {
100+
foreach (FunctionInfo derived in _derived) {
101+
var derivedResult = derived.DoCall(node, unit, derived._analysisUnit, callArgs);
102+
res = res.Union(derivedResult);
103+
}
104+
}
98105

99106
if (_callsWithClosure != null) {
100107
var chain = new CallChain(node, unit, _callDepthLimit);
@@ -159,6 +166,16 @@ private IVersioned GetAggregate(AnalysisUnit unit) {
159166
return agg;
160167
}
161168

169+
internal bool AddDerived(FunctionInfo derived) {
170+
if (derived == null) throw new ArgumentNullException(nameof(derived));
171+
172+
_derived = _derived ?? new HashSet<FunctionInfo>();
173+
174+
bool @new = _derived.Add(derived);
175+
// TODO: do we need to re-queue this function analysis if a new derived was added?
176+
return @new;
177+
}
178+
162179
internal void AddParameterReference(Node node, AnalysisUnit unit, string name) {
163180
var vd = (_analysisUnit.Scope as FunctionScope)?.GetParameter(name);
164181
vd?.AddReference(node, unit);

src/Analysis/Engine/Test/InheritanceTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,31 @@ def virt():
6464
analysis.Should().HaveVariable("b").OfTypes(BuiltinTypeId.Int, BuiltinTypeId.Function);
6565
}
6666
}
67+
68+
[TestMethod]
69+
public async Task ParameterTypesPropagateToDerivedFunctions() {
70+
var code = @"
71+
class Baze:
72+
def foo(self, x):
73+
pass
74+
75+
class Derived(Baze):
76+
def foo(self, x):
77+
pass
78+
79+
Baze().foo(42)
80+
";
81+
82+
using (var server = await new Server().InitializeAsync(PythonVersions.Required_Python36X)) {
83+
var analysis = await server.OpenDefaultDocumentAndGetAnalysisAsync(code);
84+
85+
// the class, for which we know parameter type initially
86+
analysis.Should().HaveClass("Baze").WithFunction("foo")
87+
.WithParameter("x").OfType(BuiltinTypeId.Int);
88+
// its derived class
89+
analysis.Should().HaveClass("Derived").WithFunction("foo")
90+
.WithParameter("x").OfType(BuiltinTypeId.Int);
91+
}
92+
}
6793
}
6894
}

0 commit comments

Comments
 (0)