| // Copyright (c) 2022, 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:front_end/src/testing/analysis_helper.dart'; |
| import 'verifying_analysis.dart'; |
| |
| import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'; |
| import 'package:kernel/ast.dart'; |
| |
| Future<void> main(List<String> args) async { |
| await run(cfeAndBackendsEntryPoints, |
| 'pkg/front_end/test/static_types/type_arguments.json', |
| analyzedUrisFilter: cfeAndBackends, |
| verbose: args.contains('-v'), |
| generate: args.contains('-g')); |
| } |
| |
| Future<void> run(List<Uri> entryPoints, String allowedListPath, |
| {bool verbose = false, |
| bool generate = false, |
| bool Function(Uri uri)? analyzedUrisFilter}) async { |
| await runAnalysis(entryPoints, |
| (DiagnosticMessageHandler onDiagnostic, Component component) { |
| new TypeArgumentsVisitor( |
| onDiagnostic, component, allowedListPath, analyzedUrisFilter) |
| .run(verbose: verbose, generate: generate); |
| }); |
| } |
| |
| class TypeArgumentsVisitor extends VerifyingAnalysis { |
| TypeArgumentsVisitor( |
| DiagnosticMessageHandler onDiagnostic, |
| Component component, |
| String? allowedListPath, |
| UriFilter? analyzedUrisFilter) |
| : super(onDiagnostic, component, allowedListPath, analyzedUrisFilter); |
| |
| @override |
| void visitInstanceInvocation(InstanceInvocation node) { |
| if (node.name.text == 'toList') { |
| TreeNode receiver = node.receiver; |
| if (receiver is InstanceInvocation && |
| receiver.name.text == 'map' && |
| receiver.arguments.types.length == 1) { |
| String astUri = 'package:kernel/ast.dart'; |
| InterfaceType expressionType = |
| interface.createInterfaceType('Expression', uri: astUri); |
| InterfaceType statementType = |
| interface.createInterfaceType('Statement', uri: astUri); |
| InterfaceType assertStatementType = |
| interface.createInterfaceType('AssertStatement', uri: astUri); |
| InterfaceType variableDeclarationType = |
| interface.createInterfaceType('VariableDeclaration', uri: astUri); |
| DartType typeArgument = receiver.arguments.types.single; |
| if (interface.isSubtypeOf(typeArgument, expressionType) && |
| typeArgument != expressionType) { |
| registerError( |
| node, |
| "map().toList() with type argument " |
| "${typeArgument} instead of ${expressionType}"); |
| } |
| if (interface.isSubtypeOf(typeArgument, statementType)) { |
| if (interface.isSubtypeOf(typeArgument, assertStatementType)) { |
| // [AssertStatement] is used as an exclusive member of |
| // `InstanceCreation.asserts`. |
| if (typeArgument != assertStatementType) { |
| registerError( |
| node, |
| "map().toList() with type argument " |
| "${typeArgument} instead of ${assertStatementType}"); |
| } |
| } else if (interface.isSubtypeOf( |
| typeArgument, variableDeclarationType)) { |
| // [VariableDeclaration] is used as an exclusive member of, for |
| // instance, `FunctionNode.positionalParameters`. |
| if (typeArgument != variableDeclarationType) { |
| registerError( |
| node, |
| "map().toList() with type argument " |
| "${typeArgument} instead of ${variableDeclarationType}"); |
| } |
| } else if (typeArgument != statementType) { |
| registerError( |
| node, |
| "map().toList() with type argument " |
| "${typeArgument} instead of ${statementType}"); |
| } |
| } |
| } |
| } |
| super.visitInstanceInvocation(node); |
| } |
| } |