| 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 |