diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/RootIndex.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/RootIndex.java index bbc8115411d6..b9f0e729f541 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/RootIndex.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/RootIndex.java @@ -46,7 +46,6 @@ class RootIndex { private static final DirectoryInfo NULL_INFO = DirectoryInfo.createNew(); private final Set myProjectExcludedRoots = ContainerUtil.newHashSet(); - private final RootInfo myRoots = new RootInfo(); private final MultiMap myPackagePrefixRoots = new MultiMap() { @Override protected Collection createCollection() { @@ -61,6 +60,22 @@ class RootIndex { private final TObjectIntHashMap> myRootTypeId = new TObjectIntHashMap>(); RootIndex(@NotNull final Project project) { + final RootInfo info = buildRootInfo(project); + + Set allRoots = info.getAllRoots(); + for (VirtualFile root : allRoots) { + List hierarchy = getHierarchy(root, allRoots); + Pair pair = hierarchy == null ? new Pair(null, null) : info.calcDirectoryInfo(root, hierarchy); + cacheInfos(root, root, pair.first); + myPackagePrefixRoots.putValue(pair.second, root); + if (info.shouldMarkAsProjectExcluded(root, hierarchy)) { + myProjectExcludedRoots.add(root); + } + } + } + + private RootInfo buildRootInfo(Project project) { + final RootInfo info = new RootInfo(); for (final Module module : ModuleManager.getInstance(project).getModules()) { final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); final OrderEntry[] orderEntries = moduleRootManager.getOrderEntries(); @@ -68,24 +83,24 @@ class RootIndex { final VirtualFile[] contentRoots = moduleRootManager.getContentRoots(); for (final VirtualFile contentRoot : contentRoots) { - if (!myRoots.contentRootOf.containsKey(contentRoot)) { - myRoots.contentRootOf.put(contentRoot, module); + if (!info.contentRootOf.containsKey(contentRoot)) { + info.contentRootOf.put(contentRoot, module); } } for (ContentEntry contentEntry : contentEntries) { for (VirtualFile excludeRoot : contentEntry.getExcludeFolderFiles()) { - myRoots.excludedFromModule.put(excludeRoot, module); + info.excludedFromModule.put(excludeRoot, module); } // Init module sources for (final SourceFolder sourceFolder : contentEntry.getSourceFolders()) { final VirtualFile sourceFolderRoot = sourceFolder.getFile(); if (sourceFolderRoot != null) { - myRoots.rootTypeId.put(sourceFolderRoot, getRootTypeId(sourceFolder.getRootType())); - myRoots.classAndSourceRoots.add(sourceFolderRoot); - myRoots.sourceRootOf.putValue(sourceFolderRoot, module); - myRoots.packagePrefix.put(sourceFolderRoot, sourceFolder.getPackagePrefix()); + info.rootTypeId.put(sourceFolderRoot, getRootTypeId(sourceFolder.getRootType())); + info.classAndSourceRoots.add(sourceFolderRoot); + info.sourceRootOf.putValue(sourceFolderRoot, module); + info.packagePrefix.put(sourceFolderRoot, sourceFolder.getPackagePrefix()); } } } @@ -97,11 +112,11 @@ class RootIndex { if (depModule != null) { VirtualFile[] importedClassRoots = OrderEnumerator.orderEntries(depModule).exportedOnly().recursively().classes().usingCache().getRoots(); for (VirtualFile importedClassRoot : importedClassRoots) { - myRoots.depEntries.putValue(importedClassRoot, orderEntry); + info.depEntries.putValue(importedClassRoot, orderEntry); } } for (VirtualFile sourceRoot : orderEntry.getFiles(OrderRootType.SOURCES)) { - myRoots.depEntries.putValue(sourceRoot, orderEntry); + info.depEntries.putValue(sourceRoot, orderEntry); } } else if (orderEntry instanceof LibraryOrSdkOrderEntry) { @@ -111,29 +126,29 @@ class RootIndex { // Init library sources for (final VirtualFile sourceRoot : sourceRoots) { - myRoots.classAndSourceRoots.add(sourceRoot); - myRoots.libSourceRootEntries.putValue(sourceRoot, orderEntry); - myRoots.packagePrefix.put(sourceRoot, ""); + info.classAndSourceRoots.add(sourceRoot); + info.libSourceRootEntries.putValue(sourceRoot, orderEntry); + info.packagePrefix.put(sourceRoot, ""); } // init library classes for (final VirtualFile classRoot : classRoots) { - myRoots.classAndSourceRoots.add(classRoot); - myRoots.libClassRootEntries.putValue(classRoot, orderEntry); - myRoots.packagePrefix.put(classRoot, ""); + info.classAndSourceRoots.add(classRoot); + info.libClassRootEntries.putValue(classRoot, orderEntry); + info.packagePrefix.put(classRoot, ""); } if (orderEntry instanceof LibraryOrderEntry) { Library library = ((LibraryOrderEntry)orderEntry).getLibrary(); if (library != null) { for (VirtualFile root : ((LibraryEx)library).getExcludedRoots()) { - myRoots.excludedFromLibraries.putValue(root, library); + info.excludedFromLibraries.putValue(root, library); } for (VirtualFile root : sourceRoots) { - myRoots.sourceOfLibraries.putValue(root, library); + info.sourceOfLibraries.putValue(root, library); } for (VirtualFile root : classRoots) { - myRoots.classOfLibraries.putValue(root, library); + info.classOfLibraries.putValue(root, library); } } } @@ -143,30 +158,9 @@ class RootIndex { } for (DirectoryIndexExcludePolicy policy : Extensions.getExtensions(DirectoryIndexExcludePolicy.EP_NAME, project)) { - Collections.addAll(myRoots.excludedFromProject, policy.getExcludeRootsForProject()); + Collections.addAll(info.excludedFromProject, policy.getExcludeRootsForProject()); } - - Set allRoots = myRoots.getAllRoots(); - for (VirtualFile root : allRoots) { - List hierarchy = getHierarchy(root, allRoots); - Pair pair = hierarchy == null ? new Pair(null, null) : calcDirectoryInfo(root, hierarchy); - cacheInfos(root, root, pair.first); - myPackagePrefixRoots.putValue(pair.second, root); - if (shouldMarkAsProjectExcluded(root, hierarchy)) { - myProjectExcludedRoots.add(root); - } - } - } - - private boolean shouldMarkAsProjectExcluded(VirtualFile root, @Nullable List hierarchy) { - if (hierarchy == null) return false; - if (!myRoots.excludedFromProject.contains(root) && !myRoots.excludedFromModule.containsKey(root)) return false; - return ContainerUtil.find(hierarchy, new Condition() { - @Override - public boolean value(VirtualFile ancestor) { - return myRoots.contentRootOf.containsKey(ancestor); - } - }) == null; + return info; } public void checkConsistency() { @@ -174,10 +168,6 @@ class RootIndex { assert file.exists() : file.getPath() + " does not exist"; } - for (VirtualFile file : myRoots.getAllRoots()) { - assert file.exists() : file.getPath() + " does not exist"; - } - for (VirtualFile file : myPackagePrefixRoots.values()) { assert file.exists() : file.getPath() + " does not exist"; } @@ -337,80 +327,6 @@ class RootIndex { return true; } - @Nullable - private VirtualFile findModuleRootInfo(List hierarchy) { - for (VirtualFile root : hierarchy) { - Module module = myRoots.contentRootOf.get(root); - Module excludedFromModule = myRoots.excludedFromModule.get(root); - if (module != null && excludedFromModule != module) { - return root; - } - if (myRoots.excludedFromProject.contains(root) || excludedFromModule != null || !root.isDirectory()) { - return null; - } - } - return null; - } - - @Nullable - private VirtualFile findLibraryRootInfo(List hierarchy, boolean source) { - Set excludedFromLibraries = ContainerUtil.newHashSet(); - for (VirtualFile root : hierarchy) { - excludedFromLibraries.addAll(myRoots.excludedFromLibraries.get(root)); - if (source && myRoots.libSourceRootEntries.containsKey(root) && - (!myRoots.sourceOfLibraries.containsKey(root) || !excludedFromLibraries.containsAll(myRoots.sourceOfLibraries.get(root)))) { - return root; - } else if (!source && myRoots.libClassRootEntries.containsKey(root) && - (!myRoots.classOfLibraries.containsKey(root) || !excludedFromLibraries.containsAll(myRoots.classOfLibraries.get(root)))) { - return root; - } - } - return null; - } - - @NotNull - private Pair calcDirectoryInfo(VirtualFile root, @NotNull final List hierarchy) { - VirtualFile moduleContentRoot = findModuleRootInfo(hierarchy); - VirtualFile libraryClassRoot = findLibraryRootInfo(hierarchy, false); - VirtualFile librarySourceRoot = findLibraryRootInfo(hierarchy, true); - if (moduleContentRoot == null && libraryClassRoot == null && librarySourceRoot == null) { - return new Pair(null, null); - } - - VirtualFile sourceRoot = findPackageRootInfo(hierarchy, moduleContentRoot, null, librarySourceRoot); - - VirtualFile moduleSourceRoot = findPackageRootInfo(hierarchy, moduleContentRoot, null, null); - boolean inModuleSources = moduleSourceRoot != null; - boolean inLibrarySource = librarySourceRoot != null; - int rootTypeId = moduleSourceRoot != null ? myRoots.rootTypeId.get(moduleSourceRoot) : 0; - - OrderEntry[] entries = getOrderEntries(hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot); - DirectoryInfo directoryInfo = new DirectoryInfo(myRoots.contentRootOf.get(moduleContentRoot), - moduleContentRoot, - sourceRoot, - libraryClassRoot, - (byte)DirectoryInfo.createSourceRootTypeData(inModuleSources, inLibrarySource, rootTypeId), - entries); - - String packagePrefix = calcPackagePrefix(root, hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot); - - return Pair.create(directoryInfo, packagePrefix); - } - - private String calcPackagePrefix(VirtualFile root, - List hierarchy, - VirtualFile moduleContentRoot, - VirtualFile libraryClassRoot, VirtualFile librarySourceRoot) { - VirtualFile packageRoot = findPackageRootInfo(hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot); - String packagePrefix = myRoots.packagePrefix.get(packageRoot); - if (packagePrefix != null && packageRoot != root) { - assert packageRoot != null; - String relative = VfsUtilCore.getRelativePath(root, packageRoot, '.'); - packagePrefix = StringUtil.isEmpty(packagePrefix) ? relative : packagePrefix + '.' + relative; - } - return packagePrefix; - } - @Nullable private static List getHierarchy(VirtualFile dir, Set allRoots) { List hierarchy = ContainerUtil.newArrayList(); @@ -426,88 +342,10 @@ class RootIndex { return hierarchy; } - @Nullable - private VirtualFile findPackageRootInfo(List hierarchy, - VirtualFile moduleContentRoot, - VirtualFile libraryClassRoot, - VirtualFile librarySourceRoot) { - for (VirtualFile root : hierarchy) { - if (moduleContentRoot != null && - myRoots.sourceRootOf.get(root).contains(myRoots.contentRootOf.get(moduleContentRoot)) && - librarySourceRoot == null) { - return root; - } - if (root == libraryClassRoot || root == librarySourceRoot) { - return root; - } - if (root == moduleContentRoot && !myRoots.sourceRootOf.containsKey(root) && librarySourceRoot == null && libraryClassRoot == null) { - return null; - } - } - return null; - } - - private LinkedHashSet getDependencyOrderEntries(List hierarchy) { - LinkedHashSet orderEntries = ContainerUtil.newLinkedHashSet(); - for (VirtualFile root : hierarchy) { - orderEntries.addAll(myRoots.depEntries.get(root)); - } - return orderEntries; - } - - private LinkedHashSet getLibraryOrderEntries(List hierarchy, - @Nullable VirtualFile libraryClassRoot, - @Nullable VirtualFile librarySourceRoot) { - LinkedHashSet orderEntries = ContainerUtil.newLinkedHashSet(); - for (VirtualFile root : hierarchy) { - if (root == libraryClassRoot && !myRoots.sourceRootOf.containsKey(root)) { - orderEntries.addAll(myRoots.libClassRootEntries.get(root)); - } - if (root == librarySourceRoot && libraryClassRoot == null) { - orderEntries.addAll(myRoots.libSourceRootEntries.get(root)); - } - if (myRoots.libClassRootEntries.containsKey(root) || myRoots.sourceRootOf.containsKey(root) && librarySourceRoot == null) { - break; - } - } - return orderEntries; - } - - @Nullable - private ModuleSourceOrderEntry getModuleSourceEntry(List hierarchy, @NotNull VirtualFile moduleContentRoot) { - Module module = myRoots.contentRootOf.get(moduleContentRoot); - for (VirtualFile root : hierarchy) { - if (myRoots.sourceRootOf.get(root).contains(module)) { - return ContainerUtil.findInstance(ModuleRootManager.getInstance(module).getOrderEntries(), ModuleSourceOrderEntry.class); - } - if (myRoots.libClassRootEntries.containsKey(root)) { - return null; - } - } - return null; - } - - private OrderEntry[] getOrderEntries(List hierarchy, - @Nullable VirtualFile moduleContentRoot, - @Nullable VirtualFile libraryClassRoot, - @Nullable VirtualFile librarySourceRoot) { - Set orderEntries = ContainerUtil.newLinkedHashSet(); - orderEntries.addAll(getLibraryOrderEntries(hierarchy, libraryClassRoot, librarySourceRoot)); - orderEntries.addAll(getDependencyOrderEntries(hierarchy)); - if (moduleContentRoot != null) { - ContainerUtil.addIfNotNull(orderEntries, getModuleSourceEntry(hierarchy, moduleContentRoot)); - } - if (orderEntries.isEmpty()) { - return null; - } - - OrderEntry[] array = orderEntries.toArray(new OrderEntry[orderEntries.size()]); - Arrays.sort(array, DirectoryInfo.BY_OWNER_MODULE); - return array; - } - private static class RootInfo { + // getDirectoriesByPackageName used to be in this order, some clients might rely on that @NotNull final LinkedHashSet classAndSourceRoots = ContainerUtil.newLinkedHashSet(); + @NotNull final Map contentRootOf = ContainerUtil.newHashMap(); @NotNull final MultiMap sourceRootOf = MultiMapBasedOnSet.createBasedOnSet(); @NotNull final TObjectIntHashMap rootTypeId = new TObjectIntHashMap(); @@ -530,7 +368,171 @@ class RootIndex { result.addAll(excludedFromProject); return result; } + + private boolean shouldMarkAsProjectExcluded(VirtualFile root, @Nullable List hierarchy) { + if (hierarchy == null) return false; + if (!excludedFromProject.contains(root) && !excludedFromModule.containsKey(root)) return false; + return ContainerUtil.find(hierarchy, new Condition() { + @Override + public boolean value(VirtualFile ancestor) { + return contentRootOf.containsKey(ancestor); + } + }) == null; + } + @Nullable + private VirtualFile findModuleRootInfo(List hierarchy) { + for (VirtualFile root : hierarchy) { + Module module = contentRootOf.get(root); + Module excludedFrom = excludedFromModule.get(root); + if (module != null && excludedFrom != module) { + return root; + } + if (excludedFromProject.contains(root) || excludedFrom != null || !root.isDirectory()) { + return null; + } + } + return null; + } + + @Nullable + private VirtualFile findLibraryRootInfo(List hierarchy, boolean source) { + Set librariesToIgnore = ContainerUtil.newHashSet(); + for (VirtualFile root : hierarchy) { + librariesToIgnore.addAll(excludedFromLibraries.get(root)); + if (source && libSourceRootEntries.containsKey(root) && + (!sourceOfLibraries.containsKey(root) || !librariesToIgnore.containsAll(sourceOfLibraries.get(root)))) { + return root; + } else if (!source && libClassRootEntries.containsKey(root) && + (!classOfLibraries.containsKey(root) || !librariesToIgnore.containsAll(classOfLibraries.get(root)))) { + return root; + } + } + return null; + } + + @NotNull + private Pair calcDirectoryInfo(VirtualFile root, @NotNull final List hierarchy) { + VirtualFile moduleContentRoot = findModuleRootInfo(hierarchy); + VirtualFile libraryClassRoot = findLibraryRootInfo(hierarchy, false); + VirtualFile librarySourceRoot = findLibraryRootInfo(hierarchy, true); + if (moduleContentRoot == null && libraryClassRoot == null && librarySourceRoot == null) { + return new Pair(null, null); + } + + VirtualFile sourceRoot = findPackageRootInfo(hierarchy, moduleContentRoot, null, librarySourceRoot); + + VirtualFile moduleSourceRoot = findPackageRootInfo(hierarchy, moduleContentRoot, null, null); + boolean inModuleSources = moduleSourceRoot != null; + boolean inLibrarySource = librarySourceRoot != null; + int typeId = moduleSourceRoot != null ? rootTypeId.get(moduleSourceRoot) : 0; + + OrderEntry[] entries = getOrderEntries(hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot); + DirectoryInfo directoryInfo = new DirectoryInfo(contentRootOf.get(moduleContentRoot), + moduleContentRoot, + sourceRoot, + libraryClassRoot, + (byte)DirectoryInfo.createSourceRootTypeData(inModuleSources, inLibrarySource, typeId), + entries); + + String packagePrefix = calcPackagePrefix(root, hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot); + + return Pair.create(directoryInfo, packagePrefix); + } + + private String calcPackagePrefix(VirtualFile root, + List hierarchy, + VirtualFile moduleContentRoot, + VirtualFile libraryClassRoot, VirtualFile librarySourceRoot) { + VirtualFile packageRoot = findPackageRootInfo(hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot); + String prefix = packagePrefix.get(packageRoot); + if (prefix != null && packageRoot != root) { + assert packageRoot != null; + String relative = VfsUtilCore.getRelativePath(root, packageRoot, '.'); + prefix = StringUtil.isEmpty(prefix) ? relative : prefix + '.' + relative; + } + return prefix; + } + + @Nullable + private VirtualFile findPackageRootInfo(List hierarchy, + VirtualFile moduleContentRoot, + VirtualFile libraryClassRoot, + VirtualFile librarySourceRoot) { + for (VirtualFile root : hierarchy) { + if (moduleContentRoot != null && + sourceRootOf.get(root).contains(contentRootOf.get(moduleContentRoot)) && + librarySourceRoot == null) { + return root; + } + if (root == libraryClassRoot || root == librarySourceRoot) { + return root; + } + if (root == moduleContentRoot && !sourceRootOf.containsKey(root) && librarySourceRoot == null && libraryClassRoot == null) { + return null; + } + } + return null; + } + + private LinkedHashSet getDependencyOrderEntries(List hierarchy) { + LinkedHashSet orderEntries = ContainerUtil.newLinkedHashSet(); + for (VirtualFile root : hierarchy) { + orderEntries.addAll(depEntries.get(root)); + } + return orderEntries; + } + + private LinkedHashSet getLibraryOrderEntries(List hierarchy, + @Nullable VirtualFile libraryClassRoot, + @Nullable VirtualFile librarySourceRoot) { + LinkedHashSet orderEntries = ContainerUtil.newLinkedHashSet(); + for (VirtualFile root : hierarchy) { + if (root == libraryClassRoot && !sourceRootOf.containsKey(root)) { + orderEntries.addAll(libClassRootEntries.get(root)); + } + if (root == librarySourceRoot && libraryClassRoot == null) { + orderEntries.addAll(libSourceRootEntries.get(root)); + } + if (libClassRootEntries.containsKey(root) || sourceRootOf.containsKey(root) && librarySourceRoot == null) { + break; + } + } + return orderEntries; + } + + @Nullable + private ModuleSourceOrderEntry getModuleSourceEntry(List hierarchy, @NotNull VirtualFile moduleContentRoot) { + Module module = contentRootOf.get(moduleContentRoot); + for (VirtualFile root : hierarchy) { + if (sourceRootOf.get(root).contains(module)) { + return ContainerUtil.findInstance(ModuleRootManager.getInstance(module).getOrderEntries(), ModuleSourceOrderEntry.class); + } + if (libClassRootEntries.containsKey(root)) { + return null; + } + } + return null; + } + + private OrderEntry[] getOrderEntries(List hierarchy, + @Nullable VirtualFile moduleContentRoot, + @Nullable VirtualFile libraryClassRoot, + @Nullable VirtualFile librarySourceRoot) { + Set orderEntries = ContainerUtil.newLinkedHashSet(); + orderEntries.addAll(getLibraryOrderEntries(hierarchy, libraryClassRoot, librarySourceRoot)); + orderEntries.addAll(getDependencyOrderEntries(hierarchy)); + if (moduleContentRoot != null) { + ContainerUtil.addIfNotNull(orderEntries, getModuleSourceEntry(hierarchy, moduleContentRoot)); + } + if (orderEntries.isEmpty()) { + return null; + } + + OrderEntry[] array = orderEntries.toArray(new OrderEntry[orderEntries.size()]); + Arrays.sort(array, DirectoryInfo.BY_OWNER_MODULE); + return array; + } } } \ No newline at end of file