Skip to content

Commit 5171534

Browse files
committed
Scope tweaks. Report REFERENCED_BEFORE_DECLARATION in more places.
Change-Id: Iac395adf15c3f636e3e7e7241e0573f83ab61372 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155304 Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 6bba750 commit 5171534

File tree

7 files changed

+219
-100
lines changed

7 files changed

+219
-100
lines changed

pkg/analyzer/lib/src/dart/resolver/scope.dart

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@ import 'package:analyzer/src/generated/engine.dart';
1414

1515
/// The scope defined by a block.
1616
class BlockScope {
17-
/// Return the elements that are declared directly in the given [block]. This
18-
/// does not include elements declared in nested blocks.
19-
static Iterable<Element> elementsInBlock(Block block) sync* {
20-
NodeList<Statement> statements = block.statements;
17+
/// Return the elements that are declared directly in the given [statements].
18+
/// This does not include elements declared in nested blocks.
19+
static Iterable<Element> elementsInStatements(
20+
List<Statement> statements,
21+
) sync* {
2122
int statementCount = statements.length;
2223
for (int i = 0; i < statementCount; i++) {
2324
Statement statement = statements[i];
25+
if (statement is LabeledStatement) {
26+
statement = (statement as LabeledStatement).statement;
27+
}
2428
if (statement is VariableDeclarationStatement) {
2529
NodeList<VariableDeclaration> variables = statement.variables.variables;
2630
int variableCount = variables.length;

pkg/analyzer/lib/src/generated/error_verifier.dart

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,10 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
359359

360360
@override
361361
void visitBlock(Block node) {
362-
_hiddenElements = HiddenElements(_hiddenElements, node);
363-
try {
362+
_withHiddenElements(node.statements, () {
364363
_duplicateDefinitionVerifier.checkStatements(node.statements);
365364
super.visitBlock(node);
366-
} finally {
367-
_hiddenElements = _hiddenElements.outerElements;
368-
}
365+
});
369366
}
370367

371368
@override
@@ -1111,14 +1108,18 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
11111108

11121109
@override
11131110
void visitSwitchCase(SwitchCase node) {
1114-
_duplicateDefinitionVerifier.checkStatements(node.statements);
1115-
super.visitSwitchCase(node);
1111+
_withHiddenElements(node.statements, () {
1112+
_duplicateDefinitionVerifier.checkStatements(node.statements);
1113+
super.visitSwitchCase(node);
1114+
});
11161115
}
11171116

11181117
@override
11191118
void visitSwitchDefault(SwitchDefault node) {
1120-
_duplicateDefinitionVerifier.checkStatements(node.statements);
1121-
super.visitSwitchDefault(node);
1119+
_withHiddenElements(node.statements, () {
1120+
_duplicateDefinitionVerifier.checkStatements(node.statements);
1121+
super.visitSwitchDefault(node);
1122+
});
11221123
}
11231124

11241125
@override
@@ -5124,6 +5125,15 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
51245125
}
51255126
}
51265127

5128+
void _withHiddenElements(List<Statement> statements, void Function() f) {
5129+
_hiddenElements = HiddenElements(_hiddenElements, statements);
5130+
try {
5131+
f();
5132+
} finally {
5133+
_hiddenElements = _hiddenElements.outerElements;
5134+
}
5135+
}
5136+
51275137
/// Return [FieldElement]s that are declared in the [ClassDeclaration] with
51285138
/// the given [constructor], but are not initialized.
51295139
static List<FieldElement> computeNotInitializedFields(
@@ -5212,9 +5222,9 @@ class HiddenElements {
52125222

52135223
/// Initialize a newly created set of hidden elements to include all of the
52145224
/// elements defined in the set of [outerElements] and all of the elements
5215-
/// declared in the given [block].
5216-
HiddenElements(this.outerElements, Block block) {
5217-
_initializeElements(block);
5225+
/// declared in the given [statements].
5226+
HiddenElements(this.outerElements, List<Statement> statements) {
5227+
_initializeElements(statements);
52185228
}
52195229

52205230
/// Return `true` if this set of elements contains the given [element].
@@ -5234,9 +5244,9 @@ class HiddenElements {
52345244
}
52355245

52365246
/// Initialize the list of elements that are not yet declared to be all of the
5237-
/// elements declared somewhere in the given [block].
5238-
void _initializeElements(Block block) {
5239-
_elements.addAll(BlockScope.elementsInBlock(block));
5247+
/// elements declared somewhere in the given [statements].
5248+
void _initializeElements(List<Statement> statements) {
5249+
_elements.addAll(BlockScope.elementsInStatements(statements));
52405250
}
52415251
}
52425252

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 31 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2154,16 +2154,9 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<void> {
21542154

21552155
@override
21562156
void visitBlock(Block node) {
2157-
Scope outerScope = nameScope;
2158-
try {
2159-
var enclosedScope = LocalScope(nameScope);
2160-
BlockScope.elementsInBlock(node).forEach(enclosedScope.add);
2161-
nameScope = enclosedScope;
2162-
_setNodeNameScope(node, nameScope);
2157+
_withDeclaredLocals(node, node.statements, () {
21632158
super.visitBlock(node);
2164-
} finally {
2165-
nameScope = outerScope;
2166-
}
2159+
});
21672160
}
21682161

21692162
@override
@@ -2296,11 +2289,7 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<void> {
22962289

22972290
@override
22982291
void visitDeclaredIdentifier(DeclaredIdentifier node) {
2299-
VariableElement element = node.declaredElement;
2300-
// TODO(scheglov) Do we need this?
2301-
if (element != null) {
2302-
_define(element);
2303-
}
2292+
_define(node.declaredElement);
23042293
super.visitDeclaredIdentifier(node);
23052294
}
23062295

@@ -2467,15 +2456,9 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<void> {
24672456

24682457
@override
24692458
void visitFunctionDeclaration(FunctionDeclaration node) {
2470-
ExecutableElement element = node.declaredElement;
2471-
// TODO(scheglov) Do we need this?
2472-
if (element != null &&
2473-
element.enclosingElement is! CompilationUnitElement) {
2474-
_define(element);
2475-
}
2476-
24772459
Scope outerScope = nameScope;
24782460
try {
2461+
var element = node.declaredElement;
24792462
nameScope = TypeParameterScope(
24802463
nameScope,
24812464
element.typeParameters,
@@ -2678,26 +2661,17 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<void> {
26782661
@override
26792662
void visitSwitchCase(SwitchCase node) {
26802663
node.expression.accept(this);
2681-
Scope outerNameScope = nameScope;
2682-
try {
2683-
nameScope = LocalScope(nameScope);
2684-
_setNodeNameScope(node, nameScope);
2664+
2665+
_withDeclaredLocals(node, node.statements, () {
26852666
node.statements.accept(this);
2686-
} finally {
2687-
nameScope = outerNameScope;
2688-
}
2667+
});
26892668
}
26902669

26912670
@override
26922671
void visitSwitchDefault(SwitchDefault node) {
2693-
Scope outerNameScope = nameScope;
2694-
try {
2695-
nameScope = LocalScope(nameScope);
2696-
_setNodeNameScope(node, nameScope);
2672+
_withDeclaredLocals(node, node.statements, () {
26972673
node.statements.accept(this);
2698-
} finally {
2699-
nameScope = outerNameScope;
2700-
}
2674+
});
27012675
}
27022676

27032677
@override
@@ -2728,13 +2702,9 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<void> {
27282702
@override
27292703
void visitVariableDeclaration(VariableDeclaration node) {
27302704
super.visitVariableDeclaration(node);
2731-
if (node.parent.parent is! TopLevelVariableDeclaration &&
2732-
node.parent.parent is! FieldDeclaration) {
2733-
// TODO(scheglov) Do we need this?
2734-
VariableElement element = node.declaredElement;
2735-
if (element != null) {
2736-
_define(element);
2737-
}
2705+
2706+
if (node.parent.parent is ForParts) {
2707+
_define(node.declaredElement);
27382708
}
27392709
}
27402710

@@ -2769,6 +2739,25 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<void> {
27692739
(nameScope as LocalScope).add(element);
27702740
}
27712741

2742+
void _withDeclaredLocals(
2743+
AstNode node,
2744+
List<Statement> statements,
2745+
void Function() f,
2746+
) {
2747+
var outerScope = nameScope;
2748+
try {
2749+
var enclosedScope = LocalScope(nameScope);
2750+
BlockScope.elementsInStatements(statements).forEach(enclosedScope.add);
2751+
2752+
nameScope = enclosedScope;
2753+
_setNodeNameScope(node, nameScope);
2754+
2755+
f();
2756+
} finally {
2757+
nameScope = outerScope;
2758+
}
2759+
}
2760+
27722761
/// Return the [Scope] to use while resolving inside the [node].
27732762
///
27742763
/// Not every node has the scope set, for example we set the scopes for

pkg/analyzer/test/generated/non_error_resolver_test.dart

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,27 +1324,6 @@ class A {
13241324
''');
13251325
}
13261326

1327-
test_for_in_scope() async {
1328-
await assertNoErrorsInCode('''
1329-
main() {
1330-
List<List<int>> x = [[1]];
1331-
for (int x in x.first) {
1332-
print(x.isEven);
1333-
}
1334-
}
1335-
''');
1336-
}
1337-
1338-
test_forEach_genericFunctionType() async {
1339-
await assertNoErrorsInCode(r'''
1340-
main() {
1341-
for (Null Function<T>(T, Null) e in <dynamic>[]) {
1342-
e;
1343-
}
1344-
}
1345-
''');
1346-
}
1347-
13481327
test_functionDeclaration_scope_returnType() async {
13491328
await assertNoErrorsInCode('''
13501329
int f(int) { return 0; }

pkg/analyzer/test/generated/resolver_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,6 @@ int f(num n) {
350350
]);
351351
}
352352

353-
// @failingTest
354353
test_for() async {
355354
await assertErrorsInCode(r'''
356355
int f(List<int> list) {

pkg/analyzer/test/src/dart/resolution/for_statement_test.dart

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'package:analyzer/src/error/codes.dart';
6-
import 'package:test/test.dart';
5+
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
76
import 'package:test_reflective_loader/test_reflective_loader.dart';
87

98
import 'driver_resolution.dart';
@@ -15,28 +14,67 @@ main() {
1514
});
1615
}
1716

17+
/// TODO(scheglov) Move other for-in tests here.
1818
@reflectiveTest
1919
class ForEachStatementResolutionTest extends DriverResolutionTest {
20-
test_importPrefix_asIterable() async {
21-
// TODO(scheglov) Remove this test (already tested as import prefix).
22-
// TODO(scheglov) Move other for-in tests here.
20+
test_iterable_missing() async {
2321
await assertErrorsInCode(r'''
24-
import 'dart:async' as p;
25-
26-
main() {
27-
for (var x in p) {}
22+
void f() {
23+
for (var v in) {
24+
v;
25+
}
2826
}
2927
''', [
30-
error(HintCode.UNUSED_LOCAL_VARIABLE, 47, 1),
31-
error(CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, 52, 1),
28+
error(ParserErrorCode.MISSING_IDENTIFIER, 26, 1),
3229
]);
3330

34-
var xRef = findNode.simple('x in');
35-
expect(xRef.staticElement, isNotNull);
31+
assertType(findElement.localVar('v').type, 'dynamic');
32+
assertType(findNode.simple('v;'), 'dynamic');
33+
}
34+
35+
/// Test that the parameter `x` is in the scope of the iterable.
36+
/// But the declared identifier `x` is in the scope of the body.
37+
test_scope() async {
38+
await assertNoErrorsInCode('''
39+
void f(List<List<int>> x) {
40+
for (int x in x.first) {
41+
x.isEven;
42+
}
43+
}
44+
''');
45+
46+
assertElement(
47+
findNode.simple('x) {'),
48+
findElement.parameter('x'),
49+
);
50+
51+
assertElement(
52+
findNode.simple('x.isEven'),
53+
findElement.localVar('x'),
54+
);
55+
}
56+
57+
test_type_genericFunctionType() async {
58+
await assertNoErrorsInCode(r'''
59+
void f() {
60+
for (Null Function<T>(T, Null) e in <dynamic>[]) {
61+
e;
62+
}
63+
}
64+
''');
65+
}
66+
67+
test_type_inferred() async {
68+
await assertNoErrorsInCode(r'''
69+
void f(List<int> a) {
70+
for (var v in a) {
71+
v;
72+
}
73+
}
74+
''');
3675

37-
var pRef = findNode.simple('p) {}');
38-
assertElement(pRef, findElement.prefix('p'));
39-
assertTypeDynamic(pRef);
76+
assertType(findElement.localVar('v').type, 'int');
77+
assertType(findNode.simple('v;'), 'int');
4078
}
4179
}
4280

0 commit comments

Comments
 (0)