root index: store information to which unloaded module a content root belongs (IDEA-27471)

This information may be used to provide special icon and actions for unloaded modules in Project View.
This commit is contained in:
nik
2017-06-02 17:41:02 +02:00
parent 28db420991
commit 36d5139503
7 changed files with 47 additions and 10 deletions
@@ -39,7 +39,14 @@ public class DirectoryIndexForUnloadedModuleTest extends DirectoryIndexTestCase
ModuleManager.getInstance(myProject).setUnloadedModules(Arrays.asList("unloaded"));
assertExcluded(file, null);
assertExcluded(contentRoot, null);
assertFromUnloadedModule(file, "unloaded");
assertFromUnloadedModule(contentRoot, "unloaded");
}
private void assertFromUnloadedModule(VirtualFile file, String moduleName) {
DirectoryInfo info = myIndex.getInfoForFile(file);
assertTrue(info.toString(), info.isExcluded(file));
assertNull(info.getModule());
assertEquals(moduleName, info.getUnloadedModuleName());
}
}
@@ -55,11 +55,13 @@ public abstract class DirectoryIndexTestCase extends IdeaTestCase {
DirectoryInfo info = myIndex.getInfoForFile(file);
assertFalse(info.toString(), info.isInProject(file));
assertFalse(info.toString(), info.isExcluded(file));
assertNull(info.toString(), info.getUnloadedModuleName());
}
protected void assertExcluded(VirtualFile file, Module module) {
DirectoryInfo info = myIndex.getInfoForFile(file);
assertTrue(info.toString(), info.isExcluded(file));
assertNull(info.toString(), info.getUnloadedModuleName());
assertEquals(module, info.getModule());
}
@@ -78,6 +80,7 @@ public abstract class DirectoryIndexTestCase extends IdeaTestCase {
protected DirectoryInfo assertInProject(VirtualFile file) {
DirectoryInfo info = myIndex.getInfoForFile(file);
assertTrue(file.toString(), info.isInProject(file));
assertNull(info.toString(), info.getUnloadedModuleName());
myIndex.assertConsistency(info);
return info;
}
@@ -86,4 +86,12 @@ public abstract class DirectoryInfo {
@Nullable
public abstract Module getModule();
/**
* Return name of an unloaded module to which content this file or directory belongs
* or {@code null} if it doesn't belong to an unloaded module.
* @see com.intellij.openapi.module.UnloadedModuleDescription
*/
@Nullable
public abstract String getUnloadedModuleName();
}
@@ -34,9 +34,10 @@ public class DirectoryInfoImpl extends DirectoryInfo {
protected final boolean myInLibrarySource;
protected final boolean myExcluded;
private final byte mySourceRootTypeId;
private final String myUnloadedModuleName;
DirectoryInfoImpl(@NotNull VirtualFile root, Module module, VirtualFile contentRoot, VirtualFile sourceRoot, VirtualFile libraryClassRoot,
boolean inModuleSource, boolean inLibrarySource, boolean isExcluded, int sourceRootTypeId) {
boolean inModuleSource, boolean inLibrarySource, boolean isExcluded, int sourceRootTypeId, @Nullable String unloadedModuleName) {
myRoot = root;
this.module = module;
this.libraryClassRoot = libraryClassRoot;
@@ -45,6 +46,7 @@ public class DirectoryInfoImpl extends DirectoryInfo {
myInModuleSource = inModuleSource;
myInLibrarySource = inLibrarySource;
myExcluded = isExcluded;
myUnloadedModuleName = unloadedModuleName;
if (sourceRootTypeId > MAX_ROOT_TYPE_ID) {
throw new IllegalArgumentException(
"Module source root type id " + sourceRootTypeId + " exceeds the maximum allowable value (" + MAX_ROOT_TYPE_ID + ")");
@@ -135,6 +137,11 @@ public class DirectoryInfoImpl extends DirectoryInfo {
return mySourceRootTypeId;
}
@Override
public String getUnloadedModuleName() {
return myUnloadedModuleName;
}
@NotNull
public VirtualFile getRoot() {
return myRoot;
@@ -34,8 +34,9 @@ public class DirectoryInfoWithExcludePatterns extends DirectoryInfoImpl {
VirtualFile libraryClassRoot, boolean inModuleSource, boolean inLibrarySource, boolean isExcluded,
int sourceRootTypeId,
@Nullable FileTypeAssocTable<Boolean> contentExcludePatterns,
@Nullable FileTypeAssocTable<Boolean> libraryExcludePatterns) {
super(root, module, contentRoot, sourceRoot, libraryClassRoot, inModuleSource, inLibrarySource, isExcluded, sourceRootTypeId);
@Nullable FileTypeAssocTable<Boolean> libraryExcludePatterns,
@Nullable String unloadedModuleName) {
super(root, module, contentRoot, sourceRoot, libraryClassRoot, inModuleSource, inLibrarySource, isExcluded, sourceRootTypeId, unloadedModuleName);
myContentExcludePatterns = contentExcludePatterns;
myLibraryExcludePatterns = libraryExcludePatterns;
LOG.assertTrue(myContentExcludePatterns != null || myLibraryExcludePatterns != null,
@@ -113,6 +113,11 @@ class NonProjectDirectoryInfo extends DirectoryInfo {
return null;
}
@Override
public String getUnloadedModuleName() {
return null;
}
public int getSourceRootTypeId() {
return 0;
}
@@ -207,7 +207,10 @@ public class RootIndex {
}
for (UnloadedModuleDescription description : moduleManager.getUnloadedModuleDescriptions()) {
for (VirtualFilePointer pointer : description.getContentRoots()) {
ContainerUtil.addIfNotNull(info.excludedFromProject, pointer.getFile());
VirtualFile contentRoot = pointer.getFile();
if (contentRoot != null) {
info.contentRootOfUnloaded.put(contentRoot, description.getName());
}
}
}
return info;
@@ -563,6 +566,7 @@ public class RootIndex {
@NotNull final Set<VirtualFile> libraryOrSdkSources = ContainerUtil.newHashSet();
@NotNull final Set<VirtualFile> libraryOrSdkClasses = ContainerUtil.newHashSet();
@NotNull final Map<VirtualFile, Module> contentRootOf = ContainerUtil.newHashMap();
@NotNull final Map<VirtualFile, String> contentRootOfUnloaded = ContainerUtil.newHashMap();
@NotNull final MultiMap<VirtualFile, Module> sourceRootOf = MultiMap.createSet();
@NotNull final TObjectIntHashMap<VirtualFile> rootTypeId = new TObjectIntHashMap<>();
@NotNull final MultiMap<VirtualFile, /*Library|SyntheticLibrary*/ Object> excludedFromLibraries = MultiMap.createSmart();
@@ -578,6 +582,7 @@ public class RootIndex {
LinkedHashSet<VirtualFile> result = ContainerUtil.newLinkedHashSet();
result.addAll(classAndSourceRoots);
result.addAll(contentRootOf.keySet());
result.addAll(contentRootOfUnloaded.keySet());
result.addAll(excludedFromLibraries.keySet());
result.addAll(excludedFromModule.keySet());
result.addAll(excludedFromProject);
@@ -604,7 +609,7 @@ public class RootIndex {
if (module != null && (excludedFrom != module || underExcludedSourceRoot && sourceRootOwners.contains(module))) {
return root;
}
if (excludedFrom != null || excludedFromProject.contains(root)) {
if (excludedFrom != null || excludedFromProject.contains(root) || contentRootOfUnloaded.containsKey(root)) {
if (sourceRootOwners != null) {
underExcludedSourceRoot = true;
}
@@ -643,7 +648,7 @@ public class RootIndex {
@Nullable
private VirtualFile findNearestContentRootForExcluded(@NotNull List<VirtualFile> hierarchy) {
for (VirtualFile root : hierarchy) {
if (contentRootOf.containsKey(root)) {
if (contentRootOf.containsKey(root) || contentRootOfUnloaded.containsKey(root)) {
return root;
}
}
@@ -809,15 +814,16 @@ public class RootIndex {
int typeId = moduleSourceRoot != null ? info.rootTypeId.get(moduleSourceRoot) : 0;
Module module = info.contentRootOf.get(nearestContentRoot);
String unloadedModuleName = info.contentRootOfUnloaded.get(nearestContentRoot);
FileTypeAssocTable<Boolean> contentExcludePatterns = moduleContentRoot != null ? info.excludeFromContentRootTables.get(moduleContentRoot) : null;
FileTypeAssocTable<Boolean> libraryExcludePatterns = getLibraryExclusionPatterns(librarySourceRootInfo);
DirectoryInfo directoryInfo = contentExcludePatterns != null || libraryExcludePatterns != null
? new DirectoryInfoWithExcludePatterns(root, module, nearestContentRoot, sourceRoot, libraryClassRoot,
inModuleSources, inLibrarySource, !inProject, typeId,
contentExcludePatterns, libraryExcludePatterns)
contentExcludePatterns, libraryExcludePatterns, unloadedModuleName)
: new DirectoryInfoImpl(root, module, nearestContentRoot, sourceRoot, libraryClassRoot, inModuleSources,
inLibrarySource, !inProject, typeId);
inLibrarySource, !inProject, typeId, unloadedModuleName);
String packagePrefix = info.calcPackagePrefix(root, hierarchy, moduleContentRoot, libraryClassRoot, librarySourceRoot);