Additional cache for not-found packages

This commit is contained in:
Nikolay Krasko
2015-01-20 16:06:33 +03:00
parent a8557180f1
commit e802044c60
2 changed files with 73 additions and 10 deletions
@@ -74,6 +74,11 @@ public class JavaClassFinderImpl implements JavaClassFinder {
public Project getProject() { public Project getProject() {
return project; return project;
} }
@Override
public String toString() {
return "JCFI: " + baseScope;
}
}; };
javaFacade = KotlinJavaPsiFacade.getInstance(project); javaFacade = KotlinJavaPsiFacade.getInstance(project);
@@ -51,7 +51,16 @@ import java.util.concurrent.ConcurrentMap;
public class KotlinJavaPsiFacade { public class KotlinJavaPsiFacade {
private volatile KotlinPsiElementFinderWrapper[] elementFinders; private volatile KotlinPsiElementFinderWrapper[] elementFinders;
private volatile SoftReference<ConcurrentMap<Pair<String, GlobalSearchScope>, PsiPackage>> packageCache;
private static class PackageCache {
final ConcurrentMap<Pair<String, GlobalSearchScope>, PsiPackage> packageInScopeCache =
new ConcurrentHashMap<Pair<String, GlobalSearchScope>, PsiPackage>();
final ConcurrentMap<String, Boolean> hasPackageInAllScopeCache =
new ConcurrentHashMap<String, Boolean>();
}
private volatile SoftReference<PackageCache> packageCache;
private final Project project; private final Project project;
public static KotlinJavaPsiFacade getInstance(Project project) { public static KotlinJavaPsiFacade getInstance(Project project) {
@@ -72,6 +81,7 @@ public class KotlinJavaPsiFacade {
long now = modificationTracker.getJavaStructureModificationCount(); long now = modificationTracker.getJavaStructureModificationCount();
if (lastTimeSeen != now) { if (lastTimeSeen != now) {
lastTimeSeen = now; lastTimeSeen = now;
packageCache = null; packageCache = null;
} }
} }
@@ -155,24 +165,56 @@ public class KotlinJavaPsiFacade {
} }
public PsiPackage findPackage(@NotNull String qualifiedName, GlobalSearchScope searchScope) { public PsiPackage findPackage(@NotNull String qualifiedName, GlobalSearchScope searchScope) {
ConcurrentMap<Pair<String, GlobalSearchScope>, PsiPackage> cache = SoftReference.dereference(packageCache); PackageCache cache = SoftReference.dereference(packageCache);
if (cache == null) { if (cache == null) {
packageCache = new SoftReference<ConcurrentMap<Pair<String, GlobalSearchScope>, PsiPackage>>( packageCache = new SoftReference<PackageCache>(cache = new PackageCache());
cache = new ConcurrentHashMap<Pair<String, GlobalSearchScope>, PsiPackage>());
} }
Pair<String, GlobalSearchScope> key = new Pair<String, GlobalSearchScope>(qualifiedName, searchScope); Pair<String, GlobalSearchScope> key = new Pair<String, GlobalSearchScope>(qualifiedName, searchScope);
PsiPackage aPackage = cache.get(key); PsiPackage aPackage = cache.packageInScopeCache.get(key);
if (aPackage != null) { if (aPackage != null) {
return aPackage; return aPackage;
} }
for (KotlinPsiElementFinderWrapper finder : filteredFinders()) { KotlinPsiElementFinderWrapper[] finders = filteredFinders();
aPackage = finder.findPackage(qualifiedName, searchScope);
if (aPackage != null) { Boolean packageFoundInAllScope = cache.hasPackageInAllScopeCache.get(qualifiedName);
return ConcurrencyUtil.cacheOrGet(cache, key, aPackage); if (packageFoundInAllScope != null) {
if (!packageFoundInAllScope.booleanValue()) return null;
// Package was found in AllScope with some of finders but is absent in packageCache for current scope.
// We check only finders that depend on scope.
for (KotlinPsiElementFinderWrapper finder : finders) {
if (!finder.isSameResultForAnyScope()) {
aPackage = finder.findPackage(qualifiedName, searchScope);
if (aPackage != null) {
return ConcurrencyUtil.cacheOrGet(cache.packageInScopeCache, key, aPackage);
}
}
} }
} }
else {
for (KotlinPsiElementFinderWrapper finder : finders) {
aPackage = finder.findPackage(qualifiedName, searchScope);
if (aPackage != null) {
return ConcurrencyUtil.cacheOrGet(cache.packageInScopeCache, key, aPackage);
}
}
boolean found = false;
for (KotlinPsiElementFinderWrapper finder : finders) {
if (!finder.isSameResultForAnyScope()) {
aPackage = finder.findPackage(qualifiedName, GlobalSearchScope.allScope(project));
if (aPackage != null) {
found = true;
break;
}
}
}
cache.hasPackageInAllScopeCache.put(qualifiedName, found);
}
return null; return null;
} }
@@ -202,12 +244,13 @@ public class KotlinJavaPsiFacade {
interface KotlinPsiElementFinderWrapper { interface KotlinPsiElementFinderWrapper {
PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope); PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope);
PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope); PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope);
boolean isSameResultForAnyScope();
} }
private static class KotlinPsiElementFinderWrapperImpl implements KotlinPsiElementFinderWrapper { private static class KotlinPsiElementFinderWrapperImpl implements KotlinPsiElementFinderWrapper {
private final PsiElementFinder finder; private final PsiElementFinder finder;
private KotlinPsiElementFinderWrapperImpl(PsiElementFinder finder) { private KotlinPsiElementFinderWrapperImpl(@NotNull PsiElementFinder finder) {
this.finder = finder; this.finder = finder;
} }
@@ -221,6 +264,16 @@ public class KotlinJavaPsiFacade {
// Original element finder can't search packages with scope // Original element finder can't search packages with scope
return finder.findPackage(qualifiedName); return finder.findPackage(qualifiedName);
} }
@Override
public boolean isSameResultForAnyScope() {
return true;
}
@Override
public String toString() {
return finder.toString();
}
} }
private static class KotlinPsiElementFinderWrapperImplDumbAware extends KotlinPsiElementFinderWrapperImpl implements DumbAware { private static class KotlinPsiElementFinderWrapperImplDumbAware extends KotlinPsiElementFinderWrapperImpl implements DumbAware {
@@ -278,6 +331,11 @@ public class KotlinJavaPsiFacade {
return hasDirectoriesInScope(dirs, scope) ? new PsiPackageImpl(psiManager, qualifiedName) : null; return hasDirectoriesInScope(dirs, scope) ? new PsiPackageImpl(psiManager, qualifiedName) : null;
} }
@Override
public boolean isSameResultForAnyScope() {
return false;
}
private static boolean hasDirectoriesInScope(Query<VirtualFile> dirs, final GlobalSearchScope scope) { private static boolean hasDirectoriesInScope(Query<VirtualFile> dirs, final GlobalSearchScope scope) {
CommonProcessors.FindProcessor<VirtualFile> findProcessor = new CommonProcessors.FindProcessor<VirtualFile>() { CommonProcessors.FindProcessor<VirtualFile> findProcessor = new CommonProcessors.FindProcessor<VirtualFile>() {
@Override @Override