Light class generation for new facades/parts.

1st working (naive) implementation.
This commit is contained in:
Dmitry Petrov
2015-07-30 15:54:18 +03:00
committed by Michael Bogdanov
parent 47f5b55e65
commit ab8b5d05ed
18 changed files with 339 additions and 61 deletions
@@ -32,6 +32,7 @@ import com.intellij.util.containers.SLRUCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.NamePackage;
import org.jetbrains.kotlin.psi.JetClassOrObject;
@@ -117,7 +118,10 @@ public class JavaElementFinder extends PsiElementFinder implements KotlinFinderM
findClassesAndObjects(qualifiedName, scope, answer);
if (PackageClassUtils.isPackageClassFqName(qualifiedName)) {
if (PackagePartClassUtils.isFacadeClassFqName(qualifiedName)) {
answer.addAll(lightClassGenerationSupport.getFacadeClasses(qualifiedName, scope));
}
else if (PackageClassUtils.isPackageClassFqName(qualifiedName)) {
answer.addAll(lightClassGenerationSupport.getPackageClasses(qualifiedName.parent(), scope));
}
@@ -66,15 +66,15 @@ import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToD
public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostics> implements CachedValueProvider<T> {
@NotNull
public static KotlinJavaFileStubProvider<KotlinPackageLightClassData> createForPackageClass(
public static KotlinJavaFileStubProvider<KotlinFacadeLightClassData> createForPackageClass(
@NotNull final Project project,
@NotNull final FqName packageFqName,
@NotNull final GlobalSearchScope searchScope
) {
return new KotlinJavaFileStubProvider<KotlinPackageLightClassData>(
return new KotlinJavaFileStubProvider<KotlinFacadeLightClassData>(
project,
false,
new StubGenerationStrategy<KotlinPackageLightClassData>() {
new StubGenerationStrategy<KotlinFacadeLightClassData>() {
@NotNull
@Override
public LightClassConstructionContext getContext(@NotNull Collection<JetFile> files) {
@@ -91,12 +91,12 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
@NotNull
@Override
public KotlinPackageLightClassData createLightClassData(
public KotlinFacadeLightClassData createLightClassData(
PsiJavaFileStub javaFileStub,
BindingContext bindingContext,
Diagnostics extraDiagnostics
) {
return new KotlinPackageLightClassData(javaFileStub, extraDiagnostics);
return new KotlinFacadeLightClassData(javaFileStub, extraDiagnostics);
}
@NotNull
@@ -149,6 +149,83 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
);
}
@NotNull
public static CachedValueProvider<KotlinFacadeLightClassData> createForFacadeClass(
@NotNull final Project project,
@NotNull final FqName facadeFqName,
@NotNull final GlobalSearchScope searchScope
) {
return new KotlinJavaFileStubProvider<KotlinFacadeLightClassData>(
project,
false,
new StubGenerationStrategy<KotlinFacadeLightClassData>() {
@NotNull
@Override
public Collection<JetFile> getFiles() {
return LightClassGenerationSupport.getInstance(project).findFilesForFacade(facadeFqName, searchScope);
}
@NotNull
@Override
public FqName getPackageFqName() {
return facadeFqName.parent();
}
@NotNull
@Override
public LightClassConstructionContext getContext(@NotNull Collection<JetFile> files) {
return LightClassGenerationSupport.getInstance(project).getContextForFacade(files);
}
@NotNull
@Override
public KotlinFacadeLightClassData createLightClassData(
PsiJavaFileStub javaFileStub,
BindingContext bindingContext,
Diagnostics extraDiagnostics
) {
return new KotlinFacadeLightClassData(javaFileStub, extraDiagnostics);
}
@Override
public GenerationState.GenerateClassFilter getGenerateClassFilter() {
return new GenerationState.GenerateClassFilter() {
@Override
public boolean shouldAnnotateClass(JetClassOrObject classOrObject) {
return shouldGenerateClass(classOrObject);
}
@Override
public boolean shouldGenerateClass(JetClassOrObject classOrObject) {
return JetPsiUtil.isLocal(classOrObject);
}
@Override
public boolean shouldGeneratePackagePart(JetFile jetFile) {
return true;
}
@Override
public boolean shouldGenerateScript(JetScript script) {
return false;
}
};
}
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
PackageCodegen codegen = state.getFactory().forFacade(facadeFqName, files);
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
state.getFactory().asList();
}
@Override
public String toString() {
return StubGenerationStrategy.class.getName() + " for facade class";
}
});
}
@NotNull
public static KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData> createForDeclaredClass(@NotNull final JetClassOrObject classOrObject) {
return new KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData>(
@@ -33,42 +33,70 @@ import org.jetbrains.annotations.NonNls
import org.jetbrains.kotlin.idea.JetLanguage
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.JetFile
import javax.swing.*
import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.psi.JetFile
import javax.swing.Icon
public class KotlinLightClassForFacade private constructor(
manager: PsiManager,
private val facadeClassFqName: FqName,
private val searchScope: GlobalSearchScope,
private val lightClassDataCache: CachedValue<KotlinFacadeLightClassData>,
files: Collection<JetFile>
) : KotlinWrappingLightClass(manager), JetJavaMirrorMarker {
public class FileStubCache(private val project: Project) {
private data class Key(val fqName: FqName, val searchScope: GlobalSearchScope)
private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope)
private inner class CacheData {
val cache = object : SLRUCache<Key, CachedValue<KotlinPackageLightClassData>>(20, 30) {
override fun createValue(key: Key): CachedValue<KotlinPackageLightClassData> {
public class PackageFacadeStubCache(private val project: Project) {
private inner class PackageFacadeCacheData {
val cache = object : SLRUCache<StubCacheKey, CachedValue<KotlinFacadeLightClassData>>(20, 30) {
override fun createValue(key: StubCacheKey): CachedValue<KotlinFacadeLightClassData> {
val stubProvider = KotlinJavaFileStubProvider.createForPackageClass(project, key.fqName, key.searchScope)
return CachedValuesManager.getManager(project).createCachedValue<KotlinPackageLightClassData>(stubProvider, /*trackValue = */false)
return CachedValuesManager.getManager(project).createCachedValue<KotlinFacadeLightClassData>(stubProvider, /*trackValue = */false)
}
}
}
private val cachedValue: CachedValue<CacheData> = CachedValuesManager.getManager(project).createCachedValue<CacheData>(
{ CachedValueProvider.Result.create<CacheData>(CacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) },
private val cachedValue: CachedValue<PackageFacadeCacheData> = CachedValuesManager.getManager(project).createCachedValue<PackageFacadeCacheData>(
{ CachedValueProvider.Result.create(PackageFacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) },
/*trackValue = */ false)
public fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<KotlinPackageLightClassData> {
public fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<KotlinFacadeLightClassData> {
synchronized (cachedValue) {
return cachedValue.getValue().cache.get(Key(qualifiedName, searchScope))
return cachedValue.getValue().cache.get(StubCacheKey(qualifiedName, searchScope))
}
}
companion object {
public fun getInstance(project: Project): FileStubCache {
return ServiceManager.getService<FileStubCache>(project, javaClass<FileStubCache>())
public fun getInstance(project: Project): PackageFacadeStubCache {
return ServiceManager.getService<PackageFacadeStubCache>(project, javaClass<PackageFacadeStubCache>())
}
}
}
public class FacadeStubCache(private val project: Project) {
private inner class FacadeCacheData {
val cache = object : SLRUCache<StubCacheKey, CachedValue<KotlinFacadeLightClassData>>(20, 30) {
override fun createValue(key: StubCacheKey): CachedValue<KotlinFacadeLightClassData> {
val stubProvider = KotlinJavaFileStubProvider.createForFacadeClass(project, key.fqName, key.searchScope)
return CachedValuesManager.getManager(project).createCachedValue<KotlinFacadeLightClassData>(stubProvider, /*trackValue = */false)
}
}
}
private val cachedValue: CachedValue<FacadeCacheData> = CachedValuesManager.getManager(project).createCachedValue<FacadeCacheData>(
{ CachedValueProvider.Result.create(FacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) },
/*trackValue = */ false)
public fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<KotlinFacadeLightClassData> {
synchronized (cachedValue) {
return cachedValue.getValue().cache.get(StubCacheKey(qualifiedName, searchScope))
}
}
companion object {
public fun getInstance(project: Project): FacadeStubCache {
return ServiceManager.getService<FacadeStubCache>(project, javaClass<FacadeStubCache>())
}
}
}
@@ -81,9 +109,6 @@ public class KotlinLightClassForFacade private constructor(
private val packageFqName: FqName =
facadeClassFqName.parent()
private val lightClassDataCache: CachedValue<KotlinPackageLightClassData> =
FileStubCache.getInstance(getProject()).get(packageFqName, searchScope)
private val modifierList: PsiModifierList =
LightModifierList(manager, JetLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL)
@@ -159,7 +184,7 @@ public class KotlinLightClassForFacade private constructor(
override fun isValid() = files.all { it.isValid() }
override fun copy() = KotlinLightClassForFacade(getManager(), facadeClassFqName, searchScope, files)
override fun copy() = KotlinLightClassForFacade(getManager(), facadeClassFqName, searchScope, lightClassDataCache, files)
override fun getDelegate(): PsiClass {
val psiClass = LightClassUtil.findClass(facadeClassFqName, lightClassDataCache.getValue().javaFileStub)
@@ -223,7 +248,24 @@ public class KotlinLightClassForFacade private constructor(
assert(files.isNotEmpty()) { "No files for package $packageFqName" }
val packageClassFqName = PackageClassUtils.getPackageClassFqName(packageFqName)
return KotlinLightClassForFacade(manager, packageClassFqName, searchScope, files)
val lightClassDataCache = PackageFacadeStubCache.getInstance(manager.project).get(packageFqName, searchScope)
return KotlinLightClassForFacade(manager, packageClassFqName, searchScope, lightClassDataCache, files)
}
public fun createForFacade(
manager: PsiManager,
facadeClassFqName: FqName,
searchScope: GlobalSearchScope,
files: Collection<JetFile>
): KotlinLightClassForFacade? {
if (files.any { LightClassUtil.belongsToKotlinBuiltIns(it) }) {
return null
}
assert(files.isNotEmpty()) { "No files for facade $facadeClassFqName" }
val lightClassDataCache = FacadeStubCache.getInstance(manager.project).get(facadeClassFqName, searchScope)
return KotlinLightClassForFacade(manager, facadeClassFqName, searchScope, lightClassDataCache, files)
}
}
}
@@ -73,6 +73,17 @@ public abstract class LightClassGenerationSupport {
@NotNull
public abstract Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope);
@Nullable
public abstract ClassDescriptor resolveClassToDescriptor(@NotNull JetClassOrObject classOrObject);
@NotNull
public abstract Collection<PsiClass> getFacadeClasses(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope);
@NotNull
public abstract Collection<JetFile> findFilesForFacade(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope);
@NotNull
public abstract LightClassConstructionContext getContextForFacade(@NotNull Collection<JetFile> files);
}
@@ -33,7 +33,7 @@ interface LightClassDataForKotlinClass: LightClassData {
val jvmQualifiedName: FqName
}
data class KotlinPackageLightClassData(
data class KotlinFacadeLightClassData(
override val javaFileStub: PsiJavaFileStub,
override val extraDiagnostics: Diagnostics
): LightClassData, WithFileStubAndExtraDiagnostics
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.psi.*
public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostics, moduleScope: GlobalSearchScope): Diagnostics? {
fun getDiagnosticsForPackage(file: JetFile): Diagnostics? {
val project = file.getProject()
val cache = KotlinLightClassForFacade.FileStubCache.getInstance(project)
val cache = KotlinLightClassForFacade.PackageFacadeStubCache.getInstance(project)
return cache[file.getPackageFqName(), moduleScope].getValue()?.extraDiagnostics
}