[analyzer] Dot shorthands: Avoid crashing with prefix and postfix operators.
When we evaluate the `target` for this `IndexExpression`, we don't cache the dot shorthand context which causes the analyzer to crash. Added a context push of the `target` (whose context is `UnknownType`) which allows the analyzer to error out without crashing. Passing co19 tests and unit tests. Bug: https://github.com/dart-lang/sdk/issues/59835 Change-Id: I6a19b3e92ed803a51d0cfd320df886a26a36b33d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/426289 Commit-Queue: Kallen Tu <kallentu@google.com> Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
@@ -1455,10 +1455,14 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
||||
if (node is IndexExpressionImpl) {
|
||||
var target = node.target;
|
||||
if (target != null) {
|
||||
analyzeExpression(
|
||||
target,
|
||||
SharedTypeSchemaView(UnknownInferredType.instance),
|
||||
);
|
||||
if (isDotShorthand(node)) {
|
||||
// Recovery.
|
||||
// It's a compile-time error to use postfix or prefix operators with
|
||||
// dot shorthands. We provide an unknown type since this shouldn't be
|
||||
// valid code, but we want to prevent any crashes.
|
||||
pushDotShorthandContext(target, operations.unknownType);
|
||||
}
|
||||
analyzeExpression(target, operations.unknownType);
|
||||
popRewrite();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
@@ -566,6 +567,40 @@ DotShorthandConstructorInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
test_postfixOperator() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class C {}
|
||||
|
||||
void main() {
|
||||
C c = .new()++;
|
||||
print(c);
|
||||
}
|
||||
''',
|
||||
[
|
||||
error(CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_INVOCATION, 35, 3),
|
||||
error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 40, 2),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_prefixOperator() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class C {}
|
||||
|
||||
void main() {
|
||||
C c = ++.new();
|
||||
print(c);
|
||||
}
|
||||
''',
|
||||
[
|
||||
error(CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_INVOCATION, 37, 3),
|
||||
error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 41, 1),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_requiredParameters_missing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
@@ -619,6 +620,48 @@ DotShorthandInvocation
|
||||
''');
|
||||
}
|
||||
|
||||
test_postfixOperator() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class C {
|
||||
static C member() => C(1);
|
||||
int x;
|
||||
C(this.x);
|
||||
}
|
||||
|
||||
void main() {
|
||||
C c = .member()++;
|
||||
print(c);
|
||||
}
|
||||
''',
|
||||
[
|
||||
error(CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_INVOCATION, 87, 6),
|
||||
error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 95, 2),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_prefixOperator() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class C {
|
||||
static C member() => C(1);
|
||||
int x;
|
||||
C(this.x);
|
||||
}
|
||||
|
||||
void main() {
|
||||
C c = ++.member();
|
||||
print(c);
|
||||
}
|
||||
''',
|
||||
[
|
||||
error(CompileTimeErrorCode.DOT_SHORTHAND_UNDEFINED_INVOCATION, 89, 6),
|
||||
error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 96, 1),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_requiredParameters_missing() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
@@ -563,6 +564,48 @@ DotShorthandPropertyAccess
|
||||
''');
|
||||
}
|
||||
|
||||
test_postfixOperator() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class C {
|
||||
static C get member => C(1);
|
||||
int x;
|
||||
C(this.x);
|
||||
}
|
||||
|
||||
void main() {
|
||||
C c = .member++;
|
||||
print(c);
|
||||
}
|
||||
''',
|
||||
[
|
||||
error(CompileTimeErrorCode.DOT_SHORTHAND_MISSING_CONTEXT, 88, 7),
|
||||
error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 95, 2),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_prefixOperator() async {
|
||||
await assertErrorsInCode(
|
||||
r'''
|
||||
class C {
|
||||
static C get member => C(1);
|
||||
int x;
|
||||
C(this.x);
|
||||
}
|
||||
|
||||
void main() {
|
||||
C c = ++.member;
|
||||
print(c);
|
||||
}
|
||||
''',
|
||||
[
|
||||
error(CompileTimeErrorCode.DOT_SHORTHAND_MISSING_CONTEXT, 90, 7),
|
||||
error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 91, 6),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
test_tearOff_constructor() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
class C1 {
|
||||
|
||||
Reference in New Issue
Block a user