This repository was archived by the owner on Apr 14, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 132
Expand file tree
/
Copy pathUndefinedVariablesWalker.cs
More file actions
119 lines (109 loc) · 4.99 KB
/
UndefinedVariablesWalker.cs
File metadata and controls
119 lines (109 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// 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 System.Linq;
using Microsoft.Python.Analysis.Analyzer;
using Microsoft.Python.Analysis.Diagnostics;
using Microsoft.Python.Core;
using Microsoft.Python.Core.Text;
using Microsoft.Python.Parsing;
using Microsoft.Python.Parsing.Ast;
using ErrorCodes = Microsoft.Python.Analysis.Diagnostics.ErrorCodes;
namespace Microsoft.Python.Analysis.Linting.UndefinedVariables {
internal sealed class UndefinedVariablesWalker : LinterWalker {
private readonly List<DiagnosticsEntry> _diagnostics = new List<DiagnosticsEntry>();
private bool _suppressDiagnostics;
public UndefinedVariablesWalker(IDocumentAnalysis analysis, IServiceContainer services)
: base(analysis, services) { }
public IReadOnlyList<DiagnosticsEntry> Diagnostics => _diagnostics;
public override bool Walk(SuiteStatement node) {
foreach (var statement in node.Statements) {
switch (statement) {
case ClassDefinition cd:
HandleScope(cd);
break;
case FunctionDefinition fd:
HandleScope(fd);
break;
case GlobalStatement gs:
HandleGlobal(gs);
break;
case NonlocalStatement nls:
HandleNonLocal(nls);
break;
case AugmentedAssignStatement augs:
augs.Left?.Walk(new ExpressionWalker(this));
augs.Right?.Walk(new ExpressionWalker(this));
break;
case AssignmentStatement asst:
var lhs = asst.Left.MaybeEnumerate().ToArray();
if (lhs.Length > 0) {
lhs[0]?.Walk(new ExpressionWalker(this));
}
_suppressDiagnostics = true;
foreach (var l in lhs.Skip(1)) {
l?.Walk(new ExpressionWalker(this));
}
_suppressDiagnostics = false;
asst.Right?.Walk(new ExpressionWalker(this));
break;
default:
statement.Walk(new ExpressionWalker(this));
break;
}
}
return false;
}
public void ReportUndefinedVariable(NameExpression node) {
var eval = Analysis.ExpressionEvaluator;
ReportUndefinedVariable(node.Name, eval.GetLocation(node).Span);
}
private void ReportUndefinedVariable(string name, SourceSpan span) {
if (!_suppressDiagnostics) {
_diagnostics.Add(new DiagnosticsEntry(
Resources.UndefinedVariable.FormatInvariant(name),
span, ErrorCodes.UndefinedVariable, Severity.Warning, DiagnosticSource.Linter));
}
}
private void HandleGlobal(GlobalStatement node) {
foreach (var nex in node.Names) {
var m = Eval.LookupNameInScopes(nex.Name, out _, LookupOptions.Global);
if (m == null) {
_diagnostics.Add(new DiagnosticsEntry(
Resources.ErrorVariableNotDefinedGlobally.FormatInvariant(nex.Name),
Eval.GetLocation(nex).Span, ErrorCodes.VariableNotDefinedGlobally, Severity.Warning, DiagnosticSource.Linter));
}
}
}
private void HandleNonLocal(NonlocalStatement node) {
foreach (var nex in node.Names) {
var m = Eval.LookupNameInScopes(nex.Name, out _, LookupOptions.Nonlocal);
if (m == null) {
_diagnostics.Add(new DiagnosticsEntry(
Resources.ErrorVariableNotDefinedNonLocal.FormatInvariant(nex.Name),
Eval.GetLocation(nex).Span, ErrorCodes.VariableNotDefinedNonLocal, Severity.Warning, DiagnosticSource.Linter));
}
}
}
private void HandleScope(ScopeStatement node) {
try {
OpenScope(node);
node.Walk(this);
} finally {
CloseScope();
}
}
}
}