// Copyright (c) 2019, 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 'dart:io'; import 'package:_fe_analyzer_shared/src/testing/id.dart'; import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/error/error.dart'; import 'package:analyzer/src/dart/analysis/testing_data.dart'; import 'package:analyzer/src/dart/element/inheritance_manager3.dart'; import 'package:analyzer/src/util/ast_data_extractor.dart'; import '../util/id_testing_helper.dart'; main(List args) async { Directory dataDir = Directory.fromUri(Platform.script .resolve('../../../_fe_analyzer_shared/test/inheritance/data')); return runTests(dataDir, args: args, createUriForFileName: createUriForFileName, onFailure: onFailure, runTest: runTestFor(const _InheritanceDataComputer(), [analyzerNnbdConfig]), skipMap: { analyzerMarker: [ // These are CFE-centric tests for an opt-in/opt-out sdk. 'object_opt_in', 'object_opt_out', ] }); } String supertypeToString(InterfaceType type) { var sb = StringBuffer(); sb.write(type.element.name); if (type.typeArguments.isNotEmpty) { sb.write('<'); var comma = ''; for (var typeArgument in type.typeArguments) { sb.write(comma); sb.write(typeArgument.getDisplayString(withNullability: true)); comma = ', '; } sb.write('>'); } return sb.toString(); } class _InheritanceDataComputer extends DataComputer { const _InheritanceDataComputer(); @override DataInterpreter get dataValidator => const StringDataInterpreter(); @override bool get supportsErrors => true; @override String computeErrorData(TestConfig config, TestingData testingData, Id id, List errors) { return errors.map((e) => e.errorCode).join(','); } @override void computeUnitData(TestingData testingData, CompilationUnit unit, Map> actualMap) { _InheritanceDataExtractor(unit.declaredElement!.source.uri, actualMap) .run(unit); } } class _InheritanceDataExtractor extends AstDataExtractor { final inheritance = InheritanceManager3(); _InheritanceDataExtractor(Uri uri, Map> actualMap) : super(uri, actualMap); @override String? computeElementValue(Id id, Element element) { if (element is LibraryElement) { return 'nnbd=${element.isNonNullableByDefault}'; } return null; } @override void computeForClass(Declaration node, Id? id) { super.computeForClass(node, id); if (node is ClassDeclaration) { var element = node.declaredElement!; void registerMember( MemberId id, int offset, Object object, DartType type) { registerValue(uri, offset, id, type.getDisplayString(withNullability: true), object); } var interface = inheritance.getInterface(element); for (var name in interface.map.keys) { var executable = interface.map[name]!; var enclosingClass = executable.enclosingElement as ClassElement; if (enclosingClass.isDartCoreObject) continue; var id = MemberId.internal( name.name, className: element.name, ); var offset = enclosingClass == element ? executable.nameOffset : element.nameOffset; DartType type; if (executable is MethodElement) { type = executable.type; } else if (executable is PropertyAccessorElement) { if (executable.isGetter) { type = executable.returnType; } else { type = executable.parameters.first.type; } } else { throw UnimplementedError('(${executable.runtimeType}) $executable'); } registerMember(id, offset, executable, type); } } } @override String? computeNodeValue(Id id, AstNode node) { if (node is ClassDeclaration) { var cls = node.declaredElement!; var supertypes = []; supertypes.add(supertypeToString(cls.thisType)); for (var supertype in cls.allSupertypes) { supertypes.add(supertypeToString(supertype)); } supertypes.sort(); return supertypes.join(','); } return null; } }