diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart index a7aacf1a502..fe3485ca60e 100644 --- a/pkg/analyzer/lib/dart/ast/ast.dart +++ b/pkg/analyzer/lib/dart/ast/ast.dart @@ -553,6 +553,15 @@ abstract class AstVisitor { R? visitRecordLiteral(RecordLiteral node); + R? visitRecordTypeAnnotation(RecordTypeAnnotation node); + + R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node); + + R? visitRecordTypeAnnotationNamedFields(RecordTypeAnnotationNamedFields node); + + R? visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node); + R? visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node); diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart index c57c9a698b4..38620841d08 100644 --- a/pkg/analyzer/lib/dart/ast/visitor.dart +++ b/pkg/analyzer/lib/dart/ast/visitor.dart @@ -520,6 +520,27 @@ class GeneralizingAstVisitor implements AstVisitor { @override R? visitRecordLiteral(RecordLiteral node) => visitLiteral(node); + @override + R? visitRecordTypeAnnotation(RecordTypeAnnotation node) => + visitTypeAnnotation(node); + + R? visitRecordTypeAnnotationField(RecordTypeAnnotationField node) => + visitNode(node); + + @override + R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node) => + visitRecordTypeAnnotationField(node); + + @override + R? visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) => + visitNode(node); + + @override + R? visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) => + visitRecordTypeAnnotationField(node); + @override R? visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) => @@ -1271,6 +1292,32 @@ class RecursiveAstVisitor implements AstVisitor { return null; } + @override + R? visitRecordTypeAnnotation(RecordTypeAnnotation node) { + node.visitChildren(this); + return null; + } + + @override + R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node) { + node.visitChildren(this); + return null; + } + + @override + R? visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) { + node.visitChildren(this); + return null; + } + + @override + R? visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) { + node.visitChildren(this); + return null; + } + @override R? visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) { @@ -1795,6 +1842,23 @@ class SimpleAstVisitor implements AstVisitor { @override R? visitRecordLiteral(RecordLiteral node) => null; + @override + R? visitRecordTypeAnnotation(RecordTypeAnnotation node) => null; + + @override + R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node) => + null; + + @override + R? visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) => + null; + + @override + R? visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) => + null; + @override R? visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) => @@ -2226,6 +2290,23 @@ class ThrowingAstVisitor implements AstVisitor { @override R? visitRecordLiteral(RecordLiteral node) => _throw(node); + @override + R? visitRecordTypeAnnotation(RecordTypeAnnotation node) => _throw(node); + + @override + R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node) => + _throw(node); + + @override + R? visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) => + _throw(node); + + @override + R? visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) => + _throw(node); + @override R? visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) => @@ -3161,6 +3242,40 @@ class TimedAstVisitor implements AstVisitor { return result; } + @override + T? visitRecordTypeAnnotation(RecordTypeAnnotation node) { + stopwatch.start(); + T? result = _baseVisitor.visitRecordTypeAnnotation(node); + stopwatch.stop(); + return result; + } + + @override + T? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node) { + stopwatch.start(); + T? result = _baseVisitor.visitRecordTypeAnnotationNamedField(node); + stopwatch.stop(); + return result; + } + + @override + T? visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) { + stopwatch.start(); + T? result = _baseVisitor.visitRecordTypeAnnotationNamedFields(node); + stopwatch.stop(); + return result; + } + + @override + T? visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) { + stopwatch.start(); + T? result = _baseVisitor.visitRecordTypeAnnotationPositionalField(node); + stopwatch.stop(); + return result; + } + @override T? visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) { @@ -3776,6 +3891,23 @@ class UnifyingAstVisitor implements AstVisitor { @override R? visitRecordLiteral(RecordLiteral node) => visitNode(node); + @override + R? visitRecordTypeAnnotation(RecordTypeAnnotation node) => visitNode(node); + + @override + R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node) => + visitNode(node); + + @override + R? visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) => + visitNode(node); + + @override + R? visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) => + visitNode(node); + @override R? visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) => diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart index b6276651a51..34da72bf867 100644 --- a/pkg/analyzer/lib/src/dart/ast/ast.dart +++ b/pkg/analyzer/lib/src/dart/ast/ast.dart @@ -9764,8 +9764,7 @@ class RecordTypeAnnotationImpl extends TypeAnnotationImpl @override E? accept(AstVisitor visitor) { - // TODO: implement accept - throw UnimplementedError(); + return visitor.visitRecordTypeAnnotation(this); } @override @@ -9789,8 +9788,7 @@ class RecordTypeAnnotationNamedFieldImpl extends RecordTypeAnnotationFieldImpl @override E? accept(AstVisitor visitor) { - // TODO: implement accept - throw UnimplementedError(); + return visitor.visitRecordTypeAnnotationNamedField(this); } } @@ -9827,8 +9825,7 @@ class RecordTypeAnnotationNamedFieldsImpl extends AstNodeImpl @override E? accept(AstVisitor visitor) { - // TODO: implement accept - throw UnimplementedError(); + return visitor.visitRecordTypeAnnotationNamedFields(this); } @override @@ -9852,8 +9849,7 @@ class RecordTypeAnnotationPositionalFieldImpl @override E? accept(AstVisitor visitor) { - // TODO: implement accept - throw UnimplementedError(); + return visitor.visitRecordTypeAnnotationPositionalField(this); } } 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 f0ed96b58d8..f09dfe3162d 100644 --- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart +++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart @@ -901,6 +901,48 @@ class ToSourceVisitor implements AstVisitor { _visitToken(node.rightParenthesis); } + @override + void visitRecordTypeAnnotation(RecordTypeAnnotation node) { + var positionalFields = node.positionalFields; + var namedFields = node.namedFields; + + sink.write('('); + if (positionalFields.isNotEmpty) { + _visitNodeList(positionalFields, separator: ', '); + if (namedFields != null) { + sink.write(', '); + } + } + _visitNode(namedFields); + sink.write(')'); + } + + @override + void visitRecordTypeAnnotationNamedField( + RecordTypeAnnotationNamedField node) { + _visitNode(node.type); + sink.write(' '); + sink.write(node.name); + } + + @override + void visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) { + sink.write('{'); + _visitNodeList(node.fields, separator: ', '); + sink.write('}'); + } + + @override + void visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) { + _visitNode(node.type); + if (node.name != null) { + sink.write(' '); + sink.write(node.name); + } + } + @override void visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) { diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart index 86a005ef0ee..87a6df9a82d 100644 --- a/pkg/analyzer/lib/src/dart/ast/utilities.dart +++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart @@ -1037,6 +1037,43 @@ class AstComparator implements AstVisitor { isEqualTokens(node.rightParenthesis, other.rightParenthesis); } + @override + bool visitRecordTypeAnnotation(RecordTypeAnnotation node) { + var other = _other as RecordTypeAnnotation; + return _isEqualNodeLists(node.positionalFields, other.positionalFields) && + isEqualNodes(node.namedFields, other.namedFields) && + isEqualTokens(node.question, other.question); + } + + @override + bool visitRecordTypeAnnotationNamedField( + RecordTypeAnnotationNamedField node) { + var other = _other as RecordTypeAnnotationNamedField; + return isEqualTokens(node.comma, other.comma) && + _isEqualNodeLists(node.metadata, other.metadata) && + isEqualTokens(node.name, other.name) && + isEqualNodes(node.type, other.type); + } + + @override + bool visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) { + var other = _other as RecordTypeAnnotationNamedFields; + return isEqualTokens(node.leftBracket, other.leftBracket) && + _isEqualNodeLists(node.fields, other.fields) && + isEqualTokens(node.rightBracket, other.rightBracket); + } + + @override + bool visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) { + var other = _other as RecordTypeAnnotationPositionalField; + return isEqualTokens(node.comma, other.comma) && + _isEqualNodeLists(node.metadata, other.metadata) && + isEqualTokens(node.name, other.name) && + isEqualNodes(node.type, other.type); + } + @override bool visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) { @@ -2768,6 +2805,50 @@ class NodeReplacer implements AstVisitor { return visitNode(node); } + @override + bool visitRecordTypeAnnotation(RecordTypeAnnotation node) { + if (_replaceInList(node.positionalFields)) { + return true; + } else if (identical(node.namedFields, _oldNode)) { + // node.namedFields = _newNode as RecordTypeAnnotationNamedFields; + throw UnimplementedError(); + } + return visitNode(node); + } + + @override + bool visitRecordTypeAnnotationNamedField( + RecordTypeAnnotationNamedField node) { + if (_replaceInList(node.metadata)) { + return true; + } else if (identical(node.type, _oldNode)) { + // node.type = _newNode as TypeAnnotation; + throw UnimplementedError(); + } + return visitNode(node); + } + + @override + bool visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) { + if (_replaceInList(node.fields)) { + return true; + } + return visitNode(node); + } + + @override + bool visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) { + if (_replaceInList(node.metadata)) { + return true; + } else if (identical(node.type, _oldNode)) { + // node.type = _newNode as TypeAnnotation; + throw UnimplementedError(); + } + return visitNode(node); + } + @override bool visitRedirectingConstructorInvocation( covariant RedirectingConstructorInvocationImpl node) { diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart index 6a9deb25205..eef8a5fc595 100644 --- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart +++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart @@ -988,6 +988,42 @@ class AstTestFactory { ); } + static RecordTypeAnnotation recordTypeAnnotation( + {required List positionalFields, + required List namedFields, + bool isNullable = false}) { + return RecordTypeAnnotationImpl( + positionalFields: positionalFields, + namedFields: namedFields.isEmpty + ? null + : RecordTypeAnnotationNamedFieldsImpl( + leftBracket: + TokenFactory.tokenFromType(TokenType.OPEN_CURLY_BRACKET), + fields: namedFields, + rightBracket: + TokenFactory.tokenFromType(TokenType.CLOSE_CURLY_BRACKET)), + question: + isNullable ? TokenFactory.tokenFromType(TokenType.QUESTION) : null); + } + + static RecordTypeAnnotationNamedField recordTypeAnnotationNamedField( + TypeAnnotationImpl type, String name) { + return RecordTypeAnnotationNamedFieldImpl( + comma: TokenFactory.tokenFromType(TokenType.COMMA), + metadata: null, + name: TokenFactory.tokenFromString(name), + type: type); + } + + static RecordTypeAnnotationPositionalField + recordTypeAnnotationPositionalField(TypeAnnotationImpl type) { + return RecordTypeAnnotationPositionalFieldImpl( + comma: TokenFactory.tokenFromType(TokenType.COMMA), + metadata: null, + name: null, + type: type); + } + static RedirectingConstructorInvocationImpl redirectingConstructorInvocation( [List arguments = const []]) => redirectingConstructorInvocation2(null, arguments); diff --git a/pkg/analyzer/lib/src/lint/linter_visitor.dart b/pkg/analyzer/lib/src/lint/linter_visitor.dart index c0c02236d1f..284732291a0 100644 --- a/pkg/analyzer/lib/src/lint/linter_visitor.dart +++ b/pkg/analyzer/lib/src/lint/linter_visitor.dart @@ -629,6 +629,33 @@ class LinterVisitor implements AstVisitor { node.visitChildren(this); } + @override + void visitRecordTypeAnnotation(RecordTypeAnnotation node) { + _runSubscriptions(node, registry._forRecordTypeAnnotation); + node.visitChildren(this); + } + + @override + void visitRecordTypeAnnotationNamedField( + RecordTypeAnnotationNamedField node) { + _runSubscriptions(node, registry._forRecordTypeAnnotationNamedField); + node.visitChildren(this); + } + + @override + void visitRecordTypeAnnotationNamedFields( + RecordTypeAnnotationNamedFields node) { + _runSubscriptions(node, registry._forRecordTypeAnnotationNamedFields); + node.visitChildren(this); + } + + @override + void visitRecordTypeAnnotationPositionalField( + RecordTypeAnnotationPositionalField node) { + _runSubscriptions(node, registry._forRecordTypeAnnotationPositionalField); + node.visitChildren(this); + } + @override void visitRedirectingConstructorInvocation( RedirectingConstructorInvocation node) { @@ -977,6 +1004,13 @@ class NodeLintRegistry { final List<_Subscription> _forPrefixExpression = []; final List<_Subscription> _forPropertyAccess = []; final List<_Subscription> _forRecordLiterals = []; + final List<_Subscription> _forRecordTypeAnnotation = []; + final List<_Subscription> + _forRecordTypeAnnotationNamedField = []; + final List<_Subscription> + _forRecordTypeAnnotationNamedFields = []; + final List<_Subscription> + _forRecordTypeAnnotationPositionalField = []; final List<_Subscription> _forRedirectingConstructorInvocation = []; final List<_Subscription> _forRethrowExpression = []; 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 a227a687a67..e4c392d1727 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 @@ -2804,6 +2804,44 @@ var v = !(a == b); ])); } + void test_visitRecordTypeAnnotation_mixed() { + _assertSource( + "(int, bool, {int a, bool b})", + AstTestFactory.recordTypeAnnotation(positionalFields: [ + AstTestFactory.recordTypeAnnotationPositionalField( + AstTestFactory.namedType4('int')), + AstTestFactory.recordTypeAnnotationPositionalField( + AstTestFactory.namedType4('bool')), + ], namedFields: [ + AstTestFactory.recordTypeAnnotationNamedField( + AstTestFactory.namedType4('int'), 'a'), + AstTestFactory.recordTypeAnnotationNamedField( + AstTestFactory.namedType4('bool'), 'b'), + ])); + } + + void test_visitRecordTypeAnnotation_named() { + _assertSource( + "({int a, bool b})", + AstTestFactory.recordTypeAnnotation(positionalFields: [], namedFields: [ + AstTestFactory.recordTypeAnnotationNamedField( + AstTestFactory.namedType4('int'), 'a'), + AstTestFactory.recordTypeAnnotationNamedField( + AstTestFactory.namedType4('bool'), 'b'), + ])); + } + + void test_visitRecordTypeAnnotation_positional() { + _assertSource( + "(int, bool)", + AstTestFactory.recordTypeAnnotation(positionalFields: [ + AstTestFactory.recordTypeAnnotationPositionalField( + AstTestFactory.namedType4('int')), + AstTestFactory.recordTypeAnnotationPositionalField( + AstTestFactory.namedType4('bool')), + ], namedFields: [])); + } + void test_visitRedirectingConstructorInvocation_named() { _assertSource( "this.c()", AstTestFactory.redirectingConstructorInvocation2("c"));