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

Side by Side Diff: pkg/analyzer_cli/lib/src/options.dart

Issue 2840703002: Refactoring analyzer_cli for code hygiene. (Closed)
Patch Set: Created 3 years, 8 months 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer_cli.src.options;
6
7 import 'dart:io';
8
9 import 'package:analyzer/file_system/physical_file_system.dart';
10 import 'package:analyzer/src/command_line/arguments.dart';
11 import 'package:analyzer/src/context/builder.dart';
12 import 'package:analyzer_cli/src/ansi.dart' as ansi;
13 import 'package:analyzer_cli/src/driver.dart';
14 import 'package:args/args.dart';
15 import 'package:cli_util/cli_util.dart' show getSdkDir;
16
17 const _binaryName = 'dartanalyzer';
18
19 /// Shared exit handler.
20 ///
21 /// *Visible for testing.*
22 ExitHandler exitHandler = exit;
23
24 /// Print the given [message] to stderr and exit with the given [exitCode].
25 void printAndFail(String message, {int exitCode: 15}) {
26 errorSink.writeln(message);
27 exitHandler(exitCode);
28 }
29
30 /// Exit handler.
31 ///
32 /// *Visible for testing.*
33 typedef void ExitHandler(int code);
34
35 /// Analyzer commandline configuration options.
36 class CommandLineOptions {
37 final bool enableNewAnalysisDriver = true;
38
39 /// Return `true` if the parser is to parse asserts in the initializer list of
40 /// a constructor.
41 final bool enableAssertInitializer;
42
43 /// The path to output analysis results when in build mode.
44 final String buildAnalysisOutput;
45
46 /// Whether to use build mode.
47 final bool buildMode;
48
49 /// Whether to use build mode as a Bazel persistent worker.
50 final bool buildModePersistentWorker;
51
52 /// List of summary file paths to use in build mode.
53 final List<String> buildSummaryInputs;
54
55 /// Whether to skip analysis when creating summaries in build mode.
56 final bool buildSummaryOnly;
57
58 /// Whether to use diet parsing, i.e. skip function bodies. We don't need to
59 /// analyze function bodies to use summaries during future compilation steps.
60 final bool buildSummaryOnlyDiet;
61
62 /// Whether to only produce unlinked summaries instead of linked summaries.
63 /// Must be used in combination with `buildSummaryOnly`.
64 final bool buildSummaryOnlyUnlinked;
65
66 /// The path to output the summary when creating summaries in build mode.
67 final String buildSummaryOutput;
68
69 /// The path to output the semantic-only summary when creating summaries in
70 /// build mode.
71 final String buildSummaryOutputSemantic;
72
73 /// Whether to suppress a nonzero exit code in build mode.
74 final bool buildSuppressExitCode;
75
76 /// The options defining the context in which analysis is performed.
77 final ContextBuilderOptions contextBuilderOptions;
78
79 /// The path to the dart SDK.
80 String dartSdkPath;
81
82 /// The path to the dart SDK summary file.
83 String dartSdkSummaryPath;
84
85 /// Whether to disable cache flushing. This option can improve analysis
86 /// speed at the expense of memory usage. It may also be useful for working
87 /// around bugs.
88 final bool disableCacheFlushing;
89
90 /// Whether to report hints
91 final bool disableHints;
92
93 /// Whether to display version information
94 final bool displayVersion;
95
96 /// Whether to treat type mismatches found during constant evaluation as
97 /// errors.
98 final bool enableTypeChecks;
99
100 /// Whether to treat hints as fatal
101 final bool hintsAreFatal;
102
103 /// Whether to ignore unrecognized flags
104 final bool ignoreUnrecognizedFlags;
105
106 /// Whether to report lints
107 final bool lints;
108
109 /// Whether to log additional analysis messages and exceptions
110 final bool log;
111
112 /// Whether to use machine format for error display
113 final bool machineFormat;
114
115 /// The path to a file to write a performance log.
116 /// (Or null if not enabled.)
117 final String perfReport;
118
119 /// Batch mode (for unit testing)
120 final bool shouldBatch;
121
122 /// Whether to show package: warnings
123 final bool showPackageWarnings;
124
125 /// If not null, show package: warnings only for matching packages.
126 final String showPackageWarningsPrefix;
127
128 /// Whether to show SDK warnings
129 final bool showSdkWarnings;
130
131 /// The source files to analyze
132 List<String> _sourceFiles;
133
134 /// Whether to treat warnings as fatal
135 final bool warningsAreFatal;
136
137 /// Whether to use strong static checking.
138 final bool strongMode;
139
140 /// Whether implicit casts are enabled (in strong mode)
141 final bool implicitCasts;
142
143 /// Whether implicit dynamic is enabled (mainly for strong mode users)
144 final bool implicitDynamic;
145
146 /// Whether to treat lints as fatal
147 final bool lintsAreFatal;
148
149 /// Whether to use memory byte store for analysis driver.
150 final bool useAnalysisDriverMemoryByteStore;
151
152 /// Emit output in a verbose mode.
153 final bool verbose;
154
155 /// Use ANSI color codes for output.
156 final bool color;
157
158 /// Initialize options from the given parsed [args].
159 CommandLineOptions._fromArgs(ArgResults args)
160 : buildAnalysisOutput = args['build-analysis-output'],
161 buildMode = args['build-mode'],
162 buildModePersistentWorker = args['persistent_worker'],
163 buildSummaryInputs = args['build-summary-input'] as List<String>,
164 buildSummaryOnly = args['build-summary-only'],
165 buildSummaryOnlyDiet = args['build-summary-only-diet'],
166 buildSummaryOnlyUnlinked = args['build-summary-only-unlinked'],
167 buildSummaryOutput = args['build-summary-output'],
168 buildSummaryOutputSemantic = args['build-summary-output-semantic'],
169 buildSuppressExitCode = args['build-suppress-exit-code'],
170 contextBuilderOptions = createContextBuilderOptions(args),
171 dartSdkPath = args['dart-sdk'],
172 dartSdkSummaryPath = args['dart-sdk-summary'],
173 disableCacheFlushing = args['disable-cache-flushing'],
174 disableHints = args['no-hints'],
175 displayVersion = args['version'],
176 enableTypeChecks = args['enable_type_checks'],
177 enableAssertInitializer = args['enable-assert-initializers'],
178 hintsAreFatal = args['fatal-hints'],
179 ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'],
180 lints = args[lintsFlag],
181 log = args['log'],
182 machineFormat = args['format'] == 'machine',
183 perfReport = args['x-perf-report'],
184 shouldBatch = args['batch'],
185 showPackageWarnings = args['show-package-warnings'] ||
186 args['package-warnings'] ||
187 args['x-package-warnings-prefix'] != null,
188 showPackageWarningsPrefix = args['x-package-warnings-prefix'],
189 showSdkWarnings = args['sdk-warnings'],
190 _sourceFiles = args.rest,
191 warningsAreFatal = args['fatal-warnings'],
192 strongMode = args['strong'],
193 implicitCasts = !args['no-implicit-casts'],
194 implicitDynamic = !args['no-implicit-dynamic'],
195 lintsAreFatal = args['fatal-lints'],
196 useAnalysisDriverMemoryByteStore =
197 args['use-analysis-driver-memory-byte-store'],
198 verbose = args['verbose'],
199 color = args['color'];
200
201 /// The path to an analysis options file
202 String get analysisOptionsFile =>
203 contextBuilderOptions.defaultAnalysisOptionsFilePath;
204
205 /// A table mapping the names of defined variables to their values.
206 Map<String, String> get definedVariables =>
207 contextBuilderOptions.declaredVariables;
208
209 /// Whether to strictly follow the specification when generating warnings on
210 /// "call" methods (fixes dartbug.com/21938).
211 bool get enableStrictCallChecks =>
212 contextBuilderOptions.defaultOptions.enableStrictCallChecks;
213
214 /// Whether to relax restrictions on mixins (DEP 34).
215 bool get enableSuperMixins =>
216 contextBuilderOptions.defaultOptions.enableSuperMixins;
217
218 /// The path to a `.packages` configuration file
219 String get packageConfigPath => contextBuilderOptions.defaultPackageFilePath;
220
221 /// The path to the package root
222 String get packageRootPath =>
223 contextBuilderOptions.defaultPackagesDirectoryPath;
224
225 /// Parse [args] into [CommandLineOptions] describing the specified
226 /// analyzer options. In case of a format error, calls [printAndFail], which
227 /// by default prints an error message to stderr and exits.
228 static CommandLineOptions parse(List<String> args,
229 [printAndFail(String msg) = printAndFail]) {
230 CommandLineOptions options = _parse(args);
231 // Check SDK.
232 if (!options.buildModePersistentWorker) {
233 // Infer if unspecified.
234 if (options.dartSdkPath == null) {
235 Directory sdkDir = getSdkDir(args);
236 if (sdkDir != null) {
237 options.dartSdkPath = sdkDir.path;
238 }
239 }
240
241 String sdkPath = options.dartSdkPath;
242
243 // Check that SDK is specified.
244 if (sdkPath == null) {
245 printAndFail('No Dart SDK found.');
246 return null; // Only reachable in testing.
247 }
248 // Check that SDK is existing directory.
249 if (!(new Directory(sdkPath)).existsSync()) {
250 printAndFail('Invalid Dart SDK path: $sdkPath');
251 return null; // Only reachable in testing.
252 }
253 }
254
255 // Check package config.
256 {
257 if (options.packageRootPath != null &&
258 options.packageConfigPath != null) {
259 printAndFail("Cannot specify both '--package-root' and '--packages.");
260 return null; // Only reachable in testing.
261 }
262 }
263
264 // Build mode.
265 if (options.buildModePersistentWorker && !options.buildMode) {
266 printAndFail('The option --persisten_worker can be used only '
267 'together with --build-mode.');
268 return null; // Only reachable in testing.
269 }
270 if (options.buildSummaryOnlyDiet && !options.buildSummaryOnly) {
271 printAndFail('The option --build-summary-only-diet can be used only '
272 'together with --build-summary-only.');
273 return null; // Only reachable in testing.
274 }
275
276 if (options.buildSummaryOnlyUnlinked) {
277 if (!options.buildSummaryOnly) {
278 printAndFail(
279 'The option --build-summary-only-unlinked can be used only '
280 'together with --build-summary-only.');
281 return null; // Only reachable in testing.
282 }
283 if (options.buildSummaryInputs.isNotEmpty) {
284 printAndFail('No summaries should be provided in combination with '
285 '--build-summary-only-unlinked, they aren\'t needed.');
286 return null; // Only reachable in testing.
287 }
288 }
289
290 return options;
291 }
292
293 /// The source files to analyze
294 List<String> get sourceFiles => _sourceFiles;
295
296 /// Replace the sourceFiles parsed from the command line.
297 void rewriteSourceFiles(List<String> newSourceFiles) {
298 _sourceFiles = newSourceFiles;
299 }
300
301 static String _getVersion() {
302 try {
303 // This is relative to bin/snapshot, so ../..
304 String versionPath =
305 Platform.script.resolve('../../version').toFilePath();
306 File versionFile = new File(versionPath);
307 return versionFile.readAsStringSync().trim();
308 } catch (_) {
309 // This happens when the script is not running in the context of an SDK.
310 return "<unknown>";
311 }
312 }
313
314 static CommandLineOptions _parse(List<String> args) {
315 args = preprocessArgs(PhysicalResourceProvider.INSTANCE, args);
316
317 bool verbose = args.contains('-v') || args.contains('--verbose');
318 bool hide = !verbose;
319
320 ArgParser parser = new ArgParser(allowTrailingOptions: true);
321
322 if (!hide) {
323 parser.addSeparator('General options:');
324 }
325
326 // TODO(devoncarew): This defines some hidden flags, which would be better
327 // defined with the rest of the hidden flags below (to group well with the
328 // other flags).
329 defineAnalysisArguments(parser, hide: hide);
330
331 parser
332 ..addOption('format',
333 help: 'Specifies the format in which errors are displayed; the only '
334 'currently allowed value is \'machine\'.')
335 ..addFlag('version',
336 help: 'Print the analyzer version.',
337 defaultsTo: false,
338 negatable: false)
339 ..addFlag('no-hints',
340 help: 'Do not show hint results.',
341 defaultsTo: false,
342 negatable: false)
343 ..addFlag('fatal-hints',
344 help: 'Treat hints as fatal.', defaultsTo: false, negatable: false)
345 ..addFlag('fatal-warnings',
346 help: 'Treat non-type warnings as fatal.',
347 defaultsTo: false,
348 negatable: false)
349 ..addFlag('fatal-lints',
350 help: 'Treat lints as fatal.', defaultsTo: false, negatable: false)
351 ..addFlag('package-warnings',
352 help: 'Show warnings from package: imports.',
353 defaultsTo: false,
354 negatable: false)
355 ..addFlag('help',
356 abbr: 'h',
357 help:
358 'Display this help message. Add --verbose to show hidden options.' ,
359 defaultsTo: false,
360 negatable: false)
361 ..addFlag('verbose',
362 abbr: 'v',
363 defaultsTo: false,
364 help: 'Verbose output.',
365 negatable: false);
366
367 // Build mode options.
368 if (!hide) {
369 parser.addSeparator('Build mode flags:');
370 }
371
372 parser
373 ..addFlag('persistent_worker',
374 help: 'Enable Bazel persistent worker mode.',
375 defaultsTo: false,
376 negatable: false,
377 hide: hide)
378 ..addOption('build-analysis-output',
379 help:
380 'Specifies the path to the file where analysis results should be w ritten.',
381 hide: hide)
382 ..addFlag('build-mode',
383 // TODO(paulberry): add more documentation.
384 help: 'Enable build mode.',
385 defaultsTo: false,
386 negatable: false,
387 hide: hide)
388 ..addOption('build-summary-input',
389 help: 'Path to a summary file that contains information from a '
390 'previous analysis run; may be specified multiple times.',
391 allowMultiple: true,
392 hide: hide)
393 ..addOption('build-summary-output',
394 help: 'Specifies the path to the file where the full summary '
395 'information should be written.',
396 hide: hide)
397 ..addOption('build-summary-output-semantic',
398 help: 'Specifies the path to the file where the semantic summary '
399 'information should be written.',
400 hide: hide)
401 ..addFlag('build-summary-only',
402 help: 'Disable analysis (only generate summaries).',
403 defaultsTo: false,
404 negatable: false,
405 hide: hide)
406 ..addFlag('build-summary-only-diet',
407 help: 'Diet parse function bodies.',
408 defaultsTo: false,
409 negatable: false,
410 hide: hide)
411 ..addFlag('build-summary-only-unlinked',
412 help: 'Only output the unlinked summary.',
413 defaultsTo: false,
414 negatable: false,
415 hide: hide)
416 ..addFlag('build-suppress-exit-code',
417 help: 'Exit with code 0 even if errors are found.',
418 defaultsTo: false,
419 negatable: false,
420 hide: hide)
421 ..addFlag('color',
422 help: 'Use ansi colors when printing messages.',
423 defaultsTo: ansi.terminalSupportsAnsi(),
424 hide: hide);
425
426 // Hidden flags.
427 if (!hide) {
428 parser.addSeparator('Less frequently used flags:');
429 }
430
431 parser
432 ..addFlag('batch',
433 help: 'Read commands from standard input (for testing).',
434 defaultsTo: false,
435 negatable: false,
436 hide: hide)
437 ..addFlag(ignoreUnrecognizedFlagsFlag,
438 help: 'Ignore unrecognized command line flags.',
439 defaultsTo: false,
440 negatable: false,
441 hide: hide)
442 ..addFlag('disable-cache-flushing', defaultsTo: false, hide: hide)
443 ..addOption('x-perf-report',
444 help: 'Writes a performance report to the given file (experimental).',
445 hide: hide)
446 ..addOption('x-package-warnings-prefix',
447 help:
448 'Show warnings from package: imports that match the given prefix.' ,
449 hide: hide)
450 ..addFlag('enable-conditional-directives',
451 help:
452 'deprecated -- Enable support for conditional directives (DEP 40). ',
453 defaultsTo: false,
454 negatable: false,
455 hide: hide)
456 ..addFlag('show-package-warnings',
457 help: 'Show warnings from package: imports (deprecated).',
458 defaultsTo: false,
459 negatable: false,
460 hide: hide)
461 ..addFlag('sdk-warnings',
462 help: 'Show warnings from SDK imports.',
463 defaultsTo: false,
464 negatable: false,
465 hide: hide)
466 ..addFlag('log',
467 help: 'Log additional messages and exceptions.',
468 defaultsTo: false,
469 negatable: false,
470 hide: hide)
471 ..addFlag('enable_type_checks',
472 help: 'Check types in constant evaluation.',
473 defaultsTo: false,
474 negatable: false,
475 hide: hide)
476 ..addFlag('enable-assert-initializers',
477 help: 'Enable parsing of asserts in constructor initializers.',
478 defaultsTo: false,
479 negatable: false,
480 hide: hide)
481 ..addFlag('use-analysis-driver-memory-byte-store',
482 help: 'Use memory byte store, not the file system cache.',
483 defaultsTo: false,
484 negatable: false,
485 hide: hide)
486 ..addOption('url-mapping',
487 help: '--url-mapping=libraryUri,/path/to/library.dart directs the '
488 'analyzer to use "library.dart" as the source for an import '
489 'of "libraryUri".',
490 allowMultiple: true,
491 splitCommas: false,
492 hide: hide);
493
494 try {
495 if (args.contains('--$ignoreUnrecognizedFlagsFlag')) {
496 args = filterUnknownArguments(args, parser);
497 }
498 ArgResults results = parser.parse(args);
499
500 // Persistent worker.
501 if (args.contains('--persistent_worker')) {
502 bool hasBuildMode = args.contains('--build-mode');
503 bool onlyDartSdkArg = args.length == 2 ||
504 (args.length == 3 && args.any((a) => a.startsWith('--dart-sdk'))) ||
505 (args.length == 4 && args.contains('--dart-sdk'));
506 if (!(hasBuildMode && onlyDartSdkArg)) {
507 printAndFail('The --persistent_worker flag should be used with and '
508 'only with the --build-mode flag, and possibly the --dart-sdk '
509 'option. Got: $args');
510 return null; // Only reachable in testing.
511 }
512 return new CommandLineOptions._fromArgs(results);
513 }
514
515 // Help requests.
516 if (results['help']) {
517 _showUsage(parser);
518 exitHandler(0);
519 return null; // Only reachable in testing.
520 }
521 // Batch mode and input files.
522 if (results['batch']) {
523 if (results.rest.isNotEmpty) {
524 errorSink.writeln('No source files expected in the batch mode.');
525 _showUsage(parser);
526 exitHandler(15);
527 return null; // Only reachable in testing.
528 }
529 } else if (results['persistent_worker']) {
530 if (results.rest.isNotEmpty) {
531 errorSink.writeln(
532 'No source files expected in the persistent worker mode.');
533 _showUsage(parser);
534 exitHandler(15);
535 return null; // Only reachable in testing.
536 }
537 } else if (results['version']) {
538 outSink.writeln('$_binaryName version ${_getVersion()}');
539 exitHandler(0);
540 return null; // Only reachable in testing.
541 } else {
542 if (results.rest.isEmpty && !results['build-mode']) {
543 _showUsage(parser);
544 exitHandler(15);
545 return null; // Only reachable in testing.
546 }
547 }
548 return new CommandLineOptions._fromArgs(results);
549 } on FormatException catch (e) {
550 errorSink.writeln(e.message);
551 _showUsage(parser);
552 exitHandler(15);
553 return null; // Only reachable in testing.
554 }
555 }
556
557 static _showUsage(ArgParser parser) {
558 errorSink.writeln(
559 'Usage: $_binaryName [options...] <directory or list of files>');
560 errorSink.writeln('');
561 errorSink.writeln(parser.usage);
562 errorSink.writeln('');
563 errorSink.writeln('''
564 Run "dartanalyzer -h -v" for verbose help output, including less commonly used o ptions.
565 For more information, see http://www.dartlang.org/tools/analyzer.
566 ''');
567 }
568 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698