// Copyright (c) 2018, 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. // @dart = 2.7 import 'package:expect/expect.dart'; import 'package:async_helper/async_helper.dart'; import 'package:compiler/src/common.dart'; import 'package:compiler/src/compiler.dart'; import 'package:compiler/src/commandline_options.dart'; import 'package:compiler/src/common_elements.dart'; import 'package:compiler/src/elements/entities.dart'; import 'package:compiler/src/elements/types.dart'; import 'package:compiler/src/world.dart'; import 'package:compiler/src/universe/use.dart'; import 'package:compiler/src/universe/world_impact.dart'; import '../helpers/memory_compiler.dart'; main() { asyncTest(() async { await runTest(); }); } runTest() async { String source = ''' class A {} class B {} int method1() => 0; int method2(dynamic o) => o; method3(int i) {} int method4(dynamic o) => o as int; void method5() {} method6() => []; method7() => [0]; method8() => [0]; method9(dynamic o) => [o]; method10() => {}; method11() => {0: ''}; method12() => {0: ''}; method13(dynamic k, String v) => {k: v}; main() { method1(); method2(null); method3(0); method4(0); method5(); method6(); method7(); method8(); method9(0); method10(); method11(); method12(); method13(0, ''); } '''; Map expectedImpactMap = { 'method1': const Impact(), 'method2': new Impact(implicitCasts: ['int*']), 'method3': new Impact(parameterChecks: ['int*']), 'method4': new Impact(asCasts: ['int*']), 'method5': const Impact(), 'method6': const Impact(), 'method7': const Impact(), 'method8': const Impact(), 'method9': new Impact(implicitCasts: ['int*']), 'method10': const Impact(), 'method11': const Impact(), 'method12': const Impact(), 'method13': new Impact(implicitCasts: ['int*'], parameterChecks: ['String*']), }; retainDataForTesting = true; CompilationResult result = await runCompiler( memorySourceFiles: {'main.dart': source}, options: [Flags.printLegacyStars]); Expect.isTrue(result.isSuccess); Compiler compiler = result.compiler; var options = compiler.options; KClosedWorld closedWorld = compiler.frontendClosedWorldForTesting; DartTypes types = closedWorld.dartTypes; ElementEnvironment elementEnvironment = closedWorld.elementEnvironment; String printType(DartType type) { return type.toStructuredText(types, options); } elementEnvironment.forEachLibraryMember(elementEnvironment.mainLibrary, (MemberEntity member) { if (member == elementEnvironment.mainFunction) return; Impact expectedImpact = expectedImpactMap[member.name]; Expect.isNotNull(expectedImpact, "Not expected impact for $member"); WorldImpact actualImpact = compiler.impactCache[member]; Set typeUses = actualImpact.typeUses.toSet(); Set asCasts = expectedImpact.asCasts.toSet(); Set checkedModeChecks = expectedImpact.checkedModeChecks.toSet(); Set implicitCasts = expectedImpact.implicitCasts.toSet(); Set parameterChecks = expectedImpact.parameterChecks.toSet(); String context = 'in $member:\n' 'Expected: $expectedImpact\nActual: $typeUses'; for (TypeUse typeUse in typeUses) { String type = printType(typeUse.type); switch (typeUse.kind) { case TypeUseKind.AS_CAST: Expect.isTrue(asCasts.contains(type), "Extra $typeUse $context"); asCasts.remove(type); break; case TypeUseKind.IMPLICIT_CAST: Expect.isTrue( implicitCasts.contains(type), "Extra $typeUse $context"); implicitCasts.remove(type); break; case TypeUseKind.PARAMETER_CHECK: Expect.isTrue( parameterChecks.contains(type), "Extra $typeUse $context"); parameterChecks.remove(type); break; default: } } Expect.isTrue(asCasts.isEmpty, "Missing as casts $asCasts $context"); Expect.isTrue(checkedModeChecks.isEmpty, "Missing checked mode checks $checkedModeChecks $context"); }); } class Impact { final List checkedModeChecks; final List asCasts; final List implicitCasts; final List parameterChecks; const Impact( {this.checkedModeChecks: const [], this.asCasts: const [], this.implicitCasts: const [], this.parameterChecks: const []}); @override String toString() { StringBuffer sb = new StringBuffer(); sb.write('Impact('); String comma = ''; if (checkedModeChecks.isNotEmpty) { sb.write('checkedModeChecks='); sb.write(checkedModeChecks.join(',')); comma = ','; } if (asCasts.isNotEmpty) { sb.write(comma); sb.write('asCasts='); sb.write(asCasts.join(',')); comma = ','; } if (implicitCasts.isNotEmpty) { sb.write(comma); sb.write('syntheticCasts='); sb.write(implicitCasts.join(',')); comma = ','; } if (parameterChecks.isNotEmpty) { sb.write(comma); sb.write('parameterChecks='); sb.write(parameterChecks.join(',')); comma = ','; } sb.write(')'); return sb.toString(); } }