From 577a7abf67cc4e50a1fd303b99da45bd29d35926 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Tue, 14 Apr 2026 10:58:25 -0700 Subject: [PATCH] analyzer: Validate plugin diagnostic configuration This adds validation that plugin diagnostics are configured with one of the valid values (taken from one of the test cases): ``` plugins: one: diagnostics: code1: ignore code2: warning code3: error code4: info ``` Change-Id: I2a77988c2efe1d9e0fdcd33558ed970fbe4c47c0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/494781 Reviewed-by: Konstantin Shcheglov Commit-Queue: Samuel Rawlins --- .../options_file_validator.dart | 61 +++++++++++++++++-- .../options/options_file_validator_test.dart | 52 +++++++++++++++- 2 files changed, 107 insertions(+), 6 deletions(-) diff --git a/pkg/analyzer/lib/src/analysis_options/options_file_validator.dart b/pkg/analyzer/lib/src/analysis_options/options_file_validator.dart index 4e05320ba51..93cd34bd886 100644 --- a/pkg/analyzer/lib/src/analysis_options/options_file_validator.dart +++ b/pkg/analyzer/lib/src/analysis_options/options_file_validator.dart @@ -606,7 +606,7 @@ class _ErrorFilterOptionValidator extends OptionsValidator { /// Legal values. static final List legalValues = [ ...AnalysisOptionsFileKeys.ignoreSynonyms, - ...AnalysisOptionsFileKeys.includeSynonyms, + ...AnalysisOptionsFileKeys.trueOrFalse, ...AnalysisOptionsFileKeys.severities, ]; @@ -1068,7 +1068,11 @@ class _PluginsOptionsValidator extends OptionsValidator { .atSourceSpan(plugins.span), ); } - plugins.nodes.forEach((pluginName, pluginValue) { + plugins.nodes.forEach((pluginNameNode, pluginValue) { + if (pluginNameNode is! YamlScalar) { + return; + } + var pluginName = pluginNameNode.value; if (pluginName is! String) { return; } @@ -1086,7 +1090,7 @@ class _PluginsOptionsValidator extends OptionsValidator { sectionName: '${AnalysisOptionsFileKeys.plugins}/$pluginName', ) - .atSourceSpan(plugins.span), + .atSourceSpan(pluginValue.span), ); } }); @@ -1107,6 +1111,51 @@ class _PluginsOptionsValidator extends OptionsValidator { } } + void _validateDiagnostics( + DiagnosticReporter reporter, + String pluginName, + YamlNode diagnosticsValue, + ) { + var sectionName = [ + AnalysisOptionsFileKeys.plugins, + pluginName, + AnalysisOptionsFileKeys.diagnostics, + ].join('/'); + if (diagnosticsValue is! YamlMap) { + reporter.report( + diag.invalidSectionFormat + .withArguments(sectionName: sectionName) + .atSourceSpan(diagnosticsValue.span), + ); + return; + } + + diagnosticsValue.nodes.forEach((codeNameNode, severityNode) { + // The keys are diagnostic codes. + if (severityNode is! YamlScalar) { + reporter.report( + diag.invalidSectionFormat + .withArguments(sectionName: sectionName) + .atSourceSpan(severityNode.span), + ); + return; + } + + var severity = severityNode.value?.toString().toLowerCase(); + if (!_ErrorFilterOptionValidator.legalValues.contains(severity)) { + reporter.report( + diag.unsupportedOptionWithLegalValues + .withArguments( + sectionName: sectionName, + optionKey: severityNode.value.toString(), + legalValues: _ErrorFilterOptionValidator.legalValueString, + ) + .atSourceSpan(severityNode.span), + ); + } + }); + } + void _validatePluginMap( DiagnosticReporter reporter, String pluginName, @@ -1114,7 +1163,11 @@ class _PluginsOptionsValidator extends OptionsValidator { ) { pluginValue.nodes.forEach((pluginMapKeyNode, pluginMapValueNode) { if (pluginMapKeyNode case YamlScalar(value: String pluginMapKey)) { - if (!AnalysisOptionsFileKeys.pluginsOptions.contains(pluginMapKey)) { + if (pluginMapKey == AnalysisOptionsFileKeys.diagnostics) { + _validateDiagnostics(reporter, pluginName, pluginMapValueNode); + } else if (!AnalysisOptionsFileKeys.pluginsOptions.contains( + pluginMapKey, + )) { _builder.reportError( reporter, '${AnalysisOptionsFileKeys.plugins}/$pluginName', diff --git a/pkg/analyzer/test/src/options/options_file_validator_test.dart b/pkg/analyzer/test/src/options/options_file_validator_test.dart index ca8a5cd5460..3246afd2781 100644 --- a/pkg/analyzer/test/src/options/options_file_validator_test.dart +++ b/pkg/analyzer/test/src/options/options_file_validator_test.dart @@ -616,14 +616,62 @@ linter: ); } - test_plugins_each_invalid_mapKey() { + test_plugins_diagnostics_invalid() { + validate( + ''' +plugins: + one: + diagnostics: + code: abc +''', + [diag.unsupportedOptionWithLegalValues], + ); + } + + test_plugins_diagnostics_notAMap() { + validate( + ''' +plugins: + one: + diagnostics: 7 +''', + [diag.invalidSectionFormat], + ); + } + + test_plugins_diagnostics_supported_severity() { validate(''' plugins: one: - ppath: foo/bar + diagnostics: + code1: ignore + code2: warning + code3: error + code4: info ''', []); } + test_plugins_diagnostics_supported_trueOrFalse() { + validate(''' +plugins: + one: + diagnostics: + code1: true + code2: false +''', []); + } + + test_plugins_each_invalid_mapKey() { + validate( + ''' +plugins: + one: + ppath: foo/bar +''', + [diag.unsupportedOptionWithLegalValues], + ); + } + test_plugins_each_valid_mapKey() { validate(''' plugins: