blob: be6780fcb739eaf90bfd9d3062e40d02110b9c2f [file] [log] [blame]
// Copyright (c) 2013, 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.
library dart2js.test.memory_compiler;
import 'dart:async';
import 'package:compiler/compiler.dart' show
DiagnosticHandler;
import 'package:compiler/compiler_new.dart' show
CompilationResult,
CompilerDiagnostics,
CompilerOutput,
Diagnostic,
PackagesDiscoveryProvider;
import 'package:compiler/src/diagnostics/messages.dart' show
Message;
import 'package:compiler/src/mirrors/source_mirrors.dart';
import 'package:compiler/src/mirrors/analyze.dart';
import 'package:compiler/src/null_compiler_output.dart' show
NullCompilerOutput;
import 'package:compiler/src/library_loader.dart' show
LoadedLibraries;
import 'memory_source_file_helper.dart';
export 'output_collector.dart';
export 'package:compiler/compiler_new.dart' show
CompilationResult;
class DiagnosticMessage {
final Message message;
final Uri uri;
final int begin;
final int end;
final String text;
final Diagnostic kind;
DiagnosticMessage(
this.message, this.uri, this.begin, this.end, this.text, this.kind);
String toString() => '$uri:$begin:$end:$text:$kind';
}
class DiagnosticCollector implements CompilerDiagnostics {
List<DiagnosticMessage> messages = <DiagnosticMessage>[];
void call(Uri uri, int begin, int end, String message, Diagnostic kind) {
report(null, uri, begin, end, message, kind);
}
@override
void report(Message message,
Uri uri, int begin, int end, String text, Diagnostic kind) {
messages.add(new DiagnosticMessage(message, uri, begin, end, text, kind));
}
Iterable<DiagnosticMessage> filterMessagesByKinds(List<Diagnostic> kinds) {
return messages.where(
(DiagnosticMessage message) => kinds.contains(message.kind));
}
Iterable<DiagnosticMessage> get errors {
return filterMessagesByKinds([Diagnostic.ERROR]);
}
Iterable<DiagnosticMessage> get warnings {
return filterMessagesByKinds([Diagnostic.WARNING]);
}
Iterable<DiagnosticMessage> get hints {
return filterMessagesByKinds([Diagnostic.HINT]);
}
Iterable<DiagnosticMessage> get infos {
return filterMessagesByKinds([Diagnostic.INFO]);
}
/// `true` if non-verbose messages has been collected.
bool get hasRegularMessages {
return messages.any((m) => m.kind != Diagnostic.VERBOSE_INFO);
}
void clear() {
messages.clear();
}
}
class MultiDiagnostics implements CompilerDiagnostics {
final List<CompilerDiagnostics> diagnosticsList;
const MultiDiagnostics([this.diagnosticsList = const []]);
@override
void report(Message message, Uri uri, int begin, int end,
String text, Diagnostic kind) {
for (CompilerDiagnostics diagnostics in diagnosticsList) {
diagnostics.report(message, uri, begin, end, text, kind);
}
}
}
CompilerDiagnostics createCompilerDiagnostics(
CompilerDiagnostics diagnostics,
SourceFileProvider provider,
{bool showDiagnostics: true,
bool verbose: false}) {
CompilerDiagnostics handler = diagnostics;
if (showDiagnostics) {
if (diagnostics == null) {
handler = new FormattingDiagnosticHandler(provider)..verbose = verbose;
} else {
var formattingHandler =
new FormattingDiagnosticHandler(provider)..verbose = verbose;
handler = new MultiDiagnostics([diagnostics, formattingHandler]);
}
} else if (diagnostics == null) {
handler = new MultiDiagnostics();
}
return handler;
}
Expando<MemorySourceFileProvider> expando =
new Expando<MemorySourceFileProvider>();
Future<CompilationResult> runCompiler(
{Map<String, String> memorySourceFiles: const <String, String>{},
Uri entryPoint,
List<Uri> entryPoints,
CompilerDiagnostics diagnosticHandler,
CompilerOutput outputProvider,
List<String> options: const <String>[],
Compiler cachedCompiler,
bool showDiagnostics: true,
Uri packageRoot,
Uri packageConfig,
PackagesDiscoveryProvider packagesDiscoveryProvider,
void beforeRun(Compiler compiler)}) async {
if (entryPoint == null) {
entryPoint = Uri.parse('memory:main.dart');
}
Compiler compiler = compilerFor(
memorySourceFiles: memorySourceFiles,
diagnosticHandler: diagnosticHandler,
outputProvider: outputProvider,
options: options,
cachedCompiler: cachedCompiler,
showDiagnostics: showDiagnostics,
packageRoot: packageRoot,
packageConfig: packageConfig,
packagesDiscoveryProvider: packagesDiscoveryProvider);
compiler.librariesToAnalyzeWhenRun = entryPoints;
if (beforeRun != null) {
beforeRun(compiler);
}
bool isSuccess = await compiler.run(entryPoint);
return new CompilationResult(compiler, isSuccess: isSuccess);
}
Compiler compilerFor(
{Map<String, String> memorySourceFiles: const <String, String>{},
CompilerDiagnostics diagnosticHandler,
CompilerOutput outputProvider,
List<String> options: const <String>[],
Compiler cachedCompiler,
bool showDiagnostics: true,
Uri packageRoot,
Uri packageConfig,
PackagesDiscoveryProvider packagesDiscoveryProvider}) {
Uri libraryRoot = Uri.base.resolve('sdk/');
if (packageRoot == null &&
packageConfig == null &&
packagesDiscoveryProvider == null) {
packageRoot = Uri.base.resolveUri(new Uri.file('${Platform.packageRoot}/'));
}
MemorySourceFileProvider provider;
if (cachedCompiler == null) {
provider = new MemorySourceFileProvider(memorySourceFiles);
// Saving the provider in case we need it later for a cached compiler.
expando[provider] = provider;
} else {
// When using a cached compiler, it has read a number of files from disk
// already (and will not attempt to read them again due to caching). These
// files must be available to the new diagnostic handler.
provider = expando[cachedCompiler.provider];
provider.memorySourceFiles = memorySourceFiles;
}
diagnosticHandler = createCompilerDiagnostics(
diagnosticHandler, provider,
showDiagnostics: showDiagnostics,
verbose: options.contains('-v') || options.contains('--verbose'));
if (outputProvider == null) {
outputProvider = const NullCompilerOutput();
}
Compiler compiler = new Compiler(
provider,
outputProvider,
diagnosticHandler,
libraryRoot,
packageRoot,
options,
{},
packageConfig,
packagesDiscoveryProvider);
if (cachedCompiler != null) {
compiler.coreLibrary =
cachedCompiler.libraryLoader.lookupLibrary(Uri.parse('dart:core'));
compiler.types = cachedCompiler.types.copy(compiler.resolution);
Map copiedLibraries = {};
cachedCompiler.libraryLoader.libraries.forEach((library) {
if (library.isPlatformLibrary) {
var libraryLoader = compiler.libraryLoader;
libraryLoader.mapLibrary(library);
compiler.onLibraryCreated(library);
compiler.onLibraryScanned(library, null);
if (library.isPatched) {
var patchLibrary = library.patch;
compiler.onLibraryCreated(patchLibrary);
compiler.onLibraryScanned(patchLibrary, null);
}
copiedLibraries[library.canonicalUri] = library;
}
});
// TODO(johnniwinther): Assert that no libraries are loaded lazily from
// this call.
compiler.onLibrariesLoaded(new MemoryLoadedLibraries(copiedLibraries));
compiler.backend.constantCompilerTask.copyConstantValues(
cachedCompiler.backend.constantCompilerTask);
compiler.symbolConstructor = cachedCompiler.symbolConstructor;
compiler.mirrorSystemClass = cachedCompiler.mirrorSystemClass;
compiler.mirrorsUsedClass = cachedCompiler.mirrorsUsedClass;
compiler.mirrorSystemGetNameFunction =
cachedCompiler.mirrorSystemGetNameFunction;
compiler.symbolImplementationClass =
cachedCompiler.symbolImplementationClass;
compiler.symbolValidatedConstructor =
cachedCompiler.symbolValidatedConstructor;
compiler.mirrorsUsedConstructor = cachedCompiler.mirrorsUsedConstructor;
compiler.deferredLibraryClass = cachedCompiler.deferredLibraryClass;
Iterable cachedTreeElements =
cachedCompiler.enqueuer.resolution.processedElements;
cachedTreeElements.forEach((element) {
if (element.library.isPlatformLibrary) {
compiler.enqueuer.resolution.registerProcessedElement(element);
}
});
// One potential problem that can occur when reusing elements is that there
// is a stale reference to an old compiler object. By nulling out the old
// compiler's fields, such stale references are easier to identify.
cachedCompiler.scanner = null;
cachedCompiler.dietParser = null;
cachedCompiler.parser = null;
cachedCompiler.patchParser = null;
cachedCompiler.libraryLoader = null;
cachedCompiler.resolver = null;
cachedCompiler.closureToClassMapper = null;
cachedCompiler.checker = null;
cachedCompiler.typesTask = null;
cachedCompiler.backend = null;
// Don't null out the enqueuer as it prevents us from using cachedCompiler
// more than once.
cachedCompiler.deferredLoadTask = null;
cachedCompiler.mirrorUsageAnalyzerTask = null;
cachedCompiler.dumpInfoTask = null;
cachedCompiler.buildId = null;
}
return compiler;
}
class MemoryLoadedLibraries implements LoadedLibraries {
final Map copiedLibraries;
MemoryLoadedLibraries(this.copiedLibraries);
@override
bool containsLibrary(Uri uri) => copiedLibraries.containsKey(uri);
@override
void forEachImportChain(f, {callback}) {}
@override
void forEachLibrary(f) {}
@override
getLibrary(Uri uri) => copiedLibraries[uri];
@override
Uri get rootUri => null;
}
DiagnosticHandler createDiagnosticHandler(DiagnosticHandler diagnosticHandler,
SourceFileProvider provider,
bool showDiagnostics) {
var handler = diagnosticHandler;
if (showDiagnostics) {
if (diagnosticHandler == null) {
handler = new FormattingDiagnosticHandler(provider);
} else {
var formattingHandler = new FormattingDiagnosticHandler(provider);
handler = (Uri uri, int begin, int end, String message, Diagnostic kind) {
diagnosticHandler(uri, begin, end, message, kind);
formattingHandler(uri, begin, end, message, kind);
};
}
} else if (diagnosticHandler == null) {
handler = (Uri uri, int begin, int end, String message, Diagnostic kind) {};
}
return handler;
}
Future<MirrorSystem> mirrorSystemFor(Map<String,String> memorySourceFiles,
{DiagnosticHandler diagnosticHandler,
List<String> options: const [],
bool showDiagnostics: true}) {
Uri libraryRoot = Uri.base.resolve('sdk/');
Uri packageRoot = Uri.base.resolveUri(
new Uri.file('${Platform.packageRoot}/'));
var provider = new MemorySourceFileProvider(memorySourceFiles);
var handler =
createDiagnosticHandler(diagnosticHandler, provider, showDiagnostics);
List<Uri> libraries = <Uri>[];
memorySourceFiles.forEach((String path, _) {
libraries.add(new Uri(scheme: 'memory', path: path));
});
return analyze(libraries, libraryRoot, packageRoot,
provider, handler, options);
}