Skip to content

Commit

Permalink
Recover from exension type declarations with no representation field
Browse files Browse the repository at this point in the history
Change-Id: I2fdd0c281ba8a8458248d00b91a0cb1abfed02da
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/331749
Commit-Queue: Brian Wilkerson <[email protected]>
Reviewed-by: Konstantin Shcheglov <[email protected]>
  • Loading branch information
bwilkerson authored and Commit Queue committed Oct 24, 2023
1 parent 9542aa4 commit 3659b3e
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ suggestions
''');
}

@FailingTest(reason: 'The AstBuilder drops the incomplete extension type')
Future<void> test_afterType_beforeEof() async {
await computeSuggestions('''
extension type ^
Expand Down
35 changes: 25 additions & 10 deletions pkg/analyzer/lib/src/fasta/ast_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1634,23 +1634,38 @@ class AstBuilder extends StackListener {
Token typeKeyword, Token endToken) {
final implementsClause =
pop(NullValues.IdentifierList) as ImplementsClauseImpl?;
final representation = pop(const NullValue<RepresentationDeclarationImpl>())
var representation = pop(const NullValue<RepresentationDeclarationImpl>())
as RepresentationDeclarationImpl?;
final constKeyword = pop() as Token?;

if (enableInlineClass) {
final builder = _classLikeBuilder as _ExtensionTypeDeclarationBuilder;
if (representation != null) {
// TODO(scheglov): Handle missing primary constructor.
declarations.add(
builder.build(
typeKeyword: typeKeyword,
constKeyword: constKeyword,
representation: representation,
implementsClause: implementsClause,
),
if (representation == null) {
var leftParenthesis = parser.rewriter.insertParens(builder.name, true);
var typeName = leftParenthesis.next!;
var rightParenthesis = leftParenthesis.endGroup!;
var fieldName = parser.rewriter.insertSyntheticIdentifier(typeName);
representation = RepresentationDeclarationImpl(
constructorName: null,
leftParenthesis: leftParenthesis,
fieldMetadata: [],
fieldType: NamedTypeImpl(
importPrefix: null,
name2: typeName,
question: null,
typeArguments: null),
fieldName: fieldName,
rightParenthesis: rightParenthesis,
);
}
declarations.add(
builder.build(
typeKeyword: typeKeyword,
constKeyword: constKeyword,
representation: representation,
implementsClause: implementsClause,
),
);
} else {
_reportFeatureNotEnabled(
feature: ExperimentalFeatures.inline_class,
Expand Down
4 changes: 4 additions & 0 deletions pkg/analyzer/lib/src/test_utilities/find_node.dart
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,10 @@ class FindNode {
return _node(search, (n) => n is ExtensionOverride);
}

ExtensionTypeDeclaration extensionTypeDeclaration(String search) {
return _node(search, (n) => n is ExtensionTypeDeclaration);
}

FieldDeclaration fieldDeclaration(String search) {
return _node(search, (n) => n is FieldDeclaration);
}
Expand Down
27 changes: 27 additions & 0 deletions pkg/analyzer/test/src/dart/parser/extension_type_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,33 @@ ExtensionTypeDeclaration
''');
}

void test_primaryConstructor_missing() {
var parseResult = parseStringWithErrors(r'''
extension type E {}
''');
parseResult.assertErrors(
[error(ParserErrorCode.MISSING_PRIMARY_CONSTRUCTOR, 15, 1)]);

final node = parseResult.findNode.extensionTypeDeclaration('E');
assertParsedNodeText(
node,
r'''
ExtensionTypeDeclaration
extensionKeyword: extension @0
typeKeyword: type @10
name: E @15
representation: RepresentationDeclaration
leftParenthesis: ( @17 <synthetic>
fieldType: NamedType
name: <empty> @17 <synthetic>
fieldName: <empty> @17 <synthetic>
rightParenthesis: ) @17 <synthetic>
leftBracket: { @17
rightBracket: } @18
''',
withOffsets: true);
}

test_primaryConstructor_named() {
final parseResult = parseStringWithErrors(r'''
extension type A.named(int it) {}
Expand Down
13 changes: 12 additions & 1 deletion pkg/analyzer/test/verify_docs_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ class SnippetTester {
SnippetTester._(
this.provider, this.docFolder, this.snippetDirPath, this.snippetPath);

/// Return `true` if the given error is a diagnostic produced by a lint that
/// is allowed to occur in documentation.
bool isAllowedLint(AnalysisError error) {
var errorCode = error.errorCode;
return errorCode is LintCode &&
errorCode.name == 'non_constant_identifier_names' &&
error.message.contains("'test_");
}

Future<void> verify() async {
await verifyFolder(docFolder);
}
Expand Down Expand Up @@ -128,8 +137,10 @@ $snippet
if (results is ErrorsResult) {
Iterable<AnalysisError> errors = results.errors.where((error) {
ErrorCode errorCode = error.errorCode;
// TODO(brianwilkerson)
return errorCode != WarningCode.UNUSED_IMPORT &&
errorCode != HintCode.UNUSED_LOCAL_VARIABLE;
errorCode != HintCode.UNUSED_LOCAL_VARIABLE &&
!isAllowedLint(error);
});
if (errors.isNotEmpty) {
String filePath =
Expand Down

0 comments on commit 3659b3e

Please sign in to comment.