Skip to content

Commit dc0aae5

Browse files
danrubelcommit-bot@chromium.org
danrubel
authored andcommitted
Improve super initializer recovery
This CL addresses one of the issues in #34041 by fixing an AstBuilder crash and improving recovery of super constructor calls in a constructor initializer list. In addition, this adds a TestDescriptor adjustValidUnitBeforeComparison field to support the new recovery tests. Change-Id: I9e687aed34ea293700bd45d7c13ce36e83a00a05 Reviewed-on: https://dart-review.googlesource.com/73286 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Dan Rubel <[email protected]>
1 parent 1699499 commit dc0aae5

File tree

7 files changed

+136
-7
lines changed

7 files changed

+136
-7
lines changed

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,12 +595,15 @@ class AstBuilder extends StackListener {
595595
initializerObject.operator,
596596
initializerObject.methodName,
597597
initializerObject.argumentList));
598-
} else {
598+
} else if (target is ThisExpression) {
599599
initializers.add(ast.redirectingConstructorInvocation(
600-
(target as ThisExpression).thisKeyword,
600+
target.thisKeyword,
601601
initializerObject.operator,
602602
initializerObject.methodName,
603603
initializerObject.argumentList));
604+
} else {
605+
// Invalid initializer
606+
// TODO(danrubel): Capture this in the AST.
604607
}
605608
} else if (initializerObject is AssignmentExpression) {
606609
Token thisKeyword;

pkg/analyzer/test/generated/parser_fasta_test.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ class ErrorParserTest_Fasta extends FastaParserTestCase
9191
]);
9292
}
9393
}
94+
95+
void test_invalidOperatorAfterSuper_constructorInitializer2() {
96+
parseCompilationUnit('class C { C() : super?.namedConstructor(); }',
97+
errors: [
98+
expectedError(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, 21, 2)
99+
]);
100+
}
94101
}
95102

96103
/**
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import 'package:analyzer/analyzer.dart';
2+
import 'package:analyzer/dart/ast/token.dart';
3+
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
4+
5+
import 'partial_code_support.dart';
6+
7+
main() {
8+
new ConstructorTest().buildAll();
9+
}
10+
11+
class ConstructorTest extends PartialCodeTest {
12+
buildAll() {
13+
buildTests(
14+
'constructor',
15+
[
16+
new TestDescriptor(
17+
'colon',
18+
'C() :',
19+
[
20+
ParserErrorCode.MISSING_INITIALIZER,
21+
ParserErrorCode.MISSING_FUNCTION_BODY
22+
],
23+
'C() {}',
24+
adjustValidUnitBeforeComparison: setSeparator,
25+
failing: ['methodNonVoid', 'getter', 'setter'],
26+
),
27+
new TestDescriptor(
28+
'colon_block',
29+
'C() : {}',
30+
[ParserErrorCode.MISSING_INITIALIZER],
31+
'C() {}',
32+
adjustValidUnitBeforeComparison: setSeparator,
33+
),
34+
new TestDescriptor(
35+
'colon_semicolon',
36+
'C() : ;',
37+
[ParserErrorCode.MISSING_INITIALIZER],
38+
'C();',
39+
adjustValidUnitBeforeComparison: setSeparator,
40+
),
41+
new TestDescriptor(
42+
'super',
43+
'C() : super',
44+
[
45+
ParserErrorCode.EXPECTED_TOKEN,
46+
ParserErrorCode.MISSING_FUNCTION_BODY
47+
],
48+
'C() : super() {}',
49+
),
50+
new TestDescriptor(
51+
'super_dot',
52+
'C() : super.',
53+
[
54+
ParserErrorCode.EXPECTED_TOKEN,
55+
ParserErrorCode.MISSING_IDENTIFIER,
56+
ParserErrorCode.MISSING_FUNCTION_BODY
57+
],
58+
'C() : super._s_() {}',
59+
failing: ['fieldConst', 'methodNonVoid', 'getter', 'setter'],
60+
),
61+
new TestDescriptor(
62+
'super_qdot',
63+
'C() : super?.',
64+
[
65+
ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
66+
ParserErrorCode.EXPECTED_TOKEN,
67+
ParserErrorCode.MISSING_FUNCTION_BODY,
68+
],
69+
'C() : super?._s_() {}',
70+
expectedErrorsInValidCode: [
71+
ParserErrorCode.INVALID_OPERATOR_FOR_SUPER
72+
],
73+
failing: ['methodNonVoid', 'getter', 'setter'],
74+
),
75+
],
76+
PartialCodeTest.classMemberSuffixes,
77+
head: 'class C {',
78+
tail: '}');
79+
}
80+
81+
CompilationUnit setSeparator(CompilationUnit unit) {
82+
ClassDeclaration declaration = unit.declarations[0];
83+
ConstructorDeclaration member = declaration.members[0];
84+
member.separator =
85+
new Token(TokenType.COLON, member.parameters.endToken.charOffset + 1);
86+
return unit;
87+
}
88+
}

pkg/analyzer/test/src/fasta/recovery/partial_code/partial_code_support.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
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/analyzer.dart';
56
import 'package:analyzer/error/error.dart';
67
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
78
import 'package:test/test.dart';
89

910
import '../../../../generated/test_support.dart';
1011
import '../recovery_test_support.dart';
1112

13+
typedef CompilationUnit AdjustValidUnitBeforeComparison(CompilationUnit unit);
14+
1215
/**
1316
* A base class that adds support for tests that test how well the parser
1417
* recovers when the user has entered an incomplete (but otherwise correct)
@@ -198,6 +201,8 @@ abstract class PartialCodeTest extends AbstractRecoveryTest {
198201
try {
199202
testRecovery(
200203
invalid.toString(), expectedInvalidCodeErrors, valid.toString(),
204+
adjustValidUnitBeforeComparison:
205+
descriptor.adjustValidUnitBeforeComparison,
201206
expectedErrorsInValidCode: expectedValidCodeErrors);
202207
failed = true;
203208
} catch (e) {
@@ -209,6 +214,8 @@ abstract class PartialCodeTest extends AbstractRecoveryTest {
209214
} else {
210215
testRecovery(
211216
invalid.toString(), expectedInvalidCodeErrors, valid.toString(),
217+
adjustValidUnitBeforeComparison:
218+
descriptor.adjustValidUnitBeforeComparison,
212219
expectedErrorsInValidCode: expectedValidCodeErrors);
213220
}
214221
});
@@ -256,11 +263,20 @@ class TestDescriptor {
256263
*/
257264
final List<String> failing;
258265

266+
/**
267+
* A function that modifies the valid compilation unit before it is compared
268+
* with the invalid compilation unit, or `null` if no modification needed.
269+
*/
270+
AdjustValidUnitBeforeComparison adjustValidUnitBeforeComparison;
271+
259272
/**
260273
* Initialize a newly created test descriptor.
261274
*/
262275
TestDescriptor(this.name, this.invalid, this.errorCodes, this.valid,
263-
{this.allFailing: false, this.failing, this.expectedErrorsInValidCode});
276+
{this.allFailing: false,
277+
this.failing,
278+
this.expectedErrorsInValidCode,
279+
this.adjustValidUnitBeforeComparison});
264280
}
265281

266282
/**

pkg/analyzer/test/src/fasta/recovery/partial_code/test_all.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'annotation_test.dart' as annotation;
88
import 'assert_statement_test.dart' as assert_statement;
99
import 'break_statement_test.dart' as break_statement;
1010
import 'class_declaration_test.dart' as class_declaration;
11+
import 'constructor_test.dart' as constructor;
1112
import 'mixin_declaration_test.dart' as mixin_declaration;
1213
import 'continue_statement_test.dart' as continue_statement;
1314
import 'do_statement_test.dart' as do_statement;
@@ -39,6 +40,7 @@ main() {
3940
assert_statement.main();
4041
break_statement.main();
4142
class_declaration.main();
43+
constructor.main();
4244
continue_statement.main();
4345
do_statement.main();
4446
enum_declaration.main();

pkg/front_end/lib/src/fasta/parser/parser.dart

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2491,9 +2491,23 @@ class Parser {
24912491
next = token.next;
24922492
}
24932493
if (!optional('(', next)) {
2494-
reportRecoverableError(
2495-
token, fasta.templateExpectedAfterButGot.withArguments('('));
2496-
rewriter.insertParens(token, false);
2494+
// Recovery
2495+
if (optional('?.', next)) {
2496+
// An error for `super?.` is reported in parseSuperExpression.
2497+
token = next;
2498+
next = token.next;
2499+
if (!next.isIdentifier) {
2500+
// Insert a synthetic identifier but don't report another error.
2501+
next = rewriter.insertSyntheticIdentifier(token);
2502+
}
2503+
token = next;
2504+
next = token.next;
2505+
}
2506+
if (!optional('(', next)) {
2507+
reportRecoverableError(
2508+
next, fasta.templateExpectedAfterButGot.withArguments('('));
2509+
rewriter.insertParens(token, false);
2510+
}
24972511
}
24982512
return parseInitializerExpressionRest(start);
24992513
}

tests/language_2/language_2_dartdevc.status

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ string_split_test: CompileTimeError
169169
string_supertype_checked_test: CompileTimeError
170170
super_bound_closure_test/none: CompileTimeError
171171
super_call4_test/01: MissingCompileTimeError
172-
super_conditional_operator_test/01: Crash # Issue 34041
173172
super_no_such_method4_test/01: MissingCompileTimeError # Requires Dart 2 semantics. See http://dartbug.com/33380.
174173
super_no_such_method5_test/01: MissingCompileTimeError # Requires Dart 2 semantics. See http://dartbug.com/33380.
175174
super_operator_index5_test: RuntimeError # 33470

0 commit comments

Comments
 (0)