diff --git a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java index 3d7358c0de9..b4c74880bd4 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/jvm/compiler/JetCoreEnvironment.java @@ -43,6 +43,7 @@ import org.jetbrains.annotations.TestOnly; import org.jetbrains.jet.CompilerModeProvider; import org.jetbrains.jet.OperationModeProvider; import org.jetbrains.jet.asJava.JavaElementFinder; +import org.jetbrains.jet.asJava.KotlinLightClassForPackage; import org.jetbrains.jet.asJava.LightClassGenerationSupport; import org.jetbrains.jet.cli.common.CLIConfigurationKeys; import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation; @@ -183,6 +184,7 @@ public class JetCoreEnvironment { CliLightClassGenerationSupport cliLightClassGenerationSupport = new CliLightClassGenerationSupport(); project.registerService(LightClassGenerationSupport.class, cliLightClassGenerationSupport); project.registerService(CliLightClassGenerationSupport.class, cliLightClassGenerationSupport); + project.registerService(KotlinLightClassForPackage.FileStubCache.class, new KotlinLightClassForPackage.FileStubCache(project)); Extensions.getArea(project) .getExtensionPoint(PsiElementFinder.EP_NAME) diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForPackage.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForPackage.java index a32b81d3974..d5ac2ba994f 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForPackage.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/KotlinLightClassForPackage.java @@ -19,6 +19,8 @@ package org.jetbrains.jet.asJava; import com.google.common.collect.Sets; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightEmptyImplementsList; @@ -26,7 +28,10 @@ import com.intellij.psi.impl.light.LightModifierList; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.search.GlobalSearchScope; 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.containers.SLRUCache; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,6 +48,88 @@ import java.util.Collections; import java.util.List; public class KotlinLightClassForPackage extends KotlinWrappingLightClass implements JetJavaMirrorMarker { + + public static class FileStubCache { + + public static FileStubCache getInstance(@NotNull Project project) { + return ServiceManager.getService(project, FileStubCache.class); + } + + private static final class Key { + private final FqName fqName; + private final GlobalSearchScope searchScope; + + private Key( + @NotNull FqName fqName, + @NotNull GlobalSearchScope searchScope + ) { + this.fqName = fqName; + this.searchScope = searchScope; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Key key = (Key) o; + + if (!fqName.equals(key.fqName)) return false; + if (!searchScope.equals(key.searchScope)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = fqName.hashCode(); + result = 31 * result + searchScope.hashCode(); + return result; + } + } + + private final class CacheData { + + private final SLRUCache> cache = new SLRUCache>(20, 30) { + @NotNull + @Override + public CachedValue createValue(Key key) { + KotlinJavaFileStubProvider stubProvider = + KotlinJavaFileStubProvider.createForPackageClass(project, key.fqName, key.searchScope); + return CachedValuesManager.getManager(project).createCachedValue(stubProvider, /*trackValue = */false); + } + }; + } + + private final Project project; + private final CachedValue cachedValue; + + public FileStubCache(@NotNull Project project) { + this.project = project; + this.cachedValue = CachedValuesManager.getManager(project).createCachedValue( + new CachedValueProvider() { + @Nullable + @Override + public Result compute() { + return Result.create(new CacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT); + } + }, + /*trackValue = */ false + ); + } + + @NotNull + public CachedValue get( + @NotNull FqName qualifiedName, + @NotNull GlobalSearchScope searchScope + ) { + synchronized (cachedValue) { + return cachedValue.getValue().cache.get(new Key(qualifiedName, searchScope)); + } + } + + } + private final FqName packageFqName; private final FqName packageClassFqName; // derived from packageFqName private final GlobalSearchScope searchScope; @@ -67,9 +154,7 @@ public class KotlinLightClassForPackage extends KotlinWrappingLightClass impleme assert !files.isEmpty() : "No files for package " + packageFqName; this.files = Sets.newHashSet(files); // needed for hashCode this.hashCode = computeHashCode(); - KotlinJavaFileStubProvider stubProvider = - KotlinJavaFileStubProvider.createForPackageClass(getProject(), packageFqName, searchScope); - this.lightClassDataCache = CachedValuesManager.getManager(getProject()).createCachedValue(stubProvider, /*trackValue = */false); + this.lightClassDataCache = FileStubCache.getInstance(getProject()).get(packageFqName, searchScope); } @Nullable diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 29ac30ed576..4ed61ec01b6 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -152,6 +152,9 @@ + +