OLD | NEW |
| (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 } | |
OLD | NEW |