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

Side by Side Diff: pkg/analysis_server/lib/src/context_manager.dart

Issue 1487903002: Issue 25048. Ignore inner analysis roots which are already managed by outer roots. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Additional test. Created 5 years 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 | pkg/analysis_server/test/context_manager_test.dart » ('j') | 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) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 context.directory.manager; 5 library context.directory.manager;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 import 'dart:convert'; 9 import 'dart:convert';
10 import 'dart:core' hide Resource; 10 import 'dart:core' hide Resource;
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 */ 174 */
175 bool isPathToPackageDescription(String path) => 175 bool isPathToPackageDescription(String path) =>
176 path == packageDescriptionPath; 176 path == packageDescriptionPath;
177 177
178 /** 178 /**
179 * Update the set of dependencies for this context. 179 * Update the set of dependencies for this context.
180 */ 180 */
181 void setDependencies(Iterable<String> newDependencies) { 181 void setDependencies(Iterable<String> newDependencies) {
182 _dependencies = newDependencies.toSet(); 182 _dependencies = newDependencies.toSet();
183 } 183 }
184
185 /**
186 * Return `true` if the given [path] is managed by this context or by
187 * any of its children.
188 */
189 bool _managesOrHasChildThatManages(String path) {
190 if (parent == null) {
191 for (ContextInfo child in children) {
192 if (child._managesOrHasChildThatManages(path)) {
193 return true;
194 }
195 }
196 return false;
197 } else {
198 if (!folder.isOrContains(path)) {
199 return false;
200 }
201 for (ContextInfo child in children) {
202 if (child._managesOrHasChildThatManages(path)) {
203 return true;
204 }
205 }
206 return !pathFilter.ignored(path);
207 }
208 }
184 } 209 }
185 210
186 /** 211 /**
187 * Class that maintains a mapping from included/excluded paths to a set of 212 * Class that maintains a mapping from included/excluded paths to a set of
188 * folders that should correspond to analysis contexts. 213 * folders that should correspond to analysis contexts.
189 */ 214 */
190 abstract class ContextManager { 215 abstract class ContextManager {
191 // TODO(brianwilkerson) Support: 216 // TODO(brianwilkerson) Support:
192 // setting the default analysis options 217 // setting the default analysis options
193 // setting the default content cache 218 // setting the default content cache
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 */ 443 */
419 final InstrumentationService _instrumentationService; 444 final InstrumentationService _instrumentationService;
420 445
421 @override 446 @override
422 ContextManagerCallbacks callbacks; 447 ContextManagerCallbacks callbacks;
423 448
424 /** 449 /**
425 * Virtual [ContextInfo] which acts as the ancestor of all other 450 * Virtual [ContextInfo] which acts as the ancestor of all other
426 * [ContextInfo]s. 451 * [ContextInfo]s.
427 */ 452 */
428 final ContextInfo _rootInfo = new ContextInfo._root(); 453 final ContextInfo rootInfo = new ContextInfo._root();
429 454
430 /** 455 /**
431 * Stream subscription we are using to watch each analysis root directory for 456 * Stream subscription we are using to watch each analysis root directory for
432 * changes. 457 * changes.
433 */ 458 */
434 final Map<Folder, StreamSubscription<WatchEvent>> changeSubscriptions = 459 final Map<Folder, StreamSubscription<WatchEvent>> changeSubscriptions =
435 <Folder, StreamSubscription<WatchEvent>>{}; 460 <Folder, StreamSubscription<WatchEvent>>{};
436 461
437 ContextManagerImpl(this.resourceProvider, this.packageResolverProvider, 462 ContextManagerImpl(this.resourceProvider, this.packageResolverProvider,
438 this._packageMapProvider, this._instrumentationService) { 463 this._packageMapProvider, this._instrumentationService) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 ContextInfo getContextInfoFor(Folder folder) { 499 ContextInfo getContextInfoFor(Folder folder) {
475 ContextInfo info = _getInnermostContextInfoFor(folder.path); 500 ContextInfo info = _getInnermostContextInfoFor(folder.path);
476 if (info != null && folder == info.folder) { 501 if (info != null && folder == info.folder) {
477 return info; 502 return info;
478 } 503 }
479 return null; 504 return null;
480 } 505 }
481 506
482 @override 507 @override
483 bool isIgnored(String path) { 508 bool isIgnored(String path) {
484 ContextInfo info = _rootInfo; 509 ContextInfo info = rootInfo;
485 do { 510 do {
486 info = info.findChildInfoFor(path); 511 info = info.findChildInfoFor(path);
487 if (info == null) { 512 if (info == null) {
488 return false; 513 return false;
489 } 514 }
490 if (info.ignored(path)) { 515 if (info.ignored(path)) {
491 return true; 516 return true;
492 } 517 }
493 } while (true); 518 } while (true);
494 } 519 }
495 520
496 @override 521 @override
497 bool isInAnalysisRoot(String path) { 522 bool isInAnalysisRoot(String path) {
498 // check if excluded 523 // check if excluded
499 if (_isExcluded(path)) { 524 if (_isExcluded(path)) {
500 return false; 525 return false;
501 } 526 }
502 // check if in one of the roots 527 // check if in one of the roots
503 for (ContextInfo info in _rootInfo.children) { 528 for (ContextInfo info in rootInfo.children) {
504 if (info.folder.contains(path)) { 529 if (info.folder.contains(path)) {
505 return true; 530 return true;
506 } 531 }
507 } 532 }
508 // no 533 // no
509 return false; 534 return false;
510 } 535 }
511 536
512 /** 537 /**
513 * Process [options] for the given context [info]. 538 * Process [options] for the given context [info].
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 // Set ignore patterns. 593 // Set ignore patterns.
569 YamlList exclude = analyzer[AnalyzerOptions.exclude]; 594 YamlList exclude = analyzer[AnalyzerOptions.exclude];
570 if (exclude != null) { 595 if (exclude != null) {
571 setIgnorePatternsForContext(info, exclude); 596 setIgnorePatternsForContext(info, exclude);
572 } 597 }
573 } 598 }
574 599
575 @override 600 @override
576 void refresh(List<Resource> roots) { 601 void refresh(List<Resource> roots) {
577 // Destroy old contexts 602 // Destroy old contexts
578 List<ContextInfo> contextInfos = _rootInfo.descendants.toList(); 603 List<ContextInfo> contextInfos = rootInfo.descendants.toList();
579 if (roots == null) { 604 if (roots == null) {
580 contextInfos.forEach(_destroyContext); 605 contextInfos.forEach(_destroyContext);
581 } else { 606 } else {
582 roots.forEach((Resource resource) { 607 roots.forEach((Resource resource) {
583 contextInfos.forEach((ContextInfo contextInfo) { 608 contextInfos.forEach((ContextInfo contextInfo) {
584 if (resource is Folder && 609 if (resource is Folder &&
585 resource.isOrContains(contextInfo.folder.path)) { 610 resource.isOrContains(contextInfo.folder.path)) {
586 _destroyContext(contextInfo); 611 _destroyContext(contextInfo);
587 } 612 }
588 }); 613 });
(...skipping 20 matching lines...) Expand all
609 // Normalize all package root sources by mapping them to folders on the 634 // Normalize all package root sources by mapping them to folders on the
610 // filesystem. Ignore any package root sources that aren't folders. 635 // filesystem. Ignore any package root sources that aren't folders.
611 normalizedPackageRoots = <String, String>{}; 636 normalizedPackageRoots = <String, String>{};
612 packageRoots.forEach((String sourcePath, String targetPath) { 637 packageRoots.forEach((String sourcePath, String targetPath) {
613 Resource resource = resourceProvider.getResource(sourcePath); 638 Resource resource = resourceProvider.getResource(sourcePath);
614 if (resource is Folder) { 639 if (resource is Folder) {
615 normalizedPackageRoots[resource.path] = targetPath; 640 normalizedPackageRoots[resource.path] = targetPath;
616 } 641 }
617 }); 642 });
618 643
619 List<ContextInfo> contextInfos = _rootInfo.descendants.toList(); 644 List<ContextInfo> contextInfos = rootInfo.descendants.toList();
620 // included 645 // included
621 Set<Folder> includedFolders = new HashSet<Folder>(); 646 List<Folder> includedFolders = <Folder>[];
622 for (int i = 0; i < includedPaths.length; i++) { 647 {
623 String path = includedPaths[i]; 648 // Sort paths to ensure that outer roots are handled before inner roots,
624 Resource resource = resourceProvider.getResource(path); 649 // so we can correctly ignore inner roots, which are already managed
625 if (resource is Folder) { 650 // by outer roots.
626 includedFolders.add(resource); 651 LinkedHashSet<String> uniqueIncludedPaths =
627 } else if (!resource.exists) { 652 new LinkedHashSet<String>.from(includedPaths);
628 // Non-existent resources are ignored. TODO(paulberry): we should set 653 List<String> sortedIncludedPaths = uniqueIncludedPaths.toList();
629 // up a watcher to ensure that if the resource appears later, we will 654 sortedIncludedPaths.sort((a, b) => a.length - b.length);
630 // begin analyzing it. 655 // Convert paths to folders.
631 } else { 656 for (String path in sortedIncludedPaths) {
632 // TODO(scheglov) implemented separate files analysis 657 Resource resource = resourceProvider.getResource(path);
633 throw new UnimplementedError('$path is not a folder. ' 658 if (resource is Folder) {
634 'Only support for folder analysis is implemented currently.'); 659 includedFolders.add(resource);
660 } else if (!resource.exists) {
661 // Non-existent resources are ignored. TODO(paulberry): we should set
662 // up a watcher to ensure that if the resource appears later, we will
663 // begin analyzing it.
664 } else {
665 // TODO(scheglov) implemented separate files analysis
666 throw new UnimplementedError('$path is not a folder. '
667 'Only support for folder analysis is implemented currently.');
668 }
635 } 669 }
636 } 670 }
637 this.includedPaths = includedPaths; 671 this.includedPaths = includedPaths;
638 // excluded 672 // excluded
639 List<String> oldExcludedPaths = this.excludedPaths; 673 List<String> oldExcludedPaths = this.excludedPaths;
640 this.excludedPaths = excludedPaths; 674 this.excludedPaths = excludedPaths;
641 // destroy old contexts 675 // destroy old contexts
642 for (ContextInfo contextInfo in contextInfos) { 676 for (ContextInfo contextInfo in contextInfos) {
643 bool isIncluded = includedFolders.any((folder) { 677 bool isIncluded = includedFolders.any((folder) {
644 return folder.isOrContains(contextInfo.folder.path); 678 return folder.isOrContains(contextInfo.folder.path);
645 }); 679 });
646 if (!isIncluded) { 680 if (!isIncluded) {
647 _destroyContext(contextInfo); 681 _destroyContext(contextInfo);
648 } 682 }
649 } 683 }
650 // Update package roots for existing contexts 684 // Update package roots for existing contexts
651 for (ContextInfo info in _rootInfo.descendants) { 685 for (ContextInfo info in rootInfo.descendants) {
652 String newPackageRoot = normalizedPackageRoots[info.folder.path]; 686 String newPackageRoot = normalizedPackageRoots[info.folder.path];
653 if (info.packageRoot != newPackageRoot) { 687 if (info.packageRoot != newPackageRoot) {
654 info.packageRoot = newPackageRoot; 688 info.packageRoot = newPackageRoot;
655 _recomputeFolderDisposition(info); 689 _recomputeFolderDisposition(info);
656 } 690 }
657 } 691 }
658 // create new contexts 692 // create new contexts
659 for (Folder includedFolder in includedFolders) { 693 for (Folder includedFolder in includedFolders) {
660 bool wasIncluded = contextInfos.any((info) { 694 String includedPath = includedFolder.path;
661 return info.folder.isOrContains(includedFolder.path); 695 bool isManaged = rootInfo._managesOrHasChildThatManages(includedPath);
662 }); 696 if (!isManaged) {
663 if (!wasIncluded) { 697 ContextInfo parent = _getParentForNewContext(includedPath);
664 changeSubscriptions[includedFolder] = 698 changeSubscriptions[includedFolder] =
665 includedFolder.changes.listen(_handleWatchEvent); 699 includedFolder.changes.listen(_handleWatchEvent);
666 _createContexts(_rootInfo, includedFolder, false); 700 _createContexts(parent, includedFolder, false);
667 } 701 }
668 } 702 }
669 // remove newly excluded sources 703 // remove newly excluded sources
670 for (ContextInfo info in _rootInfo.descendants) { 704 for (ContextInfo info in rootInfo.descendants) {
671 // prepare excluded sources 705 // prepare excluded sources
672 Map<String, Source> excludedSources = new HashMap<String, Source>(); 706 Map<String, Source> excludedSources = new HashMap<String, Source>();
673 info.sources.forEach((String path, Source source) { 707 info.sources.forEach((String path, Source source) {
674 if (_isExcludedBy(excludedPaths, path) && 708 if (_isExcludedBy(excludedPaths, path) &&
675 !_isExcludedBy(oldExcludedPaths, path)) { 709 !_isExcludedBy(oldExcludedPaths, path)) {
676 excludedSources[path] = source; 710 excludedSources[path] = source;
677 } 711 }
678 }); 712 });
679 // apply exclusion 713 // apply exclusion
680 ChangeSet changeSet = new ChangeSet(); 714 ChangeSet changeSet = new ChangeSet();
681 excludedSources.forEach((String path, Source source) { 715 excludedSources.forEach((String path, Source source) {
682 info.sources.remove(path); 716 info.sources.remove(path);
683 changeSet.removedSource(source); 717 changeSet.removedSource(source);
684 }); 718 });
685 callbacks.applyChangesToContext(info.folder, changeSet); 719 callbacks.applyChangesToContext(info.folder, changeSet);
686 } 720 }
687 // add previously excluded sources 721 // add previously excluded sources
688 for (ContextInfo info in _rootInfo.descendants) { 722 for (ContextInfo info in rootInfo.descendants) {
689 ChangeSet changeSet = new ChangeSet(); 723 ChangeSet changeSet = new ChangeSet();
690 _addPreviouslyExcludedSources( 724 _addPreviouslyExcludedSources(
691 info, changeSet, info.folder, oldExcludedPaths); 725 info, changeSet, info.folder, oldExcludedPaths);
692 callbacks.applyChangesToContext(info.folder, changeSet); 726 callbacks.applyChangesToContext(info.folder, changeSet);
693 } 727 }
694 } 728 }
695 729
696 /** 730 /**
697 * Recursively adds all Dart and HTML files to the [changeSet]. 731 * Recursively adds all Dart and HTML files to the [changeSet].
698 */ 732 */
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 * the set of sources in the removed context (context.sources), that are 849 * the set of sources in the removed context (context.sources), that are
816 * orphaned by this context being removed (no other context includes this 850 * orphaned by this context being removed (no other context includes this
817 * file.) 851 * file.)
818 */ 852 */
819 List<String> _computeFlushedFiles(ContextInfo info) { 853 List<String> _computeFlushedFiles(ContextInfo info) {
820 AnalysisContext context = info.context; 854 AnalysisContext context = info.context;
821 HashSet<String> flushedFiles = new HashSet<String>(); 855 HashSet<String> flushedFiles = new HashSet<String>();
822 for (Source source in context.sources) { 856 for (Source source in context.sources) {
823 flushedFiles.add(source.fullName); 857 flushedFiles.add(source.fullName);
824 } 858 }
825 for (ContextInfo contextInfo in _rootInfo.descendants) { 859 for (ContextInfo contextInfo in rootInfo.descendants) {
826 AnalysisContext contextN = contextInfo.context; 860 AnalysisContext contextN = contextInfo.context;
827 if (context != contextN) { 861 if (context != contextN) {
828 for (Source source in contextN.sources) { 862 for (Source source in contextN.sources) {
829 flushedFiles.remove(source.fullName); 863 flushedFiles.remove(source.fullName);
830 } 864 }
831 } 865 }
832 } 866 }
833 return flushedFiles.toList(growable: false); 867 return flushedFiles.toList(growable: false);
834 } 868 }
835 869
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
1075 /** 1109 /**
1076 * Return the [ContextInfo] for the "innermost" context whose associated 1110 * Return the [ContextInfo] for the "innermost" context whose associated
1077 * folder is or contains the given path. ("innermost" refers to the nesting 1111 * folder is or contains the given path. ("innermost" refers to the nesting
1078 * of contexts, so if there is a context for path /foo and a context for 1112 * of contexts, so if there is a context for path /foo and a context for
1079 * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is 1113 * path /foo/bar, then the innermost context containing /foo/bar/baz.dart is
1080 * the context for /foo/bar.) 1114 * the context for /foo/bar.)
1081 * 1115 *
1082 * If no context contains the given path, `null` is returned. 1116 * If no context contains the given path, `null` is returned.
1083 */ 1117 */
1084 ContextInfo _getInnermostContextInfoFor(String path) { 1118 ContextInfo _getInnermostContextInfoFor(String path) {
1085 ContextInfo info = _rootInfo.findChildInfoFor(path); 1119 ContextInfo info = rootInfo.findChildInfoFor(path);
1086 if (info == null) { 1120 if (info == null) {
1087 return null; 1121 return null;
1088 } 1122 }
1089 while (true) { 1123 while (true) {
1090 ContextInfo childInfo = info.findChildInfoFor(path); 1124 ContextInfo childInfo = info.findChildInfoFor(path);
1091 if (childInfo == null) { 1125 if (childInfo == null) {
1092 return info; 1126 return info;
1093 } 1127 }
1094 info = childInfo; 1128 info = childInfo;
1095 } 1129 }
1096 } 1130 }
1097 1131
1132 /**
1133 * Return the parent for a new [ContextInfo] with the given [path] folder.
1134 */
1135 ContextInfo _getParentForNewContext(String path) {
1136 ContextInfo parent = _getInnermostContextInfoFor(path);
1137 if (parent != null) {
1138 return parent;
1139 }
1140 return rootInfo;
1141 }
1142
1098 void _handleWatchEvent(WatchEvent event) { 1143 void _handleWatchEvent(WatchEvent event) {
1099 // Figure out which context this event applies to. 1144 // Figure out which context this event applies to.
1100 // TODO(brianwilkerson) If a file is explicitly included in one context 1145 // TODO(brianwilkerson) If a file is explicitly included in one context
1101 // but implicitly referenced in another context, we will only send a 1146 // but implicitly referenced in another context, we will only send a
1102 // changeSet to the context that explicitly includes the file (because 1147 // changeSet to the context that explicitly includes the file (because
1103 // that's the only context that's watching the file). 1148 // that's the only context that's watching the file).
1104 ContextInfo info = _getInnermostContextInfoFor(event.path); 1149 ContextInfo info = _getInnermostContextInfoFor(event.path);
1105 if (info == null) { 1150 if (info == null) {
1106 // This event doesn't apply to any context. This could happen due to a 1151 // This event doesn't apply to any context. This could happen due to a
1107 // race condition (e.g. a context was removed while one of its events was 1152 // race condition (e.g. a context was removed while one of its events was
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after
1542 ResourceProvider resourceProvider) { 1587 ResourceProvider resourceProvider) {
1543 if (packages != null) { 1588 if (packages != null) {
1544 // Construct package map for the SdkExtUriResolver. 1589 // Construct package map for the SdkExtUriResolver.
1545 Map<String, List<Folder>> packageMap = buildPackageMap(resourceProvider); 1590 Map<String, List<Folder>> packageMap = buildPackageMap(resourceProvider);
1546 return <UriResolver>[new SdkExtUriResolver(packageMap)]; 1591 return <UriResolver>[new SdkExtUriResolver(packageMap)];
1547 } else { 1592 } else {
1548 return const <UriResolver>[]; 1593 return const <UriResolver>[];
1549 } 1594 }
1550 } 1595 }
1551 } 1596 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/test/context_manager_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698