DirectoryInfo made immutable for less memory

This commit is contained in:
Alexey Kudravtsev
2012-11-14 18:07:37 +04:00
parent f19a33c30e
commit 1a2ac604c5
5 changed files with 195 additions and 160 deletions
@@ -32,12 +32,12 @@ import com.intellij.testFramework.IdeaTestCase;
import com.intellij.testFramework.PlatformTestCase;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -337,20 +337,20 @@ public class DirectoryIndexTest extends IdeaTestCase {
VirtualFile output1 = myModule1Dir.createChildDirectory(this, "output1");
VirtualFile output2 = myModule1Dir.createChildDirectory(this, "output2");
assertNotNull(myIndex.getInfoForDirectory(output1));
assertNotNull(myIndex.getInfoForDirectory(output2));
checkInfoNotNull(output1);
checkInfoNotNull(output2);
getCompilerProjectExtension().setCompilerOutputUrl(output1.getUrl());
fireRootsChanged();
assertNull(myIndex.getInfoForDirectory(output1));
assertNotNull(myIndex.getInfoForDirectory(output2));
checkInfoNull(output1);
checkInfoNotNull(output2);
getCompilerProjectExtension().setCompilerOutputUrl(output2.getUrl());
fireRootsChanged();
assertNotNull(myIndex.getInfoForDirectory(output1));
assertNull(myIndex.getInfoForDirectory(output2));
checkInfoNotNull(output1);
checkInfoNull(output2);
}
private void fireRootsChanged() {
@@ -363,10 +363,10 @@ public class DirectoryIndexTest extends IdeaTestCase {
VirtualFile module2Output = myModule1Dir.createChildDirectory(this, "module2Output");
VirtualFile module2TestOutput = myModule2Dir.createChildDirectory(this, "module2TestOutput");
assertNotNull(myIndex.getInfoForDirectory(excluded));
assertNotNull(myIndex.getInfoForDirectory(projectOutput));
assertNotNull(myIndex.getInfoForDirectory(module2Output));
assertNotNull(myIndex.getInfoForDirectory(module2TestOutput));
checkInfoNotNull(excluded);
checkInfoNotNull(projectOutput);
checkInfoNotNull(module2Output);
checkInfoNotNull(module2TestOutput);
getCompilerProjectExtension().setCompilerOutputUrl(projectOutput.getUrl());
@@ -375,44 +375,37 @@ public class DirectoryIndexTest extends IdeaTestCase {
PsiTestUtil.setCompilerOutputPath(myModule2, module2TestOutput.getUrl(), true);
PsiTestUtil.setExcludeCompileOutput(myModule2, true);
assertNull(myIndex.getInfoForDirectory(excluded));
assertNull(myIndex.getInfoForDirectory(projectOutput));
assertNull(myIndex.getInfoForDirectory(module2Output));
assertNull(myIndex.getInfoForDirectory(module2TestOutput));
checkInfoNull(excluded);
checkInfoNull(projectOutput);
checkInfoNull(module2Output);
checkInfoNull(module2TestOutput);
excluded.delete(this);
projectOutput.delete(this);
module2Output.delete(this);
module2TestOutput.delete(this);
final List<Boolean> isExcluded = new ArrayList<Boolean>();
final List<VirtualFile> created = new ArrayList<VirtualFile>();
VirtualFileListener l = new VirtualFileAdapter() {
@Override
public void fileCreated(VirtualFileEvent e) {
isExcluded.add(myIndex.getInfoForDirectory(e.getFile()) == null);
VirtualFile file = e.getFile();
checkInfoNull(file);
created.add(file);
}
};
VirtualFileManager.getInstance().addVirtualFileListener(l);
try {
excluded = myModule1Dir.createChildDirectory(this, excluded.getName());
projectOutput = myModule1Dir.createChildDirectory(this, projectOutput.getName());
module2Output = myModule1Dir.createChildDirectory(this, module2Output.getName());
module2TestOutput = myModule2Dir.createChildDirectory(this, module2TestOutput.getName());
}
finally {
VirtualFileManager.getInstance().removeVirtualFileListener(l);
}
VirtualFileManager.getInstance().addVirtualFileListener(l, getTestRootDisposable());
excluded = myModule1Dir.createChildDirectory(this, excluded.getName());
projectOutput = myModule1Dir.createChildDirectory(this, projectOutput.getName());
module2Output = myModule1Dir.createChildDirectory(this, module2Output.getName());
module2TestOutput = myModule2Dir.createChildDirectory(this, module2TestOutput.getName());
assertNull(myIndex.getInfoForDirectory(excluded));
assertNull(myIndex.getInfoForDirectory(projectOutput));
assertNull(myIndex.getInfoForDirectory(module2Output));
assertNull(myIndex.getInfoForDirectory(module2TestOutput));
checkInfoNull(excluded);
checkInfoNull(projectOutput);
checkInfoNull(module2Output);
checkInfoNull(module2TestOutput);
assertEquals(4, isExcluded.size());
assertTrue(isExcluded.get(0));
assertTrue(isExcluded.get(1));
assertTrue(isExcluded.get(2));
assertTrue(isExcluded.get(3));
assertEquals(created.toString(), 4, created.size());
}
public void testExcludesShouldBeRecognizedRightOnRefresh() throws Exception {
@@ -430,28 +423,20 @@ public class DirectoryIndexTest extends IdeaTestCase {
boolean created = new File(myModule1Dir.getPath(), "dir/excluded/foo").mkdirs();
assertTrue(created);
final List<Boolean> toAssert = new ArrayList<Boolean>();
VirtualFileListener l = new VirtualFileAdapter() {
@Override
public void fileCreated(VirtualFileEvent e) {
assertEquals("dir", e.getFileName());
VirtualFile file = e.getFile();
toAssert.add(myIndex.getInfoForDirectory(file) != null);
toAssert.add(myIndex.getInfoForDirectory(file.findFileByRelativePath("excluded")) == null);
toAssert.add(myIndex.getInfoForDirectory(file.findFileByRelativePath("excluded/foo")) == null);
checkInfoNotNull(file);
checkInfoNull(file.findFileByRelativePath("excluded"));
checkInfoNull(file.findFileByRelativePath("excluded/foo"));
}
};
VirtualFileManager.getInstance().addVirtualFileListener(l);
try {
VirtualFileManager.getInstance().refresh(false);
}
finally {
VirtualFileManager.getInstance().removeVirtualFileListener(l);
}
assertEquals(Arrays.asList(true, true, true), toAssert);
VirtualFileManager.getInstance().addVirtualFileListener(l, getTestRootDisposable());
VirtualFileManager.getInstance().refresh(false);
}
public void testProcessingNestedContentRootsOfExcludedDirsOnCreation() {
@@ -475,8 +460,8 @@ public class DirectoryIndexTest extends IdeaTestCase {
});
assertNull(myIndex.getInfoForDirectory(LocalFileSystem.getInstance().findFileByIoFile(f.getParentFile().getParentFile())));
assertNotNull(myIndex.getInfoForDirectory(LocalFileSystem.getInstance().findFileByIoFile(f)));
checkInfoNull(LocalFileSystem.getInstance().findFileByIoFile(f.getParentFile().getParentFile()));
checkInfoNotNull(LocalFileSystem.getInstance().findFileByIoFile(f));
}
public void testLibraryDirInContent() throws Exception {
@@ -504,9 +489,7 @@ public class DirectoryIndexTest extends IdeaTestCase {
boolean isInLibrarySource,
@Nullable String packageName,
Module... modulesOfOrderEntries) {
DirectoryInfo info = myIndex.getInfoForDirectory(dir);
assertNotNull(info);
info.assertConsistency();
DirectoryInfo info = checkInfoNotNull(dir);
assertEquals(module, info.getModule());
assertEquals(isInModuleSource, info.isInModuleSource());
assertEquals(isTestSource, info.isTestSource());
@@ -520,20 +503,19 @@ public class DirectoryIndexTest extends IdeaTestCase {
assertEquals(modulesOfOrderEntries.length, info.getOrderEntries().length);
for (Module aModule : modulesOfOrderEntries) {
boolean found = false;
for (OrderEntry orderEntry : info.getOrderEntries()) {
if (orderEntry.getOwnerModule() == aModule) {
found = true;
break;
}
}
assertTrue(found);
OrderEntry found = info.findOrderEntryWithOwnerModule(aModule);
assertNotNull(found);
}
}
private void checkInfoNull(VirtualFile dir) {
DirectoryInfo info = myIndex.getInfoForDirectory(dir);
assertNull(info);
private void checkInfoNull(@NotNull VirtualFile dir) {
assertNull(myIndex.getInfoForDirectory(dir));
}
private DirectoryInfo checkInfoNotNull(@NotNull VirtualFile output2) {
DirectoryInfo info = myIndex.getInfoForDirectory(output2);
assertNotNull(output2.toString(), info);
info.assertConsistency();
return info;
}
private void checkPackage(String packageName, VirtualFile... expectedDirs) {
@@ -109,10 +109,12 @@ public class DirectoryIndexComponent extends DirectoryIndexImpl {
myState = updateStateWithNewFile(file, parent);
}
@NotNull
private IndexState updateStateWithNewFile(@NotNull VirtualFile file, @NotNull VirtualFile parent) {
final IndexState originalState = myState;
IndexState state = originalState;
DirectoryInfo parentInfo = originalState.myDirToInfoMap.get(getId(parent));
int parentId = getId(parent);
DirectoryInfo parentInfo = originalState.myDirToInfoMap.get(parentId);
// fill info for all nested roots
for (Module eachModule : ModuleManager.getInstance(myProject).getModules()) {
@@ -147,7 +149,7 @@ public class DirectoryIndexComponent extends DirectoryIndexImpl {
if (state == originalState) state = state.copy();
state.fillMapWithModuleContent(file, module, parentInfo.getContentRoot(), null);
String parentPackage = state.myDirToPackageName.get(getId(parent));
String parentPackage = state.myDirToPackageName.get(parentId);
if (module != null) {
if (parentInfo.isInModuleSource()) {
@@ -32,16 +32,16 @@ public abstract class DirectoryIndex {
@TestOnly
public abstract void checkConsistency();
public abstract DirectoryInfo getInfoForDirectory(VirtualFile dir);
public abstract DirectoryInfo getInfoForDirectory(@NotNull VirtualFile dir);
public abstract boolean isProjectExcludeRoot(VirtualFile dir);
public abstract boolean isProjectExcludeRoot(@NotNull VirtualFile dir);
@NotNull
public abstract
Query<VirtualFile> getDirectoriesByPackageName(@NotNull String packageName, boolean includeLibrarySources);
@Nullable
public abstract String getPackageName(VirtualFile dir);
public abstract String getPackageName(@NotNull VirtualFile dir);
public abstract boolean isInitialized();
}
@@ -55,7 +55,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
private boolean myInitialized = false;
private boolean myDisposed = false;
public DirectoryIndexImpl(Project project) {
public DirectoryIndexImpl(@NotNull Project project) {
myProject = project;
myExcludePolicies = Extensions.getExtensions(DirectoryIndexExcludePolicy.EP_NAME, myProject);
myState = new IndexState();
@@ -142,18 +142,20 @@ public class DirectoryIndexImpl extends DirectoryIndex {
myState = newState;
}
private boolean isExcludeRootForModule(Module module, VirtualFile excludeRoot) {
private boolean isExcludeRootForModule(@NotNull Module module, VirtualFile excludeRoot) {
for (DirectoryIndexExcludePolicy policy : myExcludePolicies) {
if (policy.isExcludeRootForModule(module, excludeRoot)) return true;
}
return false;
}
protected static ContentEntry[] getContentEntries(Module module) {
@NotNull
protected static ContentEntry[] getContentEntries(@NotNull Module module) {
return ModuleRootManager.getInstance(module).getContentEntries();
}
private static OrderEntry[] getOrderEntries(Module module) {
@NotNull
private static OrderEntry[] getOrderEntries(@NotNull Module module) {
return ModuleRootManager.getInstance(module).getOrderEntries();
}
@@ -162,7 +164,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
}
@Override
public DirectoryInfo getInfoForDirectory(VirtualFile dir) {
public DirectoryInfo getInfoForDirectory(@NotNull VirtualFile dir) {
checkAvailability();
dispatchPendingEvents();
@@ -171,7 +173,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
}
@Override
public boolean isProjectExcludeRoot(VirtualFile dir) {
public boolean isProjectExcludeRoot(@NotNull VirtualFile dir) {
checkAvailability();
return dir instanceof VirtualFileWithId && myState.myProjectExcludeRoots.contains(getId(dir));
}
@@ -233,7 +235,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
}
@Override
public String getPackageName(VirtualFile dir) {
public String getPackageName(@NotNull VirtualFile dir) {
checkAvailability();
if (!(dir instanceof VirtualFileWithId)) return null;
return myState.myDirToPackageName.get(getId(dir));
@@ -317,11 +319,15 @@ public class DirectoryIndexImpl extends DirectoryIndex {
private DirectoryInfo getOrCreateDirInfo(int dirId) {
DirectoryInfo info = myDirToInfoMap.get(dirId);
if (info == null) {
info = new DirectoryInfo();
info = new DirectoryInfo(null, null,null,null,(byte)0,null);
myDirToInfoMap.put(dirId, info);
}
return info;
}
private DirectoryInfo storeInfo(DirectoryInfo info, int dirId) {
myDirToInfoMap.put(dirId, info);
return info;
}
void fillMapWithModuleContent(@NotNull VirtualFile root,
final Module module,
@@ -330,7 +336,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
final int contentRootId = contentRoot == null ? 0 : getId(contentRoot);
VfsUtilCore.visitChildrenRecursively(root, new DirectoryVisitor() {
@Override
protected DirectoryInfo updateInfo(VirtualFile file) {
protected DirectoryInfo updateInfo(@NotNull VirtualFile file) {
if (progress != null) {
progress.checkCanceled();
}
@@ -349,9 +355,9 @@ public class DirectoryIndexImpl extends DirectoryIndex {
}
@Override
protected void afterChildrenVisited(DirectoryInfo info) {
info.setModule(module);
info.setContentRoot(contentRoot);
protected void afterChildrenVisited(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {
info = info.withModule(module).withContentRoot(contentRoot);
storeInfo(info, getId(file));
}
});
}
@@ -372,13 +378,13 @@ public class DirectoryIndexImpl extends DirectoryIndex {
@Override
public void afterChildrenVisited(@NotNull VirtualFile file) {
afterChildrenVisited(myDirectoryInfoStack.pop());
afterChildrenVisited(file, myDirectoryInfoStack.pop());
}
@Nullable
protected abstract DirectoryInfo updateInfo(VirtualFile file);
protected abstract DirectoryInfo updateInfo(@NotNull VirtualFile file);
protected void afterChildrenVisited(DirectoryInfo info) {}
protected void afterChildrenVisited(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {}
}
private boolean isExcluded(int root, @NotNull VirtualFile dir) {
@@ -387,7 +393,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
return excludes != null && excludes.contains(dir.getUrl());
}
private void initModuleContents(Module module, boolean reverseAllSets, ProgressIndicator progress) {
private void initModuleContents(@NotNull Module module, boolean reverseAllSets, @NotNull ProgressIndicator progress) {
progress.checkCanceled();
progress.setText2(ProjectBundle.message("project.index.processing.module.content.progress", module.getName()));
@@ -436,7 +442,7 @@ public class DirectoryIndexImpl extends DirectoryIndex {
private final Stack<String> myPackages = new Stack<String>();
@Override
protected DirectoryInfo updateInfo(VirtualFile file) {
protected DirectoryInfo updateInfo(@NotNull VirtualFile file) {
if (progress != null) {
progress.checkCanceled();
}
@@ -450,9 +456,10 @@ public class DirectoryIndexImpl extends DirectoryIndex {
if (definedPackage != null && definedPackage.isEmpty()) return null; // another source root starts here
}
info.setInModuleSource(true);
info.setTestSource(isTestSource);
info.setSourceRoot(sourceRoot);
info = info.withInModuleSource(true)
.withTestSource(isTestSource)
.withSourceRoot(sourceRoot);
storeInfo(info, id);
String currentPackage = myPackages.isEmpty() ? packageName : getPackageNameForSubdir(myPackages.peek(), file.getName());
myPackages.push(currentPackage);
@@ -461,8 +468,8 @@ public class DirectoryIndexImpl extends DirectoryIndex {
}
@Override
protected void afterChildrenVisited(DirectoryInfo info) {
super.afterChildrenVisited(info);
protected void afterChildrenVisited(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {
super.afterChildrenVisited(file, info);
myPackages.pop();
}
});
@@ -501,8 +508,9 @@ public class DirectoryIndexImpl extends DirectoryIndex {
if (definedPackage != null && definedPackage.isEmpty()) return false; // another library source root starts here
}
info.setInLibrarySource(true);
info.setSourceRoot(sourceRoot);
info = info.withInLibrarySource(true)
.withSourceRoot(sourceRoot);
storeInfo(info, dirId);
final String packageName = getCurrentValue();
final String newPackageName = Comparing.equal(file, dir) ? packageName : getPackageNameForSubdir(packageName, file.getName());
@@ -548,7 +556,8 @@ public class DirectoryIndexImpl extends DirectoryIndex {
if (definedPackage != null && definedPackage.isEmpty()) return false; // another library root starts here
}
info.setLibraryClassRoot(classRoot);
info = info.withLibraryClassRoot(classRoot);
storeInfo(info, dirId);
final String packageName = getCurrentValue();
final String childPackageName = Comparing.equal(file, dir) ? packageName : getPackageNameForSubdir(packageName, file.getName());
@@ -656,13 +665,14 @@ public class DirectoryIndexImpl extends DirectoryIndex {
private final Stack<OrderEntry[]> myEntries = new Stack<OrderEntry[]>();
@Override
protected DirectoryInfo updateInfo(VirtualFile dir) {
protected DirectoryInfo updateInfo(@NotNull VirtualFile dir) {
if (progress != null) {
progress.checkCanceled();
}
if (isIgnored(dir)) return null;
DirectoryInfo info = myDirToInfoMap.get(getId(dir)); // do not create it here!
int dirId = getId(dir);
DirectoryInfo info = myDirToInfoMap.get(dirId); // do not create it here!
if (info == null) return null;
if (module != null) {
@@ -682,12 +692,13 @@ public class DirectoryIndexImpl extends DirectoryIndex {
OrderEntry[] oldParentEntries = myEntries.isEmpty() ? null : myEntries.peek();
OrderEntry[] oldEntries = info.getOrderEntries();
myEntries.push(oldEntries);
info.addOrderEntries(orderEntries, parentInfo, oldParentEntries);
info = info.withOrderEntries(orderEntries, parentInfo, oldParentEntries);
storeInfo(info, dirId);
return info;
}
@Override
protected void afterChildrenVisited(DirectoryInfo info) {
protected void afterChildrenVisited(@NotNull VirtualFile file, @NotNull DirectoryInfo info) {
myEntries.pop();
}
});
@@ -730,11 +741,12 @@ public class DirectoryIndexImpl extends DirectoryIndex {
}
fillMapWithOrderEntries(depEntries, libClassRootEntries, libSourceRootEntries, progress);
killOrderEntryArrayDuplicates();
internDirectoryInfos();
}
private void killOrderEntryArrayDuplicates() {
Map<OrderEntry[], OrderEntry[]> interner = new THashMap<OrderEntry[], OrderEntry[]>(new TObjectHashingStrategy<OrderEntry[]>() {
private void internDirectoryInfos() {
final Map<DirectoryInfo, DirectoryInfo> diInterner = new THashMap<DirectoryInfo, DirectoryInfo>();
final Map<OrderEntry[], OrderEntry[]> oeInterner = new THashMap<OrderEntry[], OrderEntry[]>(new TObjectHashingStrategy<OrderEntry[]>() {
@Override
public int computeHashCode(OrderEntry[] object) {
return Arrays.hashCode(object);
@@ -745,17 +757,25 @@ public class DirectoryIndexImpl extends DirectoryIndex {
return Arrays.equals(o1, o2);
}
});
for (Object v : myDirToInfoMap.getValues()) {
DirectoryInfo info = (DirectoryInfo)v;
OrderEntry[] entries = info.getOrderEntries();
if (entries.length != 0) {
OrderEntry[] interned = interner.get(entries);
myDirToInfoMap.transformValues(new TObjectFunction<DirectoryInfo, DirectoryInfo>() {
@Override
public DirectoryInfo execute(DirectoryInfo info) {
DirectoryInfo interned = diInterner.get(info);
if (interned == null) {
interner.put(entries, interned = entries);
OrderEntry[] entries = info.getOrderEntries();
OrderEntry[] internedEntries = oeInterner.get(entries);
if (internedEntries == null) {
oeInterner.put(entries, entries);
}
else if (internedEntries != entries) {
info = info.withInternedEntries(internedEntries);
}
diInterner.put(info, interned = info);
}
info.setInternedOrderEntries(interned);
return interned;
}
}
});
}
private void initExcludedDirMap(Module[] modules, ProgressIndicator progress) {
@@ -16,12 +16,10 @@
package com.intellij.openapi.roots.impl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.OrderEntry;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.RootPolicy;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayFactory;
import com.intellij.util.ArrayUtil;
@@ -32,52 +30,69 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public final class DirectoryInfo {
private Module module; // module to which content it belongs or null
private VirtualFile libraryClassRoot; // class root in library
private VirtualFile contentRoot;
private VirtualFile sourceRoot;
private final Module module; // module to which content it belongs or null
private final VirtualFile libraryClassRoot; // class root in library
private final VirtualFile contentRoot;
private final VirtualFile sourceRoot;
private static final byte TEST_SOURCE_FLAG = 1; // (makes sense only if MODULE_SOURCE_FLAG is set)
private static final byte LIBRARY_SOURCE_FLAG = 2; // set if it's a directory with sources of some library
private static final byte MODULE_SOURCE_FLAG = 4; // set if files in this directory belongs to sources of the module (if field 'module' is not null)
@MagicConstant(flags = {TEST_SOURCE_FLAG, LIBRARY_SOURCE_FLAG, MODULE_SOURCE_FLAG})
private byte sourceFlag;
private final byte sourceFlag;
/**
* orderEntry to (classes of) which a directory belongs
* MUST BE SORTED WITH {@link #BY_OWNER_MODULE}
*/
private OrderEntry[] orderEntries;
private final OrderEntry[] orderEntries;
public DirectoryInfo() {
public DirectoryInfo(Module module,
VirtualFile contentRoot,
VirtualFile sourceRoot,
VirtualFile libraryClassRoot,
@MagicConstant(flags = {TEST_SOURCE_FLAG, LIBRARY_SOURCE_FLAG, MODULE_SOURCE_FLAG}) byte sourceFlag,
OrderEntry[] orderEntries) {
this.module = module;
this.libraryClassRoot = libraryClassRoot;
this.contentRoot = contentRoot;
this.sourceRoot = sourceRoot;
this.sourceFlag = sourceFlag;
this.orderEntries = orderEntries;
}
@TestOnly
@SuppressWarnings({"unchecked"})
@Override
public boolean equals(Object o) {
assert ApplicationManager.getApplication().isUnitTestMode() : "DirectoryInfo.equals should only be used in tests";
if (this == o) return true;
if (!(o instanceof DirectoryInfo)) return false;
if (o == null || getClass() != o.getClass()) return false;
final DirectoryInfo info = (DirectoryInfo)o;
DirectoryInfo info = (DirectoryInfo)o;
if (sourceFlag != info.sourceFlag) return false;
if (getModule() != null ? !getModule().equals(info.getModule()) : info.getModule() != null) return false;
if (orderEntries != null ? !new HashSet(Arrays.asList(orderEntries)).equals(new HashSet(Arrays.asList(info.orderEntries))) : info.orderEntries != null) return false;
if (!Comparing.equal(getLibraryClassRoot(), info.getLibraryClassRoot())) return false;
if (!Comparing.equal(getContentRoot(), info.getContentRoot())) return false;
if (!Comparing.equal(getSourceRoot(), info.getSourceRoot())) return false;
if (contentRoot != null ? !contentRoot.equals(info.contentRoot) : info.contentRoot != null) return false;
if (libraryClassRoot != null ? !libraryClassRoot.equals(info.libraryClassRoot) : info.libraryClassRoot != null) return false;
if (module != null ? !module.equals(info.module) : info.module != null) return false;
if (!Arrays.equals(orderEntries, info.orderEntries)) return false;
if (sourceRoot != null ? !sourceRoot.equals(info.sourceRoot) : info.sourceRoot != null) return false;
return true;
}
@Override
public int hashCode() {
throw new UnsupportedOperationException("DirectoryInfo shall not be used as a key to HashMap");
int result = module != null ? module.hashCode() : 0;
result = 31 * result + (libraryClassRoot != null ? libraryClassRoot.hashCode() : 0);
result = 31 * result + (contentRoot != null ? contentRoot.hashCode() : 0);
result = 31 * result + (sourceRoot != null ? sourceRoot.hashCode() : 0);
result = 31 * result + (int)sourceFlag;
return result;
}
@SuppressWarnings({"HardCodedStringLiteral"})
@@ -95,7 +110,8 @@ public final class DirectoryInfo {
@NotNull
public OrderEntry[] getOrderEntries() {
return orderEntries == null ? OrderEntry.EMPTY_ARRAY : orderEntries;
OrderEntry[] entries = orderEntries;
return entries == null ? OrderEntry.EMPTY_ARRAY : entries;
}
@Nullable
@@ -193,21 +209,25 @@ public final class DirectoryInfo {
}
// orderEntries must be sorted BY_OWNER_MODULE
void addOrderEntries(@NotNull OrderEntry[] orderEntries,
@Nullable final DirectoryInfo parentInfo,
@Nullable final OrderEntry[] oldParentEntries) {
@NotNull
DirectoryInfo withOrderEntries(@NotNull OrderEntry[] orderEntries,
@Nullable final DirectoryInfo parentInfo,
@Nullable final OrderEntry[] oldParentEntries) {
OrderEntry[] newOrderEntries;
if (orderEntries.length == 0) {
this.orderEntries = null;
newOrderEntries = null;
}
else if (this.orderEntries == null) {
this.orderEntries = orderEntries;
newOrderEntries = orderEntries;
}
else if (parentInfo != null && oldParentEntries == this.orderEntries) {
this.orderEntries = parentInfo.orderEntries;
newOrderEntries = parentInfo.orderEntries;
}
else {
this.orderEntries = mergeWith(orderEntries);
newOrderEntries = mergeWith(orderEntries);
}
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, newOrderEntries);
}
// entries must be sorted BY_OWNER_MODULE
@@ -249,10 +269,6 @@ public final class DirectoryInfo {
}
};
public void setInternedOrderEntries(@NotNull OrderEntry[] internedOrderEntries) {
orderEntries = internedOrderEntries;
}
public VirtualFile getSourceRoot() {
return sourceRoot;
}
@@ -275,48 +291,63 @@ public final class DirectoryInfo {
return BitUtil.isSet(sourceFlag, MODULE_SOURCE_FLAG);
}
public void setInModuleSource(boolean inModuleSource) {
sourceFlag = (byte)BitUtil.set(sourceFlag, MODULE_SOURCE_FLAG, inModuleSource);
@NotNull
DirectoryInfo withInModuleSource(boolean inModuleSource) {
byte sourceFlag = (byte)BitUtil.set(this.sourceFlag, MODULE_SOURCE_FLAG, inModuleSource);
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, orderEntries);
}
public boolean isTestSource() {
return BitUtil.isSet(sourceFlag, TEST_SOURCE_FLAG);
}
public void setTestSource(boolean testSource) {
sourceFlag = (byte)BitUtil.set(sourceFlag, TEST_SOURCE_FLAG, testSource);
@NotNull
DirectoryInfo withTestSource(boolean testSource) {
byte sourceFlag = (byte)BitUtil.set(this.sourceFlag, TEST_SOURCE_FLAG, testSource);
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, orderEntries);
}
public boolean isInLibrarySource() {
return BitUtil.isSet(sourceFlag, LIBRARY_SOURCE_FLAG);
}
public void setInLibrarySource(boolean inLibrarySource) {
sourceFlag = (byte)BitUtil.set(sourceFlag, LIBRARY_SOURCE_FLAG, inLibrarySource);
@NotNull
DirectoryInfo withInLibrarySource(boolean inLibrarySource) {
byte sourceFlag = (byte)BitUtil.set(this.sourceFlag, LIBRARY_SOURCE_FLAG, inLibrarySource);
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, orderEntries);
}
public Module getModule() {
return module;
}
public void setModule(Module module) {
this.module = module;
@NotNull
DirectoryInfo withModule(Module module) {
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, orderEntries);
}
public void setLibraryClassRoot(@NotNull VirtualFile libraryClassRoot) {
this.libraryClassRoot = libraryClassRoot;
@NotNull
DirectoryInfo withLibraryClassRoot(@NotNull VirtualFile libraryClassRoot) {
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, orderEntries);
}
public void setContentRoot(VirtualFile contentRoot) {
this.contentRoot = contentRoot;
@NotNull
DirectoryInfo withContentRoot(VirtualFile contentRoot) {
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, orderEntries);
}
public void setSourceRoot(@NotNull VirtualFile sourceRoot) {
this.sourceRoot = sourceRoot;
@NotNull
DirectoryInfo withSourceRoot(@NotNull VirtualFile sourceRoot) {
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, orderEntries);
}
@NotNull
DirectoryInfo withInternedEntries(@NotNull OrderEntry[] orderEntries) {
return new DirectoryInfo(module, contentRoot, sourceRoot, libraryClassRoot, sourceFlag, orderEntries);
}
@TestOnly
public void assertConsistency() {
void assertConsistency() {
OrderEntry[] entries = getOrderEntries();
for (int i=1; i<entries.length; i++) {
assert BY_OWNER_MODULE.compare(entries[i-1], entries[i]) <= 0;