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,253 +14,245 @@
* 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, val javaFileStub = createJavaFileStub(packageFqName, files)
@NotNull final FqName facadeFqName, val bindingContext: BindingContext
@NotNull final GlobalSearchScope searchScope val forExtraDiagnostics = BindingTraceContext()
) { try {
return new KotlinJavaFileStubProvider<KotlinFacadeLightClassData>( val stubStack = Stack<StubElement<PsiElement>>()
stubStack.push(javaFileStub)
val state = GenerationState(
project,
KotlinLightClassBuilderFactory(stubStack),
context.module,
context.bindingContext,
Lists.newArrayList(files),
/*disable not-null assertions*/false, false,
/*generateClassFilter=*/stubGenerationStrategy.generateClassFilter,
/*disableInline=*/false,
/*disableOptimization=*/false,
/*useTypeTableInSerializer=*/false,
forExtraDiagnostics)
KotlinCodegenFacade.prepareForCompilation(state)
bindingContext = state.bindingContext
stubGenerationStrategy.generate(state, files)
val pop = stubStack.pop()
if (pop !== javaFileStub) {
LOG.error("Unbalanced stack operations: " + pop)
}
}
catch (e: ProcessCanceledException) {
throw e
}
catch (e: RuntimeException) {
logErrorWithOSInfo(e, packageFqName, null)
throw e
}
val extraDiagnostics = forExtraDiagnostics.bindingContext.diagnostics
return CachedValueProvider.Result.create(
stubGenerationStrategy.createLightClassData(javaFileStub, bindingContext, extraDiagnostics),
if (local) PsiModificationTracker.MODIFICATION_COUNT else PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
}
private fun createJavaFileStub(packageFqName: FqName, files: Collection<KtFile>): PsiJavaFileStub {
val javaFileStub = PsiJavaFileStubImpl(packageFqName.asString(), true)
javaFileStub.psiFactory = ClsWrapperStubPsiFactory()
val fakeFile = createFakeClsFile(project, packageFqName, files, object : Function0<PsiClassHolderFileStub<PsiFile>> {
override fun invoke(): PsiClassHolderFileStub<PsiFile> {
return javaFileStub
}
})
javaFileStub.setPsi(fakeFile)
return javaFileStub
}
companion object {
fun createForFacadeClass(
project: Project,
facadeFqName: FqName,
searchScope: GlobalSearchScope): CachedValueProvider<KotlinFacadeLightClassData> {
return KotlinJavaFileStubProvider(
project, project,
false, false,
new StubGenerationStrategy<KotlinFacadeLightClassData>() { object : StubGenerationStrategy<KotlinFacadeLightClassData> {
@NotNull override val files: Collection<KtFile>
@Override get() = LightClassGenerationSupport.getInstance(project).findFilesForFacade(facadeFqName, searchScope)
public Collection<KtFile> getFiles() {
return 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)
} }
@NotNull override fun createLightClassData(
@Override javaFileStub: PsiJavaFileStub,
public FqName getPackageFqName() { bindingContext: BindingContext,
return facadeFqName.parent(); extraDiagnostics: Diagnostics): KotlinFacadeLightClassData {
return KotlinFacadeLightClassData(javaFileStub, extraDiagnostics)
} }
@NotNull override val generateClassFilter: GenerationState.GenerateClassFilter
@Override get() = object : GenerationState.GenerateClassFilter() {
public LightClassConstructionContext getContext(@NotNull Collection<KtFile> files) { override fun shouldAnnotateClass(classOrObject: KtClassOrObject): Boolean {
return LightClassGenerationSupport.getInstance(project).getContextForFacade(files); return shouldGenerateClass(classOrObject)
} }
@NotNull override fun shouldGenerateClass(classOrObject: KtClassOrObject): Boolean {
@Override return KtPsiUtil.isLocal(classOrObject)
public KotlinFacadeLightClassData createLightClassData(
PsiJavaFileStub javaFileStub,
BindingContext bindingContext,
Diagnostics extraDiagnostics
) {
return new KotlinFacadeLightClassData(javaFileStub, extraDiagnostics);
} }
@Override override fun shouldGeneratePackagePart(jetFile: KtFile): Boolean {
public GenerationState.GenerateClassFilter getGenerateClassFilter() { return true
return new GenerationState.GenerateClassFilter() {
@Override
public boolean shouldAnnotateClass(KtClassOrObject classOrObject) {
return shouldGenerateClass(classOrObject);
} }
@Override override fun shouldGenerateScript(script: KtScript): Boolean {
public boolean shouldGenerateClass(KtClassOrObject classOrObject) { return false
return KtPsiUtil.isLocal(classOrObject); }
} }
@Override override fun generate(state: GenerationState, files: Collection<KtFile>) {
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()) { if (!files.isEmpty()) {
KtFile representativeFile = files.iterator().next(); val representativeFile = files.iterator().next()
JvmFileClassInfo fileClassInfo = NoResolveFileClassesProvider.INSTANCE.getFileClassInfo(representativeFile); val fileClassInfo = NoResolveFileClassesProvider.getFileClassInfo(representativeFile)
if (!fileClassInfo.getWithJvmMultifileClass()) { if (!fileClassInfo.withJvmMultifileClass) {
PackageCodegen codegen = state.getFactory().forPackage(representativeFile.getPackageFqName(), files); val codegen = state.factory.forPackage(representativeFile.packageFqName, files)
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION); codegen.generate(CompilationErrorHandler.THROW_EXCEPTION)
state.getFactory().asList(); state.factory.asList()
return; return
} }
} }
MultifileClassCodegen codegen = state.getFactory().forMultifileClass(facadeFqName, files); val codegen = state.factory.forMultifileClass(facadeFqName, files)
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION); codegen.generate(CompilationErrorHandler.THROW_EXCEPTION)
state.getFactory().asList(); state.factory.asList()
} }
@Override override fun toString(): String {
public String toString() { return StubGenerationStrategy::class.java.name + " for facade class"
return StubGenerationStrategy.class.getName() + " for facade class";
} }
}); })
} }
@NotNull fun createForDeclaredClass(classOrObject: KtClassOrObject): KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData> {
public static KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData> createForDeclaredClass(@NotNull final KtClassOrObject classOrObject) { return KotlinJavaFileStubProvider(
return new KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData>( classOrObject.project,
classOrObject.getProject(),
classOrObject.isLocal(), classOrObject.isLocal(),
new StubGenerationStrategy<OutermostKotlinClassLightClassData>() { object : StubGenerationStrategy<OutermostKotlinClassLightClassData> {
private KtFile getFile() { private val file: KtFile
return classOrObject.getContainingKtFile(); get() = classOrObject.getContainingKtFile()
override fun getContext(files: Collection<KtFile>): LightClassConstructionContext {
return LightClassGenerationSupport.getInstance(classOrObject.project).getContextForClassOrObject(classOrObject)
} }
@NotNull override fun createLightClassData(
@Override javaFileStub: PsiJavaFileStub,
public LightClassConstructionContext getContext(@NotNull Collection<KtFile> files) { bindingContext: BindingContext,
return LightClassGenerationSupport.getInstance(classOrObject.getProject()).getContextForClassOrObject(classOrObject); extraDiagnostics: Diagnostics): OutermostKotlinClassLightClassData {
} val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject) ?: return OutermostKotlinClassLightClassData(
@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, javaFileStub, extraDiagnostics, FqName.ROOT, classOrObject,
Collections.<KtClassOrObject, InnerKotlinClassLightClassData>emptyMap() emptyMap<KtClassOrObject, InnerKotlinClassLightClassData>())
);
}
FqName fqName = predictClassFqName(bindingContext, classDescriptor); val fqName = predictClassFqName(bindingContext, classDescriptor)
Collection<ClassDescriptor> allInnerClasses = CodegenBinding.getAllInnerClasses(bindingContext, classDescriptor); val allInnerClasses = CodegenBinding.getAllInnerClasses(bindingContext, classDescriptor)
Map<KtClassOrObject, InnerKotlinClassLightClassData> innerClassesMap = ContainerUtil.newHashMap(); val innerClassesMap = ContainerUtil.newHashMap<KtClassOrObject, InnerKotlinClassLightClassData>()
for (ClassDescriptor innerClassDescriptor : allInnerClasses) { for (innerClassDescriptor in allInnerClasses) {
PsiElement declaration = descriptorToDeclaration(innerClassDescriptor); val declaration = descriptorToDeclaration(innerClassDescriptor)
if (!(declaration instanceof KtClassOrObject)) continue; if (declaration !is KtClassOrObject) continue
KtClassOrObject innerClass = (KtClassOrObject) declaration;
InnerKotlinClassLightClassData innerLightClassData = new InnerKotlinClassLightClassData( val innerLightClassData = InnerKotlinClassLightClassData(
predictClassFqName(bindingContext, innerClassDescriptor), predictClassFqName(bindingContext, innerClassDescriptor),
innerClass declaration)
);
innerClassesMap.put(innerClass, innerLightClassData); innerClassesMap.put(declaration, innerLightClassData)
} }
return new OutermostKotlinClassLightClassData( return OutermostKotlinClassLightClassData(
javaFileStub, javaFileStub,
extraDiagnostics, extraDiagnostics,
fqName, fqName,
classOrObject, classOrObject,
innerClassesMap innerClassesMap)
);
} }
@NotNull private fun predictClassFqName(bindingContext: BindingContext, classDescriptor: ClassDescriptor): FqName {
private FqName predictClassFqName(BindingContext bindingContext, ClassDescriptor classDescriptor) { val asmType = CodegenBinding.getAsmType(bindingContext, classDescriptor)
Type asmType = CodegenBinding.getAsmType(bindingContext, classDescriptor);
//noinspection ConstantConditions //noinspection ConstantConditions
return JvmClassName.byInternalName(asmType.getClassName().replace('.', '/')).getFqNameForClassNameWithoutDollars(); return JvmClassName.byInternalName(asmType.className.replace('.', '/')).fqNameForClassNameWithoutDollars
} }
@NotNull override val files: Collection<KtFile>
@Override get() = listOf(file)
public Collection<KtFile> getFiles() {
return Collections.singletonList(getFile());
}
@NotNull override val packageFqName: FqName
@Override get() = file.packageFqName
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;
override // Trivial: generate and analyze class we are interested in.
// Process all parent classes as they are context for current class // Process all parent classes as they are context for current class
// Process child classes because they probably affect members (heuristic) // 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 // Local classes should be process by CodegenAnnotatingVisitor to
// decide what class they should be placed in. // decide what class they should be placed in.
// //
@@ -272,192 +264,110 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
// class <caret>O2: Z {} // class <caret>O2: Z {}
// } // }
// } // }
// TODO: current method will process local classes in irrelevant declarations, it should be fixed. // 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 // We generate all enclosing classes
return PsiTreeUtil.isAncestor(script, classOrObject, false); val generateClassFilter: GenerationState.GenerateClassFilter
} get() = object : GenerationState.GenerateClassFilter() {
};
override fun shouldGeneratePackagePart(jetFile: KtFile): Boolean {
return true
} }
@Override override fun shouldAnnotateClass(classOrObject: KtClassOrObject): Boolean {
public void generate(@NotNull GenerationState state, @NotNull Collection<KtFile> files) { return shouldGenerateClass(classOrObject)
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 override fun shouldGenerateClass(generatedClassOrObject: KtClassOrObject): Boolean {
public String toString() { if (generatedClassOrObject === classOrObject) return true
return StubGenerationStrategy.class.getName() + " for explicit class " + classOrObject.getName(); if (PsiTreeUtil.isAncestor(generatedClassOrObject, classOrObject, true) || PsiTreeUtil.isAncestor(classOrObject, generatedClassOrObject, true)) {
} return true
}
);
} }
private static final Logger LOG = Logger.getInstance(KotlinJavaFileStubProvider.class); if (generatedClassOrObject.isLocal() && classOrObject.isLocal()) {
val commonParent = PsiTreeUtil.findCommonParent(generatedClassOrObject, classOrObject)
private final Project project; return commonParent != null && commonParent !is PsiFile
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 return false
@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 {
Stack<StubElement> stubStack = new Stack<StubElement>();
stubStack.push(javaFileStub);
GenerationState state = new GenerationState(
project,
new KotlinLightClassBuilderFactory(stubStack),
context.getModule(),
context.getBindingContext(),
Lists.newArrayList(files),
/*disable not-null assertions*/false, false,
/*generateClassFilter=*/stubGenerationStrategy.getGenerateClassFilter(),
/*disableInline=*/false,
/*disableOptimization=*/false,
/*useTypeTableInSerializer=*/false,
forExtraDiagnostics
);
KotlinCodegenFacade.prepareForCompilation(state);
bindingContext = state.getBindingContext();
stubGenerationStrategy.generate(state, files);
StubElement pop = stubStack.pop();
if (pop != javaFileStub) {
LOG.error("Unbalanced stack operations: " + pop);
}
}
catch (ProcessCanceledException e) {
throw e;
}
catch (RuntimeException e) {
logErrorWithOSInfo(e, packageFqName, null);
throw e;
} }
Diagnostics extraDiagnostics = forExtraDiagnostics.getBindingContext().getDiagnostics(); override fun shouldGenerateScript(script: KtScript): Boolean {
return Result.create( return PsiTreeUtil.isAncestor(script, classOrObject, false)
stubGenerationStrategy.createLightClassData(javaFileStub, bindingContext, extraDiagnostics), }
local ? PsiModificationTracker.MODIFICATION_COUNT : PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
);
} }
@NotNull override fun generate(state: GenerationState, files: Collection<KtFile>) {
private static ClsFileImpl createFakeClsFile( val packageCodegen = state.factory.forPackage(packageFqName, files)
@NotNull Project project, val file = classOrObject.getContainingKtFile()
@NotNull final FqName packageFqName, val packagePartType = state.fileClassesProvider.getFileClassType(file)
@NotNull Collection<KtFile> files, val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file)
@NotNull final Function0<? extends PsiClassHolderFileStub> fileStubProvider packageCodegen.generateClassOrObject(classOrObject, context)
) { state.factory.asList()
PsiManager manager = PsiManager.getInstance(project);
VirtualFile virtualFile = getRepresentativeVirtualFile(files);
ClsFileImpl fakeFile = new ClsFileImpl(new ClassFileViewProvider(manager, virtualFile)) {
@NotNull
@Override
public PsiClassHolderFileStub getStub() {
return fileStubProvider.invoke();
} }
@NotNull override fun toString(): String {
@Override return StubGenerationStrategy::class.java.name + " for explicit class " + classOrObject.name
public String getPackageName() {
return packageFqName.asString();
} }
}; })
fakeFile.setPhysical(false);
return fakeFile;
} }
@NotNull private val LOG = Logger.getInstance(KotlinJavaFileStubProvider::class.java)
private PsiJavaFileStub createJavaFileStub(@NotNull FqName packageFqName, @NotNull Collection<KtFile> files) {
final PsiJavaFileStubImpl javaFileStub = new PsiJavaFileStubImpl(packageFqName.asString(), true);
javaFileStub.setPsiFactory(new ClsWrapperStubPsiFactory());
ClsFileImpl fakeFile = createFakeClsFile(project, packageFqName, files, new Function0<PsiClassHolderFileStub>() { private fun createFakeClsFile(
@Override project: Project,
public PsiClassHolderFileStub invoke() { packageFqName: FqName,
return javaFileStub; files: Collection<KtFile>,
} fileStubProvider: Function0<PsiClassHolderFileStub<PsiFile>>): ClsFileImpl {
}); val manager = PsiManager.getInstance(project)
javaFileStub.setPsi(fakeFile); val virtualFile = getRepresentativeVirtualFile(files)
return javaFileStub; val fakeFile = object : ClsFileImpl(ClassFileViewProvider(manager, virtualFile)) {
override fun getStub(): PsiClassHolderFileStub<PsiFile> {
return fileStubProvider.invoke()
} }
@NotNull override fun getPackageName(): String {
private static VirtualFile getRepresentativeVirtualFile(@NotNull Collection<KtFile> files) { return packageFqName.asString()
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) { fakeFile.isPhysical = false
for (KtFile file : files) { return fakeFile
if (LightClassUtil.INSTANCE$.belongsToKotlinBuiltIns(file)) { }
private fun getRepresentativeVirtualFile(files: Collection<KtFile>): VirtualFile {
val firstFile = files.iterator().next()
val virtualFile = firstFile.virtualFile
assert(virtualFile != null) { "No virtual file for " + firstFile }
return virtualFile
}
private fun checkForBuiltIns(fqName: FqName, files: Collection<KtFile>) {
for (file in files) {
if (LightClassUtil.belongsToKotlinBuiltIns(file)) {
// We may not fail later due to some luck, but generating JetLightClasses for built-ins is a bad idea anyways // 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 // If it fails later, there will be an exception logged
logErrorWithOSInfo(null, fqName, file.getVirtualFile()); logErrorWithOSInfo(null, fqName, file.virtualFile)
} }
} }
} }
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>)
}