blob: 752c36eaded1733701dab19ce54b669b14a3e081 [file] [log] [blame]
// Copyright (c) 2017, 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:async';
// ignore: deprecated_member_use
import 'package:analyzer/analyzer.dart';
import 'package:build/build.dart';
import 'module_library.dart';
import 'module_library_builder.dart';
import 'modules.dart';
/// An [Exception] that is thrown when a worker returns an error.
abstract class _WorkerException implements Exception {
final AssetId failedAsset;
final String error;
/// A message to prepend to [toString] output.
String get message;
_WorkerException(this.failedAsset, this.error);
@override
String toString() => '$message:$failedAsset\n\nResponse:$error\n';
}
/// An [Exception] that is thrown when the analyzer fails to create a summary.
class AnalyzerSummaryException extends _WorkerException {
@override
final String message = 'Error creating summary for module';
AnalyzerSummaryException(AssetId summaryId, String error)
: super(summaryId, error);
}
/// An [Exception] that is thrown when the common frontend fails to create a
/// kernel summary.
class KernelException extends _WorkerException {
@override
final String message = 'Error creating kernel summary for module';
KernelException(AssetId summaryId, String error) : super(summaryId, error);
}
/// An [Exception] that is thrown when there are some missing modules.
class MissingModulesException implements Exception {
final String message;
@override
String toString() => message;
MissingModulesException._(this.message);
static Future<MissingModulesException> create(Set<AssetId> missingSources,
Iterable<Module> transitiveModules, AssetReader reader) async {
var buffer = StringBuffer('''
Unable to find modules for some sources, this is usually the result of either a
bad import, a missing dependency in a package (or possibly a dev_dependency
needs to move to a real dependency), or a build failure (if importing a
generated file).
Please check the following imports:\n
''');
var checkedSourceDependencies = <AssetId, Set<AssetId>>{};
for (var module in transitiveModules) {
var missingIds = module.directDependencies.intersection(missingSources);
for (var missingId in missingIds) {
var checkedAlready = checkedSourceDependencies.putIfAbsent(
missingId, () => Set<AssetId>());
for (var sourceId in module.sources) {
if (checkedAlready.contains(sourceId)) {
continue;
}
checkedAlready.add(sourceId);
var message =
await _missingImportMessage(sourceId, missingId, reader);
if (message != null) buffer.writeln(message);
}
}
}
return MissingModulesException._(buffer.toString());
}
}
/// Checks if [sourceId] directly imports [missingId], and returns an error
/// message if so.
Future<String> _missingImportMessage(
AssetId sourceId, AssetId missingId, AssetReader reader) async {
var contents = await reader.readAsString(sourceId);
var parsed = parseDirectives(contents, suppressErrors: true);
var import =
parsed.directives.whereType<UriBasedDirective>().firstWhere((directive) {
var uriString = directive.uri.stringValue;
if (uriString.startsWith('dart:')) return false;
var id = AssetId.resolve(uriString, from: sourceId);
return id == missingId;
}, orElse: () => null);
if (import == null) return null;
var lineInfo = parsed.lineInfo.getLocation(import.offset);
return '`$import` from $sourceId at $lineInfo';
}
/// An [Exception] that is thrown when there are some unsupported modules.
class UnsupportedModules implements Exception {
final Set<Module> unsupportedModules;
UnsupportedModules(this.unsupportedModules);
Stream<ModuleLibrary> exactLibraries(AssetReader reader) async* {
for (var module in unsupportedModules) {
for (var source in module.sources) {
var libraryId = source.changeExtension(moduleLibraryExtension);
ModuleLibrary library;
if (await reader.canRead(libraryId)) {
library = ModuleLibrary.deserialize(
libraryId, await reader.readAsString(libraryId));
} else {
// A missing .module.library file indicates a part file, which can't
// have import statements, so we just skip them.
continue;
}
if (library.sdkDeps
.any((lib) => !module.platform.supportsLibrary(lib))) {
yield library;
}
}
}
}
@override
String toString() =>
'Some modules contained libraries that were incompatible '
'with the current platform.';
}