New evaluator that doesn't depend on the 'extract function' refactoring (KT-28192, KT-25220, KT-25222, KT-21650)

This commit is contained in:
Yan Zhulanow
2019-01-30 02:35:10 +03:00
parent 3e849294f0
commit 0657a3d399
69 changed files with 2300 additions and 1497 deletions
@@ -0,0 +1,279 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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.codegen
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.codegen.CalculatedCodeFragmentCodegenInfo.CalculatedParameter
import org.jetbrains.kotlin.codegen.CodeFragmentCodegenInfo.IParameter
import org.jetbrains.kotlin.codegen.binding.MutableClosure
import org.jetbrains.kotlin.codegen.context.*
import org.jetbrains.kotlin.codegen.context.LocalLookup.*
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension.Context as InCo
class CodeFragmentCodegenInfo(
val classDescriptor: ClassDescriptor,
val methodDescriptor: FunctionDescriptor,
val parameters: List<IParameter>
) {
val classType: Type = Type.getObjectType(classDescriptor.name.asString())
interface IParameter {
val targetDescriptor: DeclarationDescriptor
val targetType: KotlinType
}
}
class CodeFragmentCodegen private constructor(
private val codeFragment: KtCodeFragment,
private val info: CodeFragmentCodegenInfo,
private val calculatedInfo: CalculatedCodeFragmentCodegenInfo,
private val classContext: CodeFragmentContext,
state: GenerationState,
builder: ClassBuilder
) : MemberCodegen<KtCodeFragment>(state, null, classContext, codeFragment, builder) {
private val methodDescriptor = info.methodDescriptor
override fun generateDeclaration() {
v.defineClass(
codeFragment,
state.classFileVersion,
ACC_PUBLIC or ACC_SUPER,
info.classType.internalName,
null,
"java/lang/Object",
emptyArray()
)
}
override fun generateBody() {
genConstructor()
genMethod(classContext.intoFunction(methodDescriptor))
}
override fun generateKotlinMetadataAnnotation() {
writeSyntheticClassMetadata(v, state)
}
private fun genConstructor() {
val mv = v.newMethod(NO_ORIGIN, ACC_PUBLIC, "<init>", "()V", null, null)
if (state.classBuilderMode.generateBodies) {
mv.visitCode()
val iv = InstructionAdapter(mv)
iv.load(0, info.classType)
iv.invokespecial("java/lang/Object", "<init>", "()V", false)
iv.areturn(Type.VOID_TYPE)
}
mv.visitMaxs(-1, -1)
mv.visitEnd()
}
private fun genMethod(methodContext: MethodContext) {
val returnType = calculatedInfo.returnAsmType
val parameters = calculatedInfo.parameters
val methodDesc = Type.getMethodDescriptor(returnType, *parameters.map { it.asmType }.toTypedArray())
val mv = v.newMethod(
OtherOrigin(codeFragment, methodContext.functionDescriptor),
ACC_PUBLIC or ACC_STATIC,
methodDescriptor.name.asString(), methodDesc,
null, null
)
if (state.classBuilderMode.generateBodies) {
mv.visitCode()
val frameMap = FrameMap()
parameters.forEach { frameMap.enter(it.targetDescriptor, it.asmType) }
val codegen = object : ExpressionCodegen(mv, frameMap, returnType, methodContext, state, this) {
override fun findCapturedValue(descriptor: DeclarationDescriptor): StackValue? {
val parameter = calculatedInfo.findParameter(descriptor) ?: return super.findCapturedValue(descriptor)
return parameter.stackValue
}
override fun generateThisOrOuter(calleeContainingClass: ClassDescriptor, isSuper: Boolean): StackValue {
findCapturedValue(calleeContainingClass)?.let { return it }
return super.generateThisOrOuter(calleeContainingClass, isSuper)
}
override fun generateExtensionReceiver(descriptor: CallableDescriptor): StackValue {
val receiverParameter = descriptor.extensionReceiverParameter
if (receiverParameter != null) {
findCapturedValue(receiverParameter)?.let { return it }
}
return super.generateExtensionReceiver(descriptor)
}
override fun generateNonIntrinsicSimpleNameExpression(
expression: KtSimpleNameExpression, receiver: StackValue,
descriptor: DeclarationDescriptor, resolvedCall: ResolvedCall<*>?, isSyntheticField: Boolean
): StackValue {
val resultingDescriptor = resolvedCall?.resultingDescriptor
if (resultingDescriptor != null) {
findCapturedValue(resultingDescriptor)?.let { return it }
}
return super.generateNonIntrinsicSimpleNameExpression(expression, receiver, descriptor, resolvedCall, isSyntheticField)
}
override fun visitThisExpression(expression: KtThisExpression, receiver: StackValue?): StackValue {
val instanceReference = expression.instanceReference
val target = bindingContext[BindingContext.REFERENCE_TARGET, instanceReference]
if (target != null) {
findCapturedValue(target)?.let { return it }
}
return super.visitThisExpression(expression, receiver)
}
}
codegen.gen(codeFragment.getContentElement(), returnType)
codegen.v.areturn(returnType)
parameters.asReversed().forEach { frameMap.leave(it.targetDescriptor) }
}
mv.visitMaxs(-1, -1)
mv.visitEnd()
}
companion object {
private val INFO_USERDATA_KEY = Key.create<CodeFragmentCodegenInfo>("CODE_FRAGMENT_CODEGEN_INFO")
fun setCodeFragmentInfo(codeFragment: KtCodeFragment, info: CodeFragmentCodegenInfo) {
codeFragment.putUserData(INFO_USERDATA_KEY, info)
}
@JvmStatic
fun getCodeFragmentInfo(codeFragment: KtCodeFragment): CodeFragmentCodegenInfo {
return codeFragment.getUserData(INFO_USERDATA_KEY) ?: error("Codegen info user data is not set")
}
@JvmStatic
fun createCodegen(
declaration: KtCodeFragment,
state: GenerationState,
parentContext: CodegenContext<*>
): CodeFragmentCodegen {
val info = getCodeFragmentInfo(declaration)
val classDescriptor = info.classDescriptor
val builder = state.factory.newVisitor(OtherOrigin(declaration, classDescriptor), info.classType, declaration.containingFile)
val calculatedInfo = calculateInfo(info, state.typeMapper)
val classContext = CodeFragmentContext(state.typeMapper, classDescriptor, parentContext, calculatedInfo)
return CodeFragmentCodegen(declaration, info, calculatedInfo, classContext, state, builder)
}
private fun calculateInfo(info: CodeFragmentCodegenInfo, typeMapper: KotlinTypeMapper): CalculatedCodeFragmentCodegenInfo {
val methodSignature = typeMapper.mapSignatureSkipGeneric(info.methodDescriptor)
require(info.parameters.size == methodSignature.valueParameters.size)
require(info.parameters.size == info.methodDescriptor.valueParameters.size)
var stackIndex = 0
val parameters = mutableListOf<CalculatedParameter>()
for (parameterIndex in 0 until info.parameters.size) {
val parameter = info.parameters[parameterIndex]
val asmParameter = methodSignature.valueParameters[parameterIndex]
val parameterDescriptor = info.methodDescriptor.valueParameters[parameterIndex]
val asmType: Type
val stackValue: StackValue
val sharedAsmType = getSharedTypeIfApplicable(parameter.targetDescriptor, typeMapper)
if (sharedAsmType != null) {
asmType = sharedAsmType
val unwrappedType = typeMapper.mapType(parameter.targetType)
stackValue = StackValue.shared(stackIndex, unwrappedType)
} else {
asmType = asmParameter.asmType
stackValue = StackValue.local(stackIndex, asmType)
}
val calculatedParameter = CalculatedParameter(parameter, asmType, stackValue, parameterDescriptor)
parameters += calculatedParameter
stackIndex += if (asmType == Type.DOUBLE_TYPE || asmType == Type.LONG_TYPE) 2 else 1
}
return CalculatedCodeFragmentCodegenInfo(parameters, methodSignature.returnType)
}
fun getSharedTypeIfApplicable(descriptor: DeclarationDescriptor, typeMapper: KotlinTypeMapper): Type? {
return when (descriptor) {
is LocalVariableDescriptor -> typeMapper.getSharedVarType(descriptor)
else -> null
}
}
}
}
private class CalculatedCodeFragmentCodegenInfo(val parameters: List<CalculatedParameter>, val returnAsmType: Type) {
class CalculatedParameter(
parameter: IParameter,
val asmType: Type,
val stackValue: StackValue,
val parameterDescriptor: ValueParameterDescriptor
) : IParameter by parameter
fun findParameter(target: DeclarationDescriptor): CalculatedParameter? {
for (parameter in parameters) {
if (parameter.targetDescriptor == target || parameter.parameterDescriptor == target) {
return parameter
}
}
return null
}
}
private class CodeFragmentContext(
typeMapper: KotlinTypeMapper,
contextDescriptor: ClassDescriptor,
parentContext: CodegenContext<*>?,
private val calculatedInfo: CalculatedCodeFragmentCodegenInfo
) : ScriptLikeContext(typeMapper, contextDescriptor, parentContext) {
private val localLookup = object : LocalLookup {
override fun isLocal(descriptor: DeclarationDescriptor?): Boolean {
return calculatedInfo.parameters.any { descriptor == it.targetDescriptor || descriptor == it.parameterDescriptor }
}
}
override fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue {
val parameter = calculatedInfo.findParameter(thisOrOuterClass)
?: throw IllegalStateException("Can not generate outer receiver value for $thisOrOuterClass")
return parameter.stackValue
}
override fun captureVariable(closure: MutableClosure, target: DeclarationDescriptor): StackValue? {
val parameter = calculatedInfo.findParameter(target) ?: return null
val parameterDescriptor = parameter.parameterDescriptor
// Value is already captured
closure.captureVariables[parameterDescriptor]?.let { return it.innerValue }
// Capture new value
val closureAsmType = typeMapper.mapType(closure.closureClass)
return LocalLookupCase.VAR.innerValue(parameterDescriptor, localLookup, state, closure, closureAsmType)
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenForLambda;
import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
@@ -1759,6 +1760,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
StackValue intrinsicResult = applyIntrinsic(descriptor, IntrinsicPropertyGetter.class, resolvedCall, receiver);
if (intrinsicResult != null) return intrinsicResult;
return generateNonIntrinsicSimpleNameExpression(expression, receiver, descriptor, resolvedCall, isSyntheticField);
}
public StackValue generateNonIntrinsicSimpleNameExpression(
@NotNull KtSimpleNameExpression expression,
@NotNull StackValue receiver,
@NotNull DeclarationDescriptor descriptor,
@Nullable ResolvedCall<?> resolvedCall,
boolean isSyntheticField
) {
if (descriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
@@ -2132,6 +2143,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
else {
skipPropertyAccessors = forceField;
if (JvmCodegenUtil.isDebuggerContext(context)
&& Visibilities.isPrivate(propertyDescriptor.getVisibility())
&& bindingContext.get(BACKING_FIELD_REQUIRED, propertyDescriptor) == Boolean.TRUE
) {
skipPropertyAccessors = true;
}
ownerDescriptor = isBackingFieldMovedFromCompanion ? containingDeclaration : propertyDescriptor;
}
@@ -2772,7 +2791,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
private StackValue generateExtensionReceiver(@NotNull CallableDescriptor descriptor) {
public StackValue generateExtensionReceiver(@NotNull CallableDescriptor descriptor) {
ReceiverParameterDescriptor parameter = descriptor.getExtensionReceiverParameter();
if (myFrameMap.getIndex(parameter) != -1) {
KotlinType type = parameter.getReturnType();
@@ -2891,24 +2910,40 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
forceOuter = false;
CodegenContext enclosingContext;
//for constructor super call we should access to outer instance through parameter in locals, in other cases through field for captured outer
if (inStartConstructorContext) {
result = cur.getOuterExpression(result, false);
cur = getNotNullParentContextForMethod(cur);
enclosingContext = cur.getEnclosingClassContext();
inStartConstructorContext = false;
}
else {
cur = getNotNullParentContextForMethod(cur);
// for now the script codegen only passes this branch, since the method context for script constructor is defined using function context
if (cur instanceof ScriptContext && !(thisOrOuterClass instanceof ScriptDescriptor)) {
return ((ScriptContext) cur).getOuterReceiverExpression(result, thisOrOuterClass);
}
else {
result = cur.getOuterExpression(result, false);
enclosingContext = cur.getEnclosingClassContext();
if (!(thisOrOuterClass instanceof ScriptDescriptor)) {
if (cur instanceof ScriptLikeContext) {
/* for now the script codegen only passes this branch,
since the method context for script constructor is defined using function context */
return ((ScriptLikeContext) cur).getOuterReceiverExpression(result, thisOrOuterClass);
} else if (enclosingContext instanceof ScriptLikeContext) {
MutableClosure closure = cur.closure;
if (closure != null) {
StackValue captured = ((ScriptLikeContext) enclosingContext).captureVariable(closure, thisOrOuterClass);
if (captured != null) {
return captured;
}
}
}
}
result = cur.getOuterExpression(result, false);
}
cur = cur.getEnclosingClassContext();
cur = enclosingContext;
}
throw new UnsupportedOperationException();
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
import org.jetbrains.kotlin.resolve.source.PsiSourceElement;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.util.OperatorNameConventions;
@@ -242,8 +243,20 @@ public class JvmCodegenUtil {
}
public static boolean isDebuggerContext(@NotNull CodegenContext context) {
KtFile file = DescriptorToSourceUtils.getContainingFile(context.getContextDescriptor());
return file != null && CodeFragmentUtilKt.getSuppressDiagnosticsInDebugMode(file);
PsiFile file = null;
DeclarationDescriptor contextDescriptor = context.getContextDescriptor();
if (contextDescriptor instanceof DeclarationDescriptorWithSource) {
SourceElement sourceElement = ((DeclarationDescriptorWithSource) contextDescriptor).getSource();
if (sourceElement instanceof PsiSourceElement) {
PsiElement psi = ((PsiSourceElement) sourceElement).getPsi();
if (psi != null) {
file = psi.getContainingFile();
}
}
}
return file instanceof KtFile && CodeFragmentUtilKt.getSuppressDiagnosticsInDebugMode((KtFile) file);
}
@Nullable
@@ -32,10 +32,7 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtScript;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker;
@@ -98,30 +95,40 @@ public class PackageCodegenImpl implements PackageCodegen {
Type fileClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.getFileClassFqName());
PackageContext packagePartContext = state.getRootContext().intoPackagePart(packageFragment, fileClassType, file);
List<KtClassOrObject> classOrObjects = new ArrayList<>();
if (file instanceof KtCodeFragment) {
// Avoid generating light classes for code fragments
if (state.getClassBuilderMode().generateBodies
&& state.getGenerateDeclaredClassFilter().shouldGenerateCodeFragment((KtCodeFragment) file)
) {
CodeFragmentCodegen.createCodegen((KtCodeFragment) file, state, packagePartContext).generate();
}
} else {
List<KtClassOrObject> classOrObjects = new ArrayList<>();
for (KtDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof KtClassOrObject) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration);
if (PsiUtilsKt.hasExpectModifier(declaration) &&
(descriptor == null || !ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor))) {
continue;
for (KtDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof KtClassOrObject) {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, declaration);
if (PsiUtilsKt.hasExpectModifier(declaration) &&
(descriptor == null || !ExpectedActualDeclarationChecker.shouldGenerateExpectClass(descriptor))) {
continue;
}
KtClassOrObject classOrObject = (KtClassOrObject) declaration;
if (state.getGenerateDeclaredClassFilter().shouldGenerateClass(classOrObject)) {
classOrObjects.add(classOrObject);
}
}
else if (declaration instanceof KtScript) {
KtScript script = (KtScript) declaration;
KtClassOrObject classOrObject = (KtClassOrObject) declaration;
if (state.getGenerateDeclaredClassFilter().shouldGenerateClass(classOrObject)) {
classOrObjects.add(classOrObject);
if (state.getGenerateDeclaredClassFilter().shouldGenerateScript(script)) {
ScriptCodegen.createScriptCodegen(script, state, packagePartContext).generate();
}
}
}
else if (declaration instanceof KtScript) {
KtScript script = (KtScript) declaration;
if (state.getGenerateDeclaredClassFilter().shouldGenerateScript(script)) {
ScriptCodegen.createScriptCodegen(script, state, packagePartContext).generate();
}
}
generateClassesAndObjectsInFile(classOrObjects, packagePartContext);
}
generateClassesAndObjectsInFile(classOrObjects, packagePartContext);
if (!state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return;
@@ -222,7 +222,15 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
@Override
public void visitKtFile(@NotNull KtFile file) {
nameStack.push(AsmUtil.internalNameByFqNameWithoutInnerClasses(file.getPackageFqName()));
String name;
if (file instanceof KtCodeFragment) {
CodeFragmentCodegenInfo info = CodeFragmentCodegen.getCodeFragmentInfo((KtCodeFragment) file);
name = info.getClassDescriptor().getName().asString() + "$" + info.getMethodDescriptor().getName().asString();
} else {
name = AsmUtil.internalNameByFqNameWithoutInnerClasses(file.getPackageFqName());
}
nameStack.push(name);
visitKtElement(file);
nameStack.pop();
}
@@ -6,6 +6,8 @@
package org.jetbrains.kotlin.codegen.binding;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -90,6 +92,15 @@ public class CodegenBinding {
CodegenAnnotatingVisitor visitor = new CodegenAnnotatingVisitor(state);
for (KtFile file : allFilesInPackages(state.getBindingContext(), state.getFiles())) {
file.accept(visitor);
if (file instanceof KtCodeFragment) {
PsiElement context = file.getContext();
if (context != null) {
PsiFile contextFile = context.getContainingFile();
if (contextFile != null) {
contextFile.accept(visitor);
}
}
}
}
}
@@ -27,7 +27,7 @@ fun ClassFileFactory.getClassFiles(): Iterable<OutputFile> {
return asList().filterClassFiles()
}
fun List<OutputFile>.filterClassFiles(): Iterable<OutputFile> {
fun List<OutputFile>.filterClassFiles(): List<OutputFile> {
return filter { it.relativePath.endsWith(".class") }
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.codegen.context
import org.jetbrains.kotlin.codegen.FieldInfo
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -35,12 +34,12 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type
class ScriptContext(
val typeMapper: KotlinTypeMapper,
typeMapper: KotlinTypeMapper,
val scriptDescriptor: ScriptDescriptor,
val earlierScripts: List<ScriptDescriptor>,
contextDescriptor: ClassDescriptor,
parentContext: CodegenContext<*>?
) : ClassContext(typeMapper, contextDescriptor, OwnerKind.IMPLEMENTATION, parentContext, null) {
) : ScriptLikeContext(typeMapper, contextDescriptor, parentContext) {
val lastStatement: KtExpression?
val resultFieldInfo: FieldInfo
@@ -89,7 +88,7 @@ class ScriptContext(
fun getProvidedPropertyType(index: Int): Type = typeMapper.mapType(scriptDescriptor.scriptProvidedProperties[index].type)
fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue {
override fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue {
if (thisOrOuterClass.containingDeclaration == scriptDescriptor) {
return prefix ?: StackValue.LOCAL_0
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.codegen.context
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.binding.MutableClosure
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
abstract class ScriptLikeContext(
val typeMapper: KotlinTypeMapper,
contextDescriptor: ClassDescriptor,
parentContext: CodegenContext<*>?
) : ClassContext(typeMapper, contextDescriptor, OwnerKind.IMPLEMENTATION, parentContext, null) {
abstract fun getOuterReceiverExpression(prefix: StackValue?, thisOrOuterClass: ClassDescriptor): StackValue
open fun captureVariable(closure: MutableClosure, target: DeclarationDescriptor): StackValue? {
return null
}
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.resolve.*
@@ -120,18 +121,17 @@ class GenerationState private constructor(
abstract fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean
abstract fun shouldGeneratePackagePart(ktFile: KtFile): Boolean
abstract fun shouldGenerateScript(script: KtScript): Boolean
abstract fun shouldGenerateCodeFragment(script: KtCodeFragment): Boolean
open fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject)
companion object {
@JvmField
val GENERATE_ALL: GenerateClassFilter = object : GenerateClassFilter() {
override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean = true
override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean = true
override fun shouldGenerateScript(script: KtScript): Boolean = true
override fun shouldGeneratePackagePart(ktFile: KtFile): Boolean = true
override fun shouldGenerateCodeFragment(script: KtCodeFragment) = true
}
}
}
@@ -30,10 +30,7 @@ import org.jetbrains.kotlin.codegen.CompilationErrorHandler
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
import org.jetbrains.org.objectweb.asm.Type
@@ -199,6 +196,7 @@ private class ClassFilterForClassOrObject(private val classOrObject: KtClassOrOb
= shouldGenerateClassMembers(processingClassOrObject) || processingClassOrObject.isAncestor(classOrObject, true)
override fun shouldGenerateScript(script: KtScript) = PsiTreeUtil.isAncestor(script, classOrObject, false)
override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false
}
object ClassFilterForFacade : GenerationState.GenerateClassFilter() {
@@ -206,6 +204,7 @@ object ClassFilterForFacade : GenerationState.GenerateClassFilter() {
override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject) = KtPsiUtil.isLocal(processingClassOrObject)
override fun shouldGeneratePackagePart(ktFile: KtFile) = true
override fun shouldGenerateScript(script: KtScript) = false
override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false
}
private class ClassFilterForScript(val script: KtScript) : GenerationState.GenerateClassFilter() {
@@ -220,4 +219,5 @@ private class ClassFilterForScript(val script: KtScript) : GenerationState.Gener
override fun shouldGeneratePackagePart(ktFile: KtFile): Boolean = script.containingKtFile === ktFile
override fun shouldGenerateScript(script: KtScript): Boolean = this.script === script
override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false
}
@@ -337,6 +337,12 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
}
fun createNoCache(classOrObject: KtClassOrObject): KtLightClassForSourceDeclaration? {
val containingFile = classOrObject.containingFile
if (containingFile is KtCodeFragment) {
// Avoid building light classes for code fragments
return null
}
if (classOrObject.shouldNotBeVisibleAsLightClass()) {
return null
}
@@ -199,3 +199,5 @@ abstract class KtCodeFragment(
private val LOG = Logger.getInstance(KtCodeFragment::class.java)
}
}
var KtCodeFragment.externalDescriptors: List<DeclarationDescriptor>? by CopyablePsiUserDataProperty(Key.create("EXTERNAL_DESCRIPTORS"))
@@ -153,6 +153,9 @@ fun KtExpression.getQualifiedExpressionForReceiverOrThis(): KtExpression {
fun KtExpression.isDotReceiver(): Boolean =
(parent as? KtDotQualifiedExpression)?.receiverExpression == this
fun KtExpression.isDotSelector(): Boolean =
(parent as? KtDotQualifiedExpression)?.selectorExpression == this
fun KtExpression.getPossiblyQualifiedCallExpression(): KtCallExpression? =
((this as? KtQualifiedExpression)?.selectorExpression ?: this) as? KtCallExpression