Skip to content

Commit

Permalink
Augment. Issue 55324. Recover from missing ';' in 'import augment'.
Browse files Browse the repository at this point in the history
Bug: #55324
Change-Id: I7365a45718455d69985a968c683bcf6dd74f9505
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360504
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
  • Loading branch information
scheglov authored and Commit Queue committed Apr 1, 2024
1 parent dc26b30 commit 71e5a6b
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 28 deletions.
69 changes: 41 additions & 28 deletions pkg/analyzer/lib/src/fasta/ast_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5251,34 +5251,47 @@ class AstBuilder extends StackListener {
var prefix = pop(NullValues.Prefix) as SimpleIdentifierImpl?;
var configurations = pop() as List<ConfigurationImpl>?;

final directive = directives.last as ImportDirectiveImpl;

// TODO(scheglov): This code would be easier if we used one object.
var mergedAsKeyword = directive.asKeyword;
var mergedPrefix = directive.prefix;
if (directive.asKeyword == null && asKeyword != null) {
mergedAsKeyword = asKeyword;
mergedPrefix = prefix;
}

directives.last = ImportDirectiveImpl(
comment: directive.documentationComment,
metadata: directive.metadata,
importKeyword: directive.importKeyword,
uri: directive.uri,
configurations: [
...directive.configurations,
...?configurations,
],
deferredKeyword: directive.deferredKeyword ?? deferredKeyword,
asKeyword: mergedAsKeyword,
prefix: mergedPrefix,
combinators: [
...directive.combinators,
...?combinators,
],
semicolon: semicolon ?? directive.semicolon,
);
final directive = directives.last;
switch (directive) {
case AugmentationImportDirectiveImpl():
directives.last = AugmentationImportDirectiveImpl(
comment: directive.documentationComment,
metadata: directive.metadata,
importKeyword: directive.importKeyword,
augmentKeyword: directive.augmentKeyword,
uri: directive.uri,
semicolon: semicolon ?? directive.semicolon,
);
case ImportDirectiveImpl():
// TODO(scheglov): This code would be easier if we used one object.
var mergedAsKeyword = directive.asKeyword;
var mergedPrefix = directive.prefix;
if (directive.asKeyword == null && asKeyword != null) {
mergedAsKeyword = asKeyword;
mergedPrefix = prefix;
}

directives.last = ImportDirectiveImpl(
comment: directive.documentationComment,
metadata: directive.metadata,
importKeyword: directive.importKeyword,
uri: directive.uri,
configurations: [
...directive.configurations,
...?configurations,
],
deferredKeyword: directive.deferredKeyword ?? deferredKeyword,
asKeyword: mergedAsKeyword,
prefix: mergedPrefix,
combinators: [
...directive.combinators,
...?combinators,
],
semicolon: semicolon ?? directive.semicolon,
);
default:
throw UnimplementedError('${directive.runtimeType}');
}
}

@override
Expand Down
3 changes: 3 additions & 0 deletions pkg/analyzer/lib/src/test_utilities/find_node.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class FindNode {

AssignmentExpression get singleAssignmentExpression => _single();

AugmentationImportDirective get singleAugmentationImportDirective =>
_single();

AwaitExpression get singleAwaitExpression => _single();

BinaryExpression get singleBinaryExpression => _single();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// 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:test_reflective_loader/test_reflective_loader.dart';

import '../../diagnostics/parser_diagnostics.dart';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(AugmentationImportDirectiveParserTest);
});
}

@reflectiveTest
class AugmentationImportDirectiveParserTest extends ParserDiagnosticsTest {
test_it() {
final parseResult = parseStringWithErrors(r'''
import augment 'a.dart';
''');
parseResult.assertNoErrors();

final node = parseResult.findNode.singleAugmentationImportDirective;
assertParsedNodeText(node, r'''
AugmentationImportDirective
importKeyword: import
augmentKeyword: augment
uri: SimpleStringLiteral
literal: 'a.dart'
semicolon: ;
''');
}

test_noSemicolon() {
final parseResult = parseStringWithErrors(r'''
import augment 'a.dart'
''');
parseResult.assertErrors([
error(ParserErrorCode.EXPECTED_TOKEN, 15, 8),
]);

final node = parseResult.findNode.singleAugmentationImportDirective;
assertParsedNodeText(node, r'''
AugmentationImportDirective
importKeyword: import
augmentKeyword: augment
uri: SimpleStringLiteral
literal: 'a.dart'
semicolon: ; <synthetic>
''');
}

test_noUri_hasSemicolon() {
final parseResult = parseStringWithErrors(r'''
import augment ;
''');
parseResult.assertErrors([
error(ParserErrorCode.EXPECTED_STRING_LITERAL, 15, 1),
]);

final node = parseResult.findNode.singleAugmentationImportDirective;
assertParsedNodeText(node, r'''
AugmentationImportDirective
importKeyword: import
augmentKeyword: augment
uri: SimpleStringLiteral
literal: "" <synthetic>
semicolon: ;
''');
}

test_noUri_noSemicolon() {
final parseResult = parseStringWithErrors(r'''
import augment
''');
parseResult.assertErrors([
error(ParserErrorCode.EXPECTED_TOKEN, 7, 7),
error(ParserErrorCode.EXPECTED_STRING_LITERAL, 15, 0),
]);

final node = parseResult.findNode.singleAugmentationImportDirective;
assertParsedNodeText(node, r'''
AugmentationImportDirective
importKeyword: import
augmentKeyword: augment
uri: SimpleStringLiteral
literal: "" <synthetic>
semicolon: ; <synthetic>
''');
}
}
88 changes: 88 additions & 0 deletions pkg/analyzer/test/src/dart/parser/import_directive_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// 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:test_reflective_loader/test_reflective_loader.dart';

import '../../diagnostics/parser_diagnostics.dart';

main() {
defineReflectiveSuite(() {
defineReflectiveTests(ImportDirectiveParserTest);
});
}

@reflectiveTest
class ImportDirectiveParserTest extends ParserDiagnosticsTest {
test_it() {
final parseResult = parseStringWithErrors(r'''
import 'a.dart';
''');
parseResult.assertNoErrors();

final node = parseResult.findNode.singleImportDirective;
assertParsedNodeText(node, r'''
ImportDirective
importKeyword: import
uri: SimpleStringLiteral
literal: 'a.dart'
semicolon: ;
''');
}

test_noSemicolon() {
final parseResult = parseStringWithErrors(r'''
import 'a.dart'
''');
parseResult.assertErrors([
error(ParserErrorCode.EXPECTED_TOKEN, 7, 8),
]);

final node = parseResult.findNode.singleImportDirective;
assertParsedNodeText(node, r'''
ImportDirective
importKeyword: import
uri: SimpleStringLiteral
literal: 'a.dart'
semicolon: ; <synthetic>
''');
}

test_noUri_hasSemicolon() {
final parseResult = parseStringWithErrors(r'''
import ;
''');
parseResult.assertErrors([
error(ParserErrorCode.EXPECTED_STRING_LITERAL, 7, 1),
]);

final node = parseResult.findNode.singleImportDirective;
assertParsedNodeText(node, r'''
ImportDirective
importKeyword: import
uri: SimpleStringLiteral
literal: "" <synthetic>
semicolon: ;
''');
}

test_noUri_noSemicolon() {
final parseResult = parseStringWithErrors(r'''
import
''');
parseResult.assertErrors([
error(ParserErrorCode.EXPECTED_TOKEN, 0, 6),
error(ParserErrorCode.EXPECTED_STRING_LITERAL, 7, 0),
]);

final node = parseResult.findNode.singleImportDirective;
assertParsedNodeText(node, r'''
ImportDirective
importKeyword: import
uri: SimpleStringLiteral
literal: "" <synthetic>
semicolon: ; <synthetic>
''');
}
}
5 changes: 5 additions & 0 deletions pkg/analyzer/test/src/dart/parser/test_all.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

import 'package:test_reflective_loader/test_reflective_loader.dart';

import 'augmentation_import_directive_test.dart'
as augmentation_import_directive;
import 'class_test.dart' as class_;
import 'doc_comment_test.dart' as doc_comment;
import 'extension_test.dart' as extension_;
import 'extension_type_test.dart' as extension_type;
import 'import_directive_test.dart' as import_directive;
import 'mixin_test.dart' as mixin_;
import 'top_level_function_test.dart' as top_level_function;
import 'top_level_variable_test.dart' as top_level_variable;
Expand All @@ -17,10 +20,12 @@ import 'variable_declaration_statement_test.dart'
/// Utility for manually running all tests.
main() {
defineReflectiveSuite(() {
augmentation_import_directive.main();
class_.main();
doc_comment.main();
extension_.main();
extension_type.main();
import_directive.main();
mixin_.main();
top_level_function.main();
top_level_variable.main();
Expand Down

0 comments on commit 71e5a6b

Please sign in to comment.