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 960f8e8c6c06..cea7f6be00d0 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 @@ -56,21 +56,24 @@ class RootIndex { private final Map myInfoCache = ContainerUtil.newConcurrentMap(); private final List> myRootTypes = ContainerUtil.newArrayList(); private final TObjectIntHashMap> myRootTypeId = new TObjectIntHashMap>(); + @NotNull private final Project myProject; + private volatile Map myOrderEntries; RootIndex(@NotNull final Project project) { + myProject = project; final RootInfo info = buildRootInfo(project); Set allRoots = info.getAllRoots(); for (VirtualFile root : allRoots) { List hierarchy = getHierarchy(root, allRoots, info); - Pair pair = hierarchy == null ? new Pair(null, null) : info.calcDirectoryInfo(root, hierarchy); + Pair pair = hierarchy == null ? new Pair(null, null) : calcDirectoryInfo(root, hierarchy, info); cacheInfos(root, root, pair.first); myPackagePrefixRoots.putValue(pair.second, root); if (info.shouldMarkAsProjectExcluded(root, hierarchy)) { myProjectExcludedRoots.add(root); } } - + myModuleExcludedRoots = info.excludedFromModule.keySet(); } @@ -78,17 +81,14 @@ class RootIndex { final RootInfo info = new RootInfo(); for (final Module module : ModuleManager.getInstance(project).getModules()) { final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - final OrderEntry[] orderEntries = moduleRootManager.getOrderEntries(); - final ContentEntry[] contentEntries = moduleRootManager.getContentEntries(); - final VirtualFile[] contentRoots = moduleRootManager.getContentRoots(); - for (final VirtualFile contentRoot : contentRoots) { + for (final VirtualFile contentRoot : moduleRootManager.getContentRoots()) { if (!info.contentRootOf.containsKey(contentRoot)) { info.contentRootOf.put(contentRoot, module); } } - for (ContentEntry contentEntry : contentEntries) { + for (ContentEntry contentEntry : moduleRootManager.getContentEntries()) { for (VirtualFile excludeRoot : contentEntry.getExcludeFolderFiles()) { info.excludedFromModule.put(excludeRoot, module); } @@ -105,21 +105,8 @@ class RootIndex { } } - for (OrderEntry orderEntry : orderEntries) { - // init ordered entries - if (orderEntry instanceof ModuleOrderEntry) { - final Module depModule = ((ModuleOrderEntry)orderEntry).getModule(); - if (depModule != null) { - VirtualFile[] importedClassRoots = OrderEnumerator.orderEntries(depModule).exportedOnly().recursively().classes().usingCache().getRoots(); - for (VirtualFile importedClassRoot : importedClassRoots) { - info.depEntries.putValue(importedClassRoot, orderEntry); - } - } - for (VirtualFile sourceRoot : orderEntry.getFiles(OrderRootType.SOURCES)) { - info.depEntries.putValue(sourceRoot, orderEntry); - } - } - else if (orderEntry instanceof LibraryOrSdkOrderEntry) { + for (OrderEntry orderEntry : moduleRootManager.getOrderEntries()) { + if (orderEntry instanceof LibraryOrSdkOrderEntry) { final LibraryOrSdkOrderEntry entry = (LibraryOrSdkOrderEntry)orderEntry; final VirtualFile[] sourceRoots = entry.getRootFiles(OrderRootType.SOURCES); final VirtualFile[] classRoots = entry.getRootFiles(OrderRootType.CLASSES); @@ -127,14 +114,14 @@ class RootIndex { // Init library sources for (final VirtualFile sourceRoot : sourceRoots) { info.classAndSourceRoots.add(sourceRoot); - info.libSourceRootEntries.putValue(sourceRoot, orderEntry); + info.libraryOrSdkSources.add(sourceRoot); info.packagePrefix.put(sourceRoot, ""); } // init library classes for (final VirtualFile classRoot : classRoots) { info.classAndSourceRoots.add(classRoot); - info.libClassRootEntries.putValue(classRoot, orderEntry); + info.libraryOrSdkClasses.add(classRoot); info.packagePrefix.put(classRoot, ""); } @@ -163,6 +150,77 @@ class RootIndex { return info; } + private Map getOrderEntries() { + Map result = myOrderEntries; + if (result != null) return result; + + MultiMap libClassRootEntries = MultiMap.createSmartList(); + MultiMap libSourceRootEntries = MultiMap.createSmartList(); + MultiMap depEntries = MultiMap.createSmartList(); + + for (final Module module : ModuleManager.getInstance(myProject).getModules()) { + final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); + for (OrderEntry orderEntry : moduleRootManager.getOrderEntries()) { + if (orderEntry instanceof ModuleOrderEntry) { + final Module depModule = ((ModuleOrderEntry)orderEntry).getModule(); + if (depModule != null) { + VirtualFile[] importedClassRoots = OrderEnumerator.orderEntries(depModule).exportedOnly().recursively().classes().usingCache().getRoots(); + for (VirtualFile importedClassRoot : importedClassRoots) { + depEntries.putValue(importedClassRoot, orderEntry); + } + } + for (VirtualFile sourceRoot : orderEntry.getFiles(OrderRootType.SOURCES)) { + depEntries.putValue(sourceRoot, orderEntry); + } + } + else if (orderEntry instanceof LibraryOrSdkOrderEntry) { + final LibraryOrSdkOrderEntry entry = (LibraryOrSdkOrderEntry)orderEntry; + for (final VirtualFile sourceRoot : entry.getRootFiles(OrderRootType.SOURCES)) { + libSourceRootEntries.putValue(sourceRoot, orderEntry); + } + for (final VirtualFile classRoot : entry.getRootFiles(OrderRootType.CLASSES)) { + libClassRootEntries.putValue(classRoot, orderEntry); + } + } + } + } + + RootInfo rootInfo = buildRootInfo(myProject); + result = ContainerUtil.newHashMap(); + Set allRoots = rootInfo.getAllRoots(); + for (VirtualFile file : allRoots) { + List hierarchy = getHierarchy(file, allRoots, rootInfo); + result.put(file, hierarchy == null ? OrderEntry.EMPTY_ARRAY : calcOrderEntries(rootInfo, depEntries, libClassRootEntries, libSourceRootEntries, hierarchy)); + } + myOrderEntries = result; + return result; + } + + private static OrderEntry[] calcOrderEntries(RootInfo info, + MultiMap depEntries, + MultiMap libClassRootEntries, + MultiMap libSourceRootEntries, List hierarchy) { + @Nullable VirtualFile libraryClassRoot = info.findLibraryRootInfo(hierarchy, false); + @Nullable VirtualFile librarySourceRoot = info.findLibraryRootInfo(hierarchy, true); + Set orderEntries = ContainerUtil.newLinkedHashSet(); + orderEntries.addAll(info.getLibraryOrderEntries(hierarchy, libraryClassRoot, librarySourceRoot, libClassRootEntries, libSourceRootEntries)); + for (VirtualFile root : hierarchy) { + orderEntries.addAll(depEntries.get(root)); + } + VirtualFile moduleContentRoot = info.findModuleRootInfo(hierarchy); + if (moduleContentRoot != null) { + ContainerUtil.addIfNotNull(orderEntries, info.getModuleSourceEntry(hierarchy, moduleContentRoot, libClassRootEntries)); + } + if (orderEntries.isEmpty()) { + return null; + } + + OrderEntry[] array = orderEntries.toArray(new OrderEntry[orderEntries.size()]); + Arrays.sort(array, DirectoryInfo.BY_OWNER_MODULE); + return array; + } + + public void checkConsistency() { for (VirtualFile file : myProjectExcludedRoots) { assert file.exists() : file.getPath() + " does not exist"; @@ -338,19 +396,18 @@ class RootIndex { // getDirectoriesByPackageName used to be in this order, some clients might rely on that @NotNull final LinkedHashSet classAndSourceRoots = ContainerUtil.newLinkedHashSet(); + @NotNull final Set libraryOrSdkSources = ContainerUtil.newHashSet(); + @NotNull final Set libraryOrSdkClasses = ContainerUtil.newHashSet(); @NotNull final Map contentRootOf = ContainerUtil.newHashMap(); @NotNull final MultiMap sourceRootOf = MultiMap.createSet(); @NotNull final TObjectIntHashMap rootTypeId = new TObjectIntHashMap(); - @NotNull final MultiMap libClassRootEntries = MultiMap.createSmartList(); - @NotNull final MultiMap libSourceRootEntries = MultiMap.createSmartList(); - @NotNull final MultiMap depEntries = MultiMap.createSmartList(); @NotNull final MultiMap excludedFromLibraries = MultiMap.createSmartList(); @NotNull final MultiMap classOfLibraries = MultiMap.createSmartList(); @NotNull final MultiMap sourceOfLibraries = MultiMap.createSmartList(); @NotNull final Set excludedFromProject = ContainerUtil.newHashSet(); @NotNull final Map excludedFromModule = ContainerUtil.newHashMap(); @NotNull final Map packagePrefix = ContainerUtil.newHashMap(); - + Set getAllRoots() { LinkedHashSet result = ContainerUtil.newLinkedHashSet(); result.addAll(classAndSourceRoots); @@ -371,7 +428,7 @@ class RootIndex { } }) == null; } - + @Nullable private VirtualFile findModuleRootInfo(List hierarchy) { for (VirtualFile root : hierarchy) { @@ -392,10 +449,10 @@ class RootIndex { Set librariesToIgnore = ContainerUtil.newHashSet(); for (VirtualFile root : hierarchy) { librariesToIgnore.addAll(excludedFromLibraries.get(root)); - if (source && libSourceRootEntries.containsKey(root) && + if (source && libraryOrSdkSources.contains(root) && (!sourceOfLibraries.containsKey(root) || !librariesToIgnore.containsAll(sourceOfLibraries.get(root)))) { return root; - } else if (!source && libClassRootEntries.containsKey(root) && + } else if (!source && libraryOrSdkClasses.contains(root) && (!classOfLibraries.containsKey(root) || !librariesToIgnore.containsAll(classOfLibraries.get(root)))) { return root; } @@ -403,35 +460,6 @@ class RootIndex { 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, @@ -467,31 +495,28 @@ class RootIndex { return null; } - private void collectDependencyOrderEntries(List hierarchy, Set result) { - for (VirtualFile root : hierarchy) { - result.addAll(depEntries.get(root)); - } - } - - private void collectLibraryOrderEntries(List hierarchy, - @Nullable VirtualFile libraryClassRoot, - @Nullable VirtualFile librarySourceRoot, - Set result) { + private LinkedHashSet getLibraryOrderEntries(List hierarchy, + @Nullable VirtualFile libraryClassRoot, + @Nullable VirtualFile librarySourceRoot, + MultiMap libClassRootEntries, + MultiMap libSourceRootEntries) { + LinkedHashSet orderEntries = ContainerUtil.newLinkedHashSet(); for (VirtualFile root : hierarchy) { if (root == libraryClassRoot && !sourceRootOf.containsKey(root)) { - result.addAll(libClassRootEntries.get(root)); + orderEntries.addAll(libClassRootEntries.get(root)); } if (root == librarySourceRoot && libraryClassRoot == null) { - result.addAll(libSourceRootEntries.get(root)); + 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) { + private ModuleSourceOrderEntry getModuleSourceEntry(List hierarchy, @NotNull VirtualFile moduleContentRoot, MultiMap libClassRootEntries) { Module module = contentRootOf.get(moduleContentRoot); for (VirtualFile root : hierarchy) { if (sourceRootOf.get(root).contains(module)) { @@ -504,24 +529,42 @@ class RootIndex { return null; } - private OrderEntry[] getOrderEntries(List hierarchy, - @Nullable VirtualFile moduleContentRoot, - @Nullable VirtualFile libraryClassRoot, - @Nullable VirtualFile librarySourceRoot) { - LinkedHashSet orderEntries = ContainerUtil.newLinkedHashSet(); - collectLibraryOrderEntries(hierarchy, libraryClassRoot, librarySourceRoot, orderEntries); - collectDependencyOrderEntries(hierarchy, orderEntries); - 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; - } } + @NotNull + private Pair calcDirectoryInfo(final VirtualFile root, @NotNull final List hierarchy, RootInfo info) { + VirtualFile moduleContentRoot = info.findModuleRootInfo(hierarchy); + VirtualFile libraryClassRoot = info.findLibraryRootInfo(hierarchy, false); + VirtualFile librarySourceRoot = info.findLibraryRootInfo(hierarchy, true); + if (moduleContentRoot == null && libraryClassRoot == null && librarySourceRoot == null) { + return new Pair(null, null); + } + + VirtualFile sourceRoot = info.findPackageRootInfo(hierarchy, moduleContentRoot, null, librarySourceRoot); + + VirtualFile moduleSourceRoot = info.findPackageRootInfo(hierarchy, moduleContentRoot, null, null); + boolean inModuleSources = moduleSourceRoot != null; + boolean inLibrarySource = librarySourceRoot != null; + int typeId = moduleSourceRoot != null ? info.rootTypeId.get(moduleSourceRoot) : 0; + + DirectoryInfo directoryInfo = new DirectoryInfo(info.contentRootOf.get(moduleContentRoot), + moduleContentRoot, + sourceRoot, + libraryClassRoot, + (byte)DirectoryInfo.createSourceRootTypeData(inModuleSources, inLibrarySource, typeId), + null) { + @NotNull + @Override + public OrderEntry[] getOrderEntries() { + OrderEntry[] entries = RootIndex.this.getOrderEntries().get(root); + return entries == null ? OrderEntry.EMPTY_ARRAY : entries; + } + }; + + String packagePrefix = info.calcPackagePrefix(root, hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot); + + return Pair.create(directoryInfo, packagePrefix); + } + + } \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java index 4298046c8c24..550e99d82033 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/DirectoryInfo.java @@ -35,7 +35,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -public final class DirectoryInfo { +public class DirectoryInfo { public static final int MAX_ROOT_TYPE_ID = (1 << (Byte.SIZE - 2)) - 1; private final Module module; // module to which content it belongs or null private final VirtualFile libraryClassRoot; // class root in library @@ -81,7 +81,7 @@ public final class DirectoryInfo { Comparing.equal(contentRoot, info.contentRoot) && Comparing.equal(libraryClassRoot, info.libraryClassRoot) && Comparing.equal(module, info.module) && - Arrays.equals(orderEntries, info.orderEntries) && + Arrays.equals(getOrderEntries(), info.getOrderEntries()) && Comparing.equal(sourceRoot, info.sourceRoot); } @@ -105,7 +105,7 @@ public final class DirectoryInfo { ", libraryClassRoot=" + getLibraryClassRoot() + ", contentRoot=" + getContentRoot() + ", sourceRoot=" + getSourceRoot() + - ", orderEntries=" + Arrays.toString(orderEntries) + + ", orderEntries=" + Arrays.toString(getOrderEntries()) + "}"; } @@ -117,10 +117,7 @@ public final class DirectoryInfo { @Nullable OrderEntry findOrderEntryWithOwnerModule(@NotNull Module ownerModule) { - OrderEntry[] entries = orderEntries; - if (entries == null) { - return null; - } + OrderEntry[] entries = getOrderEntries(); if (entries.length < 10) { for (OrderEntry entry : entries) { if (entry.getOwnerModule() == ownerModule) return entry; @@ -133,10 +130,7 @@ public final class DirectoryInfo { @NotNull List findAllOrderEntriesWithOwnerModule(@NotNull Module ownerModule) { - OrderEntry[] entries = orderEntries; - if (entries == null) { - return Collections.emptyList(); - } + OrderEntry[] entries = getOrderEntries(); if (entries.length == 1) { OrderEntry entry = entries[0]; return entry.getOwnerModule() == ownerModule ? Arrays.asList(entries) : Collections.emptyList(); @@ -271,10 +265,6 @@ public final class DirectoryInfo { return sourceRoot; } - public boolean hasSourceRoot() { - return getSourceRoot() != null; - } - public VirtualFile getLibraryClassRoot() { return libraryClassRoot; }