diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/JavaClassFinderImpl.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/JavaClassFinderImpl.java index ea3292b4c43..149e9cd36c5 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/JavaClassFinderImpl.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/JavaClassFinderImpl.java @@ -74,6 +74,11 @@ public class JavaClassFinderImpl implements JavaClassFinder { public Project getProject() { return project; } + + @Override + public String toString() { + return "JCFI: " + baseScope; + } }; javaFacade = KotlinJavaPsiFacade.getInstance(project); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/KotlinJavaPsiFacade.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/KotlinJavaPsiFacade.java index 14adea4580b..7df4b1e80b4 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/KotlinJavaPsiFacade.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/KotlinJavaPsiFacade.java @@ -51,7 +51,16 @@ import java.util.concurrent.ConcurrentMap; public class KotlinJavaPsiFacade { private volatile KotlinPsiElementFinderWrapper[] elementFinders; - private volatile SoftReference, PsiPackage>> packageCache; + + private static class PackageCache { + final ConcurrentMap, PsiPackage> packageInScopeCache = + new ConcurrentHashMap, PsiPackage>(); + final ConcurrentMap hasPackageInAllScopeCache = + new ConcurrentHashMap(); + } + + private volatile SoftReference packageCache; + private final Project project; public static KotlinJavaPsiFacade getInstance(Project project) { @@ -72,6 +81,7 @@ public class KotlinJavaPsiFacade { long now = modificationTracker.getJavaStructureModificationCount(); if (lastTimeSeen != now) { lastTimeSeen = now; + packageCache = null; } } @@ -155,24 +165,56 @@ public class KotlinJavaPsiFacade { } public PsiPackage findPackage(@NotNull String qualifiedName, GlobalSearchScope searchScope) { - ConcurrentMap, PsiPackage> cache = SoftReference.dereference(packageCache); + PackageCache cache = SoftReference.dereference(packageCache); if (cache == null) { - packageCache = new SoftReference, PsiPackage>>( - cache = new ConcurrentHashMap, PsiPackage>()); + packageCache = new SoftReference(cache = new PackageCache()); } Pair key = new Pair(qualifiedName, searchScope); - PsiPackage aPackage = cache.get(key); + PsiPackage aPackage = cache.packageInScopeCache.get(key); if (aPackage != null) { return aPackage; } - for (KotlinPsiElementFinderWrapper finder : filteredFinders()) { - aPackage = finder.findPackage(qualifiedName, searchScope); - if (aPackage != null) { - return ConcurrencyUtil.cacheOrGet(cache, key, aPackage); + KotlinPsiElementFinderWrapper[] finders = filteredFinders(); + + Boolean packageFoundInAllScope = cache.hasPackageInAllScopeCache.get(qualifiedName); + 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; } @@ -202,12 +244,13 @@ public class KotlinJavaPsiFacade { interface KotlinPsiElementFinderWrapper { PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope); PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope); + boolean isSameResultForAnyScope(); } private static class KotlinPsiElementFinderWrapperImpl implements KotlinPsiElementFinderWrapper { private final PsiElementFinder finder; - private KotlinPsiElementFinderWrapperImpl(PsiElementFinder finder) { + private KotlinPsiElementFinderWrapperImpl(@NotNull PsiElementFinder finder) { this.finder = finder; } @@ -221,6 +264,16 @@ public class KotlinJavaPsiFacade { // Original element finder can't search packages with scope 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 { @@ -278,6 +331,11 @@ public class KotlinJavaPsiFacade { return hasDirectoriesInScope(dirs, scope) ? new PsiPackageImpl(psiManager, qualifiedName) : null; } + @Override + public boolean isSameResultForAnyScope() { + return false; + } + private static boolean hasDirectoriesInScope(Query dirs, final GlobalSearchScope scope) { CommonProcessors.FindProcessor findProcessor = new CommonProcessors.FindProcessor() { @Override