JVM: remove StubClassBuilder and its usage
After legacy light classes were removed, the only remaining usage was in KotlinLightClassBuilderFactory where we ran JVM backend in the LIGHT_CLASSES mode, and that was only used from diagnostic tests to report JVM backend diagnostics. We don't actually need to build stubs here, so we can just use ASM's class writer, which means that StubClassBuilder and all its dependencies can be removed.
This commit is contained in:
committed by
Space Team
parent
e5ad035039
commit
2f056fe155
+8
-24
@@ -5,38 +5,22 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler.builder
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import com.intellij.psi.stubs.StubElement
|
||||
import com.intellij.util.containers.Stack
|
||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactory
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderMode
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.org.objectweb.asm.ClassVisitor
|
||||
import org.jetbrains.org.objectweb.asm.ClassWriter
|
||||
|
||||
class KotlinLightClassBuilderFactory(private val javaFileStub: PsiJavaFileStub) : ClassBuilderFactory {
|
||||
private val stubStack = Stack<StubElement<PsiElement>>().apply {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
push(javaFileStub as StubElement<PsiElement>)
|
||||
}
|
||||
|
||||
object KotlinLightClassBuilderFactory : ClassBuilderFactory {
|
||||
override fun getClassBuilderMode(): ClassBuilderMode = ClassBuilderMode.LIGHT_CLASSES
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin) =
|
||||
StubClassBuilder(stubStack, javaFileStub)
|
||||
override fun newClassBuilder(origin: JvmDeclarationOrigin): ClassBuilder =
|
||||
object : AbstractClassBuilder() {
|
||||
override fun getVisitor(): ClassVisitor = ClassWriter(0)
|
||||
}
|
||||
|
||||
override fun asText(builder: ClassBuilder) = throw UnsupportedOperationException("asText is not implemented")
|
||||
override fun asBytes(builder: ClassBuilder) = throw UnsupportedOperationException("asBytes is not implemented")
|
||||
override fun close() {}
|
||||
|
||||
fun result(): PsiJavaFileStub {
|
||||
val pop = stubStack.pop()
|
||||
if (pop !== javaFileStub) {
|
||||
LOG.error("Unbalanced stack operations: $pop")
|
||||
}
|
||||
|
||||
return javaFileStub
|
||||
}
|
||||
}
|
||||
|
||||
private val LOG = Logger.getInstance(KotlinLightClassBuilderFactory::class.java)
|
||||
|
||||
+3
-24
@@ -9,10 +9,6 @@ import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.impl.compiled.ClsFileImpl
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
|
||||
import org.jetbrains.kotlin.asJava.builder.ClsWrapperStubPsiFactory
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
@@ -22,7 +18,7 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
|
||||
data class CodeGenerationResult(val stub: PsiJavaFileStub, val bindingContext: BindingContext, val diagnostics: Diagnostics)
|
||||
data class CodeGenerationResult(val bindingContext: BindingContext, val diagnostics: Diagnostics)
|
||||
|
||||
fun extraJvmDiagnosticsFromBackend(
|
||||
packageFqName: FqName,
|
||||
@@ -34,10 +30,9 @@ fun extraJvmDiagnosticsFromBackend(
|
||||
val project = files.first().project
|
||||
|
||||
try {
|
||||
val classBuilderFactory = KotlinLightClassBuilderFactory(createJavaFileStub(packageFqName, files))
|
||||
val state = GenerationState.Builder(
|
||||
project,
|
||||
classBuilderFactory,
|
||||
KotlinLightClassBuilderFactory,
|
||||
context.module,
|
||||
context.bindingContext,
|
||||
context.languageVersionSettings?.let {
|
||||
@@ -53,8 +48,7 @@ fun extraJvmDiagnosticsFromBackend(
|
||||
|
||||
generate(state, files)
|
||||
|
||||
val javaFileStub = classBuilderFactory.result()
|
||||
return CodeGenerationResult(javaFileStub, context.bindingContext, state.collectedExtraJvmDiagnostics)
|
||||
return CodeGenerationResult(context.bindingContext, state.collectedExtraJvmDiagnostics)
|
||||
} catch (e: ProcessCanceledException) {
|
||||
throw e
|
||||
} catch (e: RuntimeException) {
|
||||
@@ -63,21 +57,6 @@ fun extraJvmDiagnosticsFromBackend(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createJavaFileStub(packageFqName: FqName, files: Collection<KtFile>): PsiJavaFileStub {
|
||||
val javaFileStub = PsiJavaFileStubImpl(packageFqName.asString(), /* compiled = */true)
|
||||
javaFileStub.psiFactory = ClsWrapperStubPsiFactory.INSTANCE
|
||||
|
||||
val fakeFile = object : ClsFileImpl(files.first().viewProvider) {
|
||||
override fun getStub() = javaFileStub
|
||||
override fun getPackageName() = packageFqName.asString()
|
||||
override fun isPhysical() = false
|
||||
override fun getText(): String = files.singleOrNull()?.text ?: super.getText()
|
||||
}
|
||||
|
||||
javaFileStub.psi = fakeFile
|
||||
return javaFileStub
|
||||
}
|
||||
|
||||
private fun logErrorWithOSInfo(cause: Throwable?, fqName: FqName, virtualFile: VirtualFile?) {
|
||||
val path = virtualFile?.path ?: "<null>"
|
||||
LOG.error(
|
||||
|
||||
-203
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler.builder;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.compiled.InnerClassSourceStrategy;
|
||||
import com.intellij.psi.impl.compiled.StubBuildingVisitor;
|
||||
import com.intellij.psi.impl.java.stubs.PsiClassStub;
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
|
||||
import com.intellij.psi.stubs.StubBase;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.asJava.builder.ClsWrapperStubPsiFactory;
|
||||
import org.jetbrains.kotlin.asJava.builder.LightElementOrigin;
|
||||
import org.jetbrains.kotlin.asJava.builder.LightElementOriginKt;
|
||||
import org.jetbrains.kotlin.codegen.AbstractClassBuilder;
|
||||
import org.jetbrains.kotlin.fileClasses.OldPackageFacadeClassUtils;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
|
||||
import org.jetbrains.org.objectweb.asm.ClassVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.FieldVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StubClassBuilder extends AbstractClassBuilder {
|
||||
private static final InnerClassSourceStrategy<Object> EMPTY_STRATEGY = new InnerClassSourceStrategy<Object>() {
|
||||
@Override
|
||||
public Object findInnerClass(String s, Object o) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Object innerClass, StubBuildingVisitor<Object> visitor) {
|
||||
throw new UnsupportedOperationException("Shall not be called!");
|
||||
}
|
||||
};
|
||||
private final StubElement parent;
|
||||
private final PsiJavaFileStub fileStub;
|
||||
private StubBuildingVisitor v;
|
||||
private final Stack<StubElement> parentStack;
|
||||
private boolean isPackageClass = false;
|
||||
|
||||
public StubClassBuilder(@NotNull Stack<StubElement> parentStack, @NotNull PsiJavaFileStub fileStub) {
|
||||
this.parentStack = parentStack;
|
||||
this.parent = parentStack.peek();
|
||||
this.fileStub = fileStub;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ClassVisitor getVisitor() {
|
||||
assert v != null : "Called before class is defined";
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defineClass(
|
||||
PsiElement origin,
|
||||
int version,
|
||||
int access,
|
||||
@NotNull String name,
|
||||
@Nullable String signature,
|
||||
@NotNull String superName,
|
||||
@NotNull String[] interfaces
|
||||
) {
|
||||
assert v == null : "defineClass() called twice?";
|
||||
|
||||
//noinspection ConstantConditions
|
||||
v = new StubBuildingVisitor<>(null, EMPTY_STRATEGY, parent, access, calculateShortName(name));
|
||||
|
||||
super.defineClass(origin, version, access, name, signature, superName, interfaces);
|
||||
|
||||
if (origin instanceof KtFile) {
|
||||
FqName packageName = ((KtFile) origin).getPackageFqName();
|
||||
String packageClassName = OldPackageFacadeClassUtils.getPackageClassName(packageName);
|
||||
|
||||
if (name.equals(packageClassName) || name.endsWith("/" + packageClassName)) {
|
||||
isPackageClass = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPackageClass) {
|
||||
parentStack.push(v.getResult());
|
||||
}
|
||||
|
||||
((StubBase) v.getResult()).putUserData(ClsWrapperStubPsiFactory.ORIGIN, LightElementOriginKt.toLightClassOrigin(origin));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String calculateShortName(@NotNull String internalName) {
|
||||
if (parent instanceof PsiJavaFileStub) {
|
||||
assert parent == fileStub;
|
||||
String packagePrefix = getPackageInternalNamePrefix();
|
||||
assert internalName.startsWith(packagePrefix) : internalName + " : " + packagePrefix;
|
||||
return internalName.substring(packagePrefix.length());
|
||||
}
|
||||
if (parent instanceof PsiClassStub<?>) {
|
||||
String parentPrefix = getClassInternalNamePrefix((PsiClassStub) parent);
|
||||
if (parentPrefix == null) return null;
|
||||
|
||||
assert internalName.startsWith(parentPrefix) : internalName + " : " + parentPrefix;
|
||||
return internalName.substring(parentPrefix.length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getClassInternalNamePrefix(@NotNull PsiClassStub classStub) {
|
||||
String packageName = fileStub.getPackageName();
|
||||
|
||||
String classStubQualifiedName = classStub.getQualifiedName();
|
||||
if (classStubQualifiedName == null) return null;
|
||||
|
||||
if (packageName.isEmpty()) {
|
||||
return classStubQualifiedName.replace('.', '$') + "$";
|
||||
}
|
||||
else {
|
||||
return packageName.replace('.', '/') + "/" + classStubQualifiedName.substring(packageName.length() + 1).replace('.', '$') + "$";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private String getPackageInternalNamePrefix() {
|
||||
String packageName = fileStub.getPackageName();
|
||||
if (packageName.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return packageName.replace('.', '/') + "/";
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public MethodVisitor newMethod(
|
||||
@NotNull JvmDeclarationOrigin origin,
|
||||
int access,
|
||||
@NotNull String name,
|
||||
@NotNull String desc,
|
||||
@Nullable String signature,
|
||||
@Nullable String[] exceptions
|
||||
) {
|
||||
MethodVisitor internalVisitor = super.newMethod(origin, access, name, desc, signature, exceptions);
|
||||
|
||||
if (internalVisitor != EMPTY_METHOD_VISITOR) {
|
||||
// If stub for method generated
|
||||
markLastChild(origin);
|
||||
}
|
||||
|
||||
return internalVisitor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FieldVisitor newField(
|
||||
@NotNull JvmDeclarationOrigin origin,
|
||||
int access,
|
||||
@NotNull String name,
|
||||
@NotNull String desc,
|
||||
@Nullable String signature,
|
||||
@Nullable Object value
|
||||
) {
|
||||
FieldVisitor internalVisitor = super.newField(origin, access, name, desc, signature, value);
|
||||
|
||||
if (internalVisitor != EMPTY_FIELD_VISITOR) {
|
||||
// If stub for field generated
|
||||
markLastChild(origin);
|
||||
}
|
||||
|
||||
return internalVisitor;
|
||||
}
|
||||
|
||||
private void markLastChild(@NotNull JvmDeclarationOrigin origin) {
|
||||
List children = v.getResult().getChildrenStubs();
|
||||
StubBase last = (StubBase) children.get(children.size() - 1);
|
||||
|
||||
LightElementOrigin oldOrigin = last.getUserData(ClsWrapperStubPsiFactory.ORIGIN);
|
||||
if (oldOrigin != null) {
|
||||
PsiElement originalElement = oldOrigin.getOriginalElement();
|
||||
throw new IllegalStateException("Rewriting origin element: " +
|
||||
(originalElement != null ? originalElement.getText() : null) + " for stub " + last.toString());
|
||||
}
|
||||
|
||||
last.putUserData(ClsWrapperStubPsiFactory.ORIGIN, LightElementOriginKt.toLightMemberOrigin(origin));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void done(boolean generateSmapCopyToAnnotation) {
|
||||
if (!isPackageClass) {
|
||||
StubElement pop = parentStack.pop();
|
||||
assert pop == v.getResult() : "parentStack: got " + pop + ", expected " + v.getResult();
|
||||
}
|
||||
super.done(generateSmapCopyToAnnotation);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user