J2K KotlinJavaFileStubProvider: autoconvert and minor changes

This commit is contained in:
Pavel V. Talanov
2015-10-30 20:23:14 +03:00
parent 6f02c0593b
commit 75b8985468
@@ -14,450 +14,360 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.asJava; package org.jetbrains.kotlin.asJava
import com.google.common.collect.Lists; import com.google.common.collect.Lists
import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project
import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.ClassFileViewProvider; import com.intellij.psi.ClassFileViewProvider
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager; import com.intellij.psi.PsiManager
import com.intellij.psi.impl.compiled.ClsFileImpl; import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub; import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl; import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.PsiClassHolderFileStub; import com.intellij.psi.stubs.PsiClassHolderFileStub
import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubElement
import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiModificationTracker
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.Stack; import com.intellij.util.containers.Stack
import kotlin.jvm.functions.Function0; import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.codegen.KotlinCodegenFacade
import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.CompilationErrorHandler; import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.KotlinCodegenFacade; import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.codegen.MultifileClassCodegen; import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
import org.jetbrains.kotlin.codegen.PackageCodegen; import org.jetbrains.kotlin.fileClasses.getFileClassType
import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.codegen.context.PackageContext; import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.descriptors.ClassDescriptor; import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.fileClasses.FileClasses; import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo; import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider; import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration
import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.psi.KtPsiUtil;
import org.jetbrains.kotlin.psi.KtScript;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTraceContext;
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.org.objectweb.asm.Type;
import java.util.Collection; class KotlinJavaFileStubProvider<T : WithFileStubAndExtraDiagnostics> private constructor(
import java.util.Collections; private val project: Project,
import java.util.Map; private val local: Boolean,
private val stubGenerationStrategy: StubGenerationStrategy<T>) : CachedValueProvider<T> {
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration; override fun compute(): CachedValueProvider.Result<T>? {
val packageFqName = stubGenerationStrategy.packageFqName
val files = stubGenerationStrategy.files
public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostics> implements CachedValueProvider<T> { checkForBuiltIns(packageFqName, files)
@NotNull val context = stubGenerationStrategy.getContext(files)
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<KtFile> getFiles() {
return LightClassGenerationSupport.getInstance(project).findFilesForFacade(facadeFqName, searchScope);
}
@NotNull val javaFileStub = createJavaFileStub(packageFqName, files)
@Override val bindingContext: BindingContext
public FqName getPackageFqName() { val forExtraDiagnostics = BindingTraceContext()
return facadeFqName.parent();
}
@NotNull
@Override
public LightClassConstructionContext getContext(@NotNull Collection<KtFile> 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(KtClassOrObject classOrObject) {
return shouldGenerateClass(classOrObject);
}
@Override
public boolean shouldGenerateClass(KtClassOrObject classOrObject) {
return KtPsiUtil.isLocal(classOrObject);
}
@Override
public boolean shouldGeneratePackagePart(KtFile jetFile) {
return true;
}
@Override
public boolean shouldGenerateScript(KtScript script) {
return false;
}
};
}
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<KtFile> files) {
if (!files.isEmpty()) {
KtFile representativeFile = files.iterator().next();
JvmFileClassInfo fileClassInfo = NoResolveFileClassesProvider.INSTANCE.getFileClassInfo(representativeFile);
if (!fileClassInfo.getWithJvmMultifileClass()) {
PackageCodegen codegen = state.getFactory().forPackage(representativeFile.getPackageFqName(), files);
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
state.getFactory().asList();
return;
}
}
MultifileClassCodegen codegen = state.getFactory().forMultifileClass(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 KtClassOrObject classOrObject) {
return new KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData>(
classOrObject.getProject(),
classOrObject.isLocal(),
new StubGenerationStrategy<OutermostKotlinClassLightClassData>() {
private KtFile getFile() {
return classOrObject.getContainingKtFile();
}
@NotNull
@Override
public LightClassConstructionContext getContext(@NotNull Collection<KtFile> files) {
return LightClassGenerationSupport.getInstance(classOrObject.getProject()).getContextForClassOrObject(classOrObject);
}
@NotNull
@Override
public OutermostKotlinClassLightClassData createLightClassData(
PsiJavaFileStub javaFileStub,
BindingContext bindingContext,
Diagnostics extraDiagnostics
) {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject);
if (classDescriptor == null) {
return new OutermostKotlinClassLightClassData(
javaFileStub, extraDiagnostics, FqName.ROOT, classOrObject,
Collections.<KtClassOrObject, InnerKotlinClassLightClassData>emptyMap()
);
}
FqName fqName = predictClassFqName(bindingContext, classDescriptor);
Collection<ClassDescriptor> allInnerClasses = CodegenBinding.getAllInnerClasses(bindingContext, classDescriptor);
Map<KtClassOrObject, InnerKotlinClassLightClassData> innerClassesMap = ContainerUtil.newHashMap();
for (ClassDescriptor innerClassDescriptor : allInnerClasses) {
PsiElement declaration = descriptorToDeclaration(innerClassDescriptor);
if (!(declaration instanceof KtClassOrObject)) continue;
KtClassOrObject innerClass = (KtClassOrObject) declaration;
InnerKotlinClassLightClassData innerLightClassData = new InnerKotlinClassLightClassData(
predictClassFqName(bindingContext, innerClassDescriptor),
innerClass
);
innerClassesMap.put(innerClass, innerLightClassData);
}
return new OutermostKotlinClassLightClassData(
javaFileStub,
extraDiagnostics,
fqName,
classOrObject,
innerClassesMap
);
}
@NotNull
private FqName predictClassFqName(BindingContext bindingContext, ClassDescriptor classDescriptor) {
Type asmType = CodegenBinding.getAsmType(bindingContext, classDescriptor);
//noinspection ConstantConditions
return JvmClassName.byInternalName(asmType.getClassName().replace('.', '/')).getFqNameForClassNameWithoutDollars();
}
@NotNull
@Override
public Collection<KtFile> getFiles() {
return Collections.singletonList(getFile());
}
@NotNull
@Override
public FqName getPackageFqName() {
return getFile().getPackageFqName();
}
@Override
public GenerationState.GenerateClassFilter getGenerateClassFilter() {
return new GenerationState.GenerateClassFilter() {
@Override
public boolean shouldGeneratePackagePart(KtFile jetFile) {
return true;
}
@Override
public boolean shouldAnnotateClass(KtClassOrObject classOrObject) {
return shouldGenerateClass(classOrObject);
}
@Override
public boolean shouldGenerateClass(KtClassOrObject generatedClassOrObject) {
// Trivial: generate and analyze class we are interested in.
if (generatedClassOrObject == classOrObject) return true;
// Process all parent classes as they are context for current class
// Process child classes because they probably affect members (heuristic)
if (PsiTreeUtil.isAncestor(generatedClassOrObject, classOrObject, true) ||
PsiTreeUtil.isAncestor(classOrObject, generatedClassOrObject, true)) {
return true;
}
if (generatedClassOrObject.isLocal() && classOrObject.isLocal()) {
// Local classes should be process by CodegenAnnotatingVisitor to
// decide what class they should be placed in.
//
// Example:
// class A
// fun foo() {
// trait Z: A {}
// fun bar() {
// class <caret>O2: Z {}
// }
// }
// TODO: current method will process local classes in irrelevant declarations, it should be fixed.
PsiElement commonParent = PsiTreeUtil.findCommonParent(generatedClassOrObject, classOrObject);
return commonParent != null && !(commonParent instanceof PsiFile);
}
return false;
}
@Override
public boolean shouldGenerateScript(KtScript script) {
// We generate all enclosing classes
return PsiTreeUtil.isAncestor(script, classOrObject, false);
}
};
}
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<KtFile> files) {
PackageCodegen packageCodegen = state.getFactory().forPackage(getPackageFqName(), files);
KtFile file = classOrObject.getContainingKtFile();
Type packagePartType = FileClasses.getFileClassType(state.getFileClassesProvider(), file);
PackageContext context = state.getRootContext().intoPackagePart(packageCodegen.getPackageFragment(), packagePartType, file);
packageCodegen.generateClassOrObject(classOrObject, context);
state.getFactory().asList();
}
@Override
public String toString() {
return StubGenerationStrategy.class.getName() + " for explicit class " + classOrObject.getName();
}
}
);
}
private static final Logger LOG = Logger.getInstance(KotlinJavaFileStubProvider.class);
private final Project project;
private final StubGenerationStrategy<T> stubGenerationStrategy;
private final boolean local;
private KotlinJavaFileStubProvider(
@NotNull Project project,
boolean local,
@NotNull StubGenerationStrategy<T> stubGenerationStrategy
) {
this.project = project;
this.stubGenerationStrategy = stubGenerationStrategy;
this.local = local;
}
@Nullable
@Override
public Result<T> compute() {
FqName packageFqName = stubGenerationStrategy.getPackageFqName();
Collection<KtFile> files = stubGenerationStrategy.getFiles();
checkForBuiltIns(packageFqName, files);
LightClassConstructionContext context = stubGenerationStrategy.getContext(files);
PsiJavaFileStub javaFileStub = createJavaFileStub(packageFqName, files);
BindingContext bindingContext;
BindingTraceContext forExtraDiagnostics = new BindingTraceContext();
try { try {
Stack<StubElement> stubStack = new Stack<StubElement>(); val stubStack = Stack<StubElement<PsiElement>>()
stubStack.push(javaFileStub); stubStack.push(javaFileStub)
GenerationState state = new GenerationState( val state = GenerationState(
project, project,
new KotlinLightClassBuilderFactory(stubStack), KotlinLightClassBuilderFactory(stubStack),
context.getModule(), context.module,
context.getBindingContext(), context.bindingContext,
Lists.newArrayList(files), Lists.newArrayList(files),
/*disable not-null assertions*/false, false, /*disable not-null assertions*/false, false,
/*generateClassFilter=*/stubGenerationStrategy.getGenerateClassFilter(), /*generateClassFilter=*/stubGenerationStrategy.generateClassFilter,
/*disableInline=*/false, /*disableInline=*/false,
/*disableOptimization=*/false, /*disableOptimization=*/false,
/*useTypeTableInSerializer=*/false, /*useTypeTableInSerializer=*/false,
forExtraDiagnostics forExtraDiagnostics)
); KotlinCodegenFacade.prepareForCompilation(state)
KotlinCodegenFacade.prepareForCompilation(state);
bindingContext = state.getBindingContext(); bindingContext = state.bindingContext
stubGenerationStrategy.generate(state, files); stubGenerationStrategy.generate(state, files)
StubElement pop = stubStack.pop(); val pop = stubStack.pop()
if (pop != javaFileStub) { if (pop !== javaFileStub) {
LOG.error("Unbalanced stack operations: " + pop); LOG.error("Unbalanced stack operations: " + pop)
} }
} }
catch (ProcessCanceledException e) { catch (e: ProcessCanceledException) {
throw e; throw e
} }
catch (RuntimeException e) { catch (e: RuntimeException) {
logErrorWithOSInfo(e, packageFqName, null); logErrorWithOSInfo(e, packageFqName, null)
throw e; throw e
} }
Diagnostics extraDiagnostics = forExtraDiagnostics.getBindingContext().getDiagnostics(); val extraDiagnostics = forExtraDiagnostics.bindingContext.diagnostics
return Result.create( return CachedValueProvider.Result.create(
stubGenerationStrategy.createLightClassData(javaFileStub, bindingContext, extraDiagnostics), stubGenerationStrategy.createLightClassData(javaFileStub, bindingContext, extraDiagnostics),
local ? PsiModificationTracker.MODIFICATION_COUNT : PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT if (local) PsiModificationTracker.MODIFICATION_COUNT else PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
);
} }
@NotNull private fun createJavaFileStub(packageFqName: FqName, files: Collection<KtFile>): PsiJavaFileStub {
private static ClsFileImpl createFakeClsFile( val javaFileStub = PsiJavaFileStubImpl(packageFqName.asString(), true)
@NotNull Project project, javaFileStub.psiFactory = ClsWrapperStubPsiFactory()
@NotNull final FqName packageFqName,
@NotNull Collection<KtFile> files,
@NotNull final Function0<? extends PsiClassHolderFileStub> fileStubProvider
) {
PsiManager manager = PsiManager.getInstance(project);
VirtualFile virtualFile = getRepresentativeVirtualFile(files); val fakeFile = createFakeClsFile(project, packageFqName, files, object : Function0<PsiClassHolderFileStub<PsiFile>> {
ClsFileImpl fakeFile = new ClsFileImpl(new ClassFileViewProvider(manager, virtualFile)) { override fun invoke(): PsiClassHolderFileStub<PsiFile> {
@NotNull return javaFileStub
@Override }
public PsiClassHolderFileStub getStub() { })
return fileStubProvider.invoke();
javaFileStub.setPsi(fakeFile)
return javaFileStub
}
companion object {
fun createForFacadeClass(
project: Project,
facadeFqName: FqName,
searchScope: GlobalSearchScope): CachedValueProvider<KotlinFacadeLightClassData> {
return KotlinJavaFileStubProvider(
project,
false,
object : StubGenerationStrategy<KotlinFacadeLightClassData> {
override val files: Collection<KtFile>
get() = LightClassGenerationSupport.getInstance(project).findFilesForFacade(facadeFqName, searchScope)
override val packageFqName: FqName
get() = facadeFqName.parent()
override fun getContext(files: Collection<KtFile>): LightClassConstructionContext {
return LightClassGenerationSupport.getInstance(project).getContextForFacade(files)
}
override fun createLightClassData(
javaFileStub: PsiJavaFileStub,
bindingContext: BindingContext,
extraDiagnostics: Diagnostics): KotlinFacadeLightClassData {
return KotlinFacadeLightClassData(javaFileStub, extraDiagnostics)
}
override val generateClassFilter: GenerationState.GenerateClassFilter
get() = object : GenerationState.GenerateClassFilter() {
override fun shouldAnnotateClass(classOrObject: KtClassOrObject): Boolean {
return shouldGenerateClass(classOrObject)
}
override fun shouldGenerateClass(classOrObject: KtClassOrObject): Boolean {
return KtPsiUtil.isLocal(classOrObject)
}
override fun shouldGeneratePackagePart(jetFile: KtFile): Boolean {
return true
}
override fun shouldGenerateScript(script: KtScript): Boolean {
return false
}
}
override fun generate(state: GenerationState, files: Collection<KtFile>) {
if (!files.isEmpty()) {
val representativeFile = files.iterator().next()
val fileClassInfo = NoResolveFileClassesProvider.getFileClassInfo(representativeFile)
if (!fileClassInfo.withJvmMultifileClass) {
val codegen = state.factory.forPackage(representativeFile.packageFqName, files)
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION)
state.factory.asList()
return
}
}
val codegen = state.factory.forMultifileClass(facadeFqName, files)
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION)
state.factory.asList()
}
override fun toString(): String {
return StubGenerationStrategy::class.java.name + " for facade class"
}
})
}
fun createForDeclaredClass(classOrObject: KtClassOrObject): KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData> {
return KotlinJavaFileStubProvider(
classOrObject.project,
classOrObject.isLocal(),
object : StubGenerationStrategy<OutermostKotlinClassLightClassData> {
private val file: KtFile
get() = classOrObject.getContainingKtFile()
override fun getContext(files: Collection<KtFile>): LightClassConstructionContext {
return LightClassGenerationSupport.getInstance(classOrObject.project).getContextForClassOrObject(classOrObject)
}
override fun createLightClassData(
javaFileStub: PsiJavaFileStub,
bindingContext: BindingContext,
extraDiagnostics: Diagnostics): OutermostKotlinClassLightClassData {
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject) ?: return OutermostKotlinClassLightClassData(
javaFileStub, extraDiagnostics, FqName.ROOT, classOrObject,
emptyMap<KtClassOrObject, InnerKotlinClassLightClassData>())
val fqName = predictClassFqName(bindingContext, classDescriptor)
val allInnerClasses = CodegenBinding.getAllInnerClasses(bindingContext, classDescriptor)
val innerClassesMap = ContainerUtil.newHashMap<KtClassOrObject, InnerKotlinClassLightClassData>()
for (innerClassDescriptor in allInnerClasses) {
val declaration = descriptorToDeclaration(innerClassDescriptor)
if (declaration !is KtClassOrObject) continue
val innerLightClassData = InnerKotlinClassLightClassData(
predictClassFqName(bindingContext, innerClassDescriptor),
declaration)
innerClassesMap.put(declaration, innerLightClassData)
}
return OutermostKotlinClassLightClassData(
javaFileStub,
extraDiagnostics,
fqName,
classOrObject,
innerClassesMap)
}
private fun predictClassFqName(bindingContext: BindingContext, classDescriptor: ClassDescriptor): FqName {
val asmType = CodegenBinding.getAsmType(bindingContext, classDescriptor)
//noinspection ConstantConditions
return JvmClassName.byInternalName(asmType.className.replace('.', '/')).fqNameForClassNameWithoutDollars
}
override val files: Collection<KtFile>
get() = listOf(file)
override val packageFqName: FqName
get() = file.packageFqName
override // Trivial: generate and analyze class we are interested in.
// Process all parent classes as they are context for current class
// Process child classes because they probably affect members (heuristic)
// Local classes should be process by CodegenAnnotatingVisitor to
// decide what class they should be placed in.
//
// Example:
// class A
// fun foo() {
// trait Z: A {}
// fun bar() {
// class <caret>O2: Z {}
// }
// }
// TODO: current method will process local classes in irrelevant declarations, it should be fixed.
// We generate all enclosing classes
val generateClassFilter: GenerationState.GenerateClassFilter
get() = object : GenerationState.GenerateClassFilter() {
override fun shouldGeneratePackagePart(jetFile: KtFile): Boolean {
return true
}
override fun shouldAnnotateClass(classOrObject: KtClassOrObject): Boolean {
return shouldGenerateClass(classOrObject)
}
override fun shouldGenerateClass(generatedClassOrObject: KtClassOrObject): Boolean {
if (generatedClassOrObject === classOrObject) return true
if (PsiTreeUtil.isAncestor(generatedClassOrObject, classOrObject, true) || PsiTreeUtil.isAncestor(classOrObject, generatedClassOrObject, true)) {
return true
}
if (generatedClassOrObject.isLocal() && classOrObject.isLocal()) {
val commonParent = PsiTreeUtil.findCommonParent(generatedClassOrObject, classOrObject)
return commonParent != null && commonParent !is PsiFile
}
return false
}
override fun shouldGenerateScript(script: KtScript): Boolean {
return PsiTreeUtil.isAncestor(script, classOrObject, false)
}
}
override fun generate(state: GenerationState, files: Collection<KtFile>) {
val packageCodegen = state.factory.forPackage(packageFqName, files)
val file = classOrObject.getContainingKtFile()
val packagePartType = state.fileClassesProvider.getFileClassType(file)
val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file)
packageCodegen.generateClassOrObject(classOrObject, context)
state.factory.asList()
}
override fun toString(): String {
return StubGenerationStrategy::class.java.name + " for explicit class " + classOrObject.name
}
})
}
private val LOG = Logger.getInstance(KotlinJavaFileStubProvider::class.java)
private fun createFakeClsFile(
project: Project,
packageFqName: FqName,
files: Collection<KtFile>,
fileStubProvider: Function0<PsiClassHolderFileStub<PsiFile>>): ClsFileImpl {
val manager = PsiManager.getInstance(project)
val virtualFile = getRepresentativeVirtualFile(files)
val fakeFile = object : ClsFileImpl(ClassFileViewProvider(manager, virtualFile)) {
override fun getStub(): PsiClassHolderFileStub<PsiFile> {
return fileStubProvider.invoke()
}
override fun getPackageName(): String {
return packageFqName.asString()
}
} }
@NotNull fakeFile.isPhysical = false
@Override return fakeFile
public String getPackageName() { }
return packageFqName.asString();
}
};
fakeFile.setPhysical(false); private fun getRepresentativeVirtualFile(files: Collection<KtFile>): VirtualFile {
return fakeFile; val firstFile = files.iterator().next()
} val virtualFile = firstFile.virtualFile
assert(virtualFile != null) { "No virtual file for " + firstFile }
return virtualFile
}
@NotNull private fun checkForBuiltIns(fqName: FqName, files: Collection<KtFile>) {
private PsiJavaFileStub createJavaFileStub(@NotNull FqName packageFqName, @NotNull Collection<KtFile> files) { for (file in files) {
final PsiJavaFileStubImpl javaFileStub = new PsiJavaFileStubImpl(packageFqName.asString(), true); if (LightClassUtil.belongsToKotlinBuiltIns(file)) {
javaFileStub.setPsiFactory(new ClsWrapperStubPsiFactory()); // We may not fail later due to some luck, but generating JetLightClasses for built-ins is a bad idea anyways
// If it fails later, there will be an exception logged
ClsFileImpl fakeFile = createFakeClsFile(project, packageFqName, files, new Function0<PsiClassHolderFileStub>() { logErrorWithOSInfo(null, fqName, file.virtualFile)
@Override }
public PsiClassHolderFileStub invoke() {
return javaFileStub;
}
});
javaFileStub.setPsi(fakeFile);
return javaFileStub;
}
@NotNull
private static VirtualFile getRepresentativeVirtualFile(@NotNull Collection<KtFile> files) {
KtFile firstFile = files.iterator().next();
VirtualFile virtualFile = firstFile.getVirtualFile();
assert virtualFile != null : "No virtual file for " + firstFile;
return virtualFile;
}
private static void checkForBuiltIns(@NotNull FqName fqName, @NotNull Collection<KtFile> files) {
for (KtFile file : files) {
if (LightClassUtil.INSTANCE$.belongsToKotlinBuiltIns(file)) {
// We may not fail later due to some luck, but generating JetLightClasses for built-ins is a bad idea anyways
// If it fails later, there will be an exception logged
logErrorWithOSInfo(null, fqName, file.getVirtualFile());
} }
} }
}
private static void logErrorWithOSInfo(@Nullable Throwable cause, @NotNull FqName fqName, @Nullable VirtualFile virtualFile) { private fun logErrorWithOSInfo(cause: Throwable?, fqName: FqName, virtualFile: VirtualFile?) {
String path = virtualFile == null ? "<null>" : virtualFile.getPath(); val path = if (virtualFile == null) "<null>" else virtualFile.path
LOG.error( LOG.error(
"Could not generate LightClass for " + fqName + " declared in " + path + "\n" + "Could not generate LightClass for " + fqName + " declared in " + path + "\n" + "built-ins dir URL is " + LightClassUtil.builtInsDirUrl + "\n" + "System: " + SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION + " Java Runtime: " + SystemInfo.JAVA_RUNTIME_VERSION,
"built-ins dir URL is " + LightClassUtil.INSTANCE$.getBuiltInsDirUrl() + "\n" + cause)
"System: " + SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION + " Java Runtime: " + SystemInfo.JAVA_RUNTIME_VERSION, }
cause);
}
private interface StubGenerationStrategy<T extends WithFileStubAndExtraDiagnostics> {
@NotNull Collection<KtFile> getFiles();
@NotNull FqName getPackageFqName();
@NotNull LightClassConstructionContext getContext(@NotNull Collection<KtFile> files);
@NotNull T createLightClassData(PsiJavaFileStub javaFileStub, BindingContext bindingContext, Diagnostics extraDiagnostics);
GenerationState.GenerateClassFilter getGenerateClassFilter();
void generate(@NotNull GenerationState state, @NotNull Collection<KtFile> files);
} }
} }
private interface StubGenerationStrategy<T : WithFileStubAndExtraDiagnostics> {
val files: Collection<KtFile>
val packageFqName: FqName
fun getContext(files: Collection<KtFile>): LightClassConstructionContext
fun createLightClassData(javaFileStub: PsiJavaFileStub, bindingContext: BindingContext, extraDiagnostics: Diagnostics): T
val generateClassFilter: GenerationState.GenerateClassFilter
fun generate(state: GenerationState, files: Collection<KtFile>)
}