JspFileIndex refactored to use FBI

This commit is contained in:
Dmitry Avdeev
2010-08-02 14:06:49 +04:00
parent 93eb8cf2b7
commit d1e3929c84
8 changed files with 85 additions and 98 deletions
@@ -35,7 +35,7 @@ public abstract class JspContextManager {
public abstract BaseJspFile[] getSuitableContextFiles(@NotNull PsiFile file);
public abstract void setContextFile(@NotNull PsiFile file, @Nullable BaseJspFile contextFile, final boolean userDefined);
public abstract void setContextFile(@NotNull PsiFile file, @Nullable BaseJspFile contextFile);
public abstract @Nullable
BaseJspFile getContextFile(@NotNull PsiFile file);
@@ -35,16 +35,12 @@ public class FileIncludeInfo {
this.runtimeOnly = runtimeOnly;
}
public FileIncludeInfo(@NotNull String fileName, @NotNull String path, int offset) {
this(fileName, path, offset, false);
}
public FileIncludeInfo(@NotNull String fileName, @NotNull String path) {
this(fileName, path, -1, false);
public FileIncludeInfo(@NotNull String path, int offset) {
this(getFileName(path), path, offset, false);
}
public FileIncludeInfo(@NotNull String path) {
this(getFileName(path), path, -1, false);
this(path, -1);
}
private static String getFileName(String path) {
@@ -18,9 +18,11 @@ package com.intellij.psi.impl.include;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.util.Processor;
import org.jetbrains.annotations.Nullable;
/**
@@ -36,6 +38,8 @@ public abstract class FileIncludeManager {
public abstract VirtualFile[] getIncludingFiles(VirtualFile file, boolean compileTimeOnly);
public abstract void processIncludingFiles(PsiFile context, Processor<Pair<VirtualFile, FileIncludeInfo>> processor);
@Nullable
public abstract PsiFileSystemItem resolveFileReference(String text, PsiFile context);
public abstract PsiFileSystemItem resolveFileInclude(FileIncludeInfo info, PsiFile context);
}
@@ -163,7 +163,7 @@ public class FileIncludeIndex extends FileBasedIndexExtension<FileIncludeIndex.K
}
public int getVersion() {
return 0;
return 1;
}
interface Key {
@@ -18,6 +18,8 @@ package com.intellij.psi.impl.include;
import org.jetbrains.annotations.NotNull;
import java.io.File;
/**
* @author Dmitry Avdeev
*/
@@ -26,7 +28,7 @@ class FileIncludeInfoImpl extends FileIncludeInfo {
public final String providerId;
public FileIncludeInfoImpl(@NotNull String path, int offset, boolean runtimeOnly, String providerId) {
super("", path, offset, runtimeOnly);
super(new File(path).getName(), path, offset, runtimeOnly);
this.providerId = providerId;
}
@@ -19,6 +19,7 @@ package com.intellij.psi.impl.include;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWithId;
@@ -34,12 +35,11 @@ import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.ParameterizedCachedValue;
import com.intellij.psi.util.ParameterizedCachedValueProvider;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* @author Dmitry Avdeev
@@ -54,46 +54,68 @@ public class FileIncludeManagerImpl extends FileIncludeManager {
private final IncludeCacheHolder myIncludedHolder = new IncludeCacheHolder("compile time includes", "runtime includes") {
@Override
protected VirtualFile[] computeFiles(PsiFile file, boolean compileTimeOnly) {
GlobalSearchScope scope = GlobalSearchScope.allScope(myProject);
List<FileIncludeInfoImpl> infoList = FileIncludeIndex.getIncludes(file.getVirtualFile(), scope);
ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
for (FileIncludeInfoImpl info : infoList) {
if (compileTimeOnly && info.runtimeOnly) {
continue;
}
FileIncludeProvider includeProvider = myProviderMap.get(info.providerId);
if (includeProvider != null) {
PsiFileSystemItem virtualFile = includeProvider.resolveInclude(info, file, myProject);
if (virtualFile != null) {
files.add(virtualFile.getVirtualFile());
protected VirtualFile[] computeFiles(final PsiFile file, final boolean compileTimeOnly) {
final ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
processIncludes(file, new Processor<FileIncludeInfo>() {
@Override
public boolean process(FileIncludeInfo info) {
if (compileTimeOnly != info.runtimeOnly) {
PsiFileSystemItem virtualFile = resolveFileInclude(info, file);
if (virtualFile != null) {
files.add(virtualFile.getVirtualFile());
}
}
return true;
}
});
return files.toArray(new VirtualFile[files.size()]);
}
};
public void processIncludes(PsiFile file, Processor<FileIncludeInfo> processor) {
GlobalSearchScope scope = GlobalSearchScope.allScope(myProject);
List<FileIncludeInfoImpl> infoList = FileIncludeIndex.getIncludes(file.getVirtualFile(), scope);
for (FileIncludeInfoImpl info : infoList) {
if (!processor.process(info)) {
return;
}
}
}
private final IncludeCacheHolder myIncludingHolder = new IncludeCacheHolder("compile time contexts", "runtime contexts") {
@Override
protected VirtualFile[] computeFiles(PsiFile context, boolean compileTimeOnly) {
final ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
processIncludingFiles(context, new Processor<Pair<VirtualFile, FileIncludeInfo>>() {
@Override
public boolean process(Pair<VirtualFile, FileIncludeInfo> virtualFileFileIncludeInfoPair) {
files.add(virtualFileFileIncludeInfoPair.first);
return true;
}
});
return VfsUtil.toVirtualFileArray(files);
}
};
private final IncludeCacheHolder myIncludingHolder = new IncludeCacheHolder("compile time contexts", "runtime contexts") {
@Override
protected VirtualFile[] computeFiles(PsiFile file, boolean compileTimeOnly) {
MultiMap<VirtualFile,FileIncludeInfoImpl> infoList = FileIncludeIndex.getIncludingFileCandidates(file.getName(), GlobalSearchScope.allScope(myProject));
ArrayList<VirtualFile> files = new ArrayList<VirtualFile>();
for (VirtualFile candidate : infoList.keySet()) {
PsiFile psiFile = myPsiManager.findFile(candidate);
if (psiFile == null) continue;
for (FileIncludeInfoImpl info : infoList.get(candidate)) {
FileIncludeProvider includeProvider = myProviderMap.get(info.providerId);
if (includeProvider != null) {
if (file.equals(includeProvider.resolveInclude(info, psiFile, myProject))) {
files.add(candidate);
}
public void processIncludingFiles(PsiFile context, Processor<Pair<VirtualFile, FileIncludeInfo>> processor) {
context = context.getOriginalFile();
VirtualFile contextFile = context.getVirtualFile();
if (contextFile == null) return;
MultiMap<VirtualFile,FileIncludeInfoImpl> infoList = FileIncludeIndex.getIncludingFileCandidates(context.getName(), GlobalSearchScope.allScope(myProject));
for (VirtualFile candidate : infoList.keySet()) {
PsiFile psiFile = myPsiManager.findFile(candidate);
if (psiFile == null || context.equals(psiFile)) continue;
for (FileIncludeInfo info : infoList.get(candidate)) {
PsiFileSystemItem item = resolveFileInclude(info, psiFile);
if (item != null && contextFile.equals(item.getVirtualFile())) {
if (!processor.process(Pair.create(candidate, info))) {
return;
}
}
}
return VfsUtil.toVirtualFileArray(files);
}
};
}
public FileIncludeManagerImpl(Project project, PsiManager psiManager, PsiFileFactory psiFileFactory,
CachedValuesManager cachedValuesManager) {
@@ -120,19 +142,23 @@ public class FileIncludeManagerImpl extends FileIncludeManager {
}
}
@Override
public VirtualFile[] getIncludingFiles(VirtualFile file, boolean compileTimeOnly) {
return myIncludingHolder.getAllFiles(file, compileTimeOnly);
}
@Override
public PsiFileSystemItem resolveFileReference(String text, PsiFile context) {
PsiFileImpl psiFile = (PsiFileImpl)myPsiFileFactory.createFileFromText("dummy.txt", text);
public PsiFileSystemItem resolveFileInclude(FileIncludeInfo info, PsiFile context) {
PsiFileImpl psiFile = (PsiFileImpl)myPsiFileFactory.createFileFromText("dummy.txt", info.path);
psiFile.setOriginalFile(context);
return new FileReferenceSet(psiFile).resolve();
return new FileReferenceSet(psiFile) {
@Override
protected boolean useIncludingFileAsContext() {
return false;
}
}.resolve();
}
private abstract class IncludeCacheHolder {
@@ -140,14 +166,14 @@ public class FileIncludeManagerImpl extends FileIncludeManager {
private final Key<ParameterizedCachedValue<VirtualFile[], PsiFile>> COMPILE_TIME_KEY;
private final Key<ParameterizedCachedValue<VirtualFile[], PsiFile>> RUNTIME_KEY;
private final ParameterizedCachedValueProvider<VirtualFile[], PsiFile> COMPILE_TIME_PROVIDER = new IncludedFilesProvider(false) {
private final ParameterizedCachedValueProvider<VirtualFile[], PsiFile> COMPILE_TIME_PROVIDER = new IncludedFilesProvider(true) {
@Override
protected VirtualFile[] computeFiles(PsiFile file, boolean compileTimeOnly) {
return IncludeCacheHolder.this.computeFiles(file, compileTimeOnly);
}
};
private final ParameterizedCachedValueProvider<VirtualFile[], PsiFile> RUNTIME_PROVIDER = new IncludedFilesProvider(true) {
private final ParameterizedCachedValueProvider<VirtualFile[], PsiFile> RUNTIME_PROVIDER = new IncludedFilesProvider(false) {
@Override
protected VirtualFile[] computeFiles(PsiFile file, boolean compileTimeOnly) {
return IncludeCacheHolder.this.computeFiles(file, compileTimeOnly);
@@ -160,36 +186,20 @@ public class FileIncludeManagerImpl extends FileIncludeManager {
}
public VirtualFile[] getAllFiles(VirtualFile file, boolean compileTimeOnly) {
ArrayList<VirtualFile[]> result = new ArrayList<VirtualFile[]>();
Set<VirtualFile> result = new HashSet<VirtualFile>();
getFilesRecursively(file, compileTimeOnly, result);
switch (result.size()) {
case 0:
return VirtualFile.EMPTY_ARRAY;
case 1:
return result.get(0);
default:
int size = 0;
for (VirtualFile[] files : result) {
size+=files.length;
}
VirtualFile[] files = new VirtualFile[size];
int pos = 0;
for (VirtualFile[] virtualFiles : result) {
System.arraycopy(virtualFiles, 0, files, pos, virtualFiles.length);
pos += virtualFiles.length;
}
return files;
}
return result.toArray(new VirtualFile[result.size()]);
}
private void getFilesRecursively(VirtualFile file, boolean compileTimeOnly, List<VirtualFile[]> result) {
private void getFilesRecursively(VirtualFile file, boolean compileTimeOnly, Set<VirtualFile> result) {
if (result.contains(file)) return;
PsiFile psiFile = myPsiManager.findFile(file);
if (psiFile == null) return;
VirtualFile[] includes = compileTimeOnly
? myCachedValuesManager.getParameterizedCachedValue(psiFile, COMPILE_TIME_KEY, COMPILE_TIME_PROVIDER, false, psiFile)
: myCachedValuesManager.getParameterizedCachedValue(psiFile, RUNTIME_KEY, RUNTIME_PROVIDER, false, psiFile);
if (includes.length != 0) {
result.add(includes);
result.addAll(Arrays.asList(includes));
for (VirtualFile include : includes) {
getFilesRecursively(include, compileTimeOnly, result);
}
@@ -17,13 +17,9 @@
package com.intellij.psi.impl.include;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.util.indexing.FileContent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Avdeev
@@ -39,9 +35,4 @@ public abstract class FileIncludeProvider {
@NotNull
public abstract FileIncludeInfo[] getIncludeInfos(FileContent content);
@Nullable
public PsiFileSystemItem resolveInclude(FileIncludeInfo include, PsiFile context, Project project) {
return FileIncludeManager.getManager(project).resolveFileReference(include.path, context);
}
}
@@ -22,15 +22,10 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,7 +41,6 @@ public class FileReferenceSet {
private static final FileType[] EMPTY_FILE_TYPES = {};
private static final char SEPARATOR = '/';
private static final String SEPARATOR_STRING = "/";
private static final Key<CachedValue<Collection<PsiFileSystemItem>>> DEFAULT_CONTEXTS_KEY = new Key<CachedValue<Collection<PsiFileSystemItem>>>("default file contexts");
public static final CustomizableReferenceProvider.CustomizationKey<Function<PsiFile, Collection<PsiFileSystemItem>>> DEFAULT_PATH_EVALUATOR_OPTION =
new CustomizableReferenceProvider.CustomizationKey<Function<PsiFile, Collection<PsiFileSystemItem>>>(PsiBundle.message("default.path.evaluator.option"));
public static final Function<PsiFile, Collection<PsiFileSystemItem>> ABSOLUTE_TOP_LEVEL = new Function<PsiFile, Collection<PsiFileSystemItem>>() {
@@ -262,17 +256,7 @@ public class FileReferenceSet {
return getAbsoluteTopLevelDirLocations(file);
}
final CachedValueProvider<Collection<PsiFileSystemItem>> myDefaultContextProvider = new CachedValueProvider<Collection<PsiFileSystemItem>>() {
public Result<Collection<PsiFileSystemItem>> compute() {
final Collection<PsiFileSystemItem> contexts = getContextByFile(file);
return Result.createSingleDependency(contexts,
PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
}
};
final CachedValuesManager cachedValuesManager = CachedValuesManager.getManager(myElement.getProject());
final Collection<PsiFileSystemItem> value =
cachedValuesManager.getCachedValue(file, DEFAULT_CONTEXTS_KEY, myDefaultContextProvider, false);
return value == null ? Collections.<PsiFileSystemItem>emptyList() : value;
return getContextByFile(file);
}
@Nullable
@@ -285,7 +269,7 @@ public class FileReferenceSet {
return file.getOriginalFile();
}
@Nullable
@NotNull
private Collection<PsiFileSystemItem> getContextByFile(@NotNull PsiFile file) {
final PsiElement context = file.getContext();
if (context != null) file = context.getContainingFile();