From 1c11dfc21f2a159dc4a79a3f1e0bafc452a2c12c Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 7 Aug 2019 10:43:14 -0700 Subject: [PATCH] Fallback to function when property's declaringType is unknown --- .../Ast/Impl/Analyzer/Symbols/SymbolCollector.cs | 6 ++++++ .../Ast/Impl/Types/PythonFunctionType.cs | 4 +++- src/Analysis/Ast/Test/ClassesTests.cs | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs b/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs index a3f489cf7..70081d03c 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Symbols/SymbolCollector.cs @@ -150,6 +150,12 @@ private PythonFunctionOverload GetOverloadFromStub(FunctionDefinition node) { } private bool TryAddProperty(FunctionDefinition node, IPythonType declaringType) { + // We can't add a property to an unknown type. Fallback to a regular function for now. + // TOOD: Decouple declaring types from the property. + if (declaringType.IsUnknown()) { + return false; + } + var dec = node.Decorators?.Decorators; var decorators = dec != null ? dec.ExcludeDefault().ToArray() : Array.Empty(); diff --git a/src/Analysis/Ast/Impl/Types/PythonFunctionType.cs b/src/Analysis/Ast/Impl/Types/PythonFunctionType.cs index 80670e93c..63208bc8b 100644 --- a/src/Analysis/Ast/Impl/Types/PythonFunctionType.cs +++ b/src/Analysis/Ast/Impl/Types/PythonFunctionType.cs @@ -143,7 +143,9 @@ private void ProcessDecorators(FunctionDefinition fd) { break; case @"property": case @"abstractproperty": - Debug.Assert(false, "Found property attribute while processing function. Properties should be handled in the respective class."); + // Ignore property decorators if the declaring type is unknown. + // TODO: Restore this to a hard failure once property can handle not having a declaring type. + Debug.Assert(DeclaringType.IsUnknown(), "Found property attribute while processing function. Properties should be handled in the respective class."); break; } } diff --git a/src/Analysis/Ast/Test/ClassesTests.cs b/src/Analysis/Ast/Test/ClassesTests.cs index 1d817f3cb..06b120b31 100644 --- a/src/Analysis/Ast/Test/ClassesTests.cs +++ b/src/Analysis/Ast/Test/ClassesTests.cs @@ -634,5 +634,21 @@ def __init__(self): // Test run time: typically ~ 20 sec. sw.ElapsedMilliseconds.Should().BeLessThan(60000); } + + [TestMethod, Priority(0)] + public async Task NestedProperty() { + const string code = @" +class x(object): + def func(self): + @property + def foo(*args, **kwargs): + pass + return 42 + +a = x().func() +"; + var analysis = await GetAnalysisAsync(code); + analysis.Should().HaveVariable("a").OfType(BuiltinTypeId.Int); + } } }