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
@@ -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;
}
@@ -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))
}
}
@@ -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);
}
});
}
}
@@ -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));
}
@@ -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
}
@@ -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)
@@ -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;
}
+5 -2
View File
@@ -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
View File
@@ -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)