OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library analyzer_cli.src.driver; | 5 library analyzer_cli.src.driver; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 import 'dart:io'; | 9 import 'dart:io'; |
10 | 10 |
(...skipping 16 matching lines...) Expand all Loading... |
27 import 'package:analyzer/src/generated/java_io.dart'; | 27 import 'package:analyzer/src/generated/java_io.dart'; |
28 import 'package:analyzer/src/generated/sdk_io.dart'; | 28 import 'package:analyzer/src/generated/sdk_io.dart'; |
29 import 'package:analyzer/src/generated/source.dart'; | 29 import 'package:analyzer/src/generated/source.dart'; |
30 import 'package:analyzer/src/generated/source_io.dart'; | 30 import 'package:analyzer/src/generated/source_io.dart'; |
31 import 'package:analyzer/src/generated/utilities_general.dart' | 31 import 'package:analyzer/src/generated/utilities_general.dart' |
32 show PerformanceTag; | 32 show PerformanceTag; |
33 import 'package:analyzer/src/services/lint.dart'; | 33 import 'package:analyzer/src/services/lint.dart'; |
34 import 'package:analyzer/src/task/options.dart'; | 34 import 'package:analyzer/src/task/options.dart'; |
35 import 'package:analyzer_cli/src/analyzer_impl.dart'; | 35 import 'package:analyzer_cli/src/analyzer_impl.dart'; |
36 import 'package:analyzer_cli/src/options.dart'; | 36 import 'package:analyzer_cli/src/options.dart'; |
| 37 import 'package:analyzer_cli/src/package_analyzer.dart'; |
37 import 'package:analyzer_cli/src/perf_report.dart'; | 38 import 'package:analyzer_cli/src/perf_report.dart'; |
38 import 'package:analyzer_cli/starter.dart'; | 39 import 'package:analyzer_cli/starter.dart'; |
39 import 'package:linter/src/plugin/linter_plugin.dart'; | 40 import 'package:linter/src/plugin/linter_plugin.dart'; |
40 import 'package:package_config/discovery.dart' as pkgDiscovery; | 41 import 'package:package_config/discovery.dart' as pkgDiscovery; |
41 import 'package:package_config/packages.dart' show Packages; | 42 import 'package:package_config/packages.dart' show Packages; |
42 import 'package:package_config/packages_file.dart' as pkgfile show parse; | 43 import 'package:package_config/packages_file.dart' as pkgfile show parse; |
43 import 'package:package_config/src/packages_impl.dart' show MapPackages; | 44 import 'package:package_config/src/packages_impl.dart' show MapPackages; |
44 import 'package:path/path.dart' as path; | 45 import 'package:path/path.dart' as path; |
45 import 'package:plugin/manager.dart'; | 46 import 'package:plugin/manager.dart'; |
46 import 'package:plugin/plugin.dart'; | 47 import 'package:plugin/plugin.dart'; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 | 107 |
107 _processPlugins(); | 108 _processPlugins(); |
108 | 109 |
109 // Parse commandline options. | 110 // Parse commandline options. |
110 CommandLineOptions options = CommandLineOptions.parse(args); | 111 CommandLineOptions options = CommandLineOptions.parse(args); |
111 | 112 |
112 // Cache options of interest to inform analysis. | 113 // Cache options of interest to inform analysis. |
113 _setupEnv(options); | 114 _setupEnv(options); |
114 | 115 |
115 // Do analysis. | 116 // Do analysis. |
116 if (_isBatch) { | 117 if (options.packageMode) { |
| 118 ErrorSeverity severity = _analyzePackage(options); |
| 119 // In case of error propagate exit code. |
| 120 if (severity == ErrorSeverity.ERROR) { |
| 121 exitCode = severity.ordinal; |
| 122 } |
| 123 } else if (_isBatch) { |
117 _BatchRunner.runAsBatch(args, (List<String> args) { | 124 _BatchRunner.runAsBatch(args, (List<String> args) { |
118 CommandLineOptions options = CommandLineOptions.parse(args); | 125 CommandLineOptions options = CommandLineOptions.parse(args); |
119 return _analyzeAll(options); | 126 return _analyzeAll(options); |
120 }); | 127 }); |
121 } else { | 128 } else { |
122 ErrorSeverity severity = _analyzeAll(options); | 129 ErrorSeverity severity = _analyzeAll(options); |
123 // In case of error propagate exit code. | 130 // In case of error propagate exit code. |
124 if (severity == ErrorSeverity.ERROR) { | 131 if (severity == ErrorSeverity.ERROR) { |
125 exitCode = severity.ordinal; | 132 exitCode = severity.ordinal; |
126 } | 133 } |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 errorSink.writeln("${part.fullName} is a part and cannot be analyzed."); | 215 errorSink.writeln("${part.fullName} is a part and cannot be analyzed."); |
209 errorSink.writeln("Please pass in a library that contains this part."); | 216 errorSink.writeln("Please pass in a library that contains this part."); |
210 exitCode = ErrorSeverity.ERROR.ordinal; | 217 exitCode = ErrorSeverity.ERROR.ordinal; |
211 allResult = allResult.max(ErrorSeverity.ERROR); | 218 allResult = allResult.max(ErrorSeverity.ERROR); |
212 } | 219 } |
213 } | 220 } |
214 | 221 |
215 return allResult; | 222 return allResult; |
216 } | 223 } |
217 | 224 |
| 225 /// Perform package analysis according to the given [options]. |
| 226 ErrorSeverity _analyzePackage(CommandLineOptions options) { |
| 227 return _analyzeAllTag.makeCurrentWhile(() { |
| 228 return new PackageAnalyzer(options).analyze(); |
| 229 }); |
| 230 } |
| 231 |
218 /// Determine whether the context created during a previous call to | 232 /// Determine whether the context created during a previous call to |
219 /// [_analyzeAll] can be re-used in order to analyze using [options]. | 233 /// [_analyzeAll] can be re-used in order to analyze using [options]. |
220 bool _canContextBeReused(CommandLineOptions options) { | 234 bool _canContextBeReused(CommandLineOptions options) { |
221 // TODO(paulberry): add a command-line option that disables context re-use. | 235 // TODO(paulberry): add a command-line option that disables context re-use. |
222 if (_context == null) { | 236 if (_context == null) { |
223 return false; | 237 return false; |
224 } | 238 } |
225 if (options.packageRootPath != _previousOptions.packageRootPath) { | 239 if (options.packageRootPath != _previousOptions.packageRootPath) { |
226 return false; | 240 return false; |
227 } | 241 } |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 /// Create an analysis context that is prepared to analyze sources according | 468 /// Create an analysis context that is prepared to analyze sources according |
455 /// to the given [options], and store it in [_context]. | 469 /// to the given [options], and store it in [_context]. |
456 void _createAnalysisContext(CommandLineOptions options) { | 470 void _createAnalysisContext(CommandLineOptions options) { |
457 if (_canContextBeReused(options)) { | 471 if (_canContextBeReused(options)) { |
458 return; | 472 return; |
459 } | 473 } |
460 _previousOptions = options; | 474 _previousOptions = options; |
461 | 475 |
462 // Create a context. | 476 // Create a context. |
463 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); | 477 AnalysisContext context = AnalysisEngine.instance.createAnalysisContext(); |
| 478 _context = context; |
464 | 479 |
465 // Choose a package resolution policy and a diet parsing policy based on | 480 // Choose a package resolution policy and a diet parsing policy based on |
466 // the command-line options. | 481 // the command-line options. |
467 SourceFactory sourceFactory = _chooseUriResolutionPolicy( | 482 SourceFactory sourceFactory = _chooseUriResolutionPolicy( |
468 options, (context as InternalAnalysisContext).embedderYamlLocator); | 483 options, (context as InternalAnalysisContext).embedderYamlLocator); |
469 AnalyzeFunctionBodiesPredicate dietParsingPolicy = | 484 AnalyzeFunctionBodiesPredicate dietParsingPolicy = |
470 _chooseDietParsingPolicy(options); | 485 _chooseDietParsingPolicy(options); |
471 | 486 |
472 context.sourceFactory = sourceFactory; | 487 context.sourceFactory = sourceFactory; |
473 | 488 |
474 Map<String, String> definedVariables = options.definedVariables; | 489 setAnalysisContextOptions(_context, options, |
475 if (!definedVariables.isEmpty) { | 490 (AnalysisOptionsImpl contextOptions) { |
476 DeclaredVariables declaredVariables = context.declaredVariables; | 491 contextOptions.analyzeFunctionBodiesPredicate = dietParsingPolicy; |
477 definedVariables.forEach((String variableName, String value) { | 492 }); |
478 declaredVariables.define(variableName, value); | |
479 }); | |
480 } | |
481 | |
482 if (options.log) { | |
483 AnalysisEngine.instance.logger = new StdLogger(); | |
484 } | |
485 | |
486 // Set context options. | |
487 AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl(); | |
488 contextOptions.hint = !options.disableHints; | |
489 contextOptions.enableStrictCallChecks = options.enableStrictCallChecks; | |
490 contextOptions.enableSuperMixins = options.enableSuperMixins; | |
491 contextOptions.analyzeFunctionBodiesPredicate = dietParsingPolicy; | |
492 contextOptions.generateImplicitErrors = options.showPackageWarnings; | |
493 contextOptions.generateSdkErrors = options.showSdkWarnings; | |
494 contextOptions.lint = options.lints; | |
495 contextOptions.strongMode = options.strongMode; | |
496 context.analysisOptions = contextOptions; | |
497 sourceFactory.dartSdk.context.analysisOptions = contextOptions; | |
498 _context = context; | |
499 | |
500 // Process analysis options file (and notify all interested parties). | |
501 _processAnalysisOptions(options, context); | |
502 } | 493 } |
503 | 494 |
504 /// Return discovered packagespec, or `null` if none is found. | 495 /// Return discovered packagespec, or `null` if none is found. |
505 Packages _discoverPackagespec(Uri root) { | 496 Packages _discoverPackagespec(Uri root) { |
506 try { | 497 try { |
507 Packages packages = pkgDiscovery.findPackagesFromFile(root); | 498 Packages packages = pkgDiscovery.findPackagesFromFile(root); |
508 if (packages != Packages.noPackages) { | 499 if (packages != Packages.noPackages) { |
509 return packages; | 500 return packages; |
510 } | 501 } |
511 } catch (_) { | 502 } catch (_) { |
512 // Ignore and fall through to null. | 503 // Ignore and fall through to null. |
513 } | 504 } |
514 | 505 |
515 return null; | 506 return null; |
516 } | 507 } |
517 | 508 |
518 fileSystem.File _getOptionsFile(CommandLineOptions options) { | |
519 fileSystem.File file; | |
520 String filePath = options.analysisOptionsFile; | |
521 if (filePath != null) { | |
522 file = PhysicalResourceProvider.INSTANCE.getFile(filePath); | |
523 if (!file.exists) { | |
524 printAndFail('Options file not found: $filePath', | |
525 exitCode: ErrorSeverity.ERROR.ordinal); | |
526 } | |
527 } else { | |
528 filePath = AnalysisEngine.ANALYSIS_OPTIONS_FILE; | |
529 file = PhysicalResourceProvider.INSTANCE.getFile(filePath); | |
530 } | |
531 return file; | |
532 } | |
533 | |
534 Map<String, List<fileSystem.Folder>> _getPackageMap(Packages packages) { | 509 Map<String, List<fileSystem.Folder>> _getPackageMap(Packages packages) { |
535 if (packages == null) { | 510 if (packages == null) { |
536 return null; | 511 return null; |
537 } | 512 } |
538 | 513 |
539 Map<String, List<fileSystem.Folder>> folderMap = | 514 Map<String, List<fileSystem.Folder>> folderMap = |
540 new Map<String, List<fileSystem.Folder>>(); | 515 new Map<String, List<fileSystem.Folder>>(); |
541 packages.asMap().forEach((String packagePath, Uri uri) { | 516 packages.asMap().forEach((String packagePath, Uri uri) { |
542 folderMap[packagePath] = [ | 517 folderMap[packagePath] = [ |
543 PhysicalResourceProvider.INSTANCE.getFolder(path.fromUri(uri)) | 518 PhysicalResourceProvider.INSTANCE.getFolder(path.fromUri(uri)) |
544 ]; | 519 ]; |
545 }); | 520 }); |
546 return folderMap; | 521 return folderMap; |
547 } | 522 } |
548 | 523 |
549 void _processAnalysisOptions( | |
550 CommandLineOptions options, AnalysisContext context) { | |
551 fileSystem.File file = _getOptionsFile(options); | |
552 List<OptionsProcessor> optionsProcessors = | |
553 AnalysisEngine.instance.optionsPlugin.optionsProcessors; | |
554 try { | |
555 AnalysisOptionsProvider analysisOptionsProvider = | |
556 new AnalysisOptionsProvider(); | |
557 Map<String, YamlNode> optionMap = | |
558 analysisOptionsProvider.getOptionsFromFile(file); | |
559 optionsProcessors.forEach( | |
560 (OptionsProcessor p) => p.optionsProcessed(context, optionMap)); | |
561 | |
562 // Fill in lint rule defaults in case lints are enabled and rules are | |
563 // not specified in an options file. | |
564 if (options.lints && !containsLintRuleEntry(optionMap)) { | |
565 setLints(context, linterPlugin.contributedRules); | |
566 } | |
567 | |
568 // Ask engine to further process options. | |
569 if (optionMap != null) { | |
570 configureContextOptions(context, optionMap); | |
571 } | |
572 } on Exception catch (e) { | |
573 optionsProcessors.forEach((OptionsProcessor p) => p.onError(e)); | |
574 } | |
575 } | |
576 | |
577 void _processPlugins() { | 524 void _processPlugins() { |
578 List<Plugin> plugins = <Plugin>[]; | 525 List<Plugin> plugins = <Plugin>[]; |
579 plugins.addAll(AnalysisEngine.instance.requiredPlugins); | 526 plugins.addAll(AnalysisEngine.instance.requiredPlugins); |
580 plugins.add(AnalysisEngine.instance.commandLinePlugin); | 527 plugins.add(AnalysisEngine.instance.commandLinePlugin); |
581 plugins.add(AnalysisEngine.instance.optionsPlugin); | 528 plugins.add(AnalysisEngine.instance.optionsPlugin); |
582 plugins.add(linterPlugin); | 529 plugins.add(linterPlugin); |
583 plugins.addAll(_userDefinedPlugins); | 530 plugins.addAll(_userDefinedPlugins); |
584 | 531 |
585 ExtensionManager manager = new ExtensionManager(); | 532 ExtensionManager manager = new ExtensionManager(); |
586 manager.processPlugins(plugins); | 533 manager.processPlugins(plugins); |
(...skipping 17 matching lines...) Expand all Loading... |
604 void _setupEnv(CommandLineOptions options) { | 551 void _setupEnv(CommandLineOptions options) { |
605 // In batch mode, SDK is specified on the main command line rather than in | 552 // In batch mode, SDK is specified on the main command line rather than in |
606 // the command lines sent to stdin. So process it before deciding whether | 553 // the command lines sent to stdin. So process it before deciding whether |
607 // to activate batch mode. | 554 // to activate batch mode. |
608 if (sdk == null) { | 555 if (sdk == null) { |
609 sdk = new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath)); | 556 sdk = new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath)); |
610 } | 557 } |
611 _isBatch = options.shouldBatch; | 558 _isBatch = options.shouldBatch; |
612 } | 559 } |
613 | 560 |
| 561 static void setAnalysisContextOptions( |
| 562 AnalysisContext context, |
| 563 CommandLineOptions options, |
| 564 void configureContextOptions(AnalysisOptionsImpl contextOptions)) { |
| 565 Map<String, String> definedVariables = options.definedVariables; |
| 566 if (!definedVariables.isEmpty) { |
| 567 DeclaredVariables declaredVariables = context.declaredVariables; |
| 568 definedVariables.forEach((String variableName, String value) { |
| 569 declaredVariables.define(variableName, value); |
| 570 }); |
| 571 } |
| 572 |
| 573 if (options.log) { |
| 574 AnalysisEngine.instance.logger = new StdLogger(); |
| 575 } |
| 576 |
| 577 // Prepare context options. |
| 578 AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl(); |
| 579 contextOptions.hint = !options.disableHints; |
| 580 contextOptions.enableStrictCallChecks = options.enableStrictCallChecks; |
| 581 contextOptions.enableSuperMixins = options.enableSuperMixins; |
| 582 contextOptions.generateImplicitErrors = options.showPackageWarnings; |
| 583 contextOptions.generateSdkErrors = options.showSdkWarnings; |
| 584 contextOptions.lint = options.lints; |
| 585 contextOptions.strongMode = options.strongMode; |
| 586 configureContextOptions(contextOptions); |
| 587 |
| 588 // Set context options. |
| 589 context.analysisOptions = contextOptions; |
| 590 context.sourceFactory.dartSdk.context.analysisOptions = contextOptions; |
| 591 |
| 592 // Process analysis options file (and notify all interested parties). |
| 593 _processAnalysisOptions(context, options); |
| 594 } |
| 595 |
614 /// Perform a deep comparison of two string maps. | 596 /// Perform a deep comparison of two string maps. |
615 static bool _equalMaps(Map<String, String> m1, Map<String, String> m2) { | 597 static bool _equalMaps(Map<String, String> m1, Map<String, String> m2) { |
616 if (m1.length != m2.length) { | 598 if (m1.length != m2.length) { |
617 return false; | 599 return false; |
618 } | 600 } |
619 for (String key in m1.keys) { | 601 for (String key in m1.keys) { |
620 if (!m2.containsKey(key) || m1[key] != m2[key]) { | 602 if (!m2.containsKey(key) || m1[key] != m2[key]) { |
621 return false; | 603 return false; |
622 } | 604 } |
623 } | 605 } |
624 return true; | 606 return true; |
625 } | 607 } |
626 | 608 |
| 609 static fileSystem.File _getOptionsFile(CommandLineOptions options) { |
| 610 fileSystem.File file; |
| 611 String filePath = options.analysisOptionsFile; |
| 612 if (filePath != null) { |
| 613 file = PhysicalResourceProvider.INSTANCE.getFile(filePath); |
| 614 if (!file.exists) { |
| 615 printAndFail('Options file not found: $filePath', |
| 616 exitCode: ErrorSeverity.ERROR.ordinal); |
| 617 } |
| 618 } else { |
| 619 filePath = AnalysisEngine.ANALYSIS_OPTIONS_FILE; |
| 620 file = PhysicalResourceProvider.INSTANCE.getFile(filePath); |
| 621 } |
| 622 return file; |
| 623 } |
| 624 |
627 /// Convert [sourcePath] into an absolute path. | 625 /// Convert [sourcePath] into an absolute path. |
628 static String _normalizeSourcePath(String sourcePath) => | 626 static String _normalizeSourcePath(String sourcePath) => |
629 path.normalize(new File(sourcePath).absolute.path); | 627 path.normalize(new File(sourcePath).absolute.path); |
| 628 |
| 629 static void _processAnalysisOptions( |
| 630 AnalysisContext context, CommandLineOptions options) { |
| 631 fileSystem.File file = _getOptionsFile(options); |
| 632 List<OptionsProcessor> optionsProcessors = |
| 633 AnalysisEngine.instance.optionsPlugin.optionsProcessors; |
| 634 try { |
| 635 AnalysisOptionsProvider analysisOptionsProvider = |
| 636 new AnalysisOptionsProvider(); |
| 637 Map<String, YamlNode> optionMap = |
| 638 analysisOptionsProvider.getOptionsFromFile(file); |
| 639 optionsProcessors.forEach( |
| 640 (OptionsProcessor p) => p.optionsProcessed(context, optionMap)); |
| 641 |
| 642 // Fill in lint rule defaults in case lints are enabled and rules are |
| 643 // not specified in an options file. |
| 644 if (options.lints && !containsLintRuleEntry(optionMap)) { |
| 645 setLints(context, linterPlugin.contributedRules); |
| 646 } |
| 647 |
| 648 // Ask engine to further process options. |
| 649 if (optionMap != null) { |
| 650 configureContextOptions(context, optionMap); |
| 651 } |
| 652 } on Exception catch (e) { |
| 653 optionsProcessors.forEach((OptionsProcessor p) => p.onError(e)); |
| 654 } |
| 655 } |
630 } | 656 } |
631 | 657 |
632 /// Provides a framework to read command line options from stdin and feed them | 658 /// Provides a framework to read command line options from stdin and feed them |
633 /// to a callback. | 659 /// to a callback. |
634 class _BatchRunner { | 660 class _BatchRunner { |
635 /// Run the tool in 'batch' mode, receiving command lines through stdin and | 661 /// Run the tool in 'batch' mode, receiving command lines through stdin and |
636 /// returning pass/fail status through stdout. This feature is intended for | 662 /// returning pass/fail status through stdout. This feature is intended for |
637 /// use in unit testing. | 663 /// use in unit testing. |
638 static void runAsBatch(List<String> sharedArgs, _BatchRunnerHandler handler) { | 664 static void runAsBatch(List<String> sharedArgs, _BatchRunnerHandler handler) { |
639 outSink.writeln('>>> BATCH START'); | 665 outSink.writeln('>>> BATCH START'); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 for (var package in packages) { | 736 for (var package in packages) { |
711 var packageName = path.basename(package.path); | 737 var packageName = path.basename(package.path); |
712 var realPath = package.resolveSymbolicLinksSync(); | 738 var realPath = package.resolveSymbolicLinksSync(); |
713 result[packageName] = [ | 739 result[packageName] = [ |
714 PhysicalResourceProvider.INSTANCE.getFolder(realPath) | 740 PhysicalResourceProvider.INSTANCE.getFolder(realPath) |
715 ]; | 741 ]; |
716 } | 742 } |
717 return result; | 743 return result; |
718 } | 744 } |
719 } | 745 } |
OLD | NEW |