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

Side by Side 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, 1 month 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.task.options; 5 library analyzer.src.task.options;
6 6
7 import 'package:analyzer/analyzer.dart'; 7 import 'package:analyzer/analyzer.dart';
8 import 'package:analyzer/plugin/options.dart'; 8 import 'package:analyzer/plugin/options.dart';
9 import 'package:analyzer/source/analysis_options_provider.dart'; 9 import 'package:analyzer/source/analysis_options_provider.dart';
10 import 'package:analyzer/src/generated/engine.dart'; 10 import 'package:analyzer/src/generated/engine.dart';
11 import 'package:analyzer/src/generated/java_engine.dart'; 11 import 'package:analyzer/src/generated/java_engine.dart';
12 import 'package:analyzer/src/generated/source.dart'; 12 import 'package:analyzer/src/generated/source.dart';
13 import 'package:analyzer/src/generated/utilities_general.dart';
13 import 'package:analyzer/src/task/general.dart'; 14 import 'package:analyzer/src/task/general.dart';
14 import 'package:analyzer/task/general.dart'; 15 import 'package:analyzer/task/general.dart';
15 import 'package:analyzer/task/model.dart'; 16 import 'package:analyzer/task/model.dart';
16 import 'package:source_span/source_span.dart'; 17 import 'package:source_span/source_span.dart';
17 import 'package:yaml/yaml.dart'; 18 import 'package:yaml/yaml.dart';
18 19
19 /// The errors produced while parsing `.analysis_options` files. 20 /// The errors produced while parsing `.analysis_options` files.
20 /// 21 ///
21 /// The list will be empty if there were no errors, but will not be `null`. 22 /// The list will be empty if there were no errors, but will not be `null`.
22 final ListResultDescriptor<AnalysisError> ANALYSIS_OPTIONS_ERRORS = 23 final ListResultDescriptor<AnalysisError> ANALYSIS_OPTIONS_ERRORS =
23 new ListResultDescriptor<AnalysisError>( 24 new ListResultDescriptor<AnalysisError>(
24 'ANALYSIS_OPTIONS_ERRORS', AnalysisError.NO_ERRORS); 25 'ANALYSIS_OPTIONS_ERRORS', AnalysisError.NO_ERRORS);
25 26
27 final _OptionsProcessor _processor = new _OptionsProcessor();
28
29 /// Configure this [context] based on configuration details specified in
30 /// the given [options].
31 void configureContextOptions(
32 AnalysisContext context, Map<String, YamlNode> options) =>
33 _processor.configure(context, options);
34
26 /// `analyzer` analysis options constants. 35 /// `analyzer` analysis options constants.
27 class AnalyzerOptions { 36 class AnalyzerOptions {
28 static const String analyzer = 'analyzer'; 37 static const String analyzer = 'analyzer';
38 static const String enableSuperMixins = 'enableSuperMixins';
29 static const String errors = 'errors'; 39 static const String errors = 'errors';
30 static const String exclude = 'exclude'; 40 static const String exclude = 'exclude';
41 static const String language = 'language';
31 static const String plugins = 'plugins'; 42 static const String plugins = 'plugins';
32 static const String strong_mode = 'strong-mode'; 43 static const String strong_mode = 'strong-mode';
33 44
34 /// Ways to say `ignore`. 45 /// Ways to say `ignore`.
35 static const List<String> ignoreSynonyms = const ['ignore', 'false']; 46 static const List<String> ignoreSynonyms = const ['ignore', 'false'];
36 47
37 /// Ways to say `include`. 48 /// Ways to say `include`.
38 static const List<String> includeSynonyms = const ['include', 'true']; 49 static const List<String> includeSynonyms = const ['include', 'true'];
39 50
51 /// Ways to say `true` or `false`.
52 static const List<String> trueOrFalse = const ['true', 'false'];
53
40 /// Supported top-level `analyzer` options. 54 /// Supported top-level `analyzer` options.
41 static const List<String> top_level = const [ 55 static const List<String> topLevel = const [
42 errors, 56 errors,
43 exclude, 57 exclude,
58 language,
44 plugins, 59 plugins,
45 strong_mode 60 strong_mode
46 ]; 61 ];
62
63 /// Supported `analyzer` language configuration options.
64 static const List<String> languageOptions = const [enableSuperMixins];
65 }
66
67 /// Validates `analyzer` options.
68 class AnalyzerOptionsValidator extends CompositeValidator {
69 AnalyzerOptionsValidator()
70 : super([
71 new TopLevelAnalyzerOptionsValidator(),
72 new ErrorFilterOptionValidator(),
73 new LanguageOptionValidator()
74 ]);
75 }
76
77 /// Convenience class for composing validators.
78 class CompositeValidator extends OptionsValidator {
79 final List<OptionsValidator> validators;
80 CompositeValidator(this.validators);
81
82 @override
83 void validate(ErrorReporter reporter, Map<String, YamlNode> options) =>
84 validators.forEach((v) => v.validate(reporter, options));
85 }
86
87 /// Builds error reports with value proposals.
88 class ErrorBuilder {
89 String proposal;
90 AnalysisOptionsWarningCode code;
91
92 /// Create a builder for the given [supportedOptions].
93 ErrorBuilder(List<String> supportedOptions) {
94 assert(supportedOptions != null && !supportedOptions.isEmpty);
95 if (supportedOptions.length > 1) {
96 proposal = StringUtilities.printListOfQuotedNames(supportedOptions);
97 code = pluralProposalCode;
98 } else {
99 proposal = "'${supportedOptions.join()}'";
100 code = singularProposalCode;
101 }
102 }
103 AnalysisOptionsWarningCode get pluralProposalCode =>
104 AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES;
105
106 AnalysisOptionsWarningCode get singularProposalCode =>
107 AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUE;
108
109 /// Report an unsupported [node] value, defined in the given [scopeName].
110 void reportError(ErrorReporter reporter, String scopeName, YamlNode node) {
111 reporter.reportErrorForSpan(
112 code, node.span, [scopeName, node.value, proposal]);
113 }
47 } 114 }
48 115
49 /// Validates `analyzer` error filter options. 116 /// Validates `analyzer` error filter options.
50 class ErrorFilterOptionValidator extends OptionsValidator { 117 class ErrorFilterOptionValidator extends OptionsValidator {
51 /// Pretty list of legal includes. 118 /// Pretty list of legal includes.
52 static final String legalIncludes = StringUtilities.printListOfQuotedNames( 119 static final String legalIncludes = StringUtilities.printListOfQuotedNames(
53 new List.from(AnalyzerOptions.ignoreSynonyms) 120 new List.from(AnalyzerOptions.ignoreSynonyms)
54 ..addAll(AnalyzerOptions.includeSynonyms)); 121 ..addAll(AnalyzerOptions.includeSynonyms));
55 122
56 @override 123 @override
57 void validate(ErrorReporter reporter, Map<String, YamlNode> options) { 124 void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
58 YamlMap analyzer = options[AnalyzerOptions.analyzer]; 125 YamlMap analyzer = options[AnalyzerOptions.analyzer];
59 if (analyzer == null) { 126 if (analyzer == null) {
60 // No options for analyzer.
61 return; 127 return;
62 } 128 }
63 129
64 YamlNode filters = analyzer[AnalyzerOptions.errors]; 130 YamlNode filters = analyzer[AnalyzerOptions.errors];
65
66 if (filters is YamlMap) { 131 if (filters is YamlMap) {
67 String value; 132 String value;
68 filters.nodes.forEach((k, v) { 133 filters.nodes.forEach((k, v) {
69 if (k is YamlScalar) { 134 if (k is YamlScalar) {
70 value = k.value?.toString()?.toUpperCase(); 135 value = toUpperCase(k.value);
71 if (!ErrorCode.values.any((ErrorCode code) => code.name == value)) { 136 if (!ErrorCode.values.any((ErrorCode code) => code.name == value)) {
72 reporter.reportErrorForSpan( 137 reporter.reportErrorForSpan(
73 AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE, 138 AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
74 k.span, 139 k.span,
75 [k.value?.toString()]); 140 [k.value?.toString()]);
76 } 141 }
77 } 142 }
78 if (v is YamlScalar) { 143 if (v is YamlScalar) {
79 value = v.value?.toString()?.toLowerCase(); 144 value = toLowerCase(v.value);
80 if (!AnalyzerOptions.ignoreSynonyms.contains(value) && 145 if (!AnalyzerOptions.ignoreSynonyms.contains(value) &&
81 !AnalyzerOptions.includeSynonyms.contains(value)) { 146 !AnalyzerOptions.includeSynonyms.contains(value)) {
82 reporter.reportErrorForSpan( 147 reporter.reportErrorForSpan(
83 AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES, 148 AnalysisOptionsWarningCode.UNSUPPORTED_OPTION_WITH_LEGAL_VALUES,
84 v.span, 149 v.span,
85 [AnalyzerOptions.errors, v.value?.toString(), legalIncludes]); 150 [AnalyzerOptions.errors, v.value?.toString(), legalIncludes]);
86 } 151 }
87
88 value = v.value?.toString()?.toLowerCase();
89 } 152 }
90 }); 153 });
91 } 154 }
92 } 155 }
93 } 156 }
94 157
95 /// Validates `analyzer` top-level options.
96 class TopLevelAnalyzerOptionsValidator extends TopLevelOptionValidator {
97 TopLevelAnalyzerOptionsValidator()
98 : super(AnalyzerOptions.analyzer, AnalyzerOptions.top_level);
99 }
100
101 /// Validates `analyzer` options.
102 class AnalyzerOptionsValidator extends CompositeValidator {
103 AnalyzerOptionsValidator()
104 : super([
105 new TopLevelAnalyzerOptionsValidator(),
106 new ErrorFilterOptionValidator()
107 ]);
108 }
109
110 /// Convenience class for composing validators.
111 class CompositeValidator extends OptionsValidator {
112 final List<OptionsValidator> validators;
113 CompositeValidator(this.validators);
114
115 @override
116 void validate(ErrorReporter reporter, Map<String, YamlNode> options) =>
117 validators.forEach((v) => v.validate(reporter, options));
118 }
119
120 /// A task that generates errors for an `.analysis_options` file. 158 /// A task that generates errors for an `.analysis_options` file.
121 class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask { 159 class GenerateOptionsErrorsTask extends SourceBasedAnalysisTask {
122 /// The name of the input whose value is the content of the file. 160 /// The name of the input whose value is the content of the file.
123 static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME'; 161 static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
124 162
125 /// The task descriptor describing this kind of task. 163 /// The task descriptor describing this kind of task.
126 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor( 164 static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
127 'GenerateOptionsErrorsTask', 165 'GenerateOptionsErrorsTask',
128 createTask, 166 createTask,
129 buildInputs, 167 buildInputs,
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 List<int> lineStarts = StringUtilities.computeLineStarts(content); 215 List<int> lineStarts = StringUtilities.computeLineStarts(content);
178 return new LineInfo(lineStarts); 216 return new LineInfo(lineStarts);
179 } 217 }
180 218
181 /// Create a task based on the given [target] in the given [context]. 219 /// Create a task based on the given [target] in the given [context].
182 static GenerateOptionsErrorsTask createTask( 220 static GenerateOptionsErrorsTask createTask(
183 AnalysisContext context, AnalysisTarget target) => 221 AnalysisContext context, AnalysisTarget target) =>
184 new GenerateOptionsErrorsTask(context, target); 222 new GenerateOptionsErrorsTask(context, target);
185 } 223 }
186 224
225 /// Validates `analyzer` language configuration options.
226 class LanguageOptionValidator extends OptionsValidator {
227 ErrorBuilder builder = new ErrorBuilder(AnalyzerOptions.languageOptions);
228 ErrorBuilder trueOrFalseBuilder = new TrueOrFalseValueErrorBuilder();
229
230 @override
231 void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
232 YamlMap analyzer = options[AnalyzerOptions.analyzer];
233 if (analyzer == null) {
234 return;
235 }
236
237 YamlNode language = analyzer[AnalyzerOptions.language];
238 if (language is YamlMap) {
239 language.nodes.forEach((k, v) {
240 String key, value;
241 bool validKey = false;
242 if (k is YamlScalar) {
243 key = k.value?.toString();
244 if (!AnalyzerOptions.languageOptions.contains(key)) {
245 builder.reportError(reporter, AnalyzerOptions.language, k);
246 } else {
247 // If we have a valid key, go on and check the value.
248 validKey = true;
249 }
250 }
251 if (validKey && v is YamlScalar) {
252 value = toLowerCase(v.value);
253 if (!AnalyzerOptions.trueOrFalse.contains(value)) {
254 trueOrFalseBuilder.reportError(reporter, key, v);
255 }
256 }
257 });
258 }
259 }
260 }
261
187 /// Validates `linter` top-level options. 262 /// Validates `linter` top-level options.
188 /// TODO(pq): move into `linter` package and plugin. 263 /// TODO(pq): move into `linter` package and plugin.
189 class LinterOptionsValidator extends TopLevelOptionValidator { 264 class LinterOptionsValidator extends TopLevelOptionValidator {
190 LinterOptionsValidator() : super('linter', const ['rules']); 265 LinterOptionsValidator() : super('linter', const ['rules']);
191 } 266 }
192 267
193 /// Validates options defined in an `.analysis_options` file. 268 /// Validates options defined in an `.analysis_options` file.
194 class OptionsFileValidator { 269 class OptionsFileValidator {
195 // TODO(pq): move to an extension point. 270 // TODO(pq): move to an extension point.
196 final List<OptionsValidator> _validators = [ 271 final List<OptionsValidator> _validators = [
197 new AnalyzerOptionsValidator(), 272 new AnalyzerOptionsValidator(),
198 new LinterOptionsValidator() 273 new LinterOptionsValidator()
199 ]; 274 ];
200 275
201 final Source source; 276 final Source source;
202 OptionsFileValidator(this.source) { 277 OptionsFileValidator(this.source) {
203 _validators.addAll(AnalysisEngine.instance.optionsPlugin.optionsValidators); 278 _validators.addAll(AnalysisEngine.instance.optionsPlugin.optionsValidators);
204 } 279 }
205 280
206 List<AnalysisError> validate(Map<String, YamlNode> options) { 281 List<AnalysisError> validate(Map<String, YamlNode> options) {
207 RecordingErrorListener recorder = new RecordingErrorListener(); 282 RecordingErrorListener recorder = new RecordingErrorListener();
208 ErrorReporter reporter = new ErrorReporter(recorder, source); 283 ErrorReporter reporter = new ErrorReporter(recorder, source);
209 _validators.forEach((OptionsValidator v) => v.validate(reporter, options)); 284 _validators.forEach((OptionsValidator v) => v.validate(reporter, options));
210 return recorder.errors; 285 return recorder.errors;
211 } 286 }
212 } 287 }
213 288
289 /// Validates `analyzer` top-level options.
290 class TopLevelAnalyzerOptionsValidator extends TopLevelOptionValidator {
291 TopLevelAnalyzerOptionsValidator()
292 : super(AnalyzerOptions.analyzer, AnalyzerOptions.topLevel);
293 }
294
214 /// Validates top-level options. For example, 295 /// Validates top-level options. For example,
215 /// plugin: 296 /// plugin:
216 /// top-level-option: true 297 /// top-level-option: true
217 class TopLevelOptionValidator extends OptionsValidator { 298 class TopLevelOptionValidator extends OptionsValidator {
218 final String pluginName; 299 final String pluginName;
219 final List<String> supportedOptions; 300 final List<String> supportedOptions;
220 String _valueProposal; 301 String _valueProposal;
221 AnalysisOptionsWarningCode _warningCode; 302 AnalysisOptionsWarningCode _warningCode;
222 TopLevelOptionValidator(this.pluginName, this.supportedOptions) { 303 TopLevelOptionValidator(this.pluginName, this.supportedOptions) {
223 assert(supportedOptions != null && !supportedOptions.isEmpty); 304 assert(supportedOptions != null && !supportedOptions.isEmpty);
(...skipping 17 matching lines...) Expand all
241 if (!supportedOptions.contains(k.value)) { 322 if (!supportedOptions.contains(k.value)) {
242 reporter.reportErrorForSpan( 323 reporter.reportErrorForSpan(
243 _warningCode, k.span, [pluginName, k.value, _valueProposal]); 324 _warningCode, k.span, [pluginName, k.value, _valueProposal]);
244 } 325 }
245 } 326 }
246 //TODO(pq): consider an error if the node is not a Scalar. 327 //TODO(pq): consider an error if the node is not a Scalar.
247 }); 328 });
248 } 329 }
249 } 330 }
250 } 331 }
332
333 /// An error-builder that knows about `true` and `false` legal values.
334 class TrueOrFalseValueErrorBuilder extends ErrorBuilder {
335 TrueOrFalseValueErrorBuilder() : super(AnalyzerOptions.trueOrFalse);
336 @override
337 AnalysisOptionsWarningCode get pluralProposalCode =>
338 AnalysisOptionsWarningCode.UNSUPPORTED_VALUE;
339 }
340
341 class _OptionsProcessor {
342 void configure(AnalysisContext context, Map<String, YamlNode> options) {
343 if (options == null) {
344 return;
345 }
346
347 YamlMap analyzer = options[AnalyzerOptions.analyzer];
348 if (analyzer == null) {
349 return;
350 }
351
352 // Set strong mode (default is false).
353 bool strongMode = analyzer[AnalyzerOptions.strong_mode] ?? false;
354 setStrongMode(context, strongMode);
355
356 // Set filters.
357 YamlNode filters = analyzer[AnalyzerOptions.errors];
358 setFilters(context, filters);
359
360 // Process language options.
361 YamlNode language = analyzer[AnalyzerOptions.language];
362 setLanguageOptions(context, language);
363 }
364
365 void setFilters(AnalysisContext context, YamlNode codes) {
366 List<ErrorFilter> filters = <ErrorFilter>[];
367 // If codes are enumerated, collect them as filters; else leave filters
368 // empty to overwrite previous value.
369 if (codes is YamlMap) {
370 String value;
371 codes.nodes.forEach((k, v) {
372 if (k is YamlScalar && v is YamlScalar) {
373 value = toLowerCase(v.value);
374 if (AnalyzerOptions.ignoreSynonyms.contains(value)) {
375 // Case-insensitive.
376 String code = toUpperCase(k.value);
377 filters.add((AnalysisError error) => error.errorCode.name == code);
378 }
379 }
380 });
381 }
382 context.setConfigurationData(CONFIGURED_ERROR_FILTERS, filters);
383 }
384
385 void setLanguageOptions(AnalysisContext context, YamlNode configs) {
386 if (configs is YamlMap) {
387 configs.nodes.forEach((k, v) {
388 String feature;
389 if (k is YamlScalar && v is YamlScalar) {
390 feature = k.value?.toString();
391 if (feature == AnalyzerOptions.enableSuperMixins) {
392 if (isTrue(v.value)) {
393 AnalysisOptionsImpl options =
394 new AnalysisOptionsImpl.from(context.analysisOptions);
395 options.enableSuperMixins = true;
396 context.analysisOptions = options;
397 }
398 }
399 }
400 });
401 }
402 }
403
404 void setStrongMode(AnalysisContext context, bool strongMode) {
405 if (context.analysisOptions.strongMode != strongMode) {
406 AnalysisOptionsImpl options =
407 new AnalysisOptionsImpl.from(context.analysisOptions);
408 options.strongMode = strongMode;
409 context.analysisOptions = options;
410 }
411 }
412 }
OLDNEW
« 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