Light class generation for new facades/parts.
1st working (naive) implementation.
This commit is contained in:
committed by
Michael Bogdanov
parent
47f5b55e65
commit
ab8b5d05ed
@@ -121,6 +121,18 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
return codegen;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PackageCodegen forFacade(@NotNull FqName facadeFqName, @NotNull Collection<JetFile> files) {
|
||||
assert !isDone : "Already done!";
|
||||
PackageCodegen codegen = package2codegen.get(facadeFqName);
|
||||
if (codegen == null) {
|
||||
codegen = new PackageCodegen(state, files, facadeFqName.parent());
|
||||
package2codegen.put(facadeFqName, codegen);
|
||||
}
|
||||
|
||||
return codegen;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<File> toIoFilesIgnoringNonPhysical(@NotNull Collection<? extends PsiFile> psiFiles) {
|
||||
List<File> result = Lists.newArrayList();
|
||||
|
||||
@@ -101,7 +101,7 @@ public class PackageCodegen {
|
||||
|
||||
ClassBuilder v = PackageCodegen.this.state.getFactory().newVisitor(
|
||||
PackageFacade(packageFragment == null ? compiledPackageFragment : packageFragment),
|
||||
packageClassType, PackagePartClassUtils.getPackageFilesWithCallables(files)
|
||||
packageClassType, PackagePartClassUtils.getFilesWithCallables(files)
|
||||
);
|
||||
v.defineClass(sourceFile, V1_6,
|
||||
ACC_PUBLIC | ACC_FINAL,
|
||||
@@ -126,7 +126,7 @@ public class PackageCodegen {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<JetFile> packageFilesWithCallables = PackagePartClassUtils.getPackageFilesWithCallables(packageFiles);
|
||||
List<JetFile> packageFilesWithCallables = PackagePartClassUtils.getFilesWithCallables(packageFiles);
|
||||
return packageFilesWithCallables.size() == 1 ? packageFilesWithCallables.get(0) : null;
|
||||
}
|
||||
|
||||
|
||||
+26
-1
@@ -197,7 +197,7 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
|
||||
public Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope) {
|
||||
Collection<JetFile> filesInPackage = findFilesForPackage(packageFqName, scope);
|
||||
|
||||
List<JetFile> filesWithCallables = PackagePartClassUtils.getPackageFilesWithCallables(filesInPackage);
|
||||
List<JetFile> filesWithCallables = PackagePartClassUtils.getFilesWithCallables(filesInPackage);
|
||||
if (filesWithCallables.isEmpty()) return Collections.emptyList();
|
||||
|
||||
//noinspection RedundantTypeArguments
|
||||
@@ -211,6 +211,31 @@ public class CliLightClassGenerationSupport extends LightClassGenerationSupport
|
||||
return bindingContext.get(BindingContext.CLASS, classOrObject);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<PsiClass> getFacadeClasses(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
|
||||
Collection<JetFile> filesInPackage = findFilesForPackage(facadeFqName.parent(), scope);
|
||||
List<JetFile> filesForFacade = PackagePartClassUtils.getFilesForFacade(facadeFqName, filesInPackage);
|
||||
if (filesForFacade.isEmpty()) return Collections.emptyList();
|
||||
|
||||
//noinspection RedundantTypeArguments
|
||||
return UtilsPackage.<PsiClass>emptyOrSingletonList(
|
||||
KotlinLightClassForFacade.Factory.createForFacade(psiManager, facadeFqName, scope, filesForFacade));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JetFile> findFilesForFacade(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
|
||||
Collection<JetFile> filesInPackage = findFilesForPackage(facadeFqName.parent(), scope);
|
||||
return PackagePartClassUtils.getFilesForFacade(facadeFqName, filesInPackage);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightClassConstructionContext getContextForFacade(@NotNull Collection<JetFile> files) {
|
||||
return getContext();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public BindingTraceContext createTrace() {
|
||||
|
||||
@@ -376,7 +376,8 @@ public class KotlinCoreEnvironment private constructor(
|
||||
with (projectEnvironment.getProject()) {
|
||||
registerService(javaClass<JetScriptDefinitionProvider>(), JetScriptDefinitionProvider())
|
||||
registerService(javaClass<KotlinJavaPsiFacade>(), KotlinJavaPsiFacade(this))
|
||||
registerService(javaClass<KotlinLightClassForFacade.FileStubCache>(), KotlinLightClassForFacade.FileStubCache(this))
|
||||
registerService(javaClass<KotlinLightClassForFacade.PackageFacadeStubCache>(), KotlinLightClassForFacade.PackageFacadeStubCache(this))
|
||||
registerService(javaClass<KotlinLightClassForFacade.FacadeStubCache>(), KotlinLightClassForFacade.FacadeStubCache(this))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+29
-15
@@ -16,10 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.kotlin;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -28,7 +28,10 @@ import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.JetDeclaration;
|
||||
import org.jetbrains.kotlin.psi.JetFile;
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction;
|
||||
import org.jetbrains.kotlin.psi.JetProperty;
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf;
|
||||
@@ -45,8 +48,10 @@ public class PackagePartClassUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getSanitizedIdentifier(@NotNull String str) {
|
||||
public static String getSanitizedClassNameBase(@NotNull String str) {
|
||||
if (str.isEmpty()) return "__EMPTY__";
|
||||
str = str.replaceAll("[^\\p{L}\\p{Digit}]", "_");
|
||||
str = toUpperAscii(str.charAt(0)) + str.substring(1);
|
||||
if (!Character.isJavaIdentifierStart(str.charAt(0))) {
|
||||
str = "_" + str;
|
||||
}
|
||||
@@ -68,21 +73,16 @@ public class PackagePartClassUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String FACADE_CLASS_NAME_SUFFIX = "Kt";
|
||||
|
||||
@NotNull
|
||||
public static FqName getPackagePartFqName(@NotNull FqName facadeFqName, @NotNull VirtualFile file, @Nullable JetFile jetFile) {
|
||||
String fileName = FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.getName()));
|
||||
return facadeFqName.parent().child(Name.identifier(getSanitizedClassNameBase(fileName) + FACADE_CLASS_NAME_SUFFIX));
|
||||
}
|
||||
|
||||
if (!fileName.isEmpty()) {
|
||||
char c = fileName.charAt(0);
|
||||
// Character.isUpperCase also handles non-latin characters - this is not what we want in some locales.
|
||||
// Use "ASCII capitalization".
|
||||
if ('a' <= c && c <= 'z') {
|
||||
fileName = toUpperAscii(c) + fileName.substring(1);
|
||||
}
|
||||
fileName += "Kt";
|
||||
}
|
||||
|
||||
return facadeFqName.parent().child(Name.identifier(getSanitizedIdentifier(fileName)));
|
||||
public static boolean isFacadeClassFqName(@NotNull FqName classFqName) {
|
||||
return classFqName.shortName().asString().endsWith(FACADE_CLASS_NAME_SUFFIX);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -108,7 +108,7 @@ public class PackagePartClassUtils {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JetFile> getPackageFilesWithCallables(@NotNull Collection<JetFile> packageFiles) {
|
||||
public static List<JetFile> getFilesWithCallables(@NotNull Collection<JetFile> packageFiles) {
|
||||
return ContainerUtil.filter(packageFiles, new Condition<JetFile>() {
|
||||
@Override
|
||||
public boolean value(JetFile packageFile) {
|
||||
@@ -126,4 +126,18 @@ public class PackagePartClassUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<JetFile> getFilesForFacade(@NotNull FqName facadeFqName, @NotNull Collection<JetFile> files) {
|
||||
// TODO Naive implementation. Replace it with "smarter" version.
|
||||
assert isFacadeClassFqName(facadeFqName);
|
||||
String facadeSimpleName = facadeFqName.shortName().asString();
|
||||
final String expectedSanitizedName = facadeSimpleName.substring(0, facadeSimpleName.length() - 2);
|
||||
return ContainerUtil.filter(getFilesWithCallables(files), new Condition<JetFile>() {
|
||||
@Override
|
||||
public boolean value(JetFile input) {
|
||||
String sanitizedName = getSanitizedClassNameBase(Files.getNameWithoutExtension(input.getName()));
|
||||
return expectedSanitizedName.equals(sanitizedName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ public class IncrementalPackageFragmentProvider(
|
||||
|
||||
fqNamesToLoad = (
|
||||
obsoletePackageParts.map { JvmClassName.byInternalName(it).getPackageFqName() }
|
||||
+ PackagePartClassUtils.getPackageFilesWithCallables(sourceFiles).map { it.getPackageFqName() }
|
||||
+ PackagePartClassUtils.getFilesWithCallables(sourceFiles).map { it.getPackageFqName() }
|
||||
).toSet()
|
||||
|
||||
fqNamesToLoad.forEach { createPackageFragment(it) }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
@kotlin.jvm.internal.KotlinSyntheticClass(abiVersion = 23, kind = kotlin.jvm.internal.KotlinSyntheticClass.Kind.PACKAGE_PART)
|
||||
public final class SingleFileKt {
|
||||
public static final void foo() { /* compiled code */ }
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// SingleFileKt
|
||||
|
||||
public fun foo() {}
|
||||
@@ -62,6 +62,21 @@ public class KotlinLightClassTestGenerated extends AbstractKotlinLightClassTest
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/asJava/lightClasses/facades")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Facades extends AbstractKotlinLightClassTest {
|
||||
public void testAllFilesPresentInFacades() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/asJava/lightClasses/facades"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("SingleFile.kt")
|
||||
public void testSingleFile() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/facades/SingleFile.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/asJava/lightClasses/nullabilityAnnotations")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+78
-11
@@ -84,6 +84,11 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
public LightClassConstructionContext getContextForPackage(@NotNull Collection<JetFile> files) {
|
||||
assert !files.isEmpty() : "No files in package";
|
||||
|
||||
return getContextForFiles(files);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private LightClassConstructionContext getContextForFiles(@NotNull Collection<JetFile> files) {
|
||||
List<JetFile> sortedFiles = new ArrayList<JetFile>(files);
|
||||
Collections.sort(sortedFiles, scopeFileComparator);
|
||||
|
||||
@@ -118,6 +123,14 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
return new LightClassConstructionContext(bindingContext, moduleDescriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightClassConstructionContext getContextForFacade(@NotNull Collection<JetFile> files) {
|
||||
assert !files.isEmpty() : "No files in facade";
|
||||
|
||||
return getContextForFiles(files);
|
||||
}
|
||||
|
||||
private static void forceResolvePackageDeclarations(@NotNull Collection<JetFile> files, @NotNull KotlinCodeAnalyzer session) {
|
||||
for (JetFile file : files) {
|
||||
// SCRIPT: not supported
|
||||
@@ -272,9 +285,9 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
@Override
|
||||
public Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope) {
|
||||
List<PsiClass> result = new ArrayList<PsiClass>();
|
||||
List<KotlinLightPackageClassInfo> packageClassesInfos = findPackageClassesInfos(packageFqName, scope);
|
||||
for (KotlinLightPackageClassInfo info : packageClassesInfos) {
|
||||
List<JetFile> files = PackagePartClassUtils.getPackageFilesWithCallables(info.getFiles());
|
||||
List<KotlinLightFacadeClassInfo> packageClassesInfos = findPackageClassesInfos(packageFqName, scope);
|
||||
for (KotlinLightFacadeClassInfo info : packageClassesInfos) {
|
||||
List<JetFile> files = PackagePartClassUtils.getFilesWithCallables(info.getFiles());
|
||||
if (files.isEmpty()) continue;
|
||||
|
||||
IdeaModuleInfo moduleInfo = info.getModuleInfo();
|
||||
@@ -292,7 +305,7 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
}
|
||||
}
|
||||
else {
|
||||
PsiClass clsClass = getLightClassForDecompiledPackage(packageFqName, files);
|
||||
PsiClass clsClass = getLightClassForDecompiledFacade(packageFqName, files);
|
||||
if (clsClass != null) {
|
||||
result.add(clsClass);
|
||||
}
|
||||
@@ -301,6 +314,60 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<PsiClass> getFacadeClasses(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
|
||||
List<PsiClass> result = new ArrayList<PsiClass>();
|
||||
List<KotlinLightFacadeClassInfo> facadeClassesInfos = findFacadeClassesInfos(facadeFqName, scope);
|
||||
for (KotlinLightFacadeClassInfo info : facadeClassesInfos) {
|
||||
List<JetFile> files = PackagePartClassUtils.getFilesWithCallables(info.getFiles());
|
||||
if (files.isEmpty()) continue;
|
||||
|
||||
IdeaModuleInfo moduleInfo = info.getModuleInfo();
|
||||
if (moduleInfo instanceof ModuleSourceInfo) {
|
||||
KotlinLightClassForFacade lightClass =
|
||||
KotlinLightClassForFacade.Factory.createForFacade(psiManager, facadeFqName, moduleInfo.contentScope(), files);
|
||||
if (lightClass == null) continue;
|
||||
|
||||
result.add(lightClass);
|
||||
|
||||
if (files.size() > 1) {
|
||||
for (JetFile file : files) {
|
||||
result.add(new FakeLightClassForFileOfPackage(psiManager, lightClass, file));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PsiClass clsClass = getLightClassForDecompiledFacade(facadeFqName, files);
|
||||
if (clsClass != null) {
|
||||
result.add(clsClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JetFile> findFilesForFacade(@NotNull FqName facadeFqName, @NotNull GlobalSearchScope scope) {
|
||||
// TODO naive version. Production variant should use an equivalent of JetExactPackageIndex.
|
||||
Collection<JetFile> packageFiles = findFilesForPackage(facadeFqName.parent(), scope);
|
||||
return PackagePartClassUtils.getFilesForFacade(facadeFqName, packageFiles);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<KotlinLightFacadeClassInfo> findFacadeClassesInfos(FqName facadeFqName, GlobalSearchScope scope) {
|
||||
// TODO naive version. Production variant should use an equivalent of JetExactPackageIndex.
|
||||
Collection<JetFile> packageFiles = findFilesForPackage(facadeFqName.parent(), scope);
|
||||
List<JetFile> facadeFiles = PackagePartClassUtils.getFilesForFacade(facadeFqName, packageFiles);
|
||||
Map<IdeaModuleInfo, List<JetFile>> filesByInfo = groupByModuleInfo(facadeFiles);
|
||||
List<KotlinLightFacadeClassInfo> result = new ArrayList<KotlinLightFacadeClassInfo>();
|
||||
for (Map.Entry<IdeaModuleInfo, List<JetFile>> entry : filesByInfo.entrySet()) {
|
||||
result.add(new KotlinLightFacadeClassInfo(entry.getValue(), entry.getKey()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ClassDescriptor resolveClassToDescriptor(@NotNull JetClassOrObject classOrObject) {
|
||||
@@ -313,11 +380,11 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass getLightClassForDecompiledPackage(@NotNull FqName packageFqName, @NotNull List<JetFile> filesWithCallables) {
|
||||
private static PsiClass getLightClassForDecompiledFacade(@NotNull FqName facadeFqName, @NotNull List<JetFile> filesWithCallables) {
|
||||
JetFile firstFile = filesWithCallables.iterator().next();
|
||||
if (firstFile.isCompiled()) {
|
||||
if (filesWithCallables.size() > 1) {
|
||||
LOG.error("Several files with callables for package: " + packageFqName);
|
||||
LOG.error("Several files with callables for facade: " + facadeFqName);
|
||||
}
|
||||
return createLightClassForDecompiledKotlinFile(firstFile);
|
||||
}
|
||||
@@ -325,23 +392,23 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<KotlinLightPackageClassInfo> findPackageClassesInfos(
|
||||
private List<KotlinLightFacadeClassInfo> findPackageClassesInfos(
|
||||
@NotNull FqName fqName, @NotNull GlobalSearchScope wholeScope
|
||||
) {
|
||||
Collection<JetFile> allFiles = findFilesForPackage(fqName, wholeScope);
|
||||
Map<IdeaModuleInfo, List<JetFile>> filesByInfo = groupByModuleInfo(allFiles);
|
||||
List<KotlinLightPackageClassInfo> result = new ArrayList<KotlinLightPackageClassInfo>();
|
||||
List<KotlinLightFacadeClassInfo> result = new ArrayList<KotlinLightFacadeClassInfo>();
|
||||
for (Map.Entry<IdeaModuleInfo, List<JetFile>> entry : filesByInfo.entrySet()) {
|
||||
result.add(new KotlinLightPackageClassInfo(entry.getValue(), entry.getKey()));
|
||||
result.add(new KotlinLightFacadeClassInfo(entry.getValue(), entry.getKey()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final class KotlinLightPackageClassInfo {
|
||||
private static final class KotlinLightFacadeClassInfo {
|
||||
private final Collection<JetFile> files;
|
||||
private final IdeaModuleInfo moduleInfo;
|
||||
|
||||
public KotlinLightPackageClassInfo(@NotNull Collection<JetFile> files, @NotNull IdeaModuleInfo moduleInfo) {
|
||||
public KotlinLightFacadeClassInfo(@NotNull Collection<JetFile> files, @NotNull IdeaModuleInfo moduleInfo) {
|
||||
this.files = files;
|
||||
this.moduleInfo = moduleInfo;
|
||||
}
|
||||
|
||||
@@ -206,8 +206,11 @@
|
||||
|
||||
<projectService serviceImplementation="org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerWorkspaceSettings"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FileStubCache"
|
||||
serviceImplementation="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FileStubCache"/>
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$PackageFacadeStubCache"
|
||||
serviceImplementation="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$PackageFacadeStubCache"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FacadeStubCache"
|
||||
serviceImplementation="org.jetbrains.kotlin.asJava.KotlinLightClassForFacade$FacadeStubCache"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache"/>
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ class MyClass
|
||||
// RESULT: 2: I
|
||||
frame = main():9, FrameSimpleKt {frameSimple}
|
||||
static = static = frameSimple.FrameSimpleKt
|
||||
field = topVal1: int = 1 (sp = null)
|
||||
field = topVal1: int = 1 (sp = frameSimple.kt, 3)
|
||||
local = args: java.lang.String[] = {java.lang.String[0]@uniqueID} (sp = frameSimple.kt, 5)
|
||||
local = val1: int = 1 (sp = frameSimple.kt, 6)
|
||||
local = val2: frameSimple.MyClass = {frameSimple.MyClass@uniqueID} (sp = frameSimple.kt, 7)
|
||||
|
||||
Reference in New Issue
Block a user