From 98ec808270c2ba8d80fe750c6eb30bede24c2d36 Mon Sep 17 00:00:00 2001 From: MikhailArkhipov Date: Tue, 21 May 2019 10:06:33 -0700 Subject: [PATCH] Process class member definitions in order --- .../Impl/Analyzer/Symbols/ClassEvaluator.cs | 21 ++++++++++------ .../Impl/Definitions/IReferenceCollection.cs | 24 ------------------- .../Ast/Test/LintUndefinedVarsTests.cs | 11 +++++++++ src/Analysis/Ast/Test/ReferencesTests.cs | 15 ++++++++++++ 4 files changed, 40 insertions(+), 31 deletions(-) delete mode 100644 src/Analysis/Ast/Impl/Definitions/IReferenceCollection.cs diff --git a/src/Analysis/Ast/Impl/Analyzer/Symbols/ClassEvaluator.cs b/src/Analysis/Ast/Impl/Analyzer/Symbols/ClassEvaluator.cs index 37eed92a4..1e1e6a767 100644 --- a/src/Analysis/Ast/Impl/Analyzer/Symbols/ClassEvaluator.cs +++ b/src/Analysis/Ast/Impl/Analyzer/Symbols/ClassEvaluator.cs @@ -86,19 +86,26 @@ private void ProcessClassBody() { foreach (var s in GetStatements(_classDef)) { ImportHandler.HandleFromImport(s); } - foreach (var s in GetStatements(_classDef)) { ImportHandler.HandleImport(s); } - UpdateClassMembers(); // Process assignments so we get class variables declared. - foreach (var s in GetStatements(_classDef)) { - AssignmentHandler.HandleAssignment(s); - } - foreach (var s in GetStatements(_classDef)) { - AssignmentHandler.HandleAnnotatedExpression(s.Expression as ExpressionWithAnnotation, null); + // Note that annotated definitions and assignments can be intermixed + // and must be processed in order. Consider + // class A: + // x: int + // x = 1 + foreach (var s in GetStatements(_classDef)) { + switch (s) { + case AssignmentStatement assignment: + AssignmentHandler.HandleAssignment(assignment); + break; + case ExpressionStatement e: + AssignmentHandler.HandleAnnotatedExpression(e.Expression as ExpressionWithAnnotation, null); + break; + } } UpdateClassMembers(); diff --git a/src/Analysis/Ast/Impl/Definitions/IReferenceCollection.cs b/src/Analysis/Ast/Impl/Definitions/IReferenceCollection.cs deleted file mode 100644 index de1c46302..000000000 --- a/src/Analysis/Ast/Impl/Definitions/IReferenceCollection.cs +++ /dev/null @@ -1,24 +0,0 @@ -// 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 Microsoft.Python.Analysis.Types; -using Microsoft.Python.Parsing.Ast; - -namespace Microsoft.Python.Analysis { - public interface IReferenceCollection { - IReadOnlyList GetReferences(IPythonType type); - } -} diff --git a/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs b/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs index ede9b8012..6b4d0a73a 100644 --- a/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs +++ b/src/Analysis/Ast/Test/LintUndefinedVarsTests.cs @@ -611,6 +611,17 @@ public async Task GlobalScope() { d[0].SourceSpan.Should().Be(2, 7, 2, 16); } + [TestMethod, Priority(0)] + public async Task ClassMemberDefinition() { + const string code = @" +class A: + i: int + i = 0 +"; + var d = await LintAsync(code); + d.Should().BeEmpty(); + } + private async Task> LintAsync(string code, InterpreterConfiguration configuration = null) { var analysis = await GetAnalysisAsync(code, configuration ?? PythonVersions.LatestAvailable3X); var a = Services.GetService(); diff --git a/src/Analysis/Ast/Test/ReferencesTests.cs b/src/Analysis/Ast/Test/ReferencesTests.cs index 3301048ec..bf1fa2418 100644 --- a/src/Analysis/Ast/Test/ReferencesTests.cs +++ b/src/Analysis/Ast/Test/ReferencesTests.cs @@ -269,6 +269,21 @@ def func(a: A): x.References[1].Span.Should().Be(6, 14, 6, 15); } + [TestMethod, Priority(0)] + public async Task ClassFieldAnnotation() { + const string code = @" +class A: + x: int + x = 0 +"; + var analysis = await GetAnalysisAsync(code); + var x = analysis.GlobalScope.Children[0].Should().HaveVariable("x").Which; + x.Should().NotBeNull(); + x.References.Should().HaveCount(2); + x.References[0].Span.Should().Be(3, 5, 3, 6); + x.References[1].Span.Should().Be(4, 5, 4, 6); + } + [TestMethod, Priority(0)] public async Task Assignments() { const string code = @"