Use CodegenContext to determine outer class & enclosing method

This commit is contained in:
Alexander Udalov
2015-02-11 00:38:44 +03:00
parent c417d984c4
commit 9b28e19551
8 changed files with 239 additions and 156 deletions
@@ -203,7 +203,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
@Override
protected void done() {
writeOuterClassAndEnclosingMethod(classDescriptor);
writeOuterClassAndEnclosingMethod();
super.done();
}
@@ -256,7 +256,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
//JVMS7: A class must have an EnclosingMethod attribute if and only if it is a local class or an anonymous class.
if (isAnonymousObject(descriptor) || !(descriptor.getContainingDeclaration() instanceof ClassOrPackageFragmentDescriptor)) {
writeOuterClassAndEnclosingMethod(descriptor);
writeOuterClassAndEnclosingMethod();
}
}
@@ -20,10 +20,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import kotlin.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.context.ClassContext;
import org.jetbrains.kotlin.codegen.context.CodegenContext;
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
import org.jetbrains.kotlin.codegen.inline.NameGenerator;
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages;
@@ -37,11 +34,15 @@ import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstant;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.storage.NotNullLazyValue;
import org.jetbrains.kotlin.types.ErrorUtils;
@@ -249,41 +250,47 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
v.visitInnerClass(innerClassInternalName, outerClassInternalName, innerName, calculateInnerClassAccessFlags(innerClass));
}
protected void writeOuterClassAndEnclosingMethod(@NotNull ClassDescriptor descriptor) {
ClassDescriptor outerClass = findOuterClass(descriptor);
String outerClassName = outerClass != null
? typeMapper.mapClass(outerClass).getInternalName()
: PackagePartClassUtils.getPackagePartInternalName(element.getContainingJetFile());
FunctionDescriptor function = DescriptorUtils.getParentOfType(descriptor, FunctionDescriptor.class);
while (function != null && JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, function)) {
function = DescriptorUtils.getParentOfType(function, FunctionDescriptor.class);
protected void writeOuterClassAndEnclosingMethod() {
CodegenContext context = this.context.getParentContext();
while (context instanceof MethodContext && ((MethodContext) context).isInliningLambda()) {
// If this is a lambda which will be inlined, skip its MethodContext and enclosing ClosureContext
//noinspection ConstantConditions
context = context.getParentContext().getParentContext();
}
assert context != null : "Outermost context can't be null: " + this.context;
if (function != null) {
Method method = typeMapper.mapSignature(function).getAsmMethod();
v.visitOuterClass(outerClassName, method.getName(), method.getDescriptor());
}
else {
v.visitOuterClass(outerClassName, null, null);
Type enclosingAsmType = computeOuterClass(context);
if (enclosingAsmType != null) {
Method method = computeEnclosingMethod(context);
v.visitOuterClass(
enclosingAsmType.getInternalName(),
method == null ? null : method.getName(),
method == null ? null : method.getDescriptor()
);
}
}
@Nullable
private ClassDescriptor findOuterClass(@NotNull ClassDescriptor classDescriptor) {
DeclarationDescriptor container = classDescriptor.getContainingDeclaration();
while (container != null) {
if (container instanceof ClassDescriptor) {
return (ClassDescriptor) container;
}
else if (CodegenBinding.isLocalFunOrLambda(container) &&
!JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, container)) {
return CodegenBinding.anonymousClassForFunction(bindingContext, (FunctionDescriptor) container);
}
container = container.getContainingDeclaration();
private Type computeOuterClass(@NotNull CodegenContext<?> context) {
CodegenContext<? extends ClassOrPackageFragmentDescriptor> outermost = context.getClassOrPackageParentContext();
if (outermost instanceof ClassContext) {
return typeMapper.mapType(((ClassContext) outermost).getContextDescriptor());
}
else if (outermost instanceof PackageContext && !(outermost instanceof PackageFacadeContext)) {
return PackagePartClassUtils.getPackagePartType(element.getContainingJetFile());
}
return null;
}
@Nullable
private Method computeEnclosingMethod(@NotNull CodegenContext context) {
if (context instanceof MethodContext) {
Method method = typeMapper.mapSignature(((MethodContext) context).getFunctionDescriptor()).getAsmMethod();
if (!method.getName().equals("<clinit>")) {
return method;
}
}
return null;
}
@@ -304,7 +311,9 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
SimpleFunctionDescriptorImpl clInit =
SimpleFunctionDescriptorImpl.create(descriptor, Annotations.EMPTY, Name.special("<clinit>"), SYNTHESIZED, NO_SOURCE);
clInit.initialize(null, null, Collections.<TypeParameterDescriptor>emptyList(),
Collections.<ValueParameterDescriptor>emptyList(), null, null, Visibilities.PRIVATE);
Collections.<ValueParameterDescriptor>emptyList(),
DescriptorUtilPackage.getModule(descriptor).getBuiltIns().getUnitType(),
null, Visibilities.PRIVATE);
this.clInit = new ExpressionCodegen(mv, new FrameMap(), Type.VOID_TYPE, context.intoFunction(clInit), state, this);
}
@@ -34,16 +34,21 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
private Label methodStartLabel;
private Label methodEndLabel;
// Note: in case of code inside property accessors, functionDescriptor will be that accessor,
// but CodegenContext#contextDescriptor will be the corresponding property
private final FunctionDescriptor functionDescriptor;
protected MethodContext(
@NotNull FunctionDescriptor contextDescriptor,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull OwnerKind contextKind,
@NotNull CodegenContext parentContext,
@Nullable MutableClosure closure,
boolean isInliningLambda
) {
super(JvmCodegenUtil.getDirectMember(contextDescriptor), contextKind, parentContext, closure,
super(JvmCodegenUtil.getDirectMember(functionDescriptor), contextKind, parentContext, closure,
parentContext.hasThisDescriptor() ? parentContext.getThisDescriptor() : null, null);
this.isInliningLambda = isInliningLambda;
this.functionDescriptor = functionDescriptor;
}
@NotNull
@@ -118,4 +123,8 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
return isInliningLambda;
}
@NotNull
public FunctionDescriptor getFunctionDescriptor() {
return functionDescriptor;
}
}
@@ -0,0 +1,20 @@
trait A {
fun f(): String
}
inline fun foo(): A {
return object : A {
override fun f(): String {
return "OK"
}
}
}
fun box(): String {
val y = foo()
val enclosing = y.javaClass.getEnclosingMethod()
if (enclosing?.getName() != "foo") return "method: $enclosing"
return y.f()
}
@@ -0,0 +1,25 @@
class O {
class object {
// Currently we consider <clinit> in class O as the enclosing method of this lambda,
// so we write outer class = O and enclosing method = null
val f = {}
}
}
fun box(): String {
val javaClass = O.f.javaClass
val enclosingMethod = javaClass.getEnclosingMethod()
if (enclosingMethod != null) return "method: $enclosingMethod"
val enclosingConstructor = javaClass.getEnclosingConstructor()
if (enclosingConstructor != null) return "constructor: $enclosingConstructor"
val enclosingClass = javaClass.getEnclosingClass()
if (enclosingClass?.getName() != "O") return "enclosing class: $enclosingClass"
val declaringClass = javaClass.getDeclaringClass()
if (declaringClass != null) return "anonymous function has a declaring class: $declaringClass"
return "OK"
}
@@ -0,0 +1,21 @@
object O {
val f = {}
}
fun box(): String {
val javaClass = O.f.javaClass
val enclosingMethod = javaClass.getEnclosingMethod()
if (enclosingMethod != null) return "method: $enclosingMethod"
val enclosingConstructor = javaClass.getEnclosingConstructor()
if (enclosingConstructor == null) return "no enclosing constructor"
val enclosingClass = javaClass.getEnclosingClass()
if (enclosingClass?.getName() != "O") return "enclosing class: $enclosingClass"
val declaringClass = javaClass.getDeclaringClass()
if (declaringClass != null) return "anonymous function has a declaring class: $declaringClass"
return "OK"
}
@@ -2444,143 +2444,142 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing")
@TestDataPath("$PROJECT_ROOT")
@InnerTestClasses({Enclosing.InsideLambda.class, Enclosing.Lambda.class})
@RunWith(JUnit3RunnerWithInners.class)
public static class Enclosing extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInEnclosing() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/enclosing"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("anonymousObjectInInlinedLambda.kt")
public void testAnonymousObjectInInlinedLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/anonymousObjectInInlinedLambda.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("classInLambda.kt")
public void testClassInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/classInLambda.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("kt6368.kt")
public void testKt6368() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/kt6368.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("kt6691_lambdaInSamConstructor.kt")
public void testKt6691_lambdaInSamConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/kt6691_lambdaInSamConstructor.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInClassObject.kt")
public void testLambdaInClassObject() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInClassObject.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInConstructor.kt")
public void testLambdaInConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInConstructor.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInFunction.kt")
public void testLambdaInFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInFunction.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInLambda.kt")
public void testLambdaInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInLambda.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInLocalClassConstructor.kt")
public void testLambdaInLocalClassConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInLocalClassConstructor.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInLocalClassSuperCall.kt")
public void testLambdaInLocalClassSuperCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInLocalClassSuperCall.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInLocalFunction.kt")
public void testLambdaInLocalFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInLocalFunction.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInMemberFunction.kt")
public void testLambdaInMemberFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInMemberFunction.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInMemberFunctionInLocalClass.kt")
public void testLambdaInMemberFunctionInLocalClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInMemberFunctionInLocalClass.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInMemberFunctionInNestedClass.kt")
public void testLambdaInMemberFunctionInNestedClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInMemberFunctionInNestedClass.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInObjectDeclaration.kt")
public void testLambdaInObjectDeclaration() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInObjectDeclaration.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInObjectExpression.kt")
public void testLambdaInObjectExpression() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInObjectExpression.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInObjectLiteralSuperCall.kt")
public void testLambdaInObjectLiteralSuperCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInObjectLiteralSuperCall.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInPackage.kt")
public void testLambdaInPackage() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInPackage.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInPropertyGetter.kt")
public void testLambdaInPropertyGetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInPropertyGetter.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInPropertySetter.kt")
public void testLambdaInPropertySetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambdaInPropertySetter.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("localClassInTopLevelFunction.kt")
public void testLocalClassInTopLevelFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/localClassInTopLevelFunction.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InsideLambda extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInInsideLambda() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("classInLambda.kt")
public void testClassInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda/classInLambda.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("objectInLambda.kt")
public void testObjectInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/insideLambda/objectInLambda.kt");
doTestWithStdlib(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Lambda extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInLambda() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("kt6691_lambdaInSamConstructor.kt")
public void testKt6691_lambdaInSamConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/kt6691_lambdaInSamConstructor.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInConstructor.kt")
public void testLambdaInConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInConstructor.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInFunction.kt")
public void testLambdaInFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInFunction.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInLambda.kt")
public void testLambdaInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLambda.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInLocalClassConstructor.kt")
public void testLambdaInLocalClassConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalClassConstructor.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInLocalClassSuperCall.kt")
public void testLambdaInLocalClassSuperCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalClassSuperCall.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInLocalFunction.kt")
public void testLambdaInLocalFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInLocalFunction.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInMemberFunction.kt")
public void testLambdaInMemberFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunction.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInMemberFunctionInLocalClass.kt")
public void testLambdaInMemberFunctionInLocalClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunctionInLocalClass.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInMemberFunctionInNestedClass.kt")
public void testLambdaInMemberFunctionInNestedClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInMemberFunctionInNestedClass.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInObjectExpression.kt")
public void testLambdaInObjectExpression() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInObjectExpression.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInObjectLiteralSuperCall.kt")
public void testLambdaInObjectLiteralSuperCall() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInObjectLiteralSuperCall.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInPackage.kt")
public void testLambdaInPackage() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPackage.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInPropertyGetter.kt")
public void testLambdaInPropertyGetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPropertyGetter.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("lambdaInPropertySetter.kt")
public void testLambdaInPropertySetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/lambda/lambdaInPropertySetter.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("objectInLambda.kt")
public void testObjectInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/objectInLambda.kt");
doTestWithStdlib(fileName);
}
}