Skip to content

Commit 3659b3e

Browse files
bwilkersonCommit Queue
authored and
Commit Queue
committed
Recover from exension type declarations with no representation field
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]>
1 parent 9542aa4 commit 3659b3e

File tree

5 files changed

+68
-12
lines changed

5 files changed

+68
-12
lines changed

pkg/analysis_server/test/services/completion/dart/location/extension_type_declaration_test.dart

-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ suggestions
5252
''');
5353
}
5454

55-
@FailingTest(reason: 'The AstBuilder drops the incomplete extension type')
5655
Future<void> test_afterType_beforeEof() async {
5756
await computeSuggestions('''
5857
extension type ^

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

+25-10
Original file line numberDiff line numberDiff line change
@@ -1634,23 +1634,38 @@ class AstBuilder extends StackListener {
16341634
Token typeKeyword, Token endToken) {
16351635
final implementsClause =
16361636
pop(NullValues.IdentifierList) as ImplementsClauseImpl?;
1637-
final representation = pop(const NullValue<RepresentationDeclarationImpl>())
1637+
var representation = pop(const NullValue<RepresentationDeclarationImpl>())
16381638
as RepresentationDeclarationImpl?;
16391639
final constKeyword = pop() as Token?;
16401640

16411641
if (enableInlineClass) {
16421642
final builder = _classLikeBuilder as _ExtensionTypeDeclarationBuilder;
1643-
if (representation != null) {
1644-
// TODO(scheglov): Handle missing primary constructor.
1645-
declarations.add(
1646-
builder.build(
1647-
typeKeyword: typeKeyword,
1648-
constKeyword: constKeyword,
1649-
representation: representation,
1650-
implementsClause: implementsClause,
1651-
),
1643+
if (representation == null) {
1644+
var leftParenthesis = parser.rewriter.insertParens(builder.name, true);
1645+
var typeName = leftParenthesis.next!;
1646+
var rightParenthesis = leftParenthesis.endGroup!;
1647+
var fieldName = parser.rewriter.insertSyntheticIdentifier(typeName);
1648+
representation = RepresentationDeclarationImpl(
1649+
constructorName: null,
1650+
leftParenthesis: leftParenthesis,
1651+
fieldMetadata: [],
1652+
fieldType: NamedTypeImpl(
1653+
importPrefix: null,
1654+
name2: typeName,
1655+
question: null,
1656+
typeArguments: null),
1657+
fieldName: fieldName,
1658+
rightParenthesis: rightParenthesis,
16521659
);
16531660
}
1661+
declarations.add(
1662+
builder.build(
1663+
typeKeyword: typeKeyword,
1664+
constKeyword: constKeyword,
1665+
representation: representation,
1666+
implementsClause: implementsClause,
1667+
),
1668+
);
16541669
} else {
16551670
_reportFeatureNotEnabled(
16561671
feature: ExperimentalFeatures.inline_class,

pkg/analyzer/lib/src/test_utilities/find_node.dart

+4
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,10 @@ class FindNode {
391391
return _node(search, (n) => n is ExtensionOverride);
392392
}
393393

394+
ExtensionTypeDeclaration extensionTypeDeclaration(String search) {
395+
return _node(search, (n) => n is ExtensionTypeDeclaration);
396+
}
397+
394398
FieldDeclaration fieldDeclaration(String search) {
395399
return _node(search, (n) => n is FieldDeclaration);
396400
}

pkg/analyzer/test/src/dart/parser/extension_type_test.dart

+27
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,33 @@ ExtensionTypeDeclaration
778778
''');
779779
}
780780

781+
void test_primaryConstructor_missing() {
782+
var parseResult = parseStringWithErrors(r'''
783+
extension type E {}
784+
''');
785+
parseResult.assertErrors(
786+
[error(ParserErrorCode.MISSING_PRIMARY_CONSTRUCTOR, 15, 1)]);
787+
788+
final node = parseResult.findNode.extensionTypeDeclaration('E');
789+
assertParsedNodeText(
790+
node,
791+
r'''
792+
ExtensionTypeDeclaration
793+
extensionKeyword: extension @0
794+
typeKeyword: type @10
795+
name: E @15
796+
representation: RepresentationDeclaration
797+
leftParenthesis: ( @17 <synthetic>
798+
fieldType: NamedType
799+
name: <empty> @17 <synthetic>
800+
fieldName: <empty> @17 <synthetic>
801+
rightParenthesis: ) @17 <synthetic>
802+
leftBracket: { @17
803+
rightBracket: } @18
804+
''',
805+
withOffsets: true);
806+
}
807+
781808
test_primaryConstructor_named() {
782809
final parseResult = parseStringWithErrors(r'''
783810
extension type A.named(int it) {}

pkg/analyzer/test/verify_docs_test.dart

+12-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ class SnippetTester {
4343
SnippetTester._(
4444
this.provider, this.docFolder, this.snippetDirPath, this.snippetPath);
4545

46+
/// Return `true` if the given error is a diagnostic produced by a lint that
47+
/// is allowed to occur in documentation.
48+
bool isAllowedLint(AnalysisError error) {
49+
var errorCode = error.errorCode;
50+
return errorCode is LintCode &&
51+
errorCode.name == 'non_constant_identifier_names' &&
52+
error.message.contains("'test_");
53+
}
54+
4655
Future<void> verify() async {
4756
await verifyFolder(docFolder);
4857
}
@@ -128,8 +137,10 @@ $snippet
128137
if (results is ErrorsResult) {
129138
Iterable<AnalysisError> errors = results.errors.where((error) {
130139
ErrorCode errorCode = error.errorCode;
140+
// TODO(brianwilkerson)
131141
return errorCode != WarningCode.UNUSED_IMPORT &&
132-
errorCode != HintCode.UNUSED_LOCAL_VARIABLE;
142+
errorCode != HintCode.UNUSED_LOCAL_VARIABLE &&
143+
!isAllowedLint(error);
133144
});
134145
if (errors.isNotEmpty) {
135146
String filePath =

0 commit comments

Comments
 (0)