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

Unified Diff: pkg/analyzer/lib/src/task/options.dart

Issue 1423333002: Option support for `enableSuperMixins` (and more). (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Merge with master. 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
« no previous file with comments | « pkg/analyzer/lib/src/generated/utilities_general.dart ('k') | pkg/analyzer/pubspec.yaml » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/task/options.dart
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index fb24b0e47215d0cb05f50ad98b271aa13197130c..689bff2eebbd5b212bf0decb42562883051f97a4 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -10,6 +10,7 @@ import 'package:analyzer/source/analysis_options_provider.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/task/general.dart';
import 'package:analyzer/task/general.dart';
import 'package:analyzer/task/model.dart';
@@ -23,11 +24,21 @@ final ListResultDescriptor<AnalysisError> ANALYSIS_OPTIONS_ERRORS =
new ListResultDescriptor<AnalysisError>(
'ANALYSIS_OPTIONS_ERRORS', AnalysisError.NO_ERRORS);
+final _OptionsProcessor _processor = new _OptionsProcessor();
+
+/// Configure this [context] based on configuration details specified in
+/// the given [options].
+void configureContextOptions(
+ AnalysisContext context, Map<String, YamlNode> options) =>
+ _processor.configure(context, options);
+
/// `analyzer` analysis options constants.
class AnalyzerOptions {
static const String analyzer = 'analyzer';
+ static const String enableSuperMixins = 'enableSuperMixins';
static const String errors = 'errors';
static const String exclude = 'exclude';
+ static const String language = 'language';
static const String plugins = 'plugins';
static const String strong_mode = 'strong-mode';
@@ -37,13 +48,69 @@ class AnalyzerOptions {
/// Ways to say `include`.
static const List<String> includeSynonyms = const ['include', 'true'];
+ /// Ways to say `true` or `false`.
+ static const List<String> trueOrFalse = const ['true', 'false'];
+
/// Supported top-level `analyzer` options.
- static const List<String> top_level = const [
+ static const List<String> topLevel = const [
errors,
exclude,
+ language,
plugins,
strong_mode
];
+
+ /// Supported `analyzer` language configuration options.
+ static const List<String> languageOptions = const [enableSuperMixins];
+}
+
+/// Validates `analyzer` options.
+class AnalyzerOptionsValidator extends CompositeValidator {
+ AnalyzerOptionsValidator()
+ : super([
+ new TopLevelAnalyzerOptionsValidator(),
+ new ErrorFilterOptionValidator(),
+ new LanguageOptionValidator()
+ ]);
+}
+
+/// Convenience class for composing validators.
+class CompositeValidator extends OptionsValidator {
+ final List<OptionsValidator> validators;
+ CompositeValidator(this.validators);
+
+ @override
+ void validate(ErrorReporter reporter, Map<String, YamlNode> options) =>
+ validators.forEach((v) => v.validate(reporter, options));
+}
+
+/// Builds error reports with value proposals.
+class ErrorBuilder {
+ String proposal;
+ AnalysisOptionsWarningCode code;
+
+ /// Create a builder for the given [supportedOptions].
+ ErrorBuilder(List<String> supportedOptions) {
+ assert(supportedOptions != null && !supportedOptions.isEmpty);
+ if (supportedOptions.length > 1) {
+ proposal = StringUtilities.printListOfQuotedNames(supportedOptions);
+ code = pluralProposalCode;
+ } else {
+ proposal = "'${supportedOptions.join()}'";
+ code = singularProposalCode;
+ }
+ }
+ AnalysisOptionsWarningCode get pluralProposalCode =>
+ AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES;
+
+ AnalysisOptionsWarningCode get singularProposalCode =>
+ AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE;
+
+ /// Report an unsupported [node] value, defined in the given [scopeName].
+ void reportError(ErrorReporter reporter, String scopeName, YamlNode node) {
+ reporter.reportErrorForSpan(
+ code, node.span, [scopeName, node.value, proposal]);
+ }
}
/// Validates `analyzer` error filter options.
@@ -57,17 +124,15 @@ class ErrorFilterOptionValidator extends OptionsValidator {
void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
YamlMap analyzer = options[AnalyzerOptions.analyzer];
if (analyzer == null) {
- // No options for analyzer.
return;
}
YamlNode filters = analyzer[AnalyzerOptions.errors];
-
if (filters is YamlMap) {
String value;
filters.nodes.forEach((k, v) {
if (k is YamlScalar) {
- value = k.value?.toString()?.toUpperCase();
+ value = toUpperCase(k.value);
if (!ErrorCode.values.any((ErrorCode code) => code.name == value)) {
reporter.reportErrorForSpan(
AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
@@ -76,7 +141,7 @@ class ErrorFilterOptionValidator extends OptionsValidator {
}
}
if (v is YamlScalar) {
- value = v.value?.toString()?.toLowerCase();
+ value = toLowerCase(v.value);
if (!AnalyzerOptions.ignoreSynonyms.contains(value) &&
!AnalyzerOptions.includeSynonyms.contains(value)) {
reporter.reportErrorForSpan(
@@ -84,39 +149,12 @@ class ErrorFilterOptionValidator extends OptionsValidator {
v.span,
[AnalyzerOptions.errors, v.value?.toString(), legalIncludes]);
}
-
- value = v.value?.toString()?.toLowerCase();
}
});
}
}
}
-/// Validates `analyzer` top-level options.
-class TopLevelAnalyzerOptionsValidator extends TopLevelOptionValidator {
- TopLevelAnalyzerOptionsValidator()
- : super(AnalyzerOptions.analyzer, AnalyzerOptions.top_level);
-}
-
-/// Validates `analyzer` options.
-class AnalyzerOptionsValidator extends CompositeValidator {
- AnalyzerOptionsValidator()
- : super([
- new TopLevelAnalyzerOptionsValidator(),
- new ErrorFilterOptionValidator()
- ]);
-}
-
-/// Convenience class for composing validators.
-class CompositeValidator extends OptionsValidator {
- final List<OptionsValidator> validators;
- CompositeValidator(this.validators);
-
- @override
- void validate(ErrorReporter reporter, Map<String, YamlNode> options) =>
- validators.forEach((v) => v.validate(reporter, options));
-}
-
/// A task that generates errors for an `.analysis_options` file.
class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
/// The name of the input whose value is the content of the file.
@@ -184,6 +222,43 @@ class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
new GenerateOptionsErrorsTask(context, target);
}
+/// Validates `analyzer` language configuration options.
+class LanguageOptionValidator extends OptionsValidator {
+ ErrorBuilder builder = new ErrorBuilder(AnalyzerOptions.languageOptions);
+ ErrorBuilder trueOrFalseBuilder = new TrueOrFalseValueErrorBuilder();
+
+ @override
+ void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
+ YamlMap analyzer = options[AnalyzerOptions.analyzer];
+ if (analyzer == null) {
+ return;
+ }
+
+ YamlNode language = analyzer[AnalyzerOptions.language];
+ if (language is YamlMap) {
+ language.nodes.forEach((k, v) {
+ String key, value;
+ bool validKey = false;
+ if (k is YamlScalar) {
+ key = k.value?.toString();
+ if (!AnalyzerOptions.languageOptions.contains(key)) {
+ builder.reportError(reporter, AnalyzerOptions.language, k);
+ } else {
+ // If we have a valid key, go on and check the value.
+ validKey = true;
+ }
+ }
+ if (validKey && v is YamlScalar) {
+ value = toLowerCase(v.value);
+ if (!AnalyzerOptions.trueOrFalse.contains(value)) {
+ trueOrFalseBuilder.reportError(reporter, key, v);
+ }
+ }
+ });
+ }
+ }
+}
+
/// Validates `linter` top-level options.
/// TODO(pq): move into `linter` package and plugin.
class LinterOptionsValidator extends TopLevelOptionValidator {
@@ -211,6 +286,12 @@ class OptionsFileValidator {
}
}
+/// Validates `analyzer` top-level options.
+class TopLevelAnalyzerOptionsValidator extends TopLevelOptionValidator {
+ TopLevelAnalyzerOptionsValidator()
+ : super(AnalyzerOptions.analyzer, AnalyzerOptions.topLevel);
+}
+
/// Validates top-level options. For example,
/// plugin:
/// top-level-option: true
@@ -248,3 +329,84 @@ class TopLevelOptionValidator extends OptionsValidator {
}
}
}
+
+/// An error-builder that knows about `true` and `false` legal values.
+class TrueOrFalseValueErrorBuilder extends ErrorBuilder {
+ TrueOrFalseValueErrorBuilder() : super(AnalyzerOptions.trueOrFalse);
+ @override
+ AnalysisOptionsWarningCode get pluralProposalCode =>
+ AnalysisOptionsWarningCode.UNSUPPORTED_VALUE;
+}
+
+class _OptionsProcessor {
+ void configure(AnalysisContext context, Map<String, YamlNode> options) {
+ if (options == null) {
+ return;
+ }
+
+ YamlMap analyzer = options[AnalyzerOptions.analyzer];
+ if (analyzer == null) {
+ return;
+ }
+
+ // Set strong mode (default is false).
+ bool strongMode = analyzer[AnalyzerOptions.strong_mode] ?? false;
+ setStrongMode(context, strongMode);
+
+ // Set filters.
+ YamlNode filters = analyzer[AnalyzerOptions.errors];
+ setFilters(context, filters);
+
+ // Process language options.
+ YamlNode language = analyzer[AnalyzerOptions.language];
+ setLanguageOptions(context, language);
+ }
+
+ void setFilters(AnalysisContext context, YamlNode codes) {
+ List<ErrorFilter> filters = <ErrorFilter>[];
+ // If codes are enumerated, collect them as filters; else leave filters
+ // empty to overwrite previous value.
+ if (codes is YamlMap) {
+ String value;
+ codes.nodes.forEach((k, v) {
+ if (k is YamlScalar && v is YamlScalar) {
+ value = toLowerCase(v.value);
+ if (AnalyzerOptions.ignoreSynonyms.contains(value)) {
+ // Case-insensitive.
+ String code = toUpperCase(k.value);
+ filters.add((AnalysisError error) => error.errorCode.name == code);
+ }
+ }
+ });
+ }
+ context.setConfigurationData(CONFIGURED_ERROR_FILTERS, filters);
+ }
+
+ void setLanguageOptions(AnalysisContext context, YamlNode configs) {
+ if (configs is YamlMap) {
+ configs.nodes.forEach((k, v) {
+ String feature;
+ if (k is YamlScalar && v is YamlScalar) {
+ feature = k.value?.toString();
+ if (feature == AnalyzerOptions.enableSuperMixins) {
+ if (isTrue(v.value)) {
+ AnalysisOptionsImpl options =
+ new AnalysisOptionsImpl.from(context.analysisOptions);
+ options.enableSuperMixins = true;
+ context.analysisOptions = options;
+ }
+ }
+ }
+ });
+ }
+ }
+
+ void setStrongMode(AnalysisContext context, bool strongMode) {
+ if (context.analysisOptions.strongMode != strongMode) {
+ AnalysisOptionsImpl options =
+ new AnalysisOptionsImpl.from(context.analysisOptions);
+ options.strongMode = strongMode;
+ context.analysisOptions = options;
+ }
+ }
+}
« no previous file with comments | « pkg/analyzer/lib/src/generated/utilities_general.dart ('k') | pkg/analyzer/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698