Add an analysis option allowing linter exceptions to be propagated.
This will be used in internal builds to ensure that an exception
occuring during linting fails the build; this should help us be more
confident in the robustness of the linter code.
Change-Id: I4eaa47044b32b45433a67cc919ad047663dc771c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/208141
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart b/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
index 7f60edd..bd175b9 100644
--- a/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
+++ b/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
@@ -30,6 +30,7 @@
AnalyzerOptions.chromeOsManifestChecks: EmptyProducer(),
}),
AnalyzerOptions.plugins: EmptyProducer(),
+ AnalyzerOptions.propagateLinterExceptions: EmptyProducer(),
AnalyzerOptions.strong_mode: MapProducer({
AnalyzerOptions.declarationCasts: EmptyProducer(),
AnalyzerOptions.implicitCasts: EmptyProducer(),
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index aec3305..af4dab4 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/testing_data.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/constant/compute.dart';
import 'package:analyzer/src/dart/constant/constant_verifier.dart';
import 'package:analyzer/src/dart/constant/evaluation.dart';
@@ -351,7 +352,10 @@
}
// Run lints that handle specific node types.
- unit.accept(LinterVisitor(nodeRegistry));
+ unit.accept(LinterVisitor(
+ nodeRegistry,
+ LinterExceptionHandler(_analysisOptions.propagateLinterExceptions)
+ .logException));
}
void _computeVerifyErrors(FileState file, CompilationUnit unit) {
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index a068ad7..4387e37 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -1306,6 +1306,12 @@
///
/// Clients may not extend, implement or mix-in this class.
class LinterExceptionHandler {
+ /// Indicates whether linter exceptions should be propagated to the caller (by
+ /// re-throwing them)
+ final bool propagateLinterExceptions;
+
+ LinterExceptionHandler(this.propagateLinterExceptions);
+
/// A method that can be passed to the `LinterVisitor` constructor to handle
/// exceptions that occur during linting.
void logException(
@@ -1326,6 +1332,9 @@
// TODO(39284): should this exception be silent?
AnalysisEngine.instance.instrumentationService.logException(
SilentException(buffer.toString(), exception, stackTrace));
+ if (propagateLinterExceptions) {
+ throw exception;
+ }
}
}
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index 0b1635c..327af6e 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -348,7 +348,10 @@
}
// Run lints that handle specific node types.
- unit.accept(LinterVisitor(nodeRegistry));
+ unit.accept(LinterVisitor(
+ nodeRegistry,
+ LinterExceptionHandler(_analysisOptions.propagateLinterExceptions)
+ .logException));
}
void _computeVerifyErrors(FileState file, CompilationUnit unit) {
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 7f04b64..c678842 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -281,6 +281,10 @@
/// This option is experimental and subject to change.
bool implicitDynamic = true;
+ /// Indicates whether linter exceptions should be propagated to the caller (by
+ /// re-throwing them)
+ bool propagateLinterExceptions = false;
+
/// A flag indicating whether inference failures are allowed, off by default.
///
/// This option is experimental and subject to change.
@@ -319,6 +323,7 @@
if (options is AnalysisOptionsImpl) {
implicitCasts = options.implicitCasts;
implicitDynamic = options.implicitDynamic;
+ propagateLinterExceptions = options.propagateLinterExceptions;
strictInference = options.strictInference;
strictRawTypes = options.strictRawTypes;
}
@@ -382,6 +387,7 @@
// Append boolean flags.
buffer.addBool(implicitCasts);
buffer.addBool(implicitDynamic);
+ buffer.addBool(propagateLinterExceptions);
buffer.addBool(strictInference);
buffer.addBool(strictRawTypes);
buffer.addBool(useFastaParser);
diff --git a/pkg/analyzer/lib/src/lint/linter_visitor.dart b/pkg/analyzer/lib/src/lint/linter_visitor.dart
index 25afec4..0794a4c 100644
--- a/pkg/analyzer/lib/src/lint/linter_visitor.dart
+++ b/pkg/analyzer/lib/src/lint/linter_visitor.dart
@@ -19,7 +19,7 @@
LinterVisitor(this.registry, [LintRuleExceptionHandler? exceptionHandler])
: exceptionHandler =
- exceptionHandler ?? LinterExceptionHandler().logException;
+ exceptionHandler ?? LinterExceptionHandler(true).logException;
@override
void visitAdjacentStrings(AdjacentStrings node) {
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 28b4452..2efaaa1 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -151,6 +151,8 @@
/// Ways to say `include`.
static const List<String> includeSynonyms = ['include', 'true'];
+ static const String propagateLinterExceptions = 'propagate-linter-exceptions';
+
/// Ways to say `true` or `false`.
static const List<String> trueOrFalse = ['true', 'false'];
@@ -163,6 +165,7 @@
language,
optionalChecks,
plugins,
+ propagateLinterExceptions,
strong_mode,
];
@@ -805,6 +808,9 @@
if (feature == AnalyzerOptions.implicitDynamic) {
options.implicitDynamic = boolValue;
}
+ if (feature == AnalyzerOptions.propagateLinterExceptions) {
+ options.propagateLinterExceptions = boolValue;
+ }
}
}
diff --git a/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart b/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart
index f0a3fd2..44a7634 100644
--- a/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart
@@ -236,6 +236,8 @@
);
expect(actual.implicitCasts, expected.implicitCasts);
expect(actual.implicitDynamic, expected.implicitDynamic);
+ expect(
+ actual.propagateLinterExceptions, expected.propagateLinterExceptions);
expect(actual.strictInference, expected.strictInference);
expect(actual.strictRawTypes, expected.strictRawTypes);
}