Skip to content

Commit 7e0834a

Browse files
srawlinsCommit Queue
authored andcommitted
lint rules: rename and simplify the benchmarking script.
* Rename from `cli.dart` to `benchmark.dart`, as the purpose of this script is to benchmark the lint rules. * Move some code from `analyzer_utils.dart` to `benchmark.dart`, and simplify, as these functions were only used in the benchmark script. * Remove a number of command-line arguments that the script used to accept; some are now implied, and others are no longer used. Change-Id: I8fce2375f093778b2bd9d9aaf21afe8495731b7e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/388946 Reviewed-by: Phil Quitslund <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent 701dfa2 commit 7e0834a

File tree

3 files changed

+98
-179
lines changed

3 files changed

+98
-179
lines changed

pkg/linter/lib/src/test_utilities/analyzer_utils.dart

Lines changed: 0 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -3,110 +3,3 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
// ignore_for_file: implementation_imports
6-
7-
import 'dart:convert';
8-
import 'dart:io';
9-
import 'dart:math' as math;
10-
11-
import 'package:analyzer/error/error.dart';
12-
import 'package:analyzer/src/lint/io.dart' show errorSink;
13-
14-
import '../analyzer.dart';
15-
import 'test_linter.dart';
16-
17-
Future<Iterable<AnalysisErrorInfo>> lintFiles(
18-
TestLinter linter, List<File> filesToLint) async {
19-
// Setup an error watcher to track whether an error was logged to stderr so
20-
// we can set the exit code accordingly.
21-
var errorWatcher = ErrorWatchingSink(errorSink);
22-
errorSink = errorWatcher;
23-
24-
var errors = await linter.lintFiles(filesToLint);
25-
if (errorWatcher.encounteredError) {
26-
exitCode = loggedAnalyzerErrorExitCode;
27-
} else if (errors.isNotEmpty) {
28-
exitCode = _maxSeverity(errors.toList(), linter.options.filter);
29-
}
30-
31-
return errors;
32-
}
33-
34-
Iterable<AnalysisError> _filtered(
35-
List<AnalysisError> errors, LintFilter? filter) =>
36-
(filter == null)
37-
? errors
38-
: errors.where((AnalysisError e) => !filter.filter(e));
39-
40-
int _maxSeverity(List<AnalysisErrorInfo> errors, LintFilter? filter) {
41-
var max = 0;
42-
for (var info in errors) {
43-
_filtered(info.errors, filter).forEach((AnalysisError e) {
44-
max = math.max(max, e.errorCode.errorSeverity.ordinal);
45-
});
46-
}
47-
return max;
48-
}
49-
50-
class ErrorWatchingSink implements IOSink {
51-
bool encounteredError = false;
52-
53-
IOSink delegate;
54-
55-
ErrorWatchingSink(this.delegate);
56-
57-
@override
58-
Future<void> get done => delegate.done;
59-
60-
@override
61-
Encoding get encoding => delegate.encoding;
62-
63-
@override
64-
set encoding(Encoding encoding) {
65-
delegate.encoding = encoding;
66-
}
67-
68-
@override
69-
void add(List<int> data) {
70-
delegate.add(data);
71-
}
72-
73-
@override
74-
void addError(Object error, [StackTrace? stackTrace]) {
75-
encounteredError = true;
76-
delegate.addError(error, stackTrace);
77-
}
78-
79-
@override
80-
Future<void> addStream(Stream<List<int>> stream) =>
81-
delegate.addStream(stream);
82-
83-
@override
84-
Future<void> close() => delegate.close();
85-
86-
@override
87-
Future<void> flush() => delegate.flush();
88-
89-
@override
90-
void write(Object? obj) {
91-
delegate.write(obj);
92-
}
93-
94-
@override
95-
void writeAll(Iterable<Object?> objects, [String separator = '']) {
96-
delegate.writeAll(objects, separator);
97-
}
98-
99-
@override
100-
void writeCharCode(int charCode) {
101-
delegate.writeCharCode(charCode);
102-
}
103-
104-
@override
105-
void writeln([Object? obj = '']) {
106-
// 'Exception while using a Visitor to visit ...' (
107-
if (obj.toString().startsWith('Exception')) {
108-
encounteredError = true;
109-
}
110-
delegate.writeln(obj);
111-
}
112-
}

pkg/linter/lib/src/test_utilities/test_linter.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@ class TestLinter implements AnalysisErrorListener {
4343
}) : _resourceProvider =
4444
resourceProvider ?? file_system.PhysicalResourceProvider.INSTANCE;
4545

46-
Future<Iterable<AnalysisErrorInfo>> lintFiles(List<File> files) async {
46+
Future<List<AnalysisErrorInfo>> lintFiles(List<File> files) async {
4747
var errors = <AnalysisErrorInfo>[];
4848
var lintDriver = LintDriver(options, _resourceProvider);
4949
errors.addAll(await lintDriver.analyze(files.where(isDartFile)));
5050
numSourcesAnalyzed = lintDriver.numSourcesAnalyzed;
51-
files.where(isPubspecFile).forEach((path) {
51+
files.where(isPubspecFile).forEach((file) {
5252
numSourcesAnalyzed++;
5353
var errorsForFile = lintPubspecSource(
54-
contents: path.readAsStringSync(),
55-
sourcePath: _resourceProvider.pathContext.normalize(path.absolute.path),
54+
contents: file.readAsStringSync(),
55+
sourcePath: _resourceProvider.pathContext.normalize(file.absolute.path),
5656
);
5757
errors.addAll(errorsForFile);
5858
});

pkg/linter/tool/cli.dart renamed to pkg/linter/tool/benchmark.dart

Lines changed: 94 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:async';
6+
import 'dart:convert';
57
import 'dart:io';
6-
import 'dart:math';
8+
import 'dart:math' as math;
79

810
import 'package:analyzer/error/error.dart';
911
import 'package:analyzer/src/lint/config.dart';
@@ -14,57 +16,53 @@ import 'package:glob/glob.dart';
1416
import 'package:linter/src/analyzer.dart';
1517
import 'package:linter/src/extensions.dart';
1618
import 'package:linter/src/rules.dart';
17-
import 'package:linter/src/test_utilities/analyzer_utils.dart';
1819
import 'package:linter/src/test_utilities/formatter.dart';
1920
import 'package:linter/src/test_utilities/test_linter.dart';
2021

2122
import 'lint_sets.dart';
2223

23-
/// Starts linting from the command-line.
24+
/// Benchmarks lint rules.
2425
Future<void> main(List<String> args) async {
2526
await runLinter(args);
2627
}
2728

2829
const unableToProcessExitCode = 64;
2930

30-
String? getRoot(List<String> paths) =>
31-
paths.length == 1 && Directory(paths.first).existsSync()
32-
? paths.first
33-
: null;
31+
Future<Iterable<AnalysisErrorInfo>> lintFiles(
32+
TestLinter linter, List<File> filesToLint) async {
33+
// Setup an error watcher to track whether an error was logged to stderr so
34+
// we can set the exit code accordingly.
35+
var errorWatcher = _ErrorWatchingSink(errorSink);
36+
errorSink = errorWatcher;
37+
var errors = await linter.lintFiles(filesToLint);
38+
if (errorWatcher.encounteredError) {
39+
exitCode = loggedAnalyzerErrorExitCode;
40+
} else if (errors.isNotEmpty) {
41+
exitCode = _maxSeverity(errors, linter.options.filter);
42+
}
43+
44+
return errors;
45+
}
3446

3547
void printUsage(ArgParser parser, IOSink out, [String? error]) {
36-
var message = 'Lints Dart source files and pubspecs.';
48+
var message = 'Benchmark lint rules.';
3749
if (error != null) {
3850
message = error;
3951
}
4052

4153
out.writeln('''$message
42-
Usage: linter <file>
54+
Usage: benchmark.dart <file>
4355
${parser.usage}
44-
45-
For more information, see https://github.com/dart-lang/linter
4656
''');
4757
}
4858

49-
// TODO(pq): consider using `dart analyze` where possible
50-
// see: https://github.com/dart-lang/linter/pull/2537
5159
Future<void> runLinter(List<String> args) async {
52-
// Force the rule registry to be populated.
5360
registerLintRules();
5461

5562
var parser = ArgParser();
5663
parser
5764
..addFlag('help',
5865
abbr: 'h', negatable: false, help: 'Show usage information.')
59-
..addFlag('stats',
60-
abbr: 's', negatable: false, help: 'Show lint statistics.')
61-
..addFlag('benchmark', negatable: false, help: 'Show lint benchmarks.')
62-
..addFlag('visit-transitive-closure',
63-
help: 'Visit the transitive closure of imported/exported libraries.')
64-
..addFlag('quiet', abbr: 'q', help: "Don't show individual lint errors.")
65-
..addFlag('machine',
66-
help: 'Print results in a format suitable for parsing.',
67-
negatable: false)
6866
..addOption('config', abbr: 'c', help: 'Use configuration from this file.')
6967
..addOption('dart-sdk', help: 'Custom path to a Dart SDK.')
7068
..addMultiOption('rules',
@@ -85,7 +83,8 @@ Future<void> runLinter(List<String> args) async {
8583
return;
8684
}
8785

88-
if (options.rest.isEmpty) {
86+
var paths = options.rest;
87+
if (paths.isEmpty) {
8988
printUsage(parser, errorSink,
9089
'Please provide at least one file or directory to lint.');
9190
exitCode = unableToProcessExitCode;
@@ -122,52 +121,16 @@ Future<void> runLinter(List<String> args) async {
122121
linterOptions.dartSdkPath = customSdk;
123122
}
124123

125-
var stats = options['stats'] as bool;
126-
var benchmark = options['benchmark'] as bool;
127-
if (stats || benchmark) {
128-
linterOptions.enableTiming = true;
129-
}
124+
linterOptions.enableTiming = true;
130125

131126
var filesToLint = [
132-
for (var path in options.rest)
127+
for (var path in paths)
133128
...collectFiles(path)
134129
.map((file) => file.path.toAbsoluteNormalizedPath())
135130
.map(File.new),
136131
];
137132

138-
if (benchmark) {
139-
await writeBenchmarks(outSink, filesToLint, linterOptions);
140-
return;
141-
}
142-
143-
var linter = TestLinter(linterOptions);
144-
145-
try {
146-
var timer = Stopwatch()..start();
147-
var errors = await lintFiles(linter, filesToLint);
148-
timer.stop();
149-
150-
var commonRoot = getRoot(options.rest);
151-
var machine = options['machine'] ?? false;
152-
var quiet = options['quiet'] ?? false;
153-
ReportFormatter(
154-
errors,
155-
linterOptions.filter,
156-
outSink,
157-
elapsedMs: timer.elapsedMilliseconds,
158-
fileCount: linter.numSourcesAnalyzed,
159-
fileRoot: commonRoot,
160-
showStatistics: stats,
161-
machineOutput: machine as bool,
162-
quiet: quiet as bool,
163-
).write();
164-
// ignore: avoid_catches_without_on_clauses
165-
} catch (err, stack) {
166-
errorSink.writeln('''An error occurred while linting
167-
Please report it at: github.com/dart-lang/linter/issues
168-
$err
169-
$stack''');
170-
}
133+
await writeBenchmarks(outSink, filesToLint, linterOptions);
171134
}
172135

173136
Future<void> writeBenchmarks(
@@ -178,11 +141,7 @@ Future<void> writeBenchmarks(
178141
lintRuleTimers.timers.forEach((n, t) {
179142
var timing = t.elapsedMilliseconds;
180143
var previous = timings[n];
181-
if (previous == null) {
182-
timings[n] = timing;
183-
} else {
184-
timings[n] = min(previous, timing);
185-
}
144+
timings[n] = previous == null ? timing : math.min(previous, timing);
186145
});
187146
}
188147

@@ -208,6 +167,73 @@ Future<void> writeBenchmarks(
208167
out.writeTimings(stats, 0);
209168
}
210169

170+
Iterable<AnalysisError> _filtered(
171+
Iterable<AnalysisError> errors, LintFilter? filter) =>
172+
(filter == null)
173+
? errors
174+
: errors.where((AnalysisError e) => !filter.filter(e));
175+
176+
int _maxSeverity(List<AnalysisErrorInfo> infos, LintFilter? filter) {
177+
var allErrors = _filtered(infos.expand((i) => i.errors), filter);
178+
return allErrors.fold(
179+
0, (value, e) => math.max(value, e.errorCode.errorSeverity.ordinal));
180+
}
181+
182+
class _ErrorWatchingSink implements IOSink {
183+
bool encounteredError = false;
184+
185+
final IOSink delegate;
186+
187+
_ErrorWatchingSink(this.delegate);
188+
189+
@override
190+
Future<void> get done => delegate.done;
191+
192+
@override
193+
Encoding get encoding => delegate.encoding;
194+
195+
@override
196+
set encoding(Encoding encoding) => delegate.encoding = encoding;
197+
198+
@override
199+
void add(List<int> data) => delegate.add(data);
200+
201+
@override
202+
void addError(Object error, [StackTrace? stackTrace]) {
203+
encounteredError = true;
204+
delegate.addError(error, stackTrace);
205+
}
206+
207+
@override
208+
Future<void> addStream(Stream<List<int>> stream) =>
209+
delegate.addStream(stream);
210+
211+
@override
212+
Future<void> close() => delegate.close();
213+
214+
@override
215+
Future<void> flush() => delegate.flush();
216+
217+
@override
218+
void write(Object? obj) => delegate.write(obj);
219+
220+
@override
221+
void writeAll(Iterable<Object?> objects, [String separator = '']) =>
222+
delegate.writeAll(objects, separator);
223+
224+
@override
225+
void writeCharCode(int charCode) => delegate.writeCharCode(charCode);
226+
227+
@override
228+
void writeln([Object? obj = '']) {
229+
// 'Exception while using a Visitor to visit ...' (
230+
if (obj.toString().startsWith('Exception')) {
231+
encounteredError = true;
232+
}
233+
delegate.writeln(obj);
234+
}
235+
}
236+
211237
class _FileGlobFilter extends LintFilter {
212238
final List<Glob> includes;
213239
final List<Glob> excludes;

0 commit comments

Comments
 (0)