diff --git a/pkg/analysis_server/lib/src/services/correction/dart/bind_to_field.dart b/pkg/analysis_server/lib/src/services/correction/dart/bind_to_field.dart index 7bef682da9a..8dfc845cc9a 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/bind_to_field.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/bind_to_field.dart @@ -105,6 +105,8 @@ class BindToField extends ResolvedCorrectionProducer { ConstructorDeclaration() => false, FieldDeclaration() => false, MethodDeclaration() => member.name.lexeme == parameter.name?.lexeme, + // ignore: experimental_member_use + PrimaryConstructorBody() => false, }, )) { return; diff --git a/pkg/analysis_server/lib/src/services/correction/dart/create_method.dart b/pkg/analysis_server/lib/src/services/correction/dart/create_method.dart index 8c133279787..e55987412e6 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/create_method.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/create_method.dart @@ -160,6 +160,8 @@ class CreateMethod extends ResolvedCorrectionProducer { fields: VariableDeclarationList(:var isLate), ) => isStatic || !isLate, + // ignore: experimental_member_use + PrimaryConstructorBody() => false, }; } } else { diff --git a/pkg/analyzer/api.txt b/pkg/analyzer/api.txt index 4db2bcd1c88..3c0a052d9f9 100644 --- a/pkg/analyzer/api.txt +++ b/pkg/analyzer/api.txt @@ -247,6 +247,7 @@ package:analyzer/analysis_rule/rule_visitor_registry.dart: addPostfixExpression (method: void Function(AbstractAnalysisRule, AstVisitor)) addPrefixExpression (method: void Function(AbstractAnalysisRule, AstVisitor)) addPrefixedIdentifier (method: void Function(AbstractAnalysisRule, AstVisitor)) + addPrimaryConstructorBody (method: void Function(AbstractAnalysisRule, AstVisitor), experimental) addPrimaryConstructorDeclaration (method: void Function(AbstractAnalysisRule, AstVisitor), experimental) addPrimaryConstructorName (method: void Function(AbstractAnalysisRule, AstVisitor), experimental) addPropertyAccess (method: void Function(AbstractAnalysisRule, AstVisitor)) @@ -771,6 +772,7 @@ package:analyzer/dart/ast/ast.dart: visitPostfixExpression (method: R? Function(PostfixExpression)) visitPrefixExpression (method: R? Function(PrefixExpression)) visitPrefixedIdentifier (method: R? Function(PrefixedIdentifier)) + visitPrimaryConstructorBody (method: R? Function(PrimaryConstructorBody), experimental) visitPrimaryConstructorDeclaration (method: R? Function(PrimaryConstructorDeclaration), experimental) visitPrimaryConstructorName (method: R? Function(PrimaryConstructorName), experimental) visitPropertyAccess (method: R? Function(PropertyAccess)) @@ -893,7 +895,7 @@ package:analyzer/dart/ast/ast.dart: sealedKeyword (getter: Token?) typeParameters (getter: TypeParameterList?) withClause (getter: WithClause?) - ClassMember (class extends Object implements Declaration, sealed (immediate subtypes: ClassMemberImpl, ConstructorDeclaration, FieldDeclaration, MethodDeclaration)) + ClassMember (class extends Object implements Declaration, sealed (immediate subtypes: ClassMemberImpl, ConstructorDeclaration, FieldDeclaration, MethodDeclaration, PrimaryConstructorBody)) ClassNamePart (class extends Object implements AstNode, sealed (immediate subtypes: ClassNamePartImpl, NameWithTypeParameters, PrimaryConstructorDeclaration), experimental): typeName (getter: Token) typeParameters (getter: TypeParameterList?) @@ -1555,6 +1557,11 @@ package:analyzer/dart/ast/ast.dart: isDeferred (getter: bool) period (getter: Token) prefix (getter: SimpleIdentifier) + PrimaryConstructorBody (class extends Object implements ClassMember, experimental): + body (getter: FunctionBody) + colon (getter: Token?) + initializers (getter: NodeList) + thisKeyword (getter: Token) PrimaryConstructorDeclaration (class extends Object implements ClassNamePart, experimental): constKeyword (getter: Token?) constructorName (getter: PrimaryConstructorName?) @@ -2343,6 +2350,7 @@ package:analyzer/dart/ast/visitor.dart: visitPostfixExpression (method: R? Function(PostfixExpression)) visitPrefixExpression (method: R? Function(PrefixExpression)) visitPrefixedIdentifier (method: R? Function(PrefixedIdentifier)) + visitPrimaryConstructorBody (method: R? Function(PrimaryConstructorBody), experimental) visitPrimaryConstructorDeclaration (method: R? Function(PrimaryConstructorDeclaration), experimental) visitPrimaryConstructorName (method: R? Function(PrimaryConstructorName), experimental) visitPropertyAccess (method: R? Function(PropertyAccess)) @@ -2534,6 +2542,7 @@ package:analyzer/dart/ast/visitor.dart: visitPostfixExpression (method: R? Function(PostfixExpression)) visitPrefixExpression (method: R? Function(PrefixExpression)) visitPrefixedIdentifier (method: R? Function(PrefixedIdentifier)) + visitPrimaryConstructorBody (method: R? Function(PrimaryConstructorBody), experimental) visitPrimaryConstructorDeclaration (method: R? Function(PrimaryConstructorDeclaration), experimental) visitPrimaryConstructorName (method: R? Function(PrimaryConstructorName), experimental) visitPropertyAccess (method: R? Function(PropertyAccess)) @@ -2715,6 +2724,7 @@ package:analyzer/dart/ast/visitor.dart: visitPostfixExpression (method: R? Function(PostfixExpression)) visitPrefixExpression (method: R? Function(PrefixExpression)) visitPrefixedIdentifier (method: R? Function(PrefixedIdentifier)) + visitPrimaryConstructorBody (method: R? Function(PrimaryConstructorBody), experimental) visitPrimaryConstructorDeclaration (method: R? Function(PrimaryConstructorDeclaration), experimental) visitPrimaryConstructorName (method: R? Function(PrimaryConstructorName), experimental) visitPropertyAccess (method: R? Function(PropertyAccess)) @@ -2896,6 +2906,7 @@ package:analyzer/dart/ast/visitor.dart: visitPostfixExpression (method: R? Function(PostfixExpression)) visitPrefixExpression (method: R? Function(PrefixExpression)) visitPrefixedIdentifier (method: R? Function(PrefixedIdentifier)) + visitPrimaryConstructorBody (method: R? Function(PrimaryConstructorBody), experimental) visitPrimaryConstructorDeclaration (method: R? Function(PrimaryConstructorDeclaration), experimental) visitPrimaryConstructorName (method: R? Function(PrimaryConstructorName), experimental) visitPropertyAccess (method: R? Function(PropertyAccess)) @@ -3078,6 +3089,7 @@ package:analyzer/dart/ast/visitor.dart: visitPostfixExpression (method: T? Function(PostfixExpression)) visitPrefixExpression (method: T? Function(PrefixExpression)) visitPrefixedIdentifier (method: T? Function(PrefixedIdentifier)) + visitPrimaryConstructorBody (method: T? Function(PrimaryConstructorBody), experimental) visitPrimaryConstructorDeclaration (method: T? Function(PrimaryConstructorDeclaration), experimental) visitPrimaryConstructorName (method: T? Function(PrimaryConstructorName), experimental) visitPropertyAccess (method: T? Function(PropertyAccess)) @@ -3260,6 +3272,7 @@ package:analyzer/dart/ast/visitor.dart: visitPostfixExpression (method: R? Function(PostfixExpression)) visitPrefixExpression (method: R? Function(PrefixExpression)) visitPrefixedIdentifier (method: R? Function(PrefixedIdentifier)) + visitPrimaryConstructorBody (method: R? Function(PrimaryConstructorBody), experimental) visitPrimaryConstructorDeclaration (method: R? Function(PrimaryConstructorDeclaration), experimental) visitPrimaryConstructorName (method: R? Function(PrimaryConstructorName), experimental) visitPropertyAccess (method: R? Function(PropertyAccess)) diff --git a/pkg/analyzer/lib/analysis_rule/rule_visitor_registry.g.dart b/pkg/analyzer/lib/analysis_rule/rule_visitor_registry.g.dart index bdbfb7307aa..7091d40782e 100644 --- a/pkg/analyzer/lib/analysis_rule/rule_visitor_registry.g.dart +++ b/pkg/analyzer/lib/analysis_rule/rule_visitor_registry.g.dart @@ -335,6 +335,9 @@ abstract class RuleVisitorRegistry { void addPrefixExpression(AbstractAnalysisRule rule, AstVisitor visitor); + @experimental + void addPrimaryConstructorBody(AbstractAnalysisRule rule, AstVisitor visitor); + @experimental void addPrimaryConstructorDeclaration( AbstractAnalysisRule rule, diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart index e7dd4e53e15..b025022d637 100644 --- a/pkg/analyzer/lib/dart/ast/ast.dart +++ b/pkg/analyzer/lib/dart/ast/ast.dart @@ -203,6 +203,7 @@ export 'package:analyzer/src/dart/ast/ast.dart' PostfixExpression, PrefixedIdentifier, PrefixExpression, + PrimaryConstructorBody, PrimaryConstructorDeclaration, PrimaryConstructorName, PropertyAccess, diff --git a/pkg/analyzer/lib/dart/ast/visitor.g.dart b/pkg/analyzer/lib/dart/ast/visitor.g.dart index 7323502d90c..dff248bc90e 100644 --- a/pkg/analyzer/lib/dart/ast/visitor.g.dart +++ b/pkg/analyzer/lib/dart/ast/visitor.g.dart @@ -535,6 +535,11 @@ class GeneralizingAstVisitor implements AstVisitor { @override R? visitPrefixExpression(PrefixExpression node) => visitExpression(node); + @experimental + @override + R? visitPrimaryConstructorBody(PrimaryConstructorBody node) => + visitClassMember(node); + @experimental @override R? visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) => @@ -1529,6 +1534,13 @@ class RecursiveAstVisitor implements AstVisitor { return null; } + @experimental + @override + R? visitPrimaryConstructorBody(PrimaryConstructorBody node) { + node.visitChildren(this); + return null; + } + @experimental @override R? visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) { @@ -2245,6 +2257,10 @@ class SimpleAstVisitor implements AstVisitor { @override R? visitPrefixExpression(PrefixExpression node) => null; + @experimental + @override + R? visitPrimaryConstructorBody(PrimaryConstructorBody node) => null; + @experimental @override R? visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) => @@ -2825,6 +2841,10 @@ class ThrowingAstVisitor implements AstVisitor { @override R? visitPrefixExpression(PrefixExpression node) => _throw(node); + @experimental + @override + R? visitPrimaryConstructorBody(PrimaryConstructorBody node) => _throw(node); + @experimental @override R? visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) => @@ -4054,6 +4074,15 @@ class TimedAstVisitor implements AstVisitor { return result; } + @experimental + @override + T? visitPrimaryConstructorBody(PrimaryConstructorBody node) { + stopwatch.start(); + T? result = _baseVisitor.visitPrimaryConstructorBody(node); + stopwatch.stop(); + return result; + } + @experimental @override T? visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) { @@ -4901,6 +4930,11 @@ class UnifyingAstVisitor implements AstVisitor { @override R? visitPrefixExpression(PrefixExpression node) => visitNode(node); + @experimental + @override + R? visitPrimaryConstructorBody(PrimaryConstructorBody node) => + visitNode(node); + @experimental @override R? visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) => diff --git a/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart b/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart index 8cdc6298575..022a0cba5b1 100644 --- a/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart +++ b/pkg/analyzer/lib/src/dart/analysis/unlinked_api_signature.dart @@ -24,6 +24,7 @@ class _UnitApiSignatureComputer { static const int _kindConstructorDeclaration = 1; static const int _kindFieldDeclaration = 2; static const int _kindMethodDeclaration = 3; + static const int _kindPrimaryConstructorBody = 4; static const int _nullNode = 0; static const int _notNullNode = 1; static const int _nullToken = 0; @@ -89,6 +90,8 @@ class _UnitApiSignatureComputer { _addFieldDeclaration(member, hasConstConstructor); } else if (member is MethodDeclaration) { _addMethodDeclaration(member); + } else if (member is PrimaryConstructorBody) { + _addPrimaryConstructorBody(member); } else { throw UnimplementedError('(${member.runtimeType}) $member'); } @@ -188,6 +191,11 @@ class _UnitApiSignatureComputer { } } + void _addPrimaryConstructorBody(PrimaryConstructorBody node) { + signature.addInt(_kindPrimaryConstructorBody); + _addTokens(node.beginToken, node.body.beginToken); + } + void _addToken(Token? token) { if (token != null) { signature.addInt(_notNullToken); diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart index 76b48d4e044..aef508af60f 100644 --- a/pkg/analyzer/lib/src/dart/ast/ast.dart +++ b/pkg/analyzer/lib/src/dart/ast/ast.dart @@ -20035,6 +20035,126 @@ final class PrefixExpressionImpl extends ExpressionImpl } } +/// The body of a primary constructor. +@AnalyzerPublicApi(message: 'exported by lib/dart/ast/ast.dart') +@experimental +// TODO(scheglov): This should not be a `Declaration`. +abstract final class PrimaryConstructorBody implements ClassMember { + /// The body of the constructor. + FunctionBody get body; + + /// The token for the separator before [initializers], or `null` if there + /// are no initializers. + Token? get colon; + + /// The initializers associated with the constructor. + NodeList get initializers; + + /// The token for the `this` keyword. + Token get thisKeyword; +} + +@GenerateNodeImpl( + childEntitiesOrder: [ + GenerateNodeProperty('thisKeyword'), + GenerateNodeProperty('colon'), + GenerateNodeProperty('initializers'), + GenerateNodeProperty('body'), + ], +) +final class PrimaryConstructorBodyImpl extends ClassMemberImpl + implements PrimaryConstructorBody { + @generated + @override + final Token thisKeyword; + + @generated + @override + final Token? colon; + + @generated + @override + final NodeListImpl initializers = + NodeListImpl._(); + + @generated + FunctionBodyImpl _body; + + @generated + PrimaryConstructorBodyImpl({ + required super.comment, + required super.metadata, + required this.thisKeyword, + required this.colon, + required List initializers, + required FunctionBodyImpl body, + }) : _body = body { + this.initializers._initialize(this, initializers); + _becomeParentOf(body); + } + + @generated + @override + FunctionBodyImpl get body => _body; + + @generated + set body(FunctionBodyImpl body) { + _body = _becomeParentOf(body); + } + + @generated + @override + Token get endToken { + return body.endToken; + } + + @generated + @override + Token get firstTokenAfterCommentAndMetadata { + return thisKeyword; + } + + @generated + @override + ChildEntities get _childEntities => super._childEntities + ..addToken('thisKeyword', thisKeyword) + ..addToken('colon', colon) + ..addNodeList('initializers', initializers) + ..addNode('body', body); + + @generated + @override + E? accept(AstVisitor visitor) => + visitor.visitPrimaryConstructorBody(this); + + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); + + @generated + @override + void visitChildren(AstVisitor visitor) { + super.visitChildren(visitor); + initializers.accept(visitor); + body.accept(visitor); + } + + @generated + @override + AstNodeImpl? _childContainingRange(int rangeOffset, int rangeEnd) { + if (super._childContainingRange(rangeOffset, rangeEnd) case var result?) { + return result; + } + if (initializers._elementContainingRange(rangeOffset, rangeEnd) + case var result?) { + return result; + } + if (body._containsOffset(rangeOffset, rangeEnd)) { + return body; + } + return null; + } +} + /// The declaration of a primary constructor. @AnalyzerPublicApi(message: 'exported by lib/dart/ast/ast.dart') @experimental diff --git a/pkg/analyzer/lib/src/dart/ast/ast.g.dart b/pkg/analyzer/lib/src/dart/ast/ast.g.dart index fa8d2626e25..cd149ab1d50 100644 --- a/pkg/analyzer/lib/src/dart/ast/ast.g.dart +++ b/pkg/analyzer/lib/src/dart/ast/ast.g.dart @@ -287,6 +287,9 @@ abstract class AstVisitor { R? visitPrefixExpression(PrefixExpression node); + @experimental + R? visitPrimaryConstructorBody(PrimaryConstructorBody node); + @experimental R? visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node); diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart index 0e7078c9597..41333c136cc 100644 --- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart +++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart @@ -1151,6 +1151,17 @@ class ToSourceVisitor implements AstVisitor { _writeOperand(node, node.operand); } + @override + void visitPrimaryConstructorBody(PrimaryConstructorBody node) { + _visitNodeList(node.metadata, separator: ' ', suffix: ' '); + _visitToken(node.thisKeyword); + if (node.initializers.isNotEmpty) { + _visitToken(node.colon, prefix: ' ', suffix: ' '); + _visitNodeList(node.initializers, separator: ', '); + } + _visitFunctionBody(node.body); + } + @override void visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) { _visitToken(node.constKeyword, suffix: ' '); diff --git a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart index 0cbad83a231..33e8aae046c 100644 --- a/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart +++ b/pkg/analyzer/lib/src/error/duplicate_definition_verifier.dart @@ -477,6 +477,9 @@ class MemberDuplicateDefinitionVerifier { _checkValuesDeclarationInEnum(member.name); } } + case PrimaryConstructorBodyImpl(): + // TODO(scheglov): Handle this case. + throw UnimplementedError(); } } diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart index 33e8d024adc..b9f77444551 100644 --- a/pkg/analyzer/lib/src/fasta/ast_builder.dart +++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart @@ -3167,15 +3167,24 @@ class AstBuilder extends StackListener { Token? beginInitializers, Token endToken, ) { - // TODO(declaring-constructors): Implement primary constructor body. - // ignore: unused_local_variable - var bodyObject = pop(); - // ignore: unused_local_variable + assert(optional('this', beginToken)); + + var body = pop() as FunctionBodyImpl; var initializers = (pop() as List?) ?? const []; - // ignore: unused_local_variable - var separator = pop() as Token?; - // ignore: unused_local_variable + var colon = pop() as Token?; var metadata = pop() as List?; + var comment = _findComment(metadata, beginToken); + + _classLikeBuilder!.members.add( + PrimaryConstructorBodyImpl( + comment: comment, + metadata: metadata, + thisKeyword: beginToken, + colon: colon, + initializers: initializers, + body: body, + ), + ); } @override diff --git a/pkg/analyzer/lib/src/lint/linter_visitor.g.dart b/pkg/analyzer/lib/src/lint/linter_visitor.g.dart index 3feea101df4..999feb33637 100644 --- a/pkg/analyzer/lib/src/lint/linter_visitor.g.dart +++ b/pkg/analyzer/lib/src/lint/linter_visitor.g.dart @@ -804,6 +804,13 @@ class AnalysisRuleVisitor implements AstVisitor { node.visitChildren(this); } + @experimental + @override + void visitPrimaryConstructorBody(PrimaryConstructorBody node) { + _runSubscriptions(node, _registry._forPrimaryConstructorBody); + node.visitChildren(this); + } + @experimental @override void visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) { @@ -1462,6 +1469,9 @@ class RuleVisitorRegistryImpl implements RuleVisitorRegistry { final List<_Subscription> _forPrefixExpression = []; + final List<_Subscription> _forPrimaryConstructorBody = + []; + final List<_Subscription> _forPrimaryConstructorDeclaration = []; @@ -2356,6 +2366,16 @@ class RuleVisitorRegistryImpl implements RuleVisitorRegistry { _forPrefixExpression.add(_Subscription(rule, visitor, _getTimer(rule))); } + @override + void addPrimaryConstructorBody( + AbstractAnalysisRule rule, + AstVisitor visitor, + ) { + _forPrimaryConstructorBody.add( + _Subscription(rule, visitor, _getTimer(rule)), + ); + } + @override void addPrimaryConstructorDeclaration( AbstractAnalysisRule rule, diff --git a/pkg/analyzer/lib/src/test_utilities/find_node.dart b/pkg/analyzer/lib/src/test_utilities/find_node.dart index 790a163c97c..daf157aa939 100644 --- a/pkg/analyzer/lib/src/test_utilities/find_node.dart +++ b/pkg/analyzer/lib/src/test_utilities/find_node.dart @@ -156,6 +156,8 @@ class FindNode { PrefixExpression get singlePrefixExpression => _single(); + PrimaryConstructorBody get singlePrimaryConstructorBody => _single(); + PropertyAccess get singlePropertyAccess => _single(); RecordLiteral get singleRecordLiteral => _single(); diff --git a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart index 10c642e9186..9d465629be3 100644 --- a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart +++ b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart @@ -3,7 +3,9 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/dart/analysis/utilities.dart'; +import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/src/dart/analysis/unlinked_api_signature.dart'; +import 'package:analyzer/src/dart/ast/ast.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -17,6 +19,10 @@ main() { @reflectiveTest class UnitApiSignatureTest { + void tearDown() { + useDeclaringConstructorsAst = default_useDeclaringConstructorsAst; + } + test_class_annotation() async { _assertNotSameSignature( r''' @@ -503,6 +509,57 @@ abstract class C {} ); } + test_class_primaryConstructorBody_body() { + useDeclaringConstructorsAst = true; + _assertSameSignature( + r''' +class C() { + this { 0; } +} +''', + r''' +class C() { + this { 1; } +} +''', + ); + } + + test_class_primaryConstructorBody_initializer_const() { + useDeclaringConstructorsAst = true; + _assertNotSameSignature( + r''' +class const C() { + final int f; + this: f = 1; +} +''', + r''' +class const C() { + final int f; + this: f = 2; +} +''', + ); + } + + test_class_primaryConstructorBody_metadata() { + useDeclaringConstructorsAst = true; + _assertNotSameSignature( + r''' +class C() { + this; +} +''', + r''' +class C() { + @deprecated + this; +} +''', + ); + } + test_class_with() { _assertNotSameSignature( r''' diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart index 160080c230b..2c4d9ad5cda 100644 --- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart +++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart @@ -3953,6 +3953,48 @@ class ToSourceVisitorTest_declaringConstructors extends ToSourceVisitorTest { var findNode = _parseStringToFindNode(code); _assertSource(code, findNode.extensionTypeDeclaration(code)); } + + void test_visitPrimaryConstructorBody_block() { + var code = 'this {foo();}'; + var findNode = _parseStringToFindNode(''' +class A() { + $code +} +'''); + _assertSource(code, findNode.singlePrimaryConstructorBody); + } + + void test_visitPrimaryConstructorBody_initializers() { + var code = 'this : x = 0, y = 1;'; + var findNode = _parseStringToFindNode(''' +class A() { + final int x; + final int y; + $code +} +'''); + _assertSource(code, findNode.singlePrimaryConstructorBody); + } + + void test_visitPrimaryConstructorBody_metadata() { + var code = '@deprecated this;'; + var findNode = _parseStringToFindNode(''' +class A() { + $code +} +'''); + _assertSource(code, findNode.singlePrimaryConstructorBody); + } + + void test_visitPrimaryConstructorBody_simple() { + var code = 'this;'; + var findNode = _parseStringToFindNode(''' +class A() { + $code +} +'''); + _assertSource(code, findNode.singlePrimaryConstructorBody); + } } @reflectiveTest diff --git a/pkg/analyzer/test/src/dart/parser/class_test.dart b/pkg/analyzer/test/src/dart/parser/class_test.dart index 7ba9484bfea..b6a5ae0b5c6 100644 --- a/pkg/analyzer/test/src/dart/parser/class_test.dart +++ b/pkg/analyzer/test/src/dart/parser/class_test.dart @@ -1156,6 +1156,108 @@ ClassDeclaration '''); } + test_primaryConstructorBody_body_blockFunctionBody() { + useDeclaringConstructorsAst = true; + var parseResult = parseStringWithErrors(r''' +class A() { + this { + 0; + } +} +'''); + parseResult.assertNoErrors(); + + var node = parseResult.findNode.singlePrimaryConstructorBody; + assertParsedNodeText(node, r''' +PrimaryConstructorBody + thisKeyword: this + body: BlockFunctionBody + block: Block + leftBracket: { + statements + ExpressionStatement + expression: IntegerLiteral + literal: 0 + semicolon: ; + rightBracket: } +'''); + } + + test_primaryConstructorBody_comment() { + useDeclaringConstructorsAst = true; + var parseResult = parseStringWithErrors(r''' +class A() { + /// foo + /// bar + this; +} +'''); + parseResult.assertNoErrors(); + + var node = parseResult.findNode.singlePrimaryConstructorBody; + assertParsedNodeText(node, r''' +PrimaryConstructorBody + documentationComment: Comment + tokens + /// foo + /// bar + thisKeyword: this + body: EmptyFunctionBody + semicolon: ; +'''); + } + + test_primaryConstructorBody_fieldInitializer() { + useDeclaringConstructorsAst = true; + var parseResult = parseStringWithErrors(r''' +class A() { + final int x; + this : x = 0; +} +'''); + parseResult.assertNoErrors(); + + var node = parseResult.findNode.singlePrimaryConstructorBody; + assertParsedNodeText(node, r''' +PrimaryConstructorBody + thisKeyword: this + colon: : + initializers + ConstructorFieldInitializer + fieldName: SimpleIdentifier + token: x + equals: = + expression: IntegerLiteral + literal: 0 + body: EmptyFunctionBody + semicolon: ; +'''); + } + + test_primaryConstructorBody_metadata() { + useDeclaringConstructorsAst = true; + var parseResult = parseStringWithErrors(r''' +class A() { + @deprecated + this; +} +'''); + parseResult.assertNoErrors(); + + var node = parseResult.findNode.singlePrimaryConstructorBody; + assertParsedNodeText(node, r''' +PrimaryConstructorBody + metadata + Annotation + atSign: @ + name: SimpleIdentifier + token: deprecated + thisKeyword: this + body: EmptyFunctionBody + semicolon: ; +'''); + } + test_setter_formalParameters_absent() { var parseResult = parseStringWithErrors(r''' class A { diff --git a/pkg/analyzer/test/src/dart/parser/enum_test.dart b/pkg/analyzer/test/src/dart/parser/enum_test.dart index 7c7267ba25b..897b1ea9fa0 100644 --- a/pkg/analyzer/test/src/dart/parser/enum_test.dart +++ b/pkg/analyzer/test/src/dart/parser/enum_test.dart @@ -626,6 +626,25 @@ EnumDeclaration EnumConstantDeclaration name: v rightBracket: } +'''); + } + + test_primaryConstructorBody() { + useDeclaringConstructorsAst = true; + var parseResult = parseStringWithErrors(r''' +enum E() { + v; + this; +} +'''); + parseResult.assertNoErrors(); + + var node = parseResult.findNode.singlePrimaryConstructorBody; + assertParsedNodeText(node, r''' +PrimaryConstructorBody + thisKeyword: this + body: EmptyFunctionBody + semicolon: ; '''); } } diff --git a/pkg/analyzer/test/src/dart/parser/extension_test.dart b/pkg/analyzer/test/src/dart/parser/extension_test.dart index 13e983cada5..f0269230936 100644 --- a/pkg/analyzer/test/src/dart/parser/extension_test.dart +++ b/pkg/analyzer/test/src/dart/parser/extension_test.dart @@ -289,4 +289,33 @@ ExtensionDeclaration '''); } } + + test_primaryConstructorBody() { + useDeclaringConstructorsAst = true; + var parseResult = parseStringWithErrors(r''' +extension A on int { + this; +} +'''); + parseResult.assertNoErrors(); + + var node = parseResult.findNode.singleExtensionDeclaration; + assertParsedNodeText(node, r''' +ExtensionDeclaration + extensionKeyword: extension + name: A + onClause: ExtensionOnClause + onKeyword: on + extendedType: NamedType + name: int + body: BlockClassBody + leftBracket: { + members + PrimaryConstructorBody + thisKeyword: this + body: EmptyFunctionBody + semicolon: ; + rightBracket: } +'''); + } } diff --git a/pkg/analyzer/test/src/dart/parser/extension_type_test.dart b/pkg/analyzer/test/src/dart/parser/extension_type_test.dart index 0a374167bb0..a5f7fc39b0b 100644 --- a/pkg/analyzer/test/src/dart/parser/extension_type_test.dart +++ b/pkg/analyzer/test/src/dart/parser/extension_type_test.dart @@ -2159,6 +2159,40 @@ ExtensionTypeDeclaration } } + test_primaryConstructorBody() { + useDeclaringConstructorsAst = true; + var parseResult = parseStringWithErrors(r''' +extension type A(int it) { + this; +} +'''); + parseResult.assertNoErrors(); + + var node = parseResult.findNode.singleExtensionTypeDeclaration; + assertParsedNodeText(node, r''' +ExtensionTypeDeclaration + extensionKeyword: extension + typeKeyword: type + primaryConstructor: PrimaryConstructorDeclaration + typeName: A + formalParameters: FormalParameterList + leftParenthesis: ( + parameter: SimpleFormalParameter + type: NamedType + name: int + name: it + rightParenthesis: ) + body: BlockClassBody + leftBracket: { + members + PrimaryConstructorBody + thisKeyword: this + body: EmptyFunctionBody + semicolon: ; + rightBracket: } +'''); + } + test_withImplementsClause() { var parseResult = parseStringWithErrors(r''' extension type A(int it) implements B, C {} diff --git a/pkg/analyzer/test/src/dart/parser/mixin_test.dart b/pkg/analyzer/test/src/dart/parser/mixin_test.dart index 1966f629551..5851e0e2618 100644 --- a/pkg/analyzer/test/src/dart/parser/mixin_test.dart +++ b/pkg/analyzer/test/src/dart/parser/mixin_test.dart @@ -287,6 +287,31 @@ MixinDeclaration name: A leftBracket: { rightBracket: } +'''); + } + + test_primaryConstructorBody() { + useDeclaringConstructorsAst = true; + var parseResult = parseStringWithErrors(r''' +mixin A { + this; +} +'''); + parseResult.assertNoErrors(); + + var node = parseResult.findNode.singleMixinDeclaration; + assertParsedNodeText(node, r''' +MixinDeclaration + mixinKeyword: mixin + name: A + body: BlockClassBody + leftBracket: { + members + PrimaryConstructorBody + thisKeyword: this + body: EmptyFunctionBody + semicolon: ; + rightBracket: } '''); } } diff --git a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart index 33334856e19..ad2f51b4b84 100644 --- a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart +++ b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart @@ -1347,6 +1347,14 @@ class ResolvedAstPrinter extends ThrowingAstVisitor { }); } + @override + void visitPrimaryConstructorBody(PrimaryConstructorBody node) { + _sink.writeln('PrimaryConstructorBody'); + _sink.withIndent(() { + _writeNamedChildEntities(node); + }); + } + @override void visitPrimaryConstructorDeclaration(PrimaryConstructorDeclaration node) { _sink.writeln('PrimaryConstructorDeclaration'); diff --git a/pkg/analyzer/tool/generators/ast_generator.dart b/pkg/analyzer/tool/generators/ast_generator.dart index 2378d96adc8..da40e792de9 100644 --- a/pkg/analyzer/tool/generators/ast_generator.dart +++ b/pkg/analyzer/tool/generators/ast_generator.dart @@ -708,6 +708,8 @@ void visitChildren(AstVisitor visitor) {'''); implClass.doNotGenerateLookupNames.add(memberName); continue; } + case PrimaryConstructorBodyImpl(): + throw UnimplementedError(); } if (implClass.generatedLookupNames.contains(memberName)) { replacements.add(_Replacement(member.offset, member.end, '')); diff --git a/pkg/linter/lib/src/rules/analyzer_element_model_tracking.dart b/pkg/linter/lib/src/rules/analyzer_element_model_tracking.dart index 3bea37c95fd..575753d452f 100644 --- a/pkg/linter/lib/src/rules/analyzer_element_model_tracking.dart +++ b/pkg/linter/lib/src/rules/analyzer_element_model_tracking.dart @@ -151,6 +151,10 @@ class _Visitor extends SimpleAstVisitor { trackingAnnotations.forEach(_reportBad); } } + // ignore: experimental_member_use + case PrimaryConstructorBody(): + // TODO(scheglov): Handle this case. + throw UnimplementedError(); } } } diff --git a/pkg/linter/lib/src/rules/unreachable_from_main.dart b/pkg/linter/lib/src/rules/unreachable_from_main.dart index 8011236594f..452423e8a37 100644 --- a/pkg/linter/lib/src/rules/unreachable_from_main.dart +++ b/pkg/linter/lib/src/rules/unreachable_from_main.dart @@ -137,6 +137,10 @@ class _DeclarationGatherer { declarations.add(member); } } + // ignore: experimental_member_use + case PrimaryConstructorBody(): + // TODO(scheglov): Handle this case. + throw UnimplementedError(); } } }