Fix visibility flags for lambda classes in InnerClasses attribute
This commit is contained in:
@@ -255,7 +255,10 @@ public class AsmUtil {
|
|||||||
For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
|
For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
|
||||||
Classes in byte code should be public or package private
|
Classes in byte code should be public or package private
|
||||||
*/
|
*/
|
||||||
public static int getVisibilityAccessFlagForClass(ClassDescriptor descriptor) {
|
public static int getVisibilityAccessFlagForClass(@NotNull ClassDescriptor descriptor) {
|
||||||
|
if (descriptor instanceof SyntheticClassDescriptorForLambda) {
|
||||||
|
return getVisibilityAccessFlagForAnonymous(descriptor);
|
||||||
|
}
|
||||||
if (descriptor.getVisibility() == Visibilities.PUBLIC ||
|
if (descriptor.getVisibility() == Visibilities.PUBLIC ||
|
||||||
// TODO: should be package private, but for now Kotlin's reflection can't access members of such classes
|
// TODO: should be package private, but for now Kotlin's reflection can't access members of such classes
|
||||||
descriptor.getVisibility() == Visibilities.LOCAL ||
|
descriptor.getVisibility() == Visibilities.LOCAL ||
|
||||||
@@ -265,12 +268,17 @@ public class AsmUtil {
|
|||||||
return NO_FLAG_PACKAGE_PRIVATE;
|
return NO_FLAG_PACKAGE_PRIVATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) {
|
private static int getVisibilityAccessFlagForAnonymous(@NotNull ClassDescriptor descriptor) {
|
||||||
return InlineUtil.isInlineOrContainingInline(descriptor.getContainingDeclaration()) ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
|
return InlineUtil.isInlineOrContainingInline(descriptor.getContainingDeclaration()) ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) {
|
public static int calculateInnerClassAccessFlags(@NotNull ClassDescriptor innerClass) {
|
||||||
int visibility = (innerClass.getVisibility() == Visibilities.LOCAL) ? ACC_PUBLIC : getVisibilityAccessFlag(innerClass);
|
int visibility =
|
||||||
|
innerClass instanceof SyntheticClassDescriptorForLambda
|
||||||
|
? getVisibilityAccessFlagForAnonymous(innerClass)
|
||||||
|
: innerClass.getVisibility() == Visibilities.LOCAL
|
||||||
|
? ACC_PUBLIC
|
||||||
|
: getVisibilityAccessFlag(innerClass);
|
||||||
return visibility |
|
return visibility |
|
||||||
innerAccessFlagsForModalityAndKind(innerClass) |
|
innerAccessFlagsForModalityAndKind(innerClass) |
|
||||||
(innerClass.isInner() ? 0 : ACC_STATIC);
|
(innerClass.isInner() ? 0 : ACC_STATIC);
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
|||||||
|
|
||||||
this.asmType = typeMapper.mapClass(classDescriptor);
|
this.asmType = typeMapper.mapClass(classDescriptor);
|
||||||
|
|
||||||
visibilityFlag = AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor);
|
visibilityFlag = AsmUtil.getVisibilityAccessFlagForClass(classDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class PropertyReferenceCodegen(
|
|||||||
v.defineClass(
|
v.defineClass(
|
||||||
element,
|
element,
|
||||||
V1_6,
|
V1_6,
|
||||||
ACC_FINAL or ACC_SUPER or AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor),
|
ACC_FINAL or ACC_SUPER or AsmUtil.getVisibilityAccessFlagForClass(classDescriptor),
|
||||||
asmType.internalName,
|
asmType.internalName,
|
||||||
null,
|
null,
|
||||||
superAsmType.internalName,
|
superAsmType.internalName,
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
|
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
class SyntheticClassDescriptorForLambda(
|
||||||
|
containingDeclaration: DeclarationDescriptor,
|
||||||
|
name: Name,
|
||||||
|
supertypes: Collection<KotlinType>,
|
||||||
|
element: KtElement
|
||||||
|
) : ClassDescriptorImpl(containingDeclaration, name, Modality.FINAL, ClassKind.CLASS, supertypes, element.toSourceElement()) {
|
||||||
|
init {
|
||||||
|
initialize(MemberScope.Empty, emptySet(), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-9
@@ -24,10 +24,7 @@ import kotlin.jvm.functions.Function1;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.cfg.WhenChecker;
|
import org.jetbrains.kotlin.cfg.WhenChecker;
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil;
|
import org.jetbrains.kotlin.codegen.*;
|
||||||
import org.jetbrains.kotlin.codegen.JvmRuntimeTypes;
|
|
||||||
import org.jetbrains.kotlin.codegen.SamCodegenUtil;
|
|
||||||
import org.jetbrains.kotlin.codegen.SamType;
|
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
|
||||||
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
|
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
|
||||||
@@ -94,15 +91,12 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
@NotNull String name
|
@NotNull String name
|
||||||
) {
|
) {
|
||||||
String simpleName = name.substring(name.lastIndexOf('/') + 1);
|
String simpleName = name.substring(name.lastIndexOf('/') + 1);
|
||||||
ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl(
|
ClassDescriptor classDescriptor = new SyntheticClassDescriptorForLambda(
|
||||||
correctContainerForLambda(callableDescriptor, element),
|
correctContainerForLambda(callableDescriptor, element),
|
||||||
Name.special("<closure-" + simpleName + ">"),
|
Name.special("<closure-" + simpleName + ">"),
|
||||||
Modality.FINAL,
|
|
||||||
ClassKind.CLASS,
|
|
||||||
supertypes,
|
supertypes,
|
||||||
KotlinSourceElementKt.toSourceElement(element)
|
element
|
||||||
);
|
);
|
||||||
classDescriptor.initialize(MemberScope.Empty.INSTANCE, Collections.<ConstructorDescriptor>emptySet(), null);
|
|
||||||
|
|
||||||
bindingTrace.record(CLASS_FOR_CALLABLE, callableDescriptor, classDescriptor);
|
bindingTrace.record(CLASS_FOR_CALLABLE, callableDescriptor, classDescriptor);
|
||||||
return classDescriptor;
|
return classDescriptor;
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class A {
|
||||||
|
fun foo() = fun() {}
|
||||||
|
fun bar() = {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class Foo {
|
||||||
|
inline fun foo() = { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTED_OBJECT_KIND: class
|
||||||
|
// TESTED_OBJECTS: Foo$foo$1
|
||||||
|
// FLAGS: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class Foo {
|
||||||
|
fun foo() = { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// TESTED_OBJECT_KIND: class
|
||||||
|
// TESTED_OBJECTS: Foo$foo$1
|
||||||
|
// FLAGS: ACC_FINAL, ACC_SUPER
|
||||||
@@ -103,6 +103,15 @@ public class InnerClassInfoGenTest extends CodegenTestCase {
|
|||||||
checkAccess("A", "PublicClass", ACC_PUBLIC);
|
checkAccess("A", "PublicClass", ACC_PUBLIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLambdaClassFlags() {
|
||||||
|
InnerClassAttribute foo = new InnerClassAttribute("A$foo$1", null, null, ACC_STATIC | ACC_FINAL);
|
||||||
|
InnerClassAttribute bar = new InnerClassAttribute("A$bar$1", null, null, ACC_STATIC | ACC_FINAL);
|
||||||
|
|
||||||
|
extractAndCompareInnerClasses("A", foo, bar);
|
||||||
|
extractAndCompareInnerClasses("A$foo$1", foo);
|
||||||
|
extractAndCompareInnerClasses("A$bar$1", bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void checkAccess(@NotNull String outerName, @NotNull final String innerName, int accessFlags) {
|
private void checkAccess(@NotNull String outerName, @NotNull final String innerName, int accessFlags) {
|
||||||
|
|||||||
@@ -644,6 +644,27 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/writeFlags/lambda")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Lambda extends AbstractWriteFlagsTest {
|
||||||
|
public void testAllFilesPresentInLambda() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/writeFlags/lambda"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambdaInInlineFunction.kt")
|
||||||
|
public void testLambdaInInlineFunction() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeFlags/lambda/lambdaInInlineFunction.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleLambda.kt")
|
||||||
|
public void testSimpleLambda() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/writeFlags/lambda/simpleLambda.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/writeFlags/lateinit")
|
@TestMetadata("compiler/testData/writeFlags/lateinit")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -81,10 +81,6 @@ public class ClassDescriptorImpl extends ClassDescriptorBase {
|
|||||||
this.primaryConstructor = primaryConstructor;
|
this.primaryConstructor = primaryConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPrimaryConstructor(@NotNull ConstructorDescriptor primaryConstructor) {
|
|
||||||
this.primaryConstructor = primaryConstructor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Annotations getAnnotations() {
|
public Annotations getAnnotations() {
|
||||||
|
|||||||
Reference in New Issue
Block a user