| // 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/messages/severity.dart'; |
| import 'package:expect/expect.dart' show Expect; |
| import 'package:front_end/src/api_prototype/compiler_options.dart'; |
| import 'package:front_end/src/api_prototype/standard_file_system.dart'; |
| import 'package:front_end/src/base/compiler_context.dart'; |
| import 'package:front_end/src/base/file_system_dependency_tracker.dart'; |
| import 'package:front_end/src/base/import_chains.dart'; |
| import 'package:front_end/src/base/processed_options.dart'; |
| import 'package:front_end/src/base/ticker.dart'; |
| import 'package:front_end/src/base/uri_translator.dart'; |
| import 'package:front_end/src/builder/compilation_unit.dart'; |
| import 'package:front_end/src/compute_platform_binaries_location.dart' |
| show computePlatformBinariesLocation; |
| import 'package:front_end/src/dill/dill_target.dart'; |
| import 'package:front_end/src/kernel/kernel_target.dart'; |
| import 'package:kernel/kernel.dart'; |
| import 'package:kernel/target/targets.dart'; |
| import 'package:package_config/src/package_config.dart'; |
| import 'package:vm/modular/target/vm.dart' show VmTarget; |
| |
| import 'utils/io_utils.dart' show computeRepoDirUri; |
| |
| final Uri repoDir = computeRepoDirUri(); |
| |
| Set<String> allowlistedExternalDartFiles = { |
| // TODO(CFE-team): These files should not be included. |
| // The package isn't even in pubspec.yaml. |
| // They're included via at least |
| // _fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart |
| "pkg/meta/lib/meta.dart", |
| "pkg/meta/lib/meta_meta.dart", |
| }; |
| |
| Set<String> allowedPackages = { |
| "front_end", |
| "kernel", |
| "_fe_analyzer_shared", |
| "package_config", |
| "macros", |
| "_macros", |
| // package:front_end imports package:yaml for the 'dynamic modules' |
| // experiment. |
| "yaml", |
| // package:yaml uses package:source_span, package:string_scanner and |
| // package:collection. |
| "source_span", |
| "string_scanner", |
| "collection", |
| // package:source_span imports package:path. |
| "path", |
| // package:source_span imports package:term_glyph. |
| "term_glyph", |
| }; |
| |
| List<String> allowedRelativePaths = [ |
| // For VmTarget for macros. |
| "pkg/vm/lib/modular/", |
| // Platform. |
| "sdk/lib/", |
| ]; |
| |
| /// Returns true on no errors and false if errors was found. |
| Future<bool> main() async { |
| Ticker ticker = new Ticker(isVerbose: false); |
| CompilerOptions compilerOptions = getOptions(); |
| |
| Uri packageConfigUri = repoDir.resolve(".dart_tool/package_config.json"); |
| if (!new File.fromUri(packageConfigUri).existsSync()) { |
| throw "Couldn't find .dart_tool/package_config.json"; |
| } |
| compilerOptions.packagesFileUri = packageConfigUri; |
| FileSystemDependencyTracker tracker = new FileSystemDependencyTracker(); |
| compilerOptions.fileSystem = StandardFileSystem.instanceWithTracking(tracker); |
| |
| ProcessedOptions options = new ProcessedOptions(options: compilerOptions); |
| |
| Uri frontendLibUri = repoDir.resolve("pkg/front_end/lib/"); |
| List<FileSystemEntity> entities = |
| new Directory.fromUri(frontendLibUri).listSync(recursive: true); |
| for (FileSystemEntity entity in entities) { |
| if (entity is File && entity.path.endsWith(".dart")) { |
| options.inputs.add(entity.uri); |
| } |
| } |
| |
| LoadedLibraries? loadedLibraries; |
| Map<Uri, Uri> fileUriToImportUri = {}; |
| List<String> allowedUriPrefixes = [ |
| for (String relativePath in allowedRelativePaths) |
| repoDir.resolve(relativePath).toString() |
| ]; |
| |
| List<Uri> result = await CompilerContext.runWithOptions<List<Uri>>(options, |
| (CompilerContext c) async { |
| UriTranslator uriTranslator = await c.options.getUriTranslator(); |
| for (Package package in uriTranslator.packages.packages) { |
| if (allowedPackages.contains(package.name)) { |
| allowedUriPrefixes.add(package.packageUriRoot.toString()); |
| } |
| } |
| DillTarget dillTarget = |
| new DillTarget(c, ticker, uriTranslator, c.options.target); |
| KernelTarget kernelTarget = |
| new KernelTarget(c, c.fileSystem, false, dillTarget, uriTranslator); |
| Uri? platform = c.options.sdkSummary; |
| if (platform != null) { |
| var bytes = new File.fromUri(platform).readAsBytesSync(); |
| var platformComponent = loadComponentFromBytes(bytes); |
| dillTarget.loader |
| .appendLibraries(platformComponent, byteCount: bytes.length); |
| } |
| |
| kernelTarget.setEntryPoints(c.options.inputs); |
| dillTarget.buildOutlines(); |
| await kernelTarget.loader.buildOutlines(); |
| |
| { |
| List<CompilationUnit> compilationUnits = |
| kernelTarget.loader.compilationUnits.toList(growable: false); |
| List<CompilationUnit> rootCompilationUnits = []; |
| Set<Uri> inputs = new Set.of(options.inputs); |
| for (CompilationUnit unit in compilationUnits) { |
| fileUriToImportUri[unit.fileUri] = unit.importUri; |
| if (inputs.contains(unit.fileUri) || inputs.contains(unit.importUri)) { |
| rootCompilationUnits.add(unit); |
| } |
| } |
| loadedLibraries = |
| new LoadedLibrariesImpl(rootCompilationUnits, compilationUnits); |
| } |
| |
| return new List<Uri>.from(tracker.dependencies); |
| }); |
| |
| Set<Uri> otherDartUris = new Set<Uri>(); |
| Set<Uri> otherNonDartUris = new Set<Uri>(); |
| for (Uri uri in result) { |
| final String uriAsString = uri.toString(); |
| bool allowed = false; |
| for (String prefix in allowedUriPrefixes) { |
| if (uriAsString.startsWith(prefix)) { |
| allowed = true; |
| break; |
| } |
| } |
| if (!allowed) { |
| if (uri.toString().endsWith(".dart")) { |
| otherDartUris.add(uri); |
| } else { |
| otherNonDartUris.add(uri); |
| } |
| } |
| } |
| |
| // Remove allow-listed non-dart files. |
| otherNonDartUris.remove(packageConfigUri); |
| otherNonDartUris.remove(repoDir.resolve("sdk/lib/libraries.json")); |
| |
| // Remove allow-listed dart files. |
| for (String s in allowlistedExternalDartFiles) { |
| otherDartUris.remove(repoDir.resolve(s)); |
| } |
| |
| // Everything else is an error. |
| if (otherNonDartUris.isNotEmpty || otherDartUris.isNotEmpty) { |
| print("The following files was imported without being allowlisted:"); |
| for (Uri uri in otherNonDartUris) { |
| print(" - $uri"); |
| } |
| for (Uri uri in otherDartUris) { |
| print(" - $uri"); |
| if (loadedLibraries != null) { |
| Uri? importUri = fileUriToImportUri[uri]; |
| if (importUri != null) { |
| Set<String> importChains = (computeImportChainsFor( |
| Uri.parse("<entry>"), loadedLibraries!, importUri, |
| verbose: false)); |
| for (String s in importChains) { |
| print(" => $s"); |
| } |
| } |
| } |
| } |
| exitCode = 1; |
| return false; |
| } |
| return true; |
| } |
| |
| CompilerOptions getOptions() { |
| // Compile sdk because when this is run from a lint it uses the checked-in sdk |
| // and we might not have a suitable compiled platform.dill file. |
| Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true); |
| CompilerOptions options = new CompilerOptions() |
| ..sdkRoot = sdkRoot |
| ..compileSdk = true |
| ..target = new VmTarget(new TargetFlags()) |
| ..librariesSpecificationUri = repoDir.resolve("sdk/lib/libraries.json") |
| ..omitPlatform = true |
| ..onDiagnostic = (CfeDiagnosticMessage message) { |
| if (message.severity == CfeSeverity.error) { |
| Expect.fail( |
| "Unexpected error: ${message.plainTextFormatted.join('\n')}"); |
| } |
| } |
| ..environmentDefines = const {}; |
| return options; |
| } |