e4868ca176
Currently, diagnostic codes associated with lints are named using `lower_snake_case`, while analyzer diagnonstic codes are named using `UPPER_SNAKE_CASE`. However, when the analyzer builds instances of the `ErrorProcessor` class, it always uses `UPPER_SNAKE_CASE` names. Some pieces of logic that matched up `ErrorProcessor`s to diagnostic codes accounted for this difference; others didn't. This led to a some buggy behaviors: - If an instance of `ErrorProcessor` got constructed outside of the analyzer (by an analyzer client using the analyzer public API), and it supplied a `lower_snake_case` name, then `ErrorProcessor.appliesTo` would only successfully match if the name referred to a lint. - The resolved correction producer base class `_BaseIgnoreDiagnostic` (which forms the basis for the quick fixes "Ignore '...' in `analysis_options.yaml`", "Ignore '...' for this line", and "Ignore '...' for the whole file") would only notice that a diagnostic was unignorable if the case matched exactly. In practice, this meant that when operating on instances of `ErrorProcessor` created by the analyzer, it wouldn't properly handle lints. These buggy behaviors have been fixed by: - Changing the `ErrorProcessor` constructor to always convert the `code` to lower case. - Changing all references to `ErrorProcessor.code` to assume lower case. Change-Id: I6a6a69645284f646e0c070fc2b55c4a90203d74a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/462863 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
100 lines
3.4 KiB
Dart
100 lines
3.4 KiB
Dart
// Copyright (c) 2015, 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 'package:analyzer/diagnostic/diagnostic.dart';
|
|
import 'package:analyzer/error/error.dart';
|
|
import 'package:analyzer/src/analysis_options/analysis_options_file.dart';
|
|
import 'package:analyzer/src/generated/engine.dart';
|
|
import 'package:collection/collection.dart';
|
|
import 'package:meta/meta.dart';
|
|
import 'package:yaml/yaml.dart';
|
|
|
|
/// String identifiers mapped to associated severities.
|
|
const Map<String, DiagnosticSeverity> severityMap = {
|
|
'error': DiagnosticSeverity.ERROR,
|
|
'info': DiagnosticSeverity.INFO,
|
|
'warning': DiagnosticSeverity.WARNING,
|
|
};
|
|
|
|
/// Error processor configuration derived from analysis (or embedder) options.
|
|
class ErrorConfig {
|
|
/// The processors in this config.
|
|
final List<ErrorProcessor> processors = <ErrorProcessor>[];
|
|
|
|
/// Create an error config for the given error code map.
|
|
/// For example:
|
|
/// new ErrorConfig({'missing_return' : 'error'});
|
|
/// will create a processor config that turns `missing_return` warnings into
|
|
/// errors.
|
|
ErrorConfig(YamlNode? codeMap) {
|
|
if (codeMap is YamlMap) {
|
|
_processMap(codeMap);
|
|
}
|
|
}
|
|
|
|
void _processMap(YamlMap codes) {
|
|
codes.nodes.forEach((k, v) {
|
|
if (k is YamlScalar && v is YamlScalar) {
|
|
var code = k.value;
|
|
if (code is! String) return;
|
|
|
|
code = code.toUpperCase();
|
|
var action = v.value.toString().toLowerCase();
|
|
if (AnalysisOptionsFile.ignoreSynonyms.contains(action)) {
|
|
processors.add(ErrorProcessor.ignore(code));
|
|
} else {
|
|
var severity = severityMap[action];
|
|
if (severity != null) {
|
|
processors.add(ErrorProcessor(code, severity));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/// Process errors by filtering or changing associated [DiagnosticSeverity].
|
|
class ErrorProcessor {
|
|
/// The code name of the associated error.
|
|
final String code;
|
|
|
|
/// The desired severity of the processed error.
|
|
///
|
|
/// If `null`, this processor will "filter" the associated error code.
|
|
final DiagnosticSeverity? severity;
|
|
|
|
/// Create an error processor that assigns errors with this [code] the
|
|
/// given [severity].
|
|
///
|
|
/// If [severity] is `null`, matching errors will be filtered.
|
|
ErrorProcessor(String code, [this.severity]) : code = code.toLowerCase();
|
|
|
|
/// Create an error processor that ignores the given error by [code].
|
|
factory ErrorProcessor.ignore(String code) => ErrorProcessor(code);
|
|
|
|
/// The string that unique describes the processor.
|
|
String get description => '$code -> ${severity?.name}';
|
|
|
|
/// Check if this processor applies to the given [diagnostic].
|
|
@visibleForTesting
|
|
bool appliesTo(Diagnostic diagnostic) =>
|
|
code == diagnostic.diagnosticCode.name.toLowerCase();
|
|
|
|
@override
|
|
String toString() => "ErrorProcessor[code='$code', severity=$severity]";
|
|
|
|
/// Returns an error processor associated in the [analysisOptions] for the
|
|
/// given [diagnostic], or `null` if none is found.
|
|
static ErrorProcessor? getProcessor(
|
|
// TODO(srawlins): Make `analysisOptions` non-nullable, in a breaking
|
|
// change release.
|
|
AnalysisOptions? analysisOptions,
|
|
Diagnostic diagnostic,
|
|
) {
|
|
return analysisOptions?.errorProcessors.firstWhereOrNull(
|
|
(processor) => processor.appliesTo(diagnostic),
|
|
);
|
|
}
|
|
}
|