diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JetCoreEnvironment.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JetCoreEnvironment.java index 050000cfcd8..d148afd4662 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JetCoreEnvironment.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/JetCoreEnvironment.java @@ -58,6 +58,7 @@ import org.jetbrains.kotlin.parsing.JetParserDefinition; import org.jetbrains.kotlin.parsing.JetScriptDefinitionProvider; import org.jetbrains.kotlin.psi.JetFile; import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer; +import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade; import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService; import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService; import org.jetbrains.kotlin.utils.PathUtil; @@ -255,6 +256,7 @@ public class JetCoreEnvironment { MockProject project = projectEnvironment.getProject(); project.registerService(JetScriptDefinitionProvider.class, new JetScriptDefinitionProvider()); + project.registerService(KotlinJavaPsiFacade.class, new KotlinJavaPsiFacade(project)); project.registerService(KotlinLightClassForPackage.FileStubCache.class, new KotlinLightClassForPackage.FileStubCache(project)); } 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 20fe28eef4b..ea3292b4c43 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 @@ -75,7 +75,8 @@ public class JavaClassFinderImpl implements JavaClassFinder { return project; } }; - javaFacade = new KotlinJavaPsiFacade(project, javaSearchScope); + + javaFacade = KotlinJavaPsiFacade.getInstance(project); } @Nullable 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 b72ce362f02..14adea4580b 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 @@ -23,6 +23,7 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.PackageIndex; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiClass; @@ -32,11 +33,13 @@ import com.intellij.psi.PsiPackage; import com.intellij.psi.impl.file.PsiPackageImpl; import com.intellij.psi.impl.file.impl.JavaFileManager; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiModificationTracker; import com.intellij.reference.SoftReference; import com.intellij.util.CommonProcessors; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.Query; import com.intellij.util.containers.ConcurrentHashMap; +import com.intellij.util.messages.MessageBus; import kotlin.Function1; import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; @@ -47,19 +50,38 @@ import java.util.List; import java.util.concurrent.ConcurrentMap; public class KotlinJavaPsiFacade { - private volatile KotlinPsiElementFinderWrapper[] myElementFinders; - private volatile SoftReference> myPackageCache; - private final Project Project; - private final GlobalSearchScope searchScope; + private volatile KotlinPsiElementFinderWrapper[] elementFinders; + private volatile SoftReference, PsiPackage>> packageCache; + private final Project project; - public KotlinJavaPsiFacade(@NotNull Project project, @NotNull GlobalSearchScope searchScope) { - this.Project = project; - this.searchScope = searchScope; + public static KotlinJavaPsiFacade getInstance(Project project) { + return ServiceManager.getService(project, KotlinJavaPsiFacade.class); + } + + public KotlinJavaPsiFacade(@NotNull Project project) { + this.project = project; + + final PsiModificationTracker modificationTracker = PsiManager.getInstance(project).getModificationTracker(); + MessageBus bus = project.getMessageBus(); + + bus.connect().subscribe(PsiModificationTracker.TOPIC, new PsiModificationTracker.Listener() { + private long lastTimeSeen = -1L; + + @Override + public void modificationCountChanged() { + long now = modificationTracker.getJavaStructureModificationCount(); + if (lastTimeSeen != now) { + lastTimeSeen = now; + packageCache = null; + } + } + }); } public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { - ProgressIndicatorProvider.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly + ProgressIndicatorProvider.checkCanceled(); + // TODO: Update in IDEA 14 if (DumbService.getInstance(getProject()).isDumb()) { PsiClass[] classes = findClassesInDumbMode(qualifiedName, scope); if (classes.length != 0) { @@ -99,10 +121,10 @@ public class KotlinJavaPsiFacade { @NotNull private KotlinPsiElementFinderWrapper[] finders() { - KotlinPsiElementFinderWrapper[] answer = myElementFinders; + KotlinPsiElementFinderWrapper[] answer = elementFinders; if (answer == null) { answer = calcFinders(); - myElementFinders = answer; + elementFinders = answer; } return answer; @@ -133,14 +155,14 @@ public class KotlinJavaPsiFacade { } public PsiPackage findPackage(@NotNull String qualifiedName, GlobalSearchScope searchScope) { - assert searchScope == this.searchScope : "Illegal scope is used for package search"; - - ConcurrentMap cache = SoftReference.dereference(myPackageCache); + ConcurrentMap, PsiPackage> cache = SoftReference.dereference(packageCache); if (cache == null) { - myPackageCache = new SoftReference>(cache = new ConcurrentHashMap()); + packageCache = new SoftReference, PsiPackage>>( + cache = new ConcurrentHashMap, PsiPackage>()); } - PsiPackage aPackage = cache.get(qualifiedName); + Pair key = new Pair(qualifiedName, searchScope); + PsiPackage aPackage = cache.get(key); if (aPackage != null) { return aPackage; } @@ -148,7 +170,7 @@ public class KotlinJavaPsiFacade { for (KotlinPsiElementFinderWrapper finder : filteredFinders()) { aPackage = finder.findPackage(qualifiedName, searchScope); if (aPackage != null) { - return ConcurrencyUtil.cacheOrGet(cache, qualifiedName, aPackage); + return ConcurrencyUtil.cacheOrGet(cache, key, aPackage); } } @@ -168,7 +190,7 @@ public class KotlinJavaPsiFacade { @NotNull public Project getProject() { - return Project; + return project; } public static KotlinPsiElementFinderWrapper wrap(PsiElementFinder finder) { diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 9882ef28fb1..2c078548bed 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -195,6 +195,9 @@ + +