Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Unified Diff: pkg/compiler/lib/src/compiler.dart

Issue 1383483006: Extract DiagnosticReporter implementation from Compiler. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Fixes after rebase. Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/compiler.dart
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 6ebb7a56ba782611176b0a4fd6e79451fc10195c..5df0af3c5812b6ca112e299d66a14df9155beb58 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -44,7 +44,10 @@ import 'dart_types.dart' show
Types;
import 'deferred_load.dart' show DeferredLoadTask, OutputUnit;
import 'diagnostics/code_location.dart';
-import 'diagnostics/diagnostic_listener.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+ DiagnosticMessage,
+ DiagnosticOptions,
+ DiagnosticReporter;
import 'diagnostics/invariant.dart' show
invariant,
REPORT_EXCESS_RESOLUTION;
@@ -139,13 +142,14 @@ import 'util/util.dart' show
import 'world.dart' show
World;
-abstract class Compiler extends DiagnosticListener {
+abstract class Compiler {
final Stopwatch totalCompileTime = new Stopwatch();
int nextFreeClassId = 0;
World world;
Types types;
_CompilerCoreTypes _coreTypes;
+ _CompilerDiagnosticReporter _reporter;
_CompilerResolution _resolution;
_CompilerParsing _parsing;
@@ -248,14 +252,6 @@ abstract class Compiler extends DiagnosticListener {
/// If `true`, warnings and hints not from user code are reported.
final bool showPackageWarnings;
- /// `true` if the last diagnostic was filtered, in which case the
- /// accompanying info message should be filtered as well.
- bool lastDiagnosticWasFiltered = false;
-
- /// Map containing information about the warnings and hints that have been
- /// suppressed for each library.
- Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
-
final bool suppressWarnings;
final bool fatalWarnings;
@@ -287,7 +283,6 @@ abstract class Compiler extends DiagnosticListener {
Tracer tracer;
CompilerTask measuredTask;
- Element _currentElement;
LibraryElement coreLibrary;
LibraryElement asyncLibrary;
@@ -318,6 +313,7 @@ abstract class Compiler extends DiagnosticListener {
ClassElement get iterableClass => _coreTypes.iterableClass;
ClassElement get streamClass => _coreTypes.streamClass;
+ DiagnosticReporter get reporter => _reporter;
CoreTypes get coreTypes => _coreTypes;
Resolution get resolution => _resolution;
Parsing get parsing => _parsing;
@@ -378,49 +374,7 @@ abstract class Compiler extends DiagnosticListener {
fromEnvironment(String name) => null;
- Element get currentElement => _currentElement;
-
- String tryToString(object) {
- try {
- return object.toString();
- } catch (_) {
- return '<exception in toString()>';
- }
- }
-
- /**
- * Perform an operation, [f], returning the return value from [f]. If an
- * error occurs then report it as having occurred during compilation of
- * [element]. Can be nested.
- */
- withCurrentElement(Element element, f()) {
- Element old = currentElement;
- _currentElement = element;
- try {
- return f();
- } on SpannableAssertionFailure catch (ex) {
- if (!hasCrashed) {
- reportAssertionFailure(ex);
- pleaseReportCrash();
- }
- hasCrashed = true;
- rethrow;
- } on StackOverflowError {
- // We cannot report anything useful in this case, because we
- // do not have enough stack space.
- rethrow;
- } catch (ex) {
- if (hasCrashed) rethrow;
- try {
- unhandledExceptionOnElement(element);
- } catch (doubleFault) {
- // Ignoring exceptions in exception handling.
- }
- rethrow;
- } finally {
- _currentElement = old;
- }
- }
+ Element get currentElement => _reporter.currentElement;
List<CompilerTask> tasks;
ScannerTask scanner;
@@ -464,6 +418,8 @@ abstract class Compiler extends DiagnosticListener {
bool enabledInvokeOn = false;
bool hasIsolateSupport = false;
+ bool get hasCrashed => _reporter.hasCrashed;
+
Stopwatch progress;
bool get shouldPrintProgress {
@@ -487,8 +443,6 @@ abstract class Compiler extends DiagnosticListener {
compilationFailedInternal = value;
}
- bool hasCrashed = false;
-
/// Set by the backend if real reflection is detected in use of dart:mirrors.
bool disableTypeInferenceForMirrors = false;
@@ -549,6 +503,11 @@ abstract class Compiler extends DiagnosticListener {
world = new World(this);
// TODO(johnniwinther): Initialize core types in [initializeCoreClasses] and
// make its field final.
+ _reporter = new _CompilerDiagnosticReporter(this,
+ new DiagnosticOptions(
+ suppressWarnings: suppressWarnings,
+ terseDiagnostics: terseDiagnostics,
+ showPackageWarnings: showPackageWarnings));
_parsing = new _CompilerParsing(this);
_resolution = new _CompilerResolution(this);
_coreTypes = new _CompilerCoreTypes(_resolution);
@@ -616,118 +575,15 @@ abstract class Compiler extends DiagnosticListener {
int getNextFreeClassId() => nextFreeClassId++;
void unimplemented(Spannable spannable, String methodName) {
- internalError(spannable, "$methodName not implemented.");
- }
-
- internalError(Spannable node, reason) {
- String message = tryToString(reason);
- reportDiagnosticInternal(
- createMessage(node, MessageKind.GENERIC, {'text': message}),
- const <DiagnosticMessage>[],
- api.Diagnostic.CRASH);
- throw 'Internal Error: $message';
- }
-
- void unhandledExceptionOnElement(Element element) {
- if (hasCrashed) return;
- hasCrashed = true;
- reportDiagnostic(
- createMessage(element, MessageKind.COMPILER_CRASHED),
- const <DiagnosticMessage>[],
- api.Diagnostic.CRASH);
- pleaseReportCrash();
- }
-
- void pleaseReportCrash() {
- print(
- MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
- .message({'buildId': buildId}));
- }
-
- SourceSpan spanFromSpannable(Spannable node) {
- // TODO(johnniwinther): Disallow `node == null` ?
- if (node == null) return null;
- if (node == CURRENT_ELEMENT_SPANNABLE) {
- node = currentElement;
- } else if (node == NO_LOCATION_SPANNABLE) {
- if (currentElement == null) return null;
- node = currentElement;
- }
- if (node is SourceSpan) {
- return node;
- } else if (node is Node) {
- return spanFromNode(node);
- } else if (node is TokenPair) {
- return spanFromTokens(node.begin, node.end);
- } else if (node is Token) {
- return spanFromTokens(node, node);
- } else if (node is HInstruction) {
- return spanFromHInstruction(node);
- } else if (node is Element) {
- return spanFromElement(node);
- } else if (node is MetadataAnnotation) {
- Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
- return spanFromTokens(node.beginToken, node.endToken, uri);
- } else if (node is Local) {
- Local local = node;
- return spanFromElement(local.executableContext);
- } else {
- throw 'No error location.';
- }
- }
-
- Element _elementFromHInstruction(HInstruction instruction) {
- return instruction.sourceElement is Element
- ? instruction.sourceElement : null;
- }
-
- /// Finds the approximate [Element] for [node]. [currentElement] is used as
- /// the default value.
- Element elementFromSpannable(Spannable node) {
- Element element;
- if (node is Element) {
- element = node;
- } else if (node is HInstruction) {
- element = _elementFromHInstruction(node);
- } else if (node is MetadataAnnotation) {
- element = node.annotatedElement;
- }
- return element != null ? element : currentElement;
- }
-
- void log(message) {
- Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
- .message({'text': '$message'});
- reportDiagnostic(
- new DiagnosticMessage(null, null, msg),
- const <DiagnosticMessage>[],
- api.Diagnostic.VERBOSE_INFO);
+ reporter.internalError(spannable, "$methodName not implemented.");
}
Future<bool> run(Uri uri) {
totalCompileTime.start();
- return new Future.sync(() => runCompiler(uri)).catchError((error) {
- try {
- if (!hasCrashed) {
- hasCrashed = true;
- if (error is SpannableAssertionFailure) {
- reportAssertionFailure(error);
- } else {
- reportDiagnostic(
- createMessage(
- new SourceSpan(uri, 0, 0),
- MessageKind.COMPILER_CRASHED),
- const <DiagnosticMessage>[],
- api.Diagnostic.CRASH);
- }
- pleaseReportCrash();
- }
- } catch (doubleFault) {
- // Ignoring exceptions in exception handling.
- }
- throw error;
- }).whenComplete(() {
+ return new Future.sync(() => runCompiler(uri))
+ .catchError((error) => _reporter.onError(uri, error))
+ .whenComplete(() {
tracer.close();
totalCompileTime.stop();
}).then((_) {
@@ -866,7 +722,7 @@ abstract class Compiler extends DiagnosticListener {
if (loadedLibraries.containsLibrary(uri)) {
Set<String> importChains =
computeImportChainsFor(loadedLibraries, Uri.parse('dart:io'));
- reportInfo(NO_LOCATION_SPANNABLE,
+ reporter.reportInfo(NO_LOCATION_SPANNABLE,
MessageKind.DISALLOWED_LIBRARY_IMPORT,
{'uri': uri,
'importChain': importChains.join(
@@ -883,7 +739,7 @@ abstract class Compiler extends DiagnosticListener {
if (importsMirrorsLibrary && !backend.supportsReflection) {
Set<String> importChains =
computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
- reportErrorMessage(
+ reporter.reportErrorMessage(
NO_LOCATION_SPANNABLE,
MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
{'importChain': importChains.join(
@@ -891,7 +747,7 @@ abstract class Compiler extends DiagnosticListener {
} else if (importsMirrorsLibrary && !enableExperimentalMirrors) {
Set<String> importChains =
computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
- reportWarningMessage(
+ reporter.reportWarningMessage(
NO_LOCATION_SPANNABLE,
MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
{'importChain': importChains.join(
@@ -925,10 +781,10 @@ abstract class Compiler extends DiagnosticListener {
Element findRequiredElement(LibraryElement library, String name) {
var element = library.find(name);
if (element == null) {
- internalError(library,
+ reporter.internalError(library,
"The library '${library.canonicalUri}' does not contain required "
"element: '$name'.");
- }
+ }
return element;
}
@@ -983,7 +839,7 @@ abstract class Compiler extends DiagnosticListener {
_coreTypes.iterableClass = lookupCoreClass('Iterable');
_coreTypes.symbolClass = lookupCoreClass('Symbol');
if (!missingCoreClasses.isEmpty) {
- internalError(
+ reporter.internalError(
coreLibrary,
'dart:core library does not contain required classes: '
'$missingCoreClasses');
@@ -1020,16 +876,16 @@ abstract class Compiler extends DiagnosticListener {
return new Future.sync(() {
if (librariesToAnalyzeWhenRun != null) {
return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) {
- log('Analyzing $libraryUri ($buildId)');
+ reporter.log('Analyzing $libraryUri ($buildId)');
return libraryLoader.loadLibrary(libraryUri);
});
}
}).then((_) {
if (uri != null) {
if (analyzeOnly) {
- log('Analyzing $uri ($buildId)');
+ reporter.log('Analyzing $uri ($buildId)');
} else {
- log('Compiling $uri ($buildId)');
+ reporter.log('Compiling $uri ($buildId)');
}
return libraryLoader.loadLibrary(uri).then((LibraryElement library) {
mainApp = library;
@@ -1063,7 +919,7 @@ abstract class Compiler extends DiagnosticListener {
if (main is ErroneousElement) {
errorElement = main;
} else {
- internalError(main, 'Problem with ${Identifiers.main}.');
+ reporter.internalError(main, 'Problem with ${Identifiers.main}.');
}
mainFunction = backend.helperForBadMain();
} else if (!main.isFunction) {
@@ -1091,7 +947,7 @@ abstract class Compiler extends DiagnosticListener {
}
if (mainFunction == null) {
if (errorElement == null && !analyzeOnly && !analyzeAll) {
- internalError(mainApp, "Problem with '${Identifiers.main}'.");
+ reporter.internalError(mainApp, "Problem with '${Identifiers.main}'.");
} else {
mainFunction = errorElement;
}
@@ -1099,7 +955,7 @@ abstract class Compiler extends DiagnosticListener {
if (errorElement != null &&
errorElement.isSynthesized &&
!mainApp.isSynthesized) {
- reportWarningMessage(
+ reporter.reportWarningMessage(
errorElement, errorElement.messageKind,
errorElement.messageArguments);
}
@@ -1116,7 +972,7 @@ abstract class Compiler extends DiagnosticListener {
Uri libraryUri,
{bool skipLibraryWithPartOfTag: true}) {
assert(analyzeMain);
- log('Analyzing $libraryUri ($buildId)');
+ reporter.log('Analyzing $libraryUri ($buildId)');
return libraryLoader.loadLibrary(libraryUri).then((LibraryElement library) {
var compilationUnit = library.compilationUnit;
if (skipLibraryWithPartOfTag && compilationUnit.partTag != null) {
@@ -1124,7 +980,7 @@ abstract class Compiler extends DiagnosticListener {
}
fullyEnqueueLibrary(library, enqueuer.resolution);
emptyQueue(enqueuer.resolution);
- enqueuer.resolution.logSummary(log);
+ enqueuer.resolution.logSummary(reporter.log);
return library;
});
}
@@ -1144,7 +1000,7 @@ abstract class Compiler extends DiagnosticListener {
phase = PHASE_RESOLVING;
if (analyzeAll) {
libraryLoader.libraries.forEach((LibraryElement library) {
- log('Enqueuing ${library.canonicalUri}');
+ reporter.log('Enqueuing ${library.canonicalUri}');
fullyEnqueueLibrary(library, enqueuer.resolution);
});
} else if (analyzeMain && mainApp != null) {
@@ -1154,30 +1010,11 @@ abstract class Compiler extends DiagnosticListener {
// that are not pulled in by a particular element.
backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
resolveLibraryMetadata();
- log('Resolving...');
+ reporter.log('Resolving...');
processQueue(enqueuer.resolution, mainFunction);
- enqueuer.resolution.logSummary(log);
+ enqueuer.resolution.logSummary(reporter.log);
- if (!showPackageWarnings && !suppressWarnings) {
- suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
- MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
- if (info.warnings == 0) {
- kind = MessageKind.HIDDEN_HINTS;
- } else if (info.hints == 0) {
- kind = MessageKind.HIDDEN_WARNINGS;
- }
- MessageTemplate template = MessageTemplate.TEMPLATES[kind];
- Message message = template.message(
- {'warnings': info.warnings,
- 'hints': info.hints,
- 'uri': uri},
- terseDiagnostics);
- reportDiagnostic(
- new DiagnosticMessage(null, null, message),
- const <DiagnosticMessage>[],
- api.Diagnostic.HINT);
- });
- }
+ _reporter.reportSuppressedMessagesSummary();
if (compilationFailed){
if (!generateCodeWithCompileTimeErrors) return;
@@ -1208,14 +1045,14 @@ abstract class Compiler extends DiagnosticListener {
deferredLoadTask.onResolutionComplete(mainFunction);
- log('Inferring types...');
+ reporter.log('Inferring types...');
typesTask.onResolutionComplete(mainFunction);
if (stopAfterTypeInference) return;
backend.onTypeInferenceComplete();
- log('Compiling...');
+ reporter.log('Compiling...');
phase = PHASE_COMPILING;
backend.onCodegenStart();
// TODO(johnniwinther): Move these to [CodegenEnqueuer].
@@ -1228,7 +1065,7 @@ abstract class Compiler extends DiagnosticListener {
});
}
processQueue(enqueuer.codegen, mainFunction);
- enqueuer.codegen.logSummary(log);
+ enqueuer.codegen.logSummary(reporter.log);
int programSize = backend.assembleProgram();
@@ -1277,7 +1114,7 @@ abstract class Compiler extends DiagnosticListener {
*/
void emptyQueue(Enqueuer world) {
world.forEach((WorkItem work) {
- withCurrentElement(work.element, () {
+ reporter.withCurrentElement(work.element, () {
world.applyImpact(work.element, work.run(this, world));
});
});
@@ -1319,7 +1156,7 @@ abstract class Compiler extends DiagnosticListener {
checkQueues() {
for (Enqueuer world in [enqueuer.resolution, enqueuer.codegen]) {
world.forEach((WorkItem work) {
- internalError(work.element, "Work list is not empty.");
+ reporter.internalError(work.element, "Work list is not empty.");
});
}
if (!REPORT_EXCESS_RESOLUTION) return;
@@ -1342,9 +1179,9 @@ abstract class Compiler extends DiagnosticListener {
resolved.remove(e);
}
}
- log('Excess resolution work: ${resolved.length}.');
+ reporter.log('Excess resolution work: ${resolved.length}.');
for (Element e in resolved) {
- reportWarningMessage(e,
+ reporter.reportWarningMessage(e,
MessageKind.GENERIC,
{'text': 'Warning: $e resolved but not compiled.'});
}
@@ -1386,7 +1223,8 @@ abstract class Compiler extends DiagnosticListener {
// TODO(ahe): Add structured diagnostics to the compiler API and
// use it to separate this from the --verbose option.
if (phase == PHASE_RESOLVING) {
- log('Resolved ${enqueuer.resolution.resolvedElements.length} '
+ reporter.log(
+ 'Resolved ${enqueuer.resolution.resolvedElements.length} '
'elements.');
progress.reset();
}
@@ -1405,195 +1243,61 @@ abstract class Compiler extends DiagnosticListener {
if (shouldPrintProgress) {
// TODO(ahe): Add structured diagnostics to the compiler API and
// use it to separate this from the --verbose option.
- log('Compiled ${enqueuer.codegen.generatedCode.length} methods.');
+ reporter.log(
+ 'Compiled ${enqueuer.codegen.generatedCode.length} methods.');
progress.reset();
}
return backend.codegen(work);
}
- DiagnosticMessage createMessage(
- Spannable spannable,
- MessageKind messageKind,
- [Map arguments = const {}]) {
- SourceSpan span = spanFromSpannable(spannable);
- MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
- Message message = template.message(arguments, terseDiagnostics);
- return new DiagnosticMessage(span, spannable, message);
- }
+ void reportDiagnostic(DiagnosticMessage message,
+ List<DiagnosticMessage> infos,
+ api.Diagnostic kind);
- void reportError(
- DiagnosticMessage message,
- [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
- reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
+ void reportCrashInUserCode(String message, exception, stackTrace) {
+ _reporter.onCrashInUserCode(message, exception, stackTrace);
}
- void reportWarning(
- DiagnosticMessage message,
- [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
- reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
+ /**
+ * Translates the [resolvedUri] into a readable URI.
+ *
+ * The [importingLibrary] holds the library importing [resolvedUri] or
+ * [:null:] if [resolvedUri] is loaded as the main library. The
+ * [importingLibrary] is used to grant access to internal libraries from
+ * platform libraries and patch libraries.
+ *
+ * If the [resolvedUri] is not accessible from [importingLibrary], this method
+ * is responsible for reporting errors.
+ *
+ * See [LibraryLoader] for terminology on URIs.
+ */
+ Uri translateResolvedUri(LibraryElement importingLibrary,
+ Uri resolvedUri, Spannable spannable) {
+ unimplemented(importingLibrary, 'Compiler.translateResolvedUri');
+ return null;
}
- void reportHint(
- DiagnosticMessage message,
- [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
- reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
+ /**
+ * Reads the script specified by the [readableUri].
+ *
+ * See [LibraryLoader] for terminology on URIs.
+ */
+ Future<Script> readScript(Spannable node, Uri readableUri) {
+ unimplemented(node, 'Compiler.readScript');
+ return null;
}
- @deprecated
- void reportInfo(Spannable node, MessageKind messageKind,
- [Map arguments = const {}]) {
- reportDiagnosticInternal(
- createMessage(node, messageKind, arguments),
- const <DiagnosticMessage>[],
- api.Diagnostic.INFO);
+ /// Compatible with [readScript] and used by [LibraryLoader] to create
+ /// synthetic scripts to recover from read errors and bad URIs.
+ Future<Script> synthesizeScript(Spannable node, Uri readableUri) {
+ unimplemented(node, 'Compiler.synthesizeScript');
+ return null;
}
- void reportDiagnosticInternal(DiagnosticMessage message,
- List<DiagnosticMessage> infos,
- api.Diagnostic kind) {
- if (!showPackageWarnings && message.spannable != NO_LOCATION_SPANNABLE) {
- switch (kind) {
- case api.Diagnostic.WARNING:
- case api.Diagnostic.HINT:
- Element element = elementFromSpannable(message.spannable);
- if (!inUserCode(element, assumeInUserCode: true)) {
- Uri uri = getCanonicalUri(element);
- SuppressionInfo info =
- suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
- if (kind == api.Diagnostic.WARNING) {
- info.warnings++;
- } else {
- info.hints++;
- }
- lastDiagnosticWasFiltered = true;
- return;
- }
- break;
- case api.Diagnostic.INFO:
- if (lastDiagnosticWasFiltered) {
- return;
- }
- break;
- }
- }
- lastDiagnosticWasFiltered = false;
- reportDiagnostic(message, infos, kind);
- }
-
- void reportDiagnostic(DiagnosticMessage message,
- List<DiagnosticMessage> infos,
- api.Diagnostic kind);
-
- void reportAssertionFailure(SpannableAssertionFailure ex) {
- String message = (ex.message != null) ? tryToString(ex.message)
- : tryToString(ex);
- reportDiagnosticInternal(
- createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
- const <DiagnosticMessage>[],
- api.Diagnostic.CRASH);
- }
-
- SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
- if (begin == null || end == null) {
- // TODO(ahe): We can almost always do better. Often it is only
- // end that is null. Otherwise, we probably know the current
- // URI.
- throw 'Cannot find tokens to produce error message.';
- }
- if (uri == null && currentElement != null) {
- uri = currentElement.compilationUnit.script.resourceUri;
- }
- return new SourceSpan.fromTokens(uri, begin, end);
- }
-
- SourceSpan spanFromNode(Node node) {
- return spanFromTokens(node.getBeginToken(), node.getEndToken());
- }
-
- SourceSpan spanFromElement(Element element) {
- if (element != null && element.sourcePosition != null) {
- return element.sourcePosition;
- }
- while (element != null && element.isSynthesized) {
- element = element.enclosingElement;
- }
- if (element != null &&
- element.sourcePosition == null &&
- !element.isLibrary &&
- !element.isCompilationUnit) {
- // Sometimes, the backend fakes up elements that have no
- // position. So we use the enclosing element instead. It is
- // not a good error location, but cancel really is "internal
- // error" or "not implemented yet", so the vicinity is good
- // enough for now.
- element = element.enclosingElement;
- // TODO(ahe): I plan to overhaul this infrastructure anyways.
- }
- if (element == null) {
- element = currentElement;
- }
- if (element == null) {
- return null;
- }
-
- if (element.sourcePosition != null) {
- return element.sourcePosition;
- }
- Token position = element.position;
- Uri uri = element.compilationUnit.script.resourceUri;
- return (position == null)
- ? new SourceSpan(uri, 0, 0)
- : spanFromTokens(position, position, uri);
- }
-
- SourceSpan spanFromHInstruction(HInstruction instruction) {
- Element element = _elementFromHInstruction(instruction);
- if (element == null) element = currentElement;
- SourceInformation position = instruction.sourceInformation;
- if (position == null) return spanFromElement(element);
- return position.sourceSpan;
- }
-
- /**
- * Translates the [resolvedUri] into a readable URI.
- *
- * The [importingLibrary] holds the library importing [resolvedUri] or
- * [:null:] if [resolvedUri] is loaded as the main library. The
- * [importingLibrary] is used to grant access to internal libraries from
- * platform libraries and patch libraries.
- *
- * If the [resolvedUri] is not accessible from [importingLibrary], this method
- * is responsible for reporting errors.
- *
- * See [LibraryLoader] for terminology on URIs.
- */
- Uri translateResolvedUri(LibraryElement importingLibrary,
- Uri resolvedUri, Spannable spannable) {
- unimplemented(importingLibrary, 'Compiler.translateResolvedUri');
- return null;
- }
-
- /**
- * Reads the script specified by the [readableUri].
- *
- * See [LibraryLoader] for terminology on URIs.
- */
- Future<Script> readScript(Spannable node, Uri readableUri) {
- unimplemented(node, 'Compiler.readScript');
- return null;
- }
-
- /// Compatible with [readScript] and used by [LibraryLoader] to create
- /// synthetic scripts to recover from read errors and bad URIs.
- Future<Script> synthesizeScript(Spannable node, Uri readableUri) {
- unimplemented(node, 'Compiler.synthesizeScript');
- return null;
- }
-
- Element lookupElementIn(ScopeContainerElement container, String name) {
- Element element = container.localLookup(name);
- if (element == null) {
- throw 'Could not find $name in $container';
+ Element lookupElementIn(ScopeContainerElement container, String name) {
+ Element element = container.localLookup(name);
+ if (element == null) {
+ throw 'Could not find $name in $container';
}
return element;
}
@@ -1627,19 +1331,19 @@ abstract class Compiler extends DiagnosticListener {
if (member.isErroneous) return;
if (member.isFunction) {
if (!enqueuer.resolution.hasBeenResolved(member)) {
- reportHintMessage(
+ reporter.reportHintMessage(
member, MessageKind.UNUSED_METHOD, {'name': member.name});
}
} else if (member.isClass) {
if (!member.isResolved) {
- reportHintMessage(
+ reporter.reportHintMessage(
member, MessageKind.UNUSED_CLASS, {'name': member.name});
} else {
member.forEachLocalMember(checkLive);
}
} else if (member.isTypedef) {
if (!member.isResolved) {
- reportHintMessage(
+ reporter.reportHintMessage(
member, MessageKind.UNUSED_TYPEDEF, {'name': member.name});
}
}
@@ -1869,6 +1573,350 @@ class _CompilerCoreTypes implements CoreTypes {
}
}
+class _CompilerDiagnosticReporter extends DiagnosticReporter {
+ final Compiler compiler;
+ final DiagnosticOptions options;
+
+ Element _currentElement;
+ bool hasCrashed = false;
+
+ /// `true` if the last diagnostic was filtered, in which case the
+ /// accompanying info message should be filtered as well.
+ bool lastDiagnosticWasFiltered = false;
+
+ /// Map containing information about the warnings and hints that have been
+ /// suppressed for each library.
+ Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
+
+ _CompilerDiagnosticReporter(this.compiler, this.options);
+
+ Element get currentElement => _currentElement;
+
+ DiagnosticMessage createMessage(
+ Spannable spannable,
+ MessageKind messageKind,
+ [Map arguments = const {}]) {
+ SourceSpan span = spanFromSpannable(spannable);
+ MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+ Message message = template.message(arguments, options.terseDiagnostics);
+ return new DiagnosticMessage(span, spannable, message);
+ }
+
+ void reportError(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
+ }
+
+ void reportWarning(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
+ }
+
+ void reportHint(
+ DiagnosticMessage message,
+ [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+ reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
+ }
+
+ @deprecated
+ void reportInfo(Spannable node, MessageKind messageKind,
+ [Map arguments = const {}]) {
+ reportDiagnosticInternal(
+ createMessage(node, messageKind, arguments),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.INFO);
+ }
+
+ void reportDiagnosticInternal(DiagnosticMessage message,
+ List<DiagnosticMessage> infos,
+ api.Diagnostic kind) {
+ if (!options.showPackageWarnings &&
+ message.spannable != NO_LOCATION_SPANNABLE) {
+ switch (kind) {
+ case api.Diagnostic.WARNING:
+ case api.Diagnostic.HINT:
+ Element element = elementFromSpannable(message.spannable);
+ if (!compiler.inUserCode(element, assumeInUserCode: true)) {
+ Uri uri = compiler.getCanonicalUri(element);
+ SuppressionInfo info =
+ suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
+ if (kind == api.Diagnostic.WARNING) {
+ info.warnings++;
+ } else {
+ info.hints++;
+ }
+ lastDiagnosticWasFiltered = true;
+ return;
+ }
+ break;
+ case api.Diagnostic.INFO:
+ if (lastDiagnosticWasFiltered) {
+ return;
+ }
+ break;
+ }
+ }
+ lastDiagnosticWasFiltered = false;
+ reportDiagnostic(message, infos, kind);
+ }
+
+ void reportDiagnostic(DiagnosticMessage message,
+ List<DiagnosticMessage> infos,
+ api.Diagnostic kind) {
+ compiler.reportDiagnostic(message, infos, kind);
+ }
+
+ /**
+ * Perform an operation, [f], returning the return value from [f]. If an
+ * error occurs then report it as having occurred during compilation of
+ * [element]. Can be nested.
+ */
+ withCurrentElement(Element element, f()) {
+ Element old = currentElement;
+ _currentElement = element;
+ try {
+ return f();
+ } on SpannableAssertionFailure catch (ex) {
+ if (!hasCrashed) {
+ reportAssertionFailure(ex);
+ pleaseReportCrash();
+ }
+ hasCrashed = true;
+ rethrow;
+ } on StackOverflowError {
+ // We cannot report anything useful in this case, because we
+ // do not have enough stack space.
+ rethrow;
+ } catch (ex) {
+ if (hasCrashed) rethrow;
+ try {
+ unhandledExceptionOnElement(element);
+ } catch (doubleFault) {
+ // Ignoring exceptions in exception handling.
+ }
+ rethrow;
+ } finally {
+ _currentElement = old;
+ }
+ }
+
+ void reportAssertionFailure(SpannableAssertionFailure ex) {
+ String message = (ex.message != null) ? tryToString(ex.message)
+ : tryToString(ex);
+ reportDiagnosticInternal(
+ createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.CRASH);
+ }
+
+ SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
+ if (begin == null || end == null) {
+ // TODO(ahe): We can almost always do better. Often it is only
+ // end that is null. Otherwise, we probably know the current
+ // URI.
+ throw 'Cannot find tokens to produce error message.';
+ }
+ if (uri == null && currentElement != null) {
+ uri = currentElement.compilationUnit.script.resourceUri;
+ }
+ return new SourceSpan.fromTokens(uri, begin, end);
+ }
+
+ SourceSpan spanFromNode(Node node) {
+ return spanFromTokens(node.getBeginToken(), node.getEndToken());
+ }
+
+ SourceSpan spanFromElement(Element element) {
+ if (element != null && element.sourcePosition != null) {
+ return element.sourcePosition;
+ }
+ while (element != null && element.isSynthesized) {
+ element = element.enclosingElement;
+ }
+ if (element != null &&
+ element.sourcePosition == null &&
+ !element.isLibrary &&
+ !element.isCompilationUnit) {
+ // Sometimes, the backend fakes up elements that have no
+ // position. So we use the enclosing element instead. It is
+ // not a good error location, but cancel really is "internal
+ // error" or "not implemented yet", so the vicinity is good
+ // enough for now.
+ element = element.enclosingElement;
+ // TODO(ahe): I plan to overhaul this infrastructure anyways.
+ }
+ if (element == null) {
+ element = currentElement;
+ }
+ if (element == null) {
+ return null;
+ }
+
+ if (element.sourcePosition != null) {
+ return element.sourcePosition;
+ }
+ Token position = element.position;
+ Uri uri = element.compilationUnit.script.resourceUri;
+ return (position == null)
+ ? new SourceSpan(uri, 0, 0)
+ : spanFromTokens(position, position, uri);
+ }
+
+ SourceSpan spanFromHInstruction(HInstruction instruction) {
+ Element element = _elementFromHInstruction(instruction);
+ if (element == null) element = currentElement;
+ SourceInformation position = instruction.sourceInformation;
+ if (position == null) return spanFromElement(element);
+ return position.sourceSpan;
+ }
+
+ SourceSpan spanFromSpannable(Spannable node) {
+ // TODO(johnniwinther): Disallow `node == null` ?
+ if (node == null) return null;
+ if (node == CURRENT_ELEMENT_SPANNABLE) {
+ node = currentElement;
+ } else if (node == NO_LOCATION_SPANNABLE) {
+ if (currentElement == null) return null;
+ node = currentElement;
+ }
+ if (node is SourceSpan) {
+ return node;
+ } else if (node is Node) {
+ return spanFromNode(node);
+ } else if (node is TokenPair) {
+ return spanFromTokens(node.begin, node.end);
+ } else if (node is Token) {
+ return spanFromTokens(node, node);
+ } else if (node is HInstruction) {
+ return spanFromHInstruction(node);
+ } else if (node is Element) {
+ return spanFromElement(node);
+ } else if (node is MetadataAnnotation) {
+ Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
+ return spanFromTokens(node.beginToken, node.endToken, uri);
+ } else if (node is Local) {
+ Local local = node;
+ return spanFromElement(local.executableContext);
+ } else {
+ throw 'No error location.';
+ }
+ }
+
+ Element _elementFromHInstruction(HInstruction instruction) {
+ return instruction.sourceElement is Element
+ ? instruction.sourceElement : null;
+ }
+
+ internalError(Spannable node, reason) {
+ String message = tryToString(reason);
+ reportDiagnosticInternal(
+ createMessage(node, MessageKind.GENERIC, {'text': message}),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.CRASH);
+ throw 'Internal Error: $message';
+ }
+
+ void unhandledExceptionOnElement(Element element) {
+ if (hasCrashed) return;
+ hasCrashed = true;
+ reportDiagnostic(
+ createMessage(element, MessageKind.COMPILER_CRASHED),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.CRASH);
+ pleaseReportCrash();
+ }
+
+ void pleaseReportCrash() {
+ print(
+ MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
+ .message({'buildId': compiler.buildId}));
+ }
+
+ /// Finds the approximate [Element] for [node]. [currentElement] is used as
+ /// the default value.
+ Element elementFromSpannable(Spannable node) {
+ Element element;
+ if (node is Element) {
+ element = node;
+ } else if (node is HInstruction) {
+ element = _elementFromHInstruction(node);
+ } else if (node is MetadataAnnotation) {
+ element = node.annotatedElement;
+ }
+ return element != null ? element : currentElement;
+ }
+
+ void log(message) {
+ Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
+ .message({'text': '$message'});
+ reportDiagnostic(
+ new DiagnosticMessage(null, null, msg),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.VERBOSE_INFO);
+ }
+
+ String tryToString(object) {
+ try {
+ return object.toString();
+ } catch (_) {
+ return '<exception in toString()>';
+ }
+ }
+
+ onError(Uri uri, error) {
+ try {
+ if (!hasCrashed) {
+ hasCrashed = true;
+ if (error is SpannableAssertionFailure) {
+ reportAssertionFailure(error);
+ } else {
+ reportDiagnostic(
+ createMessage(
+ new SourceSpan(uri, 0, 0),
+ MessageKind.COMPILER_CRASHED),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.CRASH);
+ }
+ pleaseReportCrash();
+ }
+ } catch (doubleFault) {
+ // Ignoring exceptions in exception handling.
+ }
+ throw error;
+ }
+
+ void onCrashInUserCode(String message, exception, stackTrace) {
+ hasCrashed = true;
+ print('$message: ${tryToString(exception)}');
+ print(tryToString(stackTrace));
+ }
+
+ void reportSuppressedMessagesSummary() {
+ if (!options.showPackageWarnings && !options.suppressWarnings) {
+ suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
+ MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
+ if (info.warnings == 0) {
+ kind = MessageKind.HIDDEN_HINTS;
+ } else if (info.hints == 0) {
+ kind = MessageKind.HIDDEN_WARNINGS;
+ }
+ MessageTemplate template = MessageTemplate.TEMPLATES[kind];
+ Message message = template.message(
+ {'warnings': info.warnings,
+ 'hints': info.hints,
+ 'uri': uri},
+ options.terseDiagnostics);
+ reportDiagnostic(
+ new DiagnosticMessage(null, null, message),
+ const <DiagnosticMessage>[],
+ api.Diagnostic.HINT);
+ });
+ }
+ }
+}
+
// TODO(johnniwinther): Move [ResolverTask] here.
class _CompilerResolution implements Resolution {
final Compiler compiler;
@@ -1876,7 +1924,7 @@ class _CompilerResolution implements Resolution {
_CompilerResolution(this.compiler);
@override
- DiagnosticListener get listener => compiler;
+ DiagnosticReporter get reporter => compiler.reporter;
@override
Parsing get parsing => compiler.parsing;
@@ -1923,7 +1971,7 @@ class _CompilerParsing implements Parsing {
_CompilerParsing(this.compiler);
@override
- DiagnosticListener get listener => compiler;
+ DiagnosticReporter get reporter => compiler.reporter;
@override
measure(f()) => compiler.parser.measure(f);
« no previous file with comments | « pkg/compiler/lib/src/compile_time_constants.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698