New evaluator that doesn't depend on the 'extract function' refactoring (KT-28192, KT-25220, KT-25222, KT-21650)
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
+9
-1
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -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
|
||||
}
|
||||
|
||||
+6
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user