Light class generation for new facades/parts.
1st working (naive) implementation.
This commit is contained in:
committed by
Michael Bogdanov
parent
47f5b55e65
commit
ab8b5d05ed
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
+82
-5
@@ -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>(
|
||||
|
||||
+61
-19
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user