| 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; | 
| +    } | 
| +  } | 
| +} | 
|  |