| Index: pkg/analyzer/lib/error/listener.dart
|
| diff --git a/pkg/analyzer/lib/error/listener.dart b/pkg/analyzer/lib/error/listener.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1f75fcb1b1f2366688cb53b5f61b1e00c3517311
|
| --- /dev/null
|
| +++ b/pkg/analyzer/lib/error/listener.dart
|
| @@ -0,0 +1,322 @@
|
| +// Copyright (c) 2014, 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 analyzer.error.listener;
|
| +
|
| +import 'dart:collection';
|
| +
|
| +import 'package:analyzer/dart/ast/ast.dart' show AstNode;
|
| +import 'package:analyzer/dart/ast/token.dart';
|
| +import 'package:analyzer/dart/element/element.dart';
|
| +import 'package:analyzer/dart/element/type.dart';
|
| +import 'package:analyzer/error/error.dart';
|
| +import 'package:analyzer/src/dart/element/type.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:source_span/source_span.dart';
|
| +
|
| +/**
|
| + * An object that listen for [AnalysisError]s being produced by the analysis
|
| + * engine.
|
| + */
|
| +abstract class AnalysisErrorListener {
|
| + /**
|
| + * An error listener that ignores errors that are reported to it.
|
| + */
|
| + static final AnalysisErrorListener NULL_LISTENER = new _NullErrorListener();
|
| +
|
| + /**
|
| + * This method is invoked when an [error] has been found by the analysis
|
| + * engine.
|
| + */
|
| + void onError(AnalysisError error);
|
| +}
|
| +
|
| +/**
|
| + * An [AnalysisErrorListener] that keeps track of whether any error has been
|
| + * reported to it.
|
| + */
|
| +class BooleanErrorListener implements AnalysisErrorListener {
|
| + /**
|
| + * A flag indicating whether an error has been reported to this listener.
|
| + */
|
| + bool _errorReported = false;
|
| +
|
| + /**
|
| + * Return `true` if an error has been reported to this listener.
|
| + */
|
| + bool get errorReported => _errorReported;
|
| +
|
| + @override
|
| + void onError(AnalysisError error) {
|
| + _errorReported = true;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * An object used to create analysis errors and report then to an error
|
| + * listener.
|
| + */
|
| +class ErrorReporter {
|
| + /**
|
| + * The error listener to which errors will be reported.
|
| + */
|
| + final AnalysisErrorListener _errorListener;
|
| +
|
| + /**
|
| + * The default source to be used when reporting errors.
|
| + */
|
| + final Source _defaultSource;
|
| +
|
| + /**
|
| + * The source to be used when reporting errors.
|
| + */
|
| + Source _source;
|
| +
|
| + /**
|
| + * Initialize a newly created error reporter that will report errors to the
|
| + * given [_errorListener]. Errors will be reported against the
|
| + * [_defaultSource] unless another source is provided later.
|
| + */
|
| + ErrorReporter(this._errorListener, this._defaultSource) {
|
| + if (_errorListener == null) {
|
| + throw new ArgumentError("An error listener must be provided");
|
| + } else if (_defaultSource == null) {
|
| + throw new ArgumentError("A default source must be provided");
|
| + }
|
| + this._source = _defaultSource;
|
| + }
|
| +
|
| + Source get source => _source;
|
| +
|
| + /**
|
| + * Set the source to be used when reporting errors to the given [source].
|
| + * Setting the source to `null` will cause the default source to be used.
|
| + */
|
| + void set source(Source source) {
|
| + this._source = source ?? _defaultSource;
|
| + }
|
| +
|
| + /**
|
| + * Creates an error with properties with the given [errorCode] and
|
| + * [arguments]. The [node] is used to compute the location of the error.
|
| + */
|
| + AnalysisErrorWithProperties newErrorWithProperties(
|
| + ErrorCode errorCode, AstNode node, List<Object> arguments) =>
|
| + new AnalysisErrorWithProperties(
|
| + _source, node.offset, node.length, errorCode, arguments);
|
| +
|
| + /**
|
| + * Report the given [error].
|
| + */
|
| + void reportError(AnalysisError error) {
|
| + _errorListener.onError(error);
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given [errorCode] and [arguments]. The [element]
|
| + * is used to compute the location of the error.
|
| + */
|
| + void reportErrorForElement(ErrorCode errorCode, Element element,
|
| + [List<Object> arguments]) {
|
| + int length = 0;
|
| + if (element is ImportElement) {
|
| + length = 6; // 'import'.length
|
| + } else if (element is ExportElement) {
|
| + length = 6; // 'export'.length
|
| + } else {
|
| + length = element.nameLength;
|
| + }
|
| + reportErrorForOffset(errorCode, element.nameOffset, length, arguments);
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given [errorCode] and [arguments].
|
| + * The [node] is used to compute the location of the error.
|
| + *
|
| + * If the arguments contain the names of two or more types, the method
|
| + * [reportTypeErrorForNode] should be used and the types
|
| + * themselves (rather than their names) should be passed as arguments.
|
| + */
|
| + void reportErrorForNode(ErrorCode errorCode, AstNode node,
|
| + [List<Object> arguments]) {
|
| + reportErrorForOffset(errorCode, node.offset, node.length, arguments);
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given [errorCode] and [arguments]. The location of
|
| + * the error is specified by the given [offset] and [length].
|
| + */
|
| + void reportErrorForOffset(ErrorCode errorCode, int offset, int length,
|
| + [List<Object> arguments]) {
|
| + _errorListener.onError(
|
| + new AnalysisError(_source, offset, length, errorCode, arguments));
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given [errorCode] and [arguments]. The location of
|
| + * the error is specified by the given [span].
|
| + */
|
| + void reportErrorForSpan(ErrorCode errorCode, SourceSpan span,
|
| + [List<Object> arguments]) {
|
| + reportErrorForOffset(errorCode, span.start.offset, span.length, arguments);
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given [errorCode] and [arguments]. The [token] is
|
| + * used to compute the location of the error.
|
| + */
|
| + void reportErrorForToken(ErrorCode errorCode, Token token,
|
| + [List<Object> arguments]) {
|
| + reportErrorForOffset(errorCode, token.offset, token.length, arguments);
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given [errorCode] and [arguments]. The [node] is
|
| + * used to compute the location of the error. The arguments are expected to
|
| + * contain two or more types. Convert the types into strings by using the
|
| + * display names of the types, unless there are two or more types with the
|
| + * same names, in which case the extended display names of the types will be
|
| + * used in order to clarify the message.
|
| + *
|
| + * If there are not two or more types in the argument list, the method
|
| + * [reportErrorForNode] should be used instead.
|
| + */
|
| + void reportTypeErrorForNode(
|
| + ErrorCode errorCode, AstNode node, List<Object> arguments) {
|
| + _convertTypeNames(arguments);
|
| + reportErrorForOffset(errorCode, node.offset, node.length, arguments);
|
| + }
|
| +
|
| + /**
|
| + * Given an array of [arguments] that is expected to contain two or more
|
| + * types, convert the types into strings by using the display names of the
|
| + * types, unless there are two or more types with the same names, in which
|
| + * case the extended display names of the types will be used in order to
|
| + * clarify the message.
|
| + */
|
| + void _convertTypeNames(List<Object> arguments) {
|
| + String displayName(DartType type) {
|
| + if (type is FunctionType) {
|
| + String name = type.name;
|
| + if (name != null && name.length > 0) {
|
| + StringBuffer buffer = new StringBuffer();
|
| + buffer.write(name);
|
| + (type as TypeImpl).appendTo(buffer);
|
| + return buffer.toString();
|
| + }
|
| + }
|
| + return type.displayName;
|
| + }
|
| +
|
| + if (_hasEqualTypeNames(arguments)) {
|
| + int count = arguments.length;
|
| + for (int i = 0; i < count; i++) {
|
| + Object argument = arguments[i];
|
| + if (argument is DartType) {
|
| + Element element = argument.element;
|
| + if (element == null) {
|
| + arguments[i] = displayName(argument);
|
| + } else {
|
| + arguments[i] =
|
| + element.getExtendedDisplayName(displayName(argument));
|
| + }
|
| + }
|
| + }
|
| + } else {
|
| + int count = arguments.length;
|
| + for (int i = 0; i < count; i++) {
|
| + Object argument = arguments[i];
|
| + if (argument is DartType) {
|
| + arguments[i] = displayName(argument);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given array of [arguments] contains two or more types
|
| + * with the same display name.
|
| + */
|
| + bool _hasEqualTypeNames(List<Object> arguments) {
|
| + int count = arguments.length;
|
| + HashSet<String> typeNames = new HashSet<String>();
|
| + for (int i = 0; i < count; i++) {
|
| + Object argument = arguments[i];
|
| + if (argument is DartType && !typeNames.add(argument.displayName)) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * An error listener that will record the errors that are reported to it in a
|
| + * way that is appropriate for caching those errors within an analysis context.
|
| + */
|
| +class RecordingErrorListener implements AnalysisErrorListener {
|
| + /**
|
| + * A map of sets containing the errors that were collected, keyed by each
|
| + * source.
|
| + */
|
| + Map<Source, HashSet<AnalysisError>> _errors =
|
| + new HashMap<Source, HashSet<AnalysisError>>();
|
| +
|
| + /**
|
| + * Return the errors collected by the listener.
|
| + */
|
| + List<AnalysisError> get errors {
|
| + int numEntries = _errors.length;
|
| + if (numEntries == 0) {
|
| + return AnalysisError.NO_ERRORS;
|
| + }
|
| + List<AnalysisError> resultList = new List<AnalysisError>();
|
| + for (HashSet<AnalysisError> errors in _errors.values) {
|
| + resultList.addAll(errors);
|
| + }
|
| + return resultList;
|
| + }
|
| +
|
| + /**
|
| + * Add all of the errors recorded by the given [listener] to this listener.
|
| + */
|
| + void addAll(RecordingErrorListener listener) {
|
| + for (AnalysisError error in listener.errors) {
|
| + onError(error);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Return the errors collected by the listener for the given [source].
|
| + */
|
| + List<AnalysisError> getErrorsForSource(Source source) {
|
| + HashSet<AnalysisError> errorsForSource = _errors[source];
|
| + if (errorsForSource == null) {
|
| + return AnalysisError.NO_ERRORS;
|
| + } else {
|
| + return new List.from(errorsForSource);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + void onError(AnalysisError error) {
|
| + Source source = error.source;
|
| + HashSet<AnalysisError> errorsForSource = _errors[source];
|
| + if (_errors[source] == null) {
|
| + errorsForSource = new HashSet<AnalysisError>();
|
| + _errors[source] = errorsForSource;
|
| + }
|
| + errorsForSource.add(error);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * An [AnalysisErrorListener] that ignores error.
|
| + */
|
| +class _NullErrorListener implements AnalysisErrorListener {
|
| + @override
|
| + void onError(AnalysisError event) {
|
| + // Ignore errors
|
| + }
|
| +}
|
|
|