caching for OrderRootsEnumerator added

This commit is contained in:
nik
2010-07-02 09:28:53 +04:00
parent 1095598295
commit 5d9564e48b
17 changed files with 402 additions and 122 deletions
@@ -198,7 +198,7 @@ public class ModuleChunk extends Chunk<Module> {
if ((mySourcesFilter & TEST_SOURCES) == 0) {
enumerator = enumerator.productionOnly();
}
cpFiles.addAll(enumerator.recursively().exportedOnly().getClassesRoots());
Collections.addAll(cpFiles, enumerator.recursively().exportedOnly().getClassesRoots());
}
cpFiles = JarClasspathHelper.patchFiles(cpFiles, myContext.getProject());
@@ -218,8 +218,8 @@ public class ModuleChunk extends Chunk<Module> {
if ((mySourcesFilter & TEST_SOURCES) == 0) {
enumerator = enumerator.productionOnly();
}
cpFiles.addAll(enumerator.recursively().exportedOnly().getClassesRoots());
jdkFiles.addAll(OrderEnumerator.orderEntries(module).sdkOnly().getClassesRoots());
Collections.addAll(cpFiles, enumerator.recursively().exportedOnly().getClassesRoots());
Collections.addAll(jdkFiles, OrderEnumerator.orderEntries(module).sdkOnly().getClassesRoots());
}
cpFiles.addAll(jdkFiles);
return cpFiles;
@@ -25,7 +25,9 @@ import com.intellij.util.containers.OrderedSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
/**
* @author Dmitry Avdeev
@@ -38,7 +40,8 @@ public class JarClasspathHelper {
}
String path = getJarsPath(project);
final OrderedSet<VirtualFile> result = new OrderedSet<VirtualFile>(TObjectHashingStrategy.CANONICAL);
final Collection<VirtualFile> modulesOutputs = OrderEnumerator.orderEntries(project).withoutLibraries().withoutSdk().getClassesRoots();
final Collection<VirtualFile> modulesOutputs =
new HashSet<VirtualFile>(Arrays.asList(OrderEnumerator.orderEntries(project).withoutLibraries().withoutSdk().getClassesRoots()));
for (VirtualFile file : files) {
VirtualFile jar = getJarFile(path, file.getName());
if (modulesOutputs.contains(file) && jar != null) {
@@ -10,7 +10,6 @@ import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
import com.intellij.util.PathsList;
import java.io.IOException;
import java.util.Collection;
/**
* @author yole
@@ -39,9 +38,9 @@ public class DependencyScopeTest extends ModuleTestCase {
assertFalse(moduleA.getModuleWithDependenciesAndLibrariesScope(false).contains(classB));
assertFalse(moduleA.getModuleWithDependenciesAndLibrariesScope(false).isSearchInModuleContent(moduleB));
final Collection<VirtualFile> compilationClasspath = getCompilationClasspath(moduleA);
assertEquals(1, compilationClasspath.size());
final Collection<VirtualFile> productionCompilationClasspath = getProductionCompileClasspath(moduleA);
final VirtualFile[] compilationClasspath = getCompilationClasspath(moduleA);
assertEquals(1, compilationClasspath.length);
final VirtualFile[] productionCompilationClasspath = getProductionCompileClasspath(moduleA);
assertEmpty(productionCompilationClasspath);
final PathsList pathsList = OrderEnumerator.orderEntries(moduleA).recursively().getPathsList();
@@ -78,20 +77,20 @@ public class DependencyScopeTest extends ModuleTestCase {
assertTrue(m.getModuleWithDependenciesAndLibrariesScope(true).contains(libraryClass));
assertFalse(m.getModuleWithDependenciesAndLibrariesScope(false).contains(libraryClass));
final Collection<VirtualFile> compilationClasspath = getCompilationClasspath(m);
assertEquals(1, compilationClasspath.size());
final Collection<VirtualFile> productionCompilationClasspath = getProductionCompileClasspath(m);
final VirtualFile[] compilationClasspath = getCompilationClasspath(m);
assertEquals(1, compilationClasspath.length);
final VirtualFile[] productionCompilationClasspath = getProductionCompileClasspath(m);
assertEmpty(productionCompilationClasspath);
}
public void testRuntimeModuleDependency() throws IOException {
Module moduleA = createModule("a.iml", StdModuleTypes.JAVA);
addDependentModule(moduleA, DependencyScope.RUNTIME);
final Collection<VirtualFile> runtimeClasspath = getRuntimeClasspath(moduleA);
assertEquals(1, runtimeClasspath.size());
final Collection<VirtualFile> compilationClasspath = getCompilationClasspath(moduleA);
assertEquals(1, compilationClasspath.size());
Collection<VirtualFile> production = getProductionCompileClasspath(moduleA);
final VirtualFile[] runtimeClasspath = getRuntimeClasspath(moduleA);
assertEquals(1, runtimeClasspath.length);
final VirtualFile[] compilationClasspath = getCompilationClasspath(moduleA);
assertEquals(1, compilationClasspath.length);
VirtualFile[] production = getProductionCompileClasspath(moduleA);
assertEmpty(production);
}
@@ -99,12 +98,12 @@ public class DependencyScopeTest extends ModuleTestCase {
Module m = createModule("a.iml", StdModuleTypes.JAVA);
VirtualFile libraryRoot = addLibrary(m, DependencyScope.RUNTIME);
final Collection<VirtualFile> runtimeClasspath = getRuntimeClasspath(m);
final VirtualFile[] runtimeClasspath = getRuntimeClasspath(m);
assertOrderedEquals(runtimeClasspath, libraryRoot);
final Collection<VirtualFile> compilationClasspath = getCompilationClasspath(m);
assertEquals(1, compilationClasspath.size());
Collection<VirtualFile> production = getProductionCompileClasspath(m);
final VirtualFile[] compilationClasspath = getCompilationClasspath(m);
assertEquals(1, compilationClasspath.length);
VirtualFile[] production = getProductionCompileClasspath(m);
assertEmpty(production);
VirtualFile libraryClass = myFixture.createFile("lib/Test.java", "public class Test { }");
@@ -115,20 +114,20 @@ public class DependencyScopeTest extends ModuleTestCase {
public void testProvidedModuleDependency() throws IOException {
Module moduleA = createModule("a.iml", StdModuleTypes.JAVA);
addDependentModule(moduleA, DependencyScope.PROVIDED);
Collection<VirtualFile> runtimeClasspath = getRuntimeClasspath(moduleA);
VirtualFile[] runtimeClasspath = getRuntimeClasspath(moduleA);
assertEmpty(runtimeClasspath);
final Collection<VirtualFile> compilationClasspath = getCompilationClasspath(moduleA);
assertEquals(1, compilationClasspath.size());
final VirtualFile[] compilationClasspath = getCompilationClasspath(moduleA);
assertEquals(1, compilationClasspath.length);
}
public void testProvidedLibraryDependency() throws IOException {
Module m = createModule("a.iml", StdModuleTypes.JAVA);
VirtualFile libraryRoot = addLibrary(m, DependencyScope.PROVIDED);
final Collection<VirtualFile> runtimeClasspath = getRuntimeClasspath(m);
final VirtualFile[] runtimeClasspath = getRuntimeClasspath(m);
assertEmpty(runtimeClasspath);
final Collection<VirtualFile> compilationClasspath = getCompilationClasspath(m);
final VirtualFile[] compilationClasspath = getCompilationClasspath(m);
assertOrderedEquals(compilationClasspath, libraryRoot);
VirtualFile libraryClass = myFixture.createFile("lib/Test.java", "public class Test { }");
@@ -136,15 +135,15 @@ public class DependencyScopeTest extends ModuleTestCase {
assertTrue(m.getModuleWithDependenciesAndLibrariesScope(false).contains(libraryClass));
}
private static Collection<VirtualFile> getRuntimeClasspath(Module m) {
private static VirtualFile[] getRuntimeClasspath(Module m) {
return ModuleRootManager.getInstance(m).orderEntries().productionOnly().runtimeOnly().recursively().getClassesRoots();
}
private static Collection<VirtualFile> getProductionCompileClasspath(Module moduleA) {
private static VirtualFile[] getProductionCompileClasspath(Module moduleA) {
return ModuleRootManager.getInstance(moduleA).orderEntries().productionOnly().compileOnly().recursively().exportedOnly().getClassesRoots();
}
private static Collection<VirtualFile> getCompilationClasspath(Module m) {
private static VirtualFile[] getCompilationClasspath(Module m) {
return ModuleRootManager.getInstance(m).orderEntries().recursively().exportedOnly().getClassesRoots();
}
@@ -3,9 +3,13 @@ package com.intellij.roots;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.DependencyScope;
import com.intellij.openapi.roots.OrderEnumerator;
import com.intellij.openapi.roots.OrderRootsEnumerator;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PathsList;
import com.intellij.util.ArrayUtil;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.openapi.roots.OrderEnumerator.orderEntries;
@@ -89,14 +93,51 @@ public class OrderEnumeratorTest extends ModuleRootManagerTestCase {
assertClassRoots(orderEntries(myModule).exportedOnly());
}
public void testCaching() throws Exception {
final VirtualFile[] roots = orderEntries(myModule).classes().usingCache().getRoots();
assertOrderedEquals(roots, getRtJar());
assertSame(roots, orderEntries(myModule).classes().usingCache().getRoots());
final VirtualFile[] rootsWithoutSdk = orderEntries(myModule).withoutSdk().classes().usingCache().getRoots();
assertEmpty(rootsWithoutSdk);
assertSame(roots, orderEntries(myModule).classes().usingCache().getRoots());
assertSame(rootsWithoutSdk, orderEntries(myModule).withoutSdk().classes().usingCache().getRoots());
addLibraryDependency(myModule, createJDomLibrary());
assertRoots(orderEntries(myModule).classes().usingCache().getPathsList(), getRtJar(), getJDomJar());
assertRoots(orderEntries(myModule).withoutSdk().classes().usingCache().getPathsList(), getJDomJar());
}
public void testCachingUrls() throws Exception {
final String[] urls = orderEntries(myModule).classes().usingCache().getUrls();
assertOrderedEquals(urls, getRtJar().getUrl());
assertSame(urls, orderEntries(myModule).classes().usingCache().getUrls());
final String[] sourceUrls = orderEntries(myModule).sources().usingCache().getUrls();
assertEmpty(sourceUrls);
assertSame(urls, orderEntries(myModule).classes().usingCache().getUrls());
assertSame(sourceUrls, orderEntries(myModule).sources().usingCache().getUrls());
addLibraryDependency(myModule, createJDomLibrary());
assertOrderedEquals(orderEntries(myModule).classes().usingCache().getUrls(), getRtJar().getUrl(), getJDomJar().getUrl());
assertOrderedEquals(orderEntries(myModule).sources().usingCache().getUrls(), getJDomSources().getUrl());
}
private static void assertClassRoots(final OrderEnumerator enumerator, VirtualFile... files) {
assertRoots(enumerator.getPathsList(), files);
assertEnumeratorRoots(enumerator.classes(), files);
}
private static void assertSourceRoots(final OrderEnumerator enumerator, VirtualFile... files) {
final PathsList result = new PathsList();
enumerator.sources().collectPaths(result);
assertRoots(result, files);
assertEnumeratorRoots(enumerator.sources(), files);
}
private static void assertEnumeratorRoots(OrderRootsEnumerator rootsEnumerator, VirtualFile... files) {
assertOrderedEquals(rootsEnumerator.getRoots(), files);
List<String> expectedUrls = new ArrayList<String>();
for (VirtualFile file : files) {
expectedUrls.add(file.getUrl());
}
assertOrderedEquals(rootsEnumerator.getUrls(), ArrayUtil.toStringArray(expectedUrls));
}
}
@@ -18,10 +18,9 @@ package com.intellij.openapi.roots;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Collection;
/**
* @author nik
@@ -37,7 +36,7 @@ public abstract class OrderEnumerationHandler {
return true;
}
public boolean addCustomOutput(@NotNull ModuleOrderEntry orderEntry, boolean productionOnly, @NotNull List<VirtualFile> result) {
public boolean addCustomOutput(@NotNull ModuleOrderEntry orderEntry, boolean productionOnly, @NotNull Collection<String> urls) {
return false;
}
}
@@ -25,8 +25,6 @@ import com.intellij.util.PathsList;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Interface for convenient processing dependencies of a module or a project. Allows to process {@link OrderEntry}s and collect classes
* and source roots.<p>
@@ -112,14 +110,14 @@ public abstract class OrderEnumerator {
/**
* @return classes roots for all entries processed by this enumerator
*/
public Collection<VirtualFile> getClassesRoots() {
public VirtualFile[] getClassesRoots() {
return classes().getRoots();
}
/**
* @return source roots for all entries processed by this enumerator
*/
public Collection<VirtualFile> getSourceRoots() {
public VirtualFile[] getSourceRoots() {
return sources().getRoots();
}
@@ -19,10 +19,8 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PathsList;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Interface for processing classes or source roots.
* Interface for processing roots of OrderEntry's from {@link OrderEnumerator}.
*
* @see OrderEnumerator#classes()
* @see OrderEnumerator#sources()
@@ -30,12 +28,34 @@ import java.util.Collection;
* @author nik
*/
public interface OrderRootsEnumerator {
/**
* @return all roots processed by this enumerator
*/
@NotNull
Collection<VirtualFile> getRoots();
VirtualFile[] getRoots();
/**
* @return urls of all roots processed by this enumerator
*/
@NotNull
String[] getUrls();
/**
* @return list of path to all roots processed by this enumerator
*/
@NotNull
PathsList getPathsList();
/**
* Add all source roots processed by this enumerator to <code>list</code>
* @param list list
*/
void collectPaths(@NotNull PathsList list);
/**
* If roots for this enumerator are already evaluated the cached result will be used. Otherwise roots will be evaluated and cached for
* subsequent calls
* @return this instance
*/
OrderRootsEnumerator usingCache();
}
@@ -442,7 +442,7 @@ public class FindInProjectUtil {
SearchScope customScope = findModel.getCustomScope();
if (success && customScope instanceof GlobalSearchScope && ((GlobalSearchScope)customScope).isSearchInLibraries()) {
OrderEnumerator enumerator = module == null ? OrderEnumerator.orderEntries(project) : OrderEnumerator.orderEntries(module);
final Collection<VirtualFile> librarySources = enumerator.withoutModuleSourceEntries().withoutDepModules().getSourceRoots();
final VirtualFile[] librarySources = enumerator.withoutModuleSourceEntries().withoutDepModules().getSourceRoots();
iterateAll(librarySources, (GlobalSearchScope)customScope, iterator);
}
}
@@ -462,7 +462,7 @@ public class FindInProjectUtil {
}
}
private static boolean iterateAll(Collection<VirtualFile> files, final GlobalSearchScope searchScope, final ContentIterator iterator) {
private static boolean iterateAll(VirtualFile[] files, final GlobalSearchScope searchScope, final ContentIterator iterator) {
final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
final VirtualFileFilter contentFilter = new VirtualFileFilter() {
public boolean accept(final VirtualFile file) {
@@ -27,8 +27,8 @@ import org.jetbrains.annotations.NotNull;
public class ModuleOrderEnumerator extends OrderEnumeratorBase {
private final RootModelImpl myRootModel;
public ModuleOrderEnumerator(RootModelImpl rootModel) {
super(rootModel.getModule(), rootModel.getProject());
public ModuleOrderEnumerator(RootModelImpl rootModel, final OrderRootsCache cache) {
super(rootModel.getModule(), rootModel.getProject(), cache);
myRootModel = rootModel;
}
@@ -76,6 +76,7 @@ public class ModuleRootManagerImpl extends ModuleRootManager implements ModuleCo
private final ModuleFileIndexImpl myFileIndex;
private boolean myIsDisposed = false;
private boolean isModuleAdded = false;
private final OrderRootsCache myOrderRootsCache;
private final Map<OrderRootType, Set<VirtualFilePointer>> myCachedFiles = new THashMap<OrderRootType, Set<VirtualFilePointer>>();
private final Map<OrderRootType, Set<VirtualFilePointer>> myCachedExportedFiles = new THashMap<OrderRootType, Set<VirtualFilePointer>>();
private final Map<RootModelImpl, Throwable> myModelCreations = new THashMap<RootModelImpl, Throwable>();
@@ -92,6 +93,7 @@ public class ModuleRootManagerImpl extends ModuleRootManager implements ModuleCo
myFileIndex = new ModuleFileIndexImpl(myModule, directoryIndex);
myRootModel = new RootModelImpl(this, myProjectRootManager, myFilePointerManager);
myOrderRootsCache = new OrderRootsCache(module);
}
@NotNull
@@ -223,19 +225,7 @@ public class ModuleRootManagerImpl extends ModuleRootManager implements ModuleCo
}
myCachedFiles.put(type, cachedFiles);
}
return convertPointers(cachedFiles);
}
private static VirtualFile[] convertPointers(final Set<VirtualFilePointer> cachedFiles) {
final LinkedHashSet<VirtualFile> result = new LinkedHashSet<VirtualFile>();
for (VirtualFilePointer cachedFile : cachedFiles) {
final VirtualFile virtualFile = cachedFile.getFile();
if (virtualFile != null) {
result.add(virtualFile);
}
}
return VfsUtil.toVirtualFileArray(result);
return VfsUtil.toVirtualFileArray(OrderRootsCache.convertPointersToFiles(cachedFiles));
}
@NotNull
@@ -360,7 +350,7 @@ public class ModuleRootManagerImpl extends ModuleRootManager implements ModuleCo
@NotNull
@Override
public OrderEnumerator orderEntries() {
return myRootModel.orderEntries();
return new ModuleOrderEnumerator(myRootModel, myOrderRootsCache);
}
List<String> getUrlsForOtherModules(OrderRootType rootType, Set<Module> processed) {
@@ -420,7 +410,7 @@ public class ModuleRootManagerImpl extends ModuleRootManager implements ModuleCo
myCachedExportedFiles.put(rootType, filePointers);
}
return convertPointers(filePointers);
return VfsUtil.toVirtualFileArray(OrderRootsCache.convertPointersToFiles(filePointers));
}
@NotNull
@@ -534,6 +524,7 @@ public class ModuleRootManagerImpl extends ModuleRootManager implements ModuleCo
public void dropCaches() {
myCachedFiles.clear();
myCachedExportedFiles.clear();
myOrderRootsCache.clearCache();
}
public ModuleRootManagerState getState() {
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.roots.impl;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
@@ -22,11 +23,15 @@ import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.Processor;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -34,6 +39,7 @@ import java.util.Set;
* @author nik
*/
abstract class OrderEnumeratorBase extends OrderEnumerator {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.OrderEnumeratorBase");
private boolean myProductionOnly;
private boolean myCompileOnly;
private boolean myRuntimeOnly;
@@ -47,8 +53,10 @@ abstract class OrderEnumeratorBase extends OrderEnumerator {
private Condition<OrderEntry> myCondition;
private List<OrderEnumerationHandler> myCustomHandlers;
private ModulesProvider myModulesProvider;
private OrderRootsCache myCache;
public OrderEnumeratorBase(@Nullable Module module, @NotNull Project project) {
public OrderEnumeratorBase(@Nullable Module module, @NotNull Project project, @Nullable OrderRootsCache cache) {
myCache = cache;
for (OrderEnumerationHandler handler : OrderEnumerationHandler.EP_NAME.getExtensions()) {
if (handler.isApplicable(project) && (module == null || handler.isApplicable(module))) {
if (myCustomHandlers == null) {
@@ -147,6 +155,29 @@ abstract class OrderEnumeratorBase extends OrderEnumerator {
return ModuleRootManager.getInstance(module);
}
public OrderRootsCache getCache() {
LOG.assertTrue(myCache != null, "Caching supported only for OrderEnumerator obtained by using OrderEnumerator.orderEntries(module) or ModuleRootManager.getInstance(module).orderEntries() methods");
LOG.assertTrue(myCondition == null, "Caching not supported for OrderEnumerator with 'satisfying(Condition)' option");
LOG.assertTrue(myModulesProvider == null, "Caching not supported for OrderEnumerator with 'using(ModulesProvider)' option");
return myCache;
}
public int getFlags() {
int flags = 0;
int i = 0;
if (myProductionOnly) flags |= 1 << (i++);
if (myCompileOnly) flags |= 1 << (i++);
if (myRuntimeOnly) flags |= 1 << (i++);
if (myWithoutJdk) flags |= 1 << (i++);
if (myWithoutLibraries) flags |= 1 << (i++);
if (myWithoutDepModules) flags |= 1 << (i++);
if (myWithoutThisModuleContent) flags |= 1 << (i++);
if (myRecursively) flags |= 1 << (i++);
if (myRecursivelyExportedOnly) flags |= 1 << (i++);
if (myExportedOnly) flags |= 1 << i;
return flags;
}
protected void processEntries(final ModuleRootModel rootModel,
Processor<OrderEntry> processor,
Set<Module> processed, boolean firstLevel) {
@@ -235,10 +266,26 @@ abstract class OrderEnumeratorBase extends OrderEnumerator {
return processor.myValue;
}
boolean addCustomOutput(ModuleOrderEntry moduleOrderEntry, List<VirtualFile> list) {
boolean addCustomOutput(ModuleOrderEntry moduleOrderEntry, Collection<VirtualFile> result) {
if (myCustomHandlers != null) {
for (OrderEnumerationHandler handler : myCustomHandlers) {
if (handler.addCustomOutput(moduleOrderEntry, myProductionOnly, list)) {
final List<String> urls = new ArrayList<String>();
final boolean added = handler.addCustomOutput(moduleOrderEntry, myProductionOnly, urls);
for (String url : urls) {
ContainerUtil.addIfNotNull(VirtualFileManager.getInstance().findFileByUrl(url), result);
}
if (added) {
return true;
}
}
}
return false;
}
boolean addCustomOutputUrls(ModuleOrderEntry moduleOrderEntry, Collection<String> result) {
if (myCustomHandlers != null) {
for (OrderEnumerationHandler handler : myCustomHandlers) {
if (handler.addCustomOutput(moduleOrderEntry, myProductionOnly, result)) {
return true;
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.roots.impl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerContainer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.util.containers.LockPoolSynchronizedMap;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @author nik
*/
public class OrderRootsCache {
private final LockPoolSynchronizedMap<CacheKey, VirtualFilePointerContainer> myRoots = new LockPoolSynchronizedMap<CacheKey, VirtualFilePointerContainer>();
private final Disposable myParentDisposable;
public OrderRootsCache(Disposable parentDisposable) {
myParentDisposable = parentDisposable;
}
public VirtualFilePointerContainer setCachedRoots(OrderRootType rootType, int flags, Collection<String> urls) {
final VirtualFilePointerContainer container = VirtualFilePointerManager.getInstance().createContainer(myParentDisposable);
for (String url : urls) {
container.add(url);
}
myRoots.put(new CacheKey(rootType, flags), container);
return container;
}
@Nullable
public VirtualFile[] getCachedRoots(OrderRootType rootType, int flags) {
final VirtualFilePointerContainer cached = myRoots.get(new CacheKey(rootType, flags));
return cached != null ? cached.getFiles() : null;
}
@Nullable
public String[] getCachedUrls(OrderRootType rootType, int flags) {
final VirtualFilePointerContainer cached = myRoots.get(new CacheKey(rootType, flags));
return cached != null ? cached.getUrls() : null;
}
public void clearCache() {
for (VirtualFilePointerContainer container : myRoots.values()) {
container.killAll();
}
myRoots.clear();
}
public static Set<VirtualFile> convertPointersToFiles(Set<VirtualFilePointer> cachedFiles) {
final LinkedHashSet<VirtualFile> result = new LinkedHashSet<VirtualFile>();
for (VirtualFilePointer cachedFile : cachedFiles) {
final VirtualFile virtualFile = cachedFile.getFile();
if (virtualFile != null) {
result.add(virtualFile);
}
}
return result;
}
private static final class CacheKey {
private final OrderRootType myRootType;
private int myFlags;
private CacheKey(OrderRootType rootType, int flags) {
myRootType = rootType;
myFlags = flags;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CacheKey cacheKey = (CacheKey)o;
return myFlags == cacheKey.myFlags && myRootType.equals(cacheKey.myRootType);
}
@Override
public int hashCode() {
return 31 * myRootType.hashCode() + myFlags;
}
}
}
@@ -17,15 +17,14 @@ package com.intellij.openapi.roots.impl;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PathsList;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.*;
/**
* @author nik
@@ -33,6 +32,7 @@ import java.util.List;
public class OrderRootsEnumeratorImpl implements OrderRootsEnumerator {
private final OrderEnumeratorBase myOrderEnumerator;
private final OrderRootType myRootType;
private boolean myUsingCache;
public OrderRootsEnumeratorImpl(OrderEnumeratorBase orderEnumerator, OrderRootType rootType) {
myOrderEnumerator = orderEnumerator;
@@ -41,9 +41,94 @@ public class OrderRootsEnumeratorImpl implements OrderRootsEnumerator {
@NotNull
@Override
public Collection<VirtualFile> getRoots() {
final List<VirtualFile> result = new ArrayList<VirtualFile>();
collectRoots(result);
public VirtualFile[] getRoots() {
if (myUsingCache) {
final OrderRootsCache cache = myOrderEnumerator.getCache();
if (cache != null) {
final int flags = myOrderEnumerator.getFlags();
final VirtualFile[] cached = cache.getCachedRoots(myRootType, flags);
if (cached == null) {
return cache.setCachedRoots(myRootType, flags, computeRootsUrls()).getFiles();
}
else {
return cached;
}
}
}
return VfsUtil.toVirtualFileArray(computeRoots());
}
@NotNull
@Override
public String[] getUrls() {
if (myUsingCache) {
final OrderRootsCache cache = myOrderEnumerator.getCache();
if (cache != null) {
final int flags = myOrderEnumerator.getFlags();
String[] cached = cache.getCachedUrls(myRootType, flags);
if (cached == null) {
return cache.setCachedRoots(myRootType, flags, computeRootsUrls()).getUrls();
}
else {
return cached;
}
}
}
return ArrayUtil.toStringArray(computeRootsUrls());
}
private Collection<VirtualFile> computeRoots() {
final Collection<VirtualFile> result = new LinkedHashSet<VirtualFile>();
myOrderEnumerator.forEach(new Processor<OrderEntry>() {
@Override
public boolean process(OrderEntry orderEntry) {
if (orderEntry instanceof ModuleSourceOrderEntry) {
collectModuleRoots(((ModuleSourceOrderEntry)orderEntry).getRootModel(), result);
}
else if (orderEntry instanceof ModuleOrderEntry) {
ModuleOrderEntry moduleOrderEntry = (ModuleOrderEntry)orderEntry;
final Module module = moduleOrderEntry.getModule();
if (module != null) {
if (myOrderEnumerator.addCustomOutput(moduleOrderEntry, result)) {
return true;
}
collectModuleRoots(myOrderEnumerator.getRootModel(module), result);
}
}
else {
Collections.addAll(result, orderEntry.getFiles(myRootType));
}
return true;
}
});
return result;
}
private Collection<String> computeRootsUrls() {
final Collection<String> result = new LinkedHashSet<String>();
myOrderEnumerator.forEach(new Processor<OrderEntry>() {
@Override
public boolean process(OrderEntry orderEntry) {
if (orderEntry instanceof ModuleSourceOrderEntry) {
collectModuleRootsUrls(((ModuleSourceOrderEntry)orderEntry).getRootModel(), result);
}
else if (orderEntry instanceof ModuleOrderEntry) {
ModuleOrderEntry moduleOrderEntry = (ModuleOrderEntry)orderEntry;
final Module module = moduleOrderEntry.getModule();
if (module != null) {
if (myOrderEnumerator.addCustomOutputUrls(moduleOrderEntry, result)) {
return true;
}
collectModuleRootsUrls(myOrderEnumerator.getRootModel(module), result);
}
}
else {
Collections.addAll(result, orderEntry.getUrls(myRootType));
}
return true;
}
});
return result;
}
@@ -60,64 +145,56 @@ public class OrderRootsEnumeratorImpl implements OrderRootsEnumerator {
list.addVirtualFiles(getRoots());
}
private void collectRoots(final List<VirtualFile> list) {
myOrderEnumerator.forEach(new Processor<OrderEntry>() {
@Override
public boolean process(OrderEntry orderEntry) {
if (orderEntry instanceof ModuleSourceOrderEntry) {
collectModulePaths(((ModuleSourceOrderEntry)orderEntry).getRootModel(), list);
}
else if (orderEntry instanceof ModuleOrderEntry) {
ModuleOrderEntry moduleOrderEntry = (ModuleOrderEntry)orderEntry;
final Module module = moduleOrderEntry.getModule();
if (module != null) {
if (myOrderEnumerator.addCustomOutput(moduleOrderEntry, list)) {
return true;
}
collectModulePaths(myOrderEnumerator.getRootModel(module), list);
}
}
else {
Collections.addAll(list, orderEntry.getFiles(myRootType));
}
return true;
}
});
@Override
public OrderRootsEnumerator usingCache() {
myUsingCache = true;
return this;
}
private void collectModulePaths(ModuleRootModel rootModel, List<VirtualFile> list) {
private void collectModuleRoots(ModuleRootModel rootModel, Collection<VirtualFile> result) {
if (myRootType.equals(OrderRootType.SOURCES)) {
if (myOrderEnumerator.isProductionOnly()) {
ContentEntry[] contentEntries = rootModel.getContentEntries();
for (ContentEntry contentEntry : contentEntries) {
for (ContentEntry contentEntry : rootModel.getContentEntries()) {
for (SourceFolder folder : contentEntry.getSourceFolders()) {
VirtualFile root = folder.getFile();
if (root != null && !folder.isTestSource()) {
list.add(root);
result.add(root);
}
}
}
}
else {
Collections.addAll(list, rootModel.getSourceRoots());
Collections.addAll(result, rootModel.getSourceRoots());
}
}
else if (myRootType.equals(OrderRootType.CLASSES)) {
final CompilerModuleExtension extension = rootModel.getModuleExtension(CompilerModuleExtension.class);
if (extension != null) {
VirtualFile testOutput = extension.getCompilerOutputPathForTests();
if (myOrderEnumerator.isProductionOnly()) {
testOutput = null;
}
Collections.addAll(result, extension.getOutputRoots(!myOrderEnumerator.isProductionOnly()));
}
}
}
if (testOutput != null) {
list.add(testOutput);
}
VirtualFile output = extension.getCompilerOutputPath();
if (output != null && !output.equals(testOutput)) {
list.add(output);
private void collectModuleRootsUrls(ModuleRootModel rootModel, Collection<String> result) {
if (myRootType.equals(OrderRootType.SOURCES)) {
if (myOrderEnumerator.isProductionOnly()) {
for (ContentEntry contentEntry : rootModel.getContentEntries()) {
for (SourceFolder folder : contentEntry.getSourceFolders()) {
if (!folder.isTestSource()) {
result.add(folder.getUrl());
}
}
}
}
else {
Collections.addAll(result, rootModel.getSourceRootUrls());
}
}
else if (myRootType.equals(OrderRootType.CLASSES)) {
final CompilerModuleExtension extension = rootModel.getModuleExtension(CompilerModuleExtension.class);
if (extension != null) {
Collections.addAll(result, extension.getOutputRootUrls(!myOrderEnumerator.isProductionOnly()));
}
}
}
@@ -31,7 +31,7 @@ public class ProjectOrderEnumerator extends OrderEnumeratorBase {
private Project myProject;
public ProjectOrderEnumerator(Project project) {
super(null, project);
super(null, project, null);
myProject = project;
}
@@ -521,7 +521,7 @@ public class RootModelImpl implements ModifiableRootModel {
@NotNull
@Override
public OrderEnumerator orderEntries() {
return new ModuleOrderEnumerator(this);
return new ModuleOrderEnumerator(this, null);
}
public Project getProject() {
@@ -20,14 +20,13 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.CompilerModuleExtension;
import com.intellij.openapi.roots.ModuleOrderEntry;
import com.intellij.openapi.roots.OrderEnumerationHandler;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.model.MavenArtifact;
import org.jetbrains.idea.maven.model.MavenConstants;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import java.util.List;
import java.util.Collection;
/**
* @author nik
@@ -52,7 +51,7 @@ public class MavenOrderEnumeratorHandler extends OrderEnumerationHandler {
@Override
public boolean addCustomOutput(@NotNull ModuleOrderEntry orderEntry,
boolean productionOnly,
@NotNull List<VirtualFile> result) {
@NotNull Collection<String> urls) {
final Module ownerModule = orderEntry.getOwnerModule();
final Module depModule = orderEntry.getModule();
if (depModule == null) return false;
@@ -70,18 +69,18 @@ public class MavenOrderEnumeratorHandler extends OrderEnumerationHandler {
if (productionOnly && MavenConstants.SCOPE_TEST.equals(each.getScope())) continue;
boolean isTestJar = MavenConstants.TYPE_TEST_JAR.equals(each.getType()) || "tests".equals(each.getClassifier());
addOutput(depModule, isTestJar, result);
addOutput(depModule, isTestJar, urls);
}
return true;
}
private static void addOutput(Module module, boolean tests, List<VirtualFile> result) {
private static void addOutput(Module module, boolean tests, Collection<String> urls) {
CompilerModuleExtension ex = CompilerModuleExtension.getInstance(module);
if (ex == null) return;
VirtualFile output = tests ? ex.getCompilerOutputPathForTests() : ex.getCompilerOutputPath();
String output = tests ? ex.getCompilerOutputUrlForTests() : ex.getCompilerOutputUrl();
if (output != null) {
result.add(output);
urls.add(output);
}
}
}
@@ -39,6 +39,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
public class SearchScope implements JDOMExternalizable {
@@ -214,8 +215,8 @@ public class SearchScope implements JDOMExternalizable {
if (searchScope.isSearchInLibraries()) {
final OrderEnumerator enumerator = OrderEnumerator.orderEntries(project).withoutModuleSourceEntries().withoutDepModules();
final Collection<VirtualFile> libraryFiles = new THashSet<VirtualFile>();
libraryFiles.addAll(enumerator.getClassesRoots());
libraryFiles.addAll(enumerator.getSourceRoots());
Collections.addAll(libraryFiles, enumerator.getClassesRoots());
Collections.addAll(libraryFiles, enumerator.getSourceRoots());
final Processor<VirtualFile> adapter = new Processor<VirtualFile>() {
public boolean process(VirtualFile virtualFile) {
return iterator.processFile(virtualFile);