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

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

Issue 2963583002: Cache AnalysisOptionsImpl objects for context directories. (Closed)
Patch Set: Created 3 years, 5 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 import 'dart:async'; 5 import 'dart:async';
6 import 'dart:io' as io; 6 import 'dart:io' as io;
7 7
8 import 'package:analyzer/error/error.dart'; 8 import 'package:analyzer/error/error.dart';
9 import 'package:analyzer/file_system/file_system.dart' as file_system; 9 import 'package:analyzer/file_system/file_system.dart' as file_system;
10 import 'package:analyzer/file_system/file_system.dart'; 10 import 'package:analyzer/file_system/file_system.dart';
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 /// Test this option map to see if it specifies lint rules. 64 /// Test this option map to see if it specifies lint rules.
65 bool containsLintRuleEntry(Map<String, YamlNode> options) { 65 bool containsLintRuleEntry(Map<String, YamlNode> options) {
66 var linterNode = options['linter']; 66 var linterNode = options['linter'];
67 return linterNode is YamlMap && linterNode.containsKey('rules'); 67 return linterNode is YamlMap && linterNode.containsKey('rules');
68 } 68 }
69 69
70 class Driver implements CommandLineStarter { 70 class Driver implements CommandLineStarter {
71 static final PerformanceTag _analyzeAllTag = 71 static final PerformanceTag _analyzeAllTag =
72 new PerformanceTag("Driver._analyzeAll"); 72 new PerformanceTag("Driver._analyzeAll");
73 73
74 /// Cache of [AnalysisOptionsImpl] objects that correspond to directories
75 /// with analyzed files, used to reduce searching for `analysis_options.yaml`
76 /// files.
77 static Map<String, AnalysisOptionsImpl> _directoryToAnalysisOptions = {};
78
74 static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore(); 79 static ByteStore analysisDriverMemoryByteStore = new MemoryByteStore();
75 80
76 /// The plugins that are defined outside the `analyzer_cli` package. 81 /// The plugins that are defined outside the `analyzer_cli` package.
77 List<Plugin> _userDefinedPlugins = <Plugin>[]; 82 List<Plugin> _userDefinedPlugins = <Plugin>[];
78 83
79 /// The context that was most recently created by a call to [_analyzeAll], or 84 /// The context that was most recently created by a call to [_analyzeAll], or
80 /// `null` if [_analyzeAll] hasn't been called yet. 85 /// `null` if [_analyzeAll] hasn't been called yet.
81 InternalAnalysisContext _context; 86 InternalAnalysisContext _context;
82 87
83 AnalysisDriver analysisDriver; 88 AnalysisDriver analysisDriver;
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 if (options.buildModePersistentWorker) { 309 if (options.buildModePersistentWorker) {
305 new AnalyzerWorkerLoop.std(resourceProvider, 310 new AnalyzerWorkerLoop.std(resourceProvider,
306 dartSdkPath: options.dartSdkPath) 311 dartSdkPath: options.dartSdkPath)
307 .run(); 312 .run();
308 } else { 313 } else {
309 return new BuildMode(resourceProvider, options, stats).analyze(); 314 return new BuildMode(resourceProvider, options, stats).analyze();
310 } 315 }
311 }); 316 });
312 } 317 }
313 318
314 /// Determine whether the context created during a previous call to
315 /// [_analyzeAll] can be re-used in order to analyze using [options].
316 bool _canContextBeReused(
317 CommandLineOptions options, AnalysisOptionsImpl other) {
318 // TODO(paulberry): add a command-line option that disables context re-use.
319 if (_context == null) {
320 return false;
321 }
322
323 // Check command line options.
324 if (options.packageRootPath != _previousOptions.packageRootPath) {
325 return false;
326 }
327 if (options.packageConfigPath != _previousOptions.packageConfigPath) {
328 return false;
329 }
330 if (!_equalMaps(
331 options.definedVariables, _previousOptions.definedVariables)) {
332 return false;
333 }
334 if (options.log != _previousOptions.log) {
335 return false;
336 }
337 if (options.disableHints != _previousOptions.disableHints) {
338 return false;
339 }
340 if (options.enableStrictCallChecks !=
341 _previousOptions.enableStrictCallChecks) {
342 return false;
343 }
344 if (options.enableAssertInitializer !=
345 _previousOptions.enableAssertInitializer) {
346 return false;
347 }
348 if (options.showPackageWarnings != _previousOptions.showPackageWarnings) {
349 return false;
350 }
351 if (options.showPackageWarningsPrefix !=
352 _previousOptions.showPackageWarningsPrefix) {
353 return false;
354 }
355 if (options.showSdkWarnings != _previousOptions.showSdkWarnings) {
356 return false;
357 }
358 if (options.lints != _previousOptions.lints) {
359 return false;
360 }
361 if (options.strongMode != _previousOptions.strongMode) {
362 return false;
363 }
364 if (options.enableSuperMixins != _previousOptions.enableSuperMixins) {
365 return false;
366 }
367 if (!_equalLists(
368 options.buildSummaryInputs, _previousOptions.buildSummaryInputs)) {
369 return false;
370 }
371 if (options.disableCacheFlushing != _previousOptions.disableCacheFlushing) {
372 return false;
373 }
374
375 // Check analysis options.
376 var c = _context.analysisOptions;
377 if (!(other.enableAssertInitializer == c.enableAssertInitializer &&
378 other.enableStrictCallChecks == c.enableStrictCallChecks &&
379 other.enableLazyAssignmentOperators ==
380 c.enableLazyAssignmentOperators &&
381 other.enableSuperMixins == c.enableSuperMixins &&
382 other.enableTiming == c.enableTiming &&
383 other.generateImplicitErrors == c.generateImplicitErrors &&
384 other.generateSdkErrors == c.generateSdkErrors &&
385 other.hint == c.hint &&
386 other.lint == c.lint &&
387 AnalysisOptionsImpl.compareLints(other.lintRules, c.lintRules) &&
388 other.preserveComments == c.preserveComments &&
389 other.strongMode == c.strongMode)) {
390 return false;
391 }
392
393 return true;
394 }
395
396 /// Decide on the appropriate policy for which files need to be fully parsed 319 /// Decide on the appropriate policy for which files need to be fully parsed
397 /// and which files need to be diet parsed, based on [options], and return an 320 /// and which files need to be diet parsed, based on [options], and return an
398 /// [AnalyzeFunctionBodiesPredicate] that implements this policy. 321 /// [AnalyzeFunctionBodiesPredicate] that implements this policy.
399 AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy( 322 AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy(
400 CommandLineOptions options) { 323 CommandLineOptions options) {
401 if (options.shouldBatch) { 324 if (options.shouldBatch) {
402 // As analyzer is currently implemented, once a file has been diet 325 // As analyzer is currently implemented, once a file has been diet
403 // parsed, it can't easily be un-diet parsed without creating a brand new 326 // parsed, it can't easily be un-diet parsed without creating a brand new
404 // context and losing caching. In batch mode, we can't predict which 327 // context and losing caching. In batch mode, we can't predict which
405 // files we'll need to generate errors and warnings for in the future, so 328 // files we'll need to generate errors and warnings for in the future, so
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
514 if (packageUriResolver != null) { 437 if (packageUriResolver != null) {
515 resolvers.add(packageUriResolver); 438 resolvers.add(packageUriResolver);
516 } 439 }
517 440
518 // Finally files. 441 // Finally files.
519 resolvers.add(new file_system.ResourceUriResolver(resourceProvider)); 442 resolvers.add(new file_system.ResourceUriResolver(resourceProvider));
520 443
521 return new SourceFactory(resolvers, packageInfo.packages); 444 return new SourceFactory(resolvers, packageInfo.packages);
522 } 445 }
523 446
524 // TODO(devoncarew): This needs to respect analysis_options excludes.
525
526 /// Collect all analyzable files at [filePath], recursively if it's a 447 /// Collect all analyzable files at [filePath], recursively if it's a
527 /// directory, ignoring links. 448 /// directory, ignoring links.
528 Iterable<io.File> _collectFiles(String filePath) { 449 Iterable<io.File> _collectFiles(String filePath) {
529 List<io.File> files = <io.File>[]; 450 List<io.File> files = <io.File>[];
530 io.File file = new io.File(filePath); 451 io.File file = new io.File(filePath);
531 if (file.existsSync()) { 452 if (file.existsSync()) {
532 files.add(file); 453 files.add(file);
533 } else { 454 } else {
534 io.Directory directory = new io.Directory(filePath); 455 io.Directory directory = new io.Directory(filePath);
535 if (directory.existsSync()) { 456 if (directory.existsSync()) {
536 for (io.FileSystemEntity entry 457 for (io.FileSystemEntity entry
537 in directory.listSync(recursive: true, followLinks: false)) { 458 in directory.listSync(recursive: true, followLinks: false)) {
538 String relative = path.relative(entry.path, from: directory.path); 459 String relative = path.relative(entry.path, from: directory.path);
539 if (AnalysisEngine.isDartFileName(entry.path) && 460 if (AnalysisEngine.isDartFileName(entry.path) &&
540 !_isInHiddenDir(relative)) { 461 !_isInHiddenDir(relative)) {
541 files.add(entry); 462 files.add(entry);
542 } 463 }
543 } 464 }
544 } 465 }
545 } 466 }
546 return files; 467 return files;
547 } 468 }
548 469
470 // TODO(devoncarew): This needs to respect analysis_options excludes.
Brian Wilkerson 2017/06/27 19:11:02 The comment moved. I'm not sure what it was suppos
471
549 /// Convert the given [sourcePath] (which may be relative to the current 472 /// Convert the given [sourcePath] (which may be relative to the current
550 /// working directory) to a [Source] object that can be fed to the analysis 473 /// working directory) to a [Source] object that can be fed to the analysis
551 /// context. 474 /// context.
552 Source _computeLibrarySource(String sourcePath) { 475 Source _computeLibrarySource(String sourcePath) {
553 sourcePath = _normalizeSourcePath(sourcePath); 476 sourcePath = _normalizeSourcePath(sourcePath);
554 File sourceFile = resourceProvider.getFile(sourcePath); 477 File sourceFile = resourceProvider.getFile(sourcePath);
555 Source source = sdk.fromFileUri(sourceFile.toUri()); 478 Source source = sdk.fromFileUri(sourceFile.toUri());
556 if (source != null) { 479 if (source != null) {
557 return source; 480 return source;
558 } 481 }
559 source = new FileSource(sourceFile, sourceFile.toUri()); 482 source = new FileSource(sourceFile, sourceFile.toUri());
560 Uri uri = _context.sourceFactory.restoreUri(source); 483 Uri uri = _context.sourceFactory.restoreUri(source);
561 if (uri == null) { 484 if (uri == null) {
562 return source; 485 return source;
563 } 486 }
564 return new FileSource(sourceFile, uri); 487 return new FileSource(sourceFile, uri);
565 } 488 }
566 489
567 /// Create an analysis context that is prepared to analyze sources according 490 /// Create an analysis context that is prepared to analyze sources according
568 /// to the given [options], and store it in [_context]. 491 /// to the given [options], and store it in [_context].
569 void _createAnalysisContext(CommandLineOptions options) { 492 void _createAnalysisContext(CommandLineOptions options) {
493 // If not the same command-line options, clear cached information.
494 if (!_equalCommandLineOptions(_previousOptions, options)) {
495 _previousOptions = options;
496 _directoryToAnalysisOptions.clear();
497 _context = null;
498 analysisDriver = null;
499 }
500
570 AnalysisOptionsImpl analysisOptions = 501 AnalysisOptionsImpl analysisOptions =
571 createAnalysisOptionsForCommandLineOptions(resourceProvider, options); 502 createAnalysisOptionsForCommandLineOptions(resourceProvider, options);
572 analysisOptions.analyzeFunctionBodiesPredicate = 503 analysisOptions.analyzeFunctionBodiesPredicate =
573 _chooseDietParsingPolicy(options); 504 _chooseDietParsingPolicy(options);
574 505
575 if (_canContextBeReused(options, analysisOptions)) { 506 // If we have the analysis driver, and the new analysis options are the
507 // same, we can reuse this analysis driver.
508 if (_context != null &&
509 _equalAnalysisOptions(_context.analysisOptions, analysisOptions)) {
576 return; 510 return;
577 } 511 }
578 512
579 _previousOptions = options;
580
581 // Save stats from previous context before clobbering it. 513 // Save stats from previous context before clobbering it.
582 if (_context != null) { 514 if (_context != null) {
583 _analyzedFileCount += _context.sources.length; 515 _analyzedFileCount += _context.sources.length;
584 } 516 }
585 517
586 // Find package info. 518 // Find package info.
587 _PackageInfo packageInfo = _findPackages(options); 519 _PackageInfo packageInfo = _findPackages(options);
588 520
589 // Process embedders. 521 // Process embedders.
590 Map<file_system.Folder, YamlMap> embedderMap = 522 Map<file_system.Folder, YamlMap> embedderMap =
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 if (packages != Packages.noPackages) { 585 if (packages != Packages.noPackages) {
654 return packages; 586 return packages;
655 } 587 }
656 } catch (_) { 588 } catch (_) {
657 // Ignore and fall through to null. 589 // Ignore and fall through to null.
658 } 590 }
659 591
660 return null; 592 return null;
661 } 593 }
662 594
595 /// Return whether [a] and [b] options are equal for the purpose of
596 /// command line analysis.
597 bool _equalAnalysisOptions(AnalysisOptionsImpl a, AnalysisOptions b) {
598 return a.enableAssertInitializer == b.enableAssertInitializer &&
599 a.enableStrictCallChecks == b.enableStrictCallChecks &&
600 a.enableLazyAssignmentOperators == b.enableLazyAssignmentOperators &&
601 a.enableSuperMixins == b.enableSuperMixins &&
602 a.enableTiming == b.enableTiming &&
603 a.generateImplicitErrors == b.generateImplicitErrors &&
604 a.generateSdkErrors == b.generateSdkErrors &&
605 a.hint == b.hint &&
606 a.lint == b.lint &&
607 AnalysisOptionsImpl.compareLints(a.lintRules, b.lintRules) &&
608 a.preserveComments == b.preserveComments &&
609 a.strongMode == b.strongMode;
610 }
611
663 _PackageInfo _findPackages(CommandLineOptions options) { 612 _PackageInfo _findPackages(CommandLineOptions options) {
664 if (packageResolverProvider != null) { 613 if (packageResolverProvider != null) {
665 // The resolver provider will do all the work later. 614 // The resolver provider will do all the work later.
666 return new _PackageInfo(null, null); 615 return new _PackageInfo(null, null);
667 } 616 }
668 617
669 Packages packages; 618 Packages packages;
670 Map<String, List<file_system.Folder>> packageMap; 619 Map<String, List<file_system.Folder>> packageMap;
671 620
672 if (options.packageConfigPath != null) { 621 if (options.packageConfigPath != null) {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
798 contextRoot = options.sourceFiles[0]; 747 contextRoot = options.sourceFiles[0];
799 if (!path.isAbsolute(contextRoot)) { 748 if (!path.isAbsolute(contextRoot)) {
800 contextRoot = path.absolute(contextRoot); 749 contextRoot = path.absolute(contextRoot);
801 } 750 }
802 } 751 }
803 752
804 void verbosePrint(String text) { 753 void verbosePrint(String text) {
805 outSink.writeln(text); 754 outSink.writeln(text);
806 } 755 }
807 756
808 AnalysisOptionsImpl contextOptions = new ContextBuilder( 757 // Prepare the directory which is, or contains, the context root.
809 resourceProvider, null, null, 758 String contextRootDirectory;
759 if (resourceProvider.getFolder(contextRoot).exists) {
760 contextRootDirectory = contextRoot;
761 } else {
762 contextRootDirectory = resourceProvider.pathContext.dirname(contextRoot);
763 }
764
765 // Check if there is the options object for the content directory.
766 AnalysisOptionsImpl contextOptions =
767 _directoryToAnalysisOptions[contextRootDirectory];
768 if (contextOptions != null) {
769 return contextOptions;
770 }
771
772 contextOptions = new ContextBuilder(resourceProvider, null, null,
810 options: options.contextBuilderOptions) 773 options: options.contextBuilderOptions)
811 .getAnalysisOptions(contextRoot, 774 .getAnalysisOptions(contextRoot,
812 verbosePrint: options.verbose ? verbosePrint : null); 775 verbosePrint: options.verbose ? verbosePrint : null);
813 776
814 contextOptions.trackCacheDependencies = false; 777 contextOptions.trackCacheDependencies = false;
815 contextOptions.disableCacheFlushing = options.disableCacheFlushing; 778 contextOptions.disableCacheFlushing = options.disableCacheFlushing;
816 contextOptions.hint = !options.disableHints; 779 contextOptions.hint = !options.disableHints;
817 contextOptions.generateImplicitErrors = options.showPackageWarnings; 780 contextOptions.generateImplicitErrors = options.showPackageWarnings;
818 contextOptions.generateSdkErrors = options.showSdkWarnings; 781 contextOptions.generateSdkErrors = options.showSdkWarnings;
819 if (options.enableAssertInitializer != null) { 782 if (options.enableAssertInitializer != null) {
820 contextOptions.enableAssertInitializer = options.enableAssertInitializer; 783 contextOptions.enableAssertInitializer = options.enableAssertInitializer;
821 } 784 }
822 785
786 _directoryToAnalysisOptions[contextRootDirectory] = contextOptions;
823 return contextOptions; 787 return contextOptions;
824 } 788 }
825 789
826 static void setAnalysisContextOptions( 790 static void setAnalysisContextOptions(
827 file_system.ResourceProvider resourceProvider, 791 file_system.ResourceProvider resourceProvider,
828 AnalysisContext context, 792 AnalysisContext context,
829 CommandLineOptions options, 793 CommandLineOptions options,
830 void configureContextOptions(AnalysisOptionsImpl contextOptions)) { 794 void configureContextOptions(AnalysisOptionsImpl contextOptions)) {
831 AnalysisOptionsImpl analysisOptions = 795 AnalysisOptionsImpl analysisOptions =
832 createAnalysisOptionsForCommandLineOptions(resourceProvider, options); 796 createAnalysisOptionsForCommandLineOptions(resourceProvider, options);
(...skipping 12 matching lines...) Expand all
845 } 809 }
846 810
847 if (options.log) { 811 if (options.log) {
848 AnalysisEngine.instance.logger = new StdLogger(); 812 AnalysisEngine.instance.logger = new StdLogger();
849 } 813 }
850 814
851 // Set context options. 815 // Set context options.
852 context.analysisOptions = analysisOptions; 816 context.analysisOptions = analysisOptions;
853 } 817 }
854 818
819 /// Return whether the [newOptions] are equal to the [previous].
820 static bool _equalCommandLineOptions(
821 CommandLineOptions previous, CommandLineOptions newOptions) {
822 if (previous == null || newOptions == null) {
823 return false;
824 }
825 if (newOptions.packageRootPath != previous.packageRootPath) {
826 return false;
827 }
828 if (newOptions.packageConfigPath != previous.packageConfigPath) {
829 return false;
830 }
831 if (!_equalMaps(newOptions.definedVariables, previous.definedVariables)) {
832 return false;
833 }
834 if (newOptions.log != previous.log) {
835 return false;
836 }
837 if (newOptions.disableHints != previous.disableHints) {
838 return false;
839 }
840 if (newOptions.enableStrictCallChecks != previous.enableStrictCallChecks) {
841 return false;
842 }
843 if (newOptions.enableAssertInitializer !=
844 previous.enableAssertInitializer) {
845 return false;
846 }
847 if (newOptions.showPackageWarnings != previous.showPackageWarnings) {
848 return false;
849 }
850 if (newOptions.showPackageWarningsPrefix !=
851 previous.showPackageWarningsPrefix) {
852 return false;
853 }
854 if (newOptions.showSdkWarnings != previous.showSdkWarnings) {
855 return false;
856 }
857 if (newOptions.lints != previous.lints) {
858 return false;
859 }
860 if (newOptions.strongMode != previous.strongMode) {
861 return false;
862 }
863 if (newOptions.enableSuperMixins != previous.enableSuperMixins) {
864 return false;
865 }
866 if (!_equalLists(
867 newOptions.buildSummaryInputs, previous.buildSummaryInputs)) {
868 return false;
869 }
870 if (newOptions.disableCacheFlushing != previous.disableCacheFlushing) {
871 return false;
872 }
873 return true;
874 }
875
855 /// Perform a deep comparison of two string lists. 876 /// Perform a deep comparison of two string lists.
856 static bool _equalLists(List<String> l1, List<String> l2) { 877 static bool _equalLists(List<String> l1, List<String> l2) {
857 if (l1.length != l2.length) { 878 if (l1.length != l2.length) {
858 return false; 879 return false;
859 } 880 }
860 for (int i = 0; i < l1.length; i++) { 881 for (int i = 0; i < l1.length; i++) {
861 if (l1[i] != l2[i]) { 882 if (l1[i] != l2[i]) {
862 return false; 883 return false;
863 } 884 }
864 } 885 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
912 for (var package in packages) { 933 for (var package in packages) {
913 var packageName = path.basename(package.path); 934 var packageName = path.basename(package.path);
914 var realPath = package.resolveSymbolicLinksSync(); 935 var realPath = package.resolveSymbolicLinksSync();
915 result[packageName] = [ 936 result[packageName] = [
916 PhysicalResourceProvider.INSTANCE.getFolder(realPath) 937 PhysicalResourceProvider.INSTANCE.getFolder(realPath)
917 ]; 938 ];
918 } 939 }
919 return result; 940 return result;
920 } 941 }
921 } 942 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698