Skip to content

Commit d9ce879

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Track if location has access to this.
We will need this also to implement '16.35 Lexical Lookup' from the spec. Change-Id: I3b77c4a016fd54771b07957d522074aeb8dd1938 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158802 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 5282384 commit d9ce879

File tree

3 files changed

+82
-53
lines changed

3 files changed

+82
-53
lines changed

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

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import 'package:analyzer/src/generated/engine.dart';
3939
import 'package:analyzer/src/generated/java_engine.dart';
4040
import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
4141
import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary;
42+
import 'package:analyzer/src/generated/this_access_tracker.dart';
4243
import 'package:analyzer/src/task/strong/checker.dart';
4344
import 'package:meta/meta.dart';
4445

@@ -194,6 +195,9 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
194195
/// in the scope of an extension.
195196
ExtensionElement _enclosingExtension;
196197

198+
/// The helper for tracking if the current location has access to `this`.
199+
final ThisAccessTracker _thisAccessTracker = ThisAccessTracker.unit();
200+
197201
/// The context of the method or function that we are currently visiting, or
198202
/// `null` if we are not inside a method or function.
199203
EnclosingExecutableContext _enclosingExecutable =
@@ -365,6 +369,16 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
365369
});
366370
}
367371

372+
@override
373+
void visitBlockFunctionBody(BlockFunctionBody node) {
374+
_thisAccessTracker.enterFunctionBody(node);
375+
try {
376+
super.visitBlockFunctionBody(node);
377+
} finally {
378+
_thisAccessTracker.exitFunctionBody(node);
379+
}
380+
}
381+
368382
@override
369383
void visitBreakStatement(BreakStatement node) {
370384
SimpleIdentifier labelNode = node.label;
@@ -546,8 +560,13 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
546560

547561
@override
548562
void visitExpressionFunctionBody(ExpressionFunctionBody node) {
549-
_returnTypeVerifier.verifyExpressionFunctionBody(node);
550-
super.visitExpressionFunctionBody(node);
563+
_thisAccessTracker.enterFunctionBody(node);
564+
try {
565+
_returnTypeVerifier.verifyExpressionFunctionBody(node);
566+
super.visitExpressionFunctionBody(node);
567+
} finally {
568+
_thisAccessTracker.exitFunctionBody(node);
569+
}
551570
}
552571

553572
@override
@@ -574,6 +593,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
574593
@override
575594
void visitFieldDeclaration(FieldDeclaration node) {
576595
var fields = node.fields;
596+
_thisAccessTracker.enterFieldDeclaration(node);
577597
_isInStaticVariableDeclaration = node.isStatic;
578598
_isInInstanceNotLateVariableDeclaration =
579599
!node.isStatic && !node.fields.isLate;
@@ -591,6 +611,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
591611
} finally {
592612
_isInStaticVariableDeclaration = false;
593613
_isInInstanceNotLateVariableDeclaration = false;
614+
_thisAccessTracker.exitFieldDeclaration(node);
594615
}
595616
}
596617

@@ -2976,7 +2997,7 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
29762997
///
29772998
/// See [CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS].
29782999
void _checkForInvalidReferenceToThis(ThisExpression expression) {
2979-
if (!_isThisInValidContext(expression)) {
3000+
if (!_thisAccessTracker.hasAccess) {
29803001
_errorReporter.reportErrorForNode(
29813002
CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS, expression);
29823003
}
@@ -5161,29 +5182,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void> {
51615182
return false;
51625183
}
51635184

5164-
/// Return `true` if the given 'this' [expression] is in a valid context.
5165-
bool _isThisInValidContext(ThisExpression expression) {
5166-
for (AstNode node = expression.parent; node != null; node = node.parent) {
5167-
if (node is CompilationUnit) {
5168-
return false;
5169-
} else if (node is ConstructorDeclaration) {
5170-
return node.factoryKeyword == null;
5171-
} else if (node is ConstructorInitializer) {
5172-
return false;
5173-
} else if (node is MethodDeclaration) {
5174-
return !node.isStatic;
5175-
} else if (node is FieldDeclaration) {
5176-
if (node.fields.isLate &&
5177-
(node.parent is ClassDeclaration ||
5178-
node.parent is MixinDeclaration)) {
5179-
return true;
5180-
}
5181-
// Continue; a non-late variable may still occur in a valid context.
5182-
}
5183-
}
5184-
return false;
5185-
}
5186-
51875185
/// Return `true` if the given [identifier] is in a location where it is
51885186
/// allowed to resolve to a static member of a supertype.
51895187
bool _isUnqualifiedReferenceToNonLocalStaticMemberAllowed(
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analyzer/dart/ast/ast.dart';
6+
7+
/// Tracks if the current location has access to `this`.
8+
///
9+
/// The current instance (and hence its members) can only be accessed at
10+
/// specific locations in a class: We say that a location `l` has access to
11+
/// `this` iff `l` is inside the body of a declaration of an instance member,
12+
/// or a generative constructor, or in the initializing expression of a `late`
13+
/// instance variable declaration.
14+
class ThisAccessTracker {
15+
final List<bool> _stack = [];
16+
17+
ThisAccessTracker.unit() {
18+
_stack.add(false);
19+
}
20+
21+
bool get hasAccess => _stack.last;
22+
23+
void enterFieldDeclaration(FieldDeclaration node) {
24+
_stack.add(!node.isStatic && node.fields.isLate);
25+
}
26+
27+
void enterFunctionBody(FunctionBody node) {
28+
var parent = node.parent;
29+
if (parent is ConstructorDeclaration) {
30+
_stack.add(parent.factoryKeyword == null);
31+
} else if (parent is MethodDeclaration) {
32+
_stack.add(!parent.isStatic);
33+
} else {
34+
_stack.add(_stack.last);
35+
}
36+
}
37+
38+
void exitFieldDeclaration(FieldDeclaration node) {
39+
_stack.removeLast();
40+
}
41+
42+
void exitFunctionBody(FunctionBody node) {
43+
_stack.removeLast();
44+
}
45+
}

pkg/analyzer/test/src/diagnostics/invalid_reference_to_this_test.dart

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ main() {
1616

1717
@reflectiveTest
1818
class InvalidReferenceToThisTest extends PubPackageResolutionTest {
19-
test_constructor_valid() async {
19+
test_class_constructor() async {
2020
await assertErrorsInCode(r'''
2121
class A {
2222
A() {
@@ -28,7 +28,7 @@ class A {
2828
]);
2929
}
3030

31-
test_factoryConstructor() async {
31+
test_class_factoryConstructor() async {
3232
await assertErrorsInCode(r'''
3333
class A {
3434
factory A() { return this; }
@@ -38,19 +38,17 @@ class A {
3838
]);
3939
}
4040

41-
test_instanceMethod_valid() async {
42-
await assertErrorsInCode(r'''
41+
test_class_instanceMethod() async {
42+
await assertNoErrorsInCode(r'''
4343
class A {
44-
m() {
45-
var v = this;
44+
void foo() {
45+
this;
4646
}
4747
}
48-
''', [
49-
error(HintCode.UNUSED_LOCAL_VARIABLE, 26, 1),
50-
]);
48+
''');
5149
}
5250

53-
test_instanceVariableInitializer_inConstructor() async {
51+
test_class_instanceVariableInitializer_inConstructor() async {
5452
await assertErrorsInCode(r'''
5553
class A {
5654
var f;
@@ -61,7 +59,7 @@ class A {
6159
]);
6260
}
6361

64-
test_instanceVariableInitializer_inDeclaration() async {
62+
test_class_instanceVariableInitializer_inDeclaration() async {
6563
await assertErrorsInCode(r'''
6664
class A {
6765
var f = this;
@@ -71,7 +69,7 @@ class A {
7169
]);
7270
}
7371

74-
test_staticMethod() async {
72+
test_class_staticMethod() async {
7573
await assertErrorsInCode(r'''
7674
class A {
7775
static m() { return this; }
@@ -81,7 +79,7 @@ class A {
8179
]);
8280
}
8381

84-
test_staticVariableInitializer() async {
82+
test_class_staticVariableInitializer() async {
8583
await assertErrorsInCode(r'''
8684
class A {
8785
static A f = this;
@@ -91,7 +89,7 @@ class A {
9189
]);
9290
}
9391

94-
test_superInitializer() async {
92+
test_class_superInitializer() async {
9593
await assertErrorsInCode(r'''
9694
class A {
9795
A(var x) {}
@@ -112,25 +110,13 @@ f() { return this; }
112110
]);
113111
}
114112

115-
test_variableInitializer() async {
113+
test_topLevelVariable() async {
116114
await assertErrorsInCode('''
117115
int x = this;
118116
''', [
119117
error(CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS, 8, 4),
120118
]);
121119
}
122-
123-
test_variableInitializer_inMethod_notLate() async {
124-
await assertErrorsInCode(r'''
125-
class A {
126-
f() {
127-
var r = this;
128-
}
129-
}
130-
''', [
131-
error(HintCode.UNUSED_LOCAL_VARIABLE, 26, 1),
132-
]);
133-
}
134120
}
135121

136122
@reflectiveTest

0 commit comments

Comments
 (0)