Skip to content

Commit 2fd0b1a

Browse files
srawlinsCommit Queue
authored andcommitted
linter: extract ruleConfigs earlier
Each call site for `parseLintRuleConfigs`, `processAnalysisOptionsFile` immediately just want the `ruleConfigs` (which is the only property of a LintConfig). So instead of passing around LintConfigs, just pass around the list of RuleConfigs. (LintConfig can probably be deleted now, but I'll look at that for a separate change; might need care with google3.) Change-Id: I30eba648e5f53bc5d5196ce95c09c8261535a737 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391161 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Phil Quitslund <[email protected]>
1 parent bd91181 commit 2fd0b1a

File tree

6 files changed

+75
-78
lines changed

6 files changed

+75
-78
lines changed

pkg/analyzer/lib/src/generated/engine.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,9 @@ class AnalysisOptionsImpl implements AnalysisOptions {
506506
var formatter = optionsMap.valueAt(AnalyzerOptions.formatter);
507507
builder._applyFormatterOptions(formatter);
508508

509-
var lintConfig = parseLintConfig(optionsMap);
510-
if (lintConfig != null) {
511-
var enabledRules = Registry.ruleRegistry.enabled(lintConfig);
509+
var ruleConfigs = parseLintRuleConfigs(optionsMap);
510+
if (ruleConfigs != null) {
511+
var enabledRules = Registry.ruleRegistry.enabled(ruleConfigs);
512512
if (enabledRules.isNotEmpty) {
513513
builder.lint = true;
514514
builder.lintRules = enabledRules.toList();

pkg/analyzer/lib/src/lint/config.dart

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,55 +8,32 @@ import 'package:yaml/yaml.dart';
88

99
/// Parses [optionsMap] into a [LintConfig], returning the config, or `null` if
1010
/// [optionsMap] does not have `linter` map.
11-
LintConfig? parseLintConfig(YamlMap optionsMap) {
11+
List<RuleConfig>? parseLintRuleConfigs(YamlMap optionsMap) {
1212
var options = optionsMap.valueAt('linter');
1313
// Quick check of basic contract.
1414
if (options is YamlMap) {
15-
return LintConfig.parseMap(options);
15+
return LintConfig.parseMap(options).ruleConfigs;
1616
}
1717

1818
return null;
1919
}
2020

21-
/// Process the given option [fileContents] and produce a corresponding
22-
/// [LintConfig]. Return `null` if [fileContents] is not a YAML map, or
23-
/// does not have the `linter` child map.
24-
LintConfig? processAnalysisOptionsFile(String fileContents, {String? fileUrl}) {
25-
var yaml = loadYamlNode(fileContents,
26-
sourceUrl: fileUrl != null ? Uri.parse(fileUrl) : null);
27-
if (yaml is YamlMap) {
28-
return parseLintConfig(yaml);
29-
}
30-
return null;
31-
}
32-
3321
/// The configuration of lint rules within an analysis options file.
3422
class LintConfig {
3523
final List<RuleConfig> ruleConfigs;
3624

37-
LintConfig(this.ruleConfigs);
38-
39-
factory LintConfig.parse(String source, {String? sourceUrl}) {
40-
var yaml = loadYamlNode(source,
41-
sourceUrl: sourceUrl != null ? Uri.parse(sourceUrl) : null);
42-
if (yaml is! YamlMap) {
43-
throw StateError("Expected YAML at '$source' to be a Map, but is "
44-
'${yaml.runtimeType}.');
45-
}
46-
47-
return LintConfig.parseMap(yaml);
48-
}
49-
5025
factory LintConfig.parseMap(YamlMap yaml) {
5126
var ruleConfigs = <RuleConfig>[];
5227
var rulesNode = yaml.valueAt(AnalyzerOptions.rules);
5328
if (rulesNode != null) {
5429
ruleConfigs.addAll(_ruleConfigs(rulesNode));
5530
}
5631

57-
return LintConfig(ruleConfigs);
32+
return LintConfig._(ruleConfigs);
5833
}
5934

35+
LintConfig._(this.ruleConfigs);
36+
6037
static bool? _asBool(YamlNode scalar) {
6138
var value = scalar is YamlScalar ? scalar.valueOrThrow : scalar;
6239
return switch (value) {
@@ -135,8 +112,10 @@ class RuleConfig {
135112

136113
RuleConfig({required this.name, required this.args, this.group});
137114

115+
/// Returns whether [ruleName] is disabled in this configuration.
138116
bool disables(String ruleName) =>
139117
ruleName == name && args['enabled'] == false;
140118

119+
/// Returns whether [ruleName] is enabled in this configuration.
141120
bool enables(String ruleName) => ruleName == name && args['enabled'] == true;
142121
}

pkg/analyzer/lib/src/lint/registry.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ class Registry with IterableMixin<LintRule> {
3939
/// enables `my_rule`.
4040
///
4141
/// Unspecified rules are treated as disabled by default.
42-
Iterable<LintRule> enabled(LintConfig config) => rules
43-
.where((rule) => config.ruleConfigs.any((rc) => rc.enables(rule.name)));
42+
Iterable<LintRule> enabled(List<RuleConfig> ruleConfigs) =>
43+
rules.where((rule) => ruleConfigs.any((rc) => rc.enables(rule.name)));
4444

4545
/// Return the lint rule with the given [name].
4646
LintRule? getRule(String name) => _ruleMap[name];

pkg/analyzer/test/src/lint/config_test.dart

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,28 @@ main() {
1313
}
1414

1515
defineTests() {
16-
const src = """
16+
/// Process the given option [fileContents] and produce a corresponding
17+
/// [LintConfig]. Return `null` if [fileContents] is not a YAML map, or
18+
/// does not have the `linter` child map.
19+
List<RuleConfig>? processAnalysisOptionsFile(String fileContents) {
20+
var yaml = loadYamlNode(fileContents);
21+
if (yaml is YamlMap) {
22+
return parseLintRuleConfigs(yaml);
23+
}
24+
return null;
25+
}
26+
27+
// In the future, options might be marshaled in maps and passed to rules.
28+
// acme:
29+
// some_rule:
30+
// some_option: # Note this nesting might be arbitrarily complex?
31+
// - param1
32+
// - param2
33+
34+
group('lint config', () {
35+
group('rule', () {
36+
test('configs', () {
37+
var optionsYaml = loadYamlNode('''
1738
files:
1839
include: foo # un-quoted
1940
exclude:
@@ -25,28 +46,16 @@ rules:
2546
camel_case_types: true #enable
2647
pub:
2748
package_names: false
28-
""";
29-
30-
// In the future, options might be marshaled in maps and passed to rules.
31-
// acme:
32-
// some_rule:
33-
// some_option: # Note this nesting might be arbitrarily complex?
34-
// - param1
35-
// - param2
36-
37-
var config = LintConfig.parse(src);
38-
39-
group('lint config', () {
40-
group('rule', () {
41-
test('configs', () {
49+
''');
50+
var config = LintConfig.parseMap(optionsYaml as YamlMap);
4251
expect(config.ruleConfigs, hasLength(3));
4352
});
4453

4554
test('config', () {
46-
config = LintConfig.parse('''
55+
var config = LintConfig.parseMap(loadYamlNode('''
4756
rules:
4857
style_guide:
49-
unnecessary_getters: false''');
58+
unnecessary_getters: false''') as YamlMap);
5059
expect(config.ruleConfigs, hasLength(1));
5160
var ruleConfig = config.ruleConfigs[0];
5261
expect(ruleConfig.group, 'style_guide');
@@ -72,8 +81,8 @@ linter:
7281
unnecessary_getters: false #disable
7382
camel_case_types: true #enable
7483
''';
75-
var config = processAnalysisOptionsFile(src)!;
76-
var ruleNames = config.ruleConfigs.map((rc) => rc.name);
84+
var ruleConfigs = processAnalysisOptionsFile(src)!;
85+
var ruleNames = ruleConfigs.map((rc) => rc.name);
7786
expect(ruleNames, hasLength(2));
7887
expect(ruleNames, contains('unnecessary_getters'));
7988
expect(ruleNames, contains('camel_case_types'));
@@ -91,10 +100,10 @@ linter:
91100
rules:
92101
- camel_case_types
93102
''';
94-
var config = processAnalysisOptionsFile(src)!;
95-
expect(config.ruleConfigs.length, 1);
103+
var ruleConfigs = processAnalysisOptionsFile(src)!;
104+
expect(ruleConfigs, hasLength(1));
96105
// Verify that defaults are enabled.
97-
expect(config.ruleConfigs[0].args['enabled'], isTrue);
106+
expect(ruleConfigs[0].args['enabled'], isTrue);
98107
});
99108

100109
test('rule map (bools)', () {
@@ -108,8 +117,7 @@ linter:
108117
camel_case_types: true #enable
109118
unnecessary_getters: false #disable
110119
''';
111-
var config = processAnalysisOptionsFile(src)!;
112-
var ruleConfigs = config.ruleConfigs.toList();
120+
var ruleConfigs = processAnalysisOptionsFile(src)!;
113121
ruleConfigs.sort((RuleConfig rc1, RuleConfig rc2) =>
114122
rc1.name!.compareTo(rc2.name!));
115123
expect(ruleConfigs, hasLength(2));
@@ -132,8 +140,8 @@ linter:
132140

133141
group('options processing', () {
134142
group('raw maps', () {
135-
LintConfig parseMap(Map<Object, Object?> map) {
136-
return parseLintConfig(wrap(map) as YamlMap)!;
143+
List<RuleConfig> parseMap(Map<Object, Object?> map) {
144+
return parseLintRuleConfigs(wrap(map) as YamlMap)!;
137145
}
138146

139147
test('rule list', () {
@@ -143,9 +151,9 @@ linter:
143151
};
144152
options['linter'] = lintOptions;
145153

146-
var config = parseMap(options);
147-
expect(config, isNotNull);
148-
expect(config.ruleConfigs, hasLength(1));
154+
var ruleConfigs = parseMap(options);
155+
expect(ruleConfigs, isNotNull);
156+
expect(ruleConfigs, hasLength(1));
149157
});
150158

151159
test('rule map (bool)', () {
@@ -155,9 +163,9 @@ linter:
155163
};
156164
options['linter'] = lintOptions;
157165

158-
var config = parseMap(options);
159-
expect(config, isNotNull);
160-
expect(config.ruleConfigs, hasLength(1));
166+
var ruleConfigs = parseMap(options);
167+
expect(ruleConfigs, isNotNull);
168+
expect(ruleConfigs, hasLength(1));
161169
});
162170

163171
test('rule map (string)', () {
@@ -167,9 +175,9 @@ linter:
167175
};
168176
options['linter'] = lintOptions;
169177

170-
var config = parseMap(options);
171-
expect(config, isNotNull);
172-
expect(config.ruleConfigs, hasLength(1));
178+
var ruleConfigs = parseMap(options);
179+
expect(ruleConfigs, isNotNull);
180+
expect(ruleConfigs, hasLength(1));
173181
});
174182

175183
test('nested rule map (bool)', () {
@@ -181,9 +189,9 @@ linter:
181189
};
182190
options['linter'] = lintOptions;
183191

184-
var config = parseMap(options);
185-
expect(config, isNotNull);
186-
expect(config.ruleConfigs, hasLength(1));
192+
var ruleConfigs = parseMap(options);
193+
expect(ruleConfigs, isNotNull);
194+
expect(ruleConfigs, hasLength(1));
187195
});
188196

189197
test('nested rule map (string)', () {
@@ -195,9 +203,9 @@ linter:
195203
};
196204
options['linter'] = lintOptions;
197205

198-
var config = parseMap(options);
199-
expect(config, isNotNull);
200-
expect(config.ruleConfigs, hasLength(1));
206+
var ruleConfigs = parseMap(options);
207+
expect(ruleConfigs, isNotNull);
208+
expect(ruleConfigs, hasLength(1));
201209
});
202210
});
203211
});

pkg/linter/tool/benchmark.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:linter/src/extensions.dart';
1515
import 'package:linter/src/rules.dart';
1616
import 'package:linter/src/test_utilities/formatter.dart';
1717
import 'package:linter/src/test_utilities/test_linter.dart';
18+
import 'package:yaml/yaml.dart';
1819

1920
import 'lint_sets.dart';
2021

@@ -93,7 +94,8 @@ Future<void> runLinter(List<String> args) async {
9394

9495
LinterOptions linterOptions;
9596
if (configFile is String) {
96-
var config = LintConfig.parse(readFile(configFile));
97+
var optionsContent = readFile(configFile);
98+
var config = LintConfig.parseMap(loadYamlNode(optionsContent) as YamlMap);
9799
var enabledRules = Registry.ruleRegistry.where((LintRule rule) =>
98100
!config.ruleConfigs.any((rc) => rc.disables(rule.name)));
99101

pkg/linter/tool/lint_sets.dart

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'dart:async';
77
import 'package:analyzer/src/lint/config.dart';
88
import 'package:http/http.dart' as http;
99
import 'package:linter/src/utils.dart';
10+
import 'package:yaml/yaml.dart';
1011

1112
Future<List<String>> get dartCoreLints =>
1213
_fetchRulesFromGitHub('/dart-lang/lints/blob/main/lib/core.yaml');
@@ -23,10 +24,17 @@ Future<List<String>> get flutterUserLints => _fetchRulesFromGitHub(
2324
Future<List<String>> _fetchRulesFromGitHub(String optionsPath) async {
2425
var optionsUrl = Uri.https('raw.githubusercontent.com', optionsPath);
2526
var req = await http.get(optionsUrl);
26-
var config = processAnalysisOptionsFile(req.body);
27-
if (config == null) {
27+
28+
var optionsYaml = loadYamlNode(req.body);
29+
if (optionsYaml is! YamlMap) {
30+
printToConsole('No YAML map found for: $optionsUrl (SKIPPED)');
31+
return [];
32+
}
33+
34+
var ruleConfigs = parseLintRuleConfigs(optionsYaml);
35+
if (ruleConfigs == null) {
2836
printToConsole('No config found for: $optionsUrl (SKIPPED)');
2937
return [];
3038
}
31-
return config.ruleConfigs.map((r) => r.name).nonNulls.toList(growable: false);
39+
return ruleConfigs.map((r) => r.name).nonNulls.toList(growable: false);
3240
}

0 commit comments

Comments
 (0)