|
15 | 15 |
|
16 | 16 | using System.Collections.Generic; |
17 | 17 | using System.Linq; |
| 18 | +using Microsoft.Python.Analysis.Analyzer; |
18 | 19 | using Microsoft.Python.Analysis.Types; |
19 | 20 | using Microsoft.Python.Core; |
20 | 21 | using Microsoft.Python.Core.Text; |
@@ -77,27 +78,42 @@ public override bool Walk(NameExpression node) { |
77 | 78 | } |
78 | 79 |
|
79 | 80 | var analysis = _walker.Analysis; |
80 | | - var m = analysis.ExpressionEvaluator.LookupNameInScopes(node.Name, out _, out var v); |
| 81 | + var m = analysis.ExpressionEvaluator.LookupNameInScopes(node.Name, out var variableDefinitionScope, out var v); |
81 | 82 | if (m == null) { |
82 | 83 | _walker.ReportUndefinedVariable(node); |
83 | 84 | } |
84 | 85 | v?.AddReference(new Location(analysis.Document, node.IndexSpan)); |
85 | 86 |
|
| 87 | + // Make sure we have definition and the document matches |
| 88 | + if (v?.Definition == null || v.Definition.DocumentUri != analysis.Document.Uri) { |
| 89 | + return false; |
| 90 | + } |
| 91 | + // Do not complain about functions and classes that appear later in the file |
| 92 | + if (v.Value is IPythonFunctionType || v.Value is IPythonClassType) { |
| 93 | + return false; |
| 94 | + } |
| 95 | + |
86 | 96 | // Take into account where variable is defined so we do detect |
87 | 97 | // undefined x in |
88 | 98 | // y = x |
89 | 99 | // x = 1 |
90 | | - if (v?.Definition != null && v.Definition.DocumentUri == analysis.Document.Uri) { |
91 | | - // Do not complain about functions and classes that appear later in the file |
92 | | - if (!(v.Value is IPythonFunctionType || v.Value is IPythonClassType)) { |
93 | | - var span = v.Definition.Span; |
94 | | - var nodeLoc = node.GetLocation(analysis.Document); |
95 | | - // Exclude same-name variables declared within the same statement |
96 | | - // like 'e' that appears before its declaration in '[e in for e in {}]' |
97 | | - if (span.IsAfter(nodeLoc.Span) && !IsSpanInComprehension(nodeLoc.Span)) { |
98 | | - _walker.ReportUndefinedVariable(node); |
99 | | - } |
100 | | - } |
| 100 | + var variableDefinitionSpan = v.Definition.Span; |
| 101 | + var nameUseLocation = node.GetLocation(analysis.Document); |
| 102 | + |
| 103 | + // Make sure we are in the same scope in order to avoid |
| 104 | + // def func(): |
| 105 | + // y = x |
| 106 | + // |
| 107 | + // x = 1 |
| 108 | + var nameUseScope = analysis.ExpressionEvaluator.GlobalScope.FindScope(analysis.Document, nameUseLocation.Span.Start); |
| 109 | + if (nameUseScope.IsNestedInScope(variableDefinitionScope)) { |
| 110 | + return false; |
| 111 | + } |
| 112 | + |
| 113 | + // Exclude same-name variables declared within the same statement |
| 114 | + // like 'e' that appears before its declaration in '[e in for e in {}]' |
| 115 | + if (variableDefinitionSpan.IsAfter(nameUseLocation.Span) && !IsSpanInComprehension(nameUseLocation.Span)) { |
| 116 | + _walker.ReportUndefinedVariable(node); |
101 | 117 | } |
102 | 118 | return false; |
103 | 119 | } |
|
0 commit comments