Make top-level property backing field private in bytecode

This commit is contained in:
Michael Bogdanov
2015-10-19 14:20:05 +03:00
parent 376c188cf7
commit c8c3e88c82
17 changed files with 112 additions and 41 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.codegen;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import kotlin.CollectionsKt;
import kotlin.StringsKt;
import kotlin.jvm.functions.Function1;
@@ -31,7 +32,6 @@ import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.load.kotlin.ModuleMapping;
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityUtilsKt;
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackageFragmentProvider;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetFunction;
import org.jetbrains.kotlin.psi.codeFragmentUtil.CodeFragmentUtilKt;
@@ -77,25 +77,21 @@ public class JvmCodegenUtil {
return !isFakeOverride && !isDelegate &&
(((context.hasThisDescriptor() && containingDeclaration == context.getThisDescriptor()) ||
((context.getParentContext() instanceof PackageContext || context.getParentContext() instanceof MultifileClassPartContext)
&& isSamePackageInSameModule(context.getParentContext().getContextDescriptor(), containingDeclaration)))
((context.getParentContext() instanceof FacadePartWithSourceFile)
&& isWithinSameFile(((FacadePartWithSourceFile) context.getParentContext()).getSourceFile(), descriptor)))
&& context.getContextKind() != OwnerKind.DEFAULT_IMPLS);
}
private static boolean isSamePackageInSameModule(
@NotNull DeclarationDescriptor callerOwner,
@NotNull DeclarationDescriptor calleeOwner
private static boolean isWithinSameFile(
@Nullable JetFile callerFile,
@NotNull CallableMemberDescriptor descriptor
) {
if (callerOwner instanceof PackageFragmentDescriptor && calleeOwner instanceof PackageFragmentDescriptor) {
PackageFragmentDescriptor callerFragment = (PackageFragmentDescriptor) callerOwner;
PackageFragmentDescriptor calleeFragment = (PackageFragmentDescriptor) calleeOwner;
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration().getOriginal();
if (containingDeclaration instanceof PackageFragmentDescriptor) {
PsiElement calleeElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
PsiFile calleeFile = calleeElement != null ? calleeElement.getContainingFile() : null;
return callerFile != null && callerFile != SourceFile.NO_SOURCE_FILE && calleeFile == callerFile;
// backing field should be used directly within same module of same package
if (callerFragment == calleeFragment) {
return true;
}
return callerFragment.getFqName().equals(calleeFragment.getFqName())
&& calleeFragment instanceof IncrementalPackageFragmentProvider.IncrementalPackageFragment;
}
return false;
}
@@ -162,7 +162,7 @@ public class MultifileClassCodegen(
var generatePart = false
val partClassInfo = state.fileClassesProvider.getFileClassInfo(file)
val partType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(partClassInfo.fileClassFqName)
val partContext = state.rootContext.intoMultifileClassPart(packageFragment, facadeClassType, partType)
val partContext = state.rootContext.intoMultifileClassPart(packageFragment, facadeClassType, partType, file)
for (declaration in file.declarations) {
if (declaration is JetProperty || declaration is JetNamedFunction) {
@@ -87,7 +87,7 @@ public class PackageCodegen {
}
Type fileClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.getFileClassFqName());
PackageContext packagePartContext = state.getRootContext().intoPackagePart(packageFragment, fileClassType);
PackageContext packagePartContext = state.getRootContext().intoPackagePart(packageFragment, fileClassType, file);
boolean generatePackagePart = false;
@@ -340,7 +340,7 @@ public class PropertyCodegen {
else if (!isDelegate && hasJvmFieldAnnotation) {
modifiers |= getDefaultVisibilityFlag(propertyDescriptor.getVisibility());
}
else if (kind != OwnerKind.PACKAGE || isDelegate) {
else {
modifiers |= ACC_PRIVATE;
}
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
@@ -180,17 +181,18 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
}
@NotNull
public PackageContext intoPackagePart(@NotNull PackageFragmentDescriptor descriptor, Type packagePartType) {
return new PackageContext(descriptor, this, packagePartType);
public PackageContext intoPackagePart(@NotNull PackageFragmentDescriptor descriptor, Type packagePartType, @Nullable JetFile sourceFile) {
return new PackageContext(descriptor, this, packagePartType, sourceFile);
}
@NotNull
public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClassPart(
@NotNull PackageFragmentDescriptor descriptor,
@NotNull Type multifileClassType,
@NotNull Type filePartType
@NotNull Type filePartType,
@NotNull JetFile sourceFile
) {
return new MultifileClassPartContext(descriptor, this, multifileClassType, filePartType);
return new MultifileClassPartContext(descriptor, this, multifileClassType, filePartType, sourceFile);
}
@NotNull
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2015 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.context;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.psi.JetFile;
public interface FacadePartWithSourceFile {
@Nullable
JetFile getSourceFile();
}
@@ -16,18 +16,24 @@
package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.org.objectweb.asm.Type;
public class MultifileClassPartContext extends MultifileClassContextBase implements DelegatingToPartContext {
public class MultifileClassPartContext extends MultifileClassContextBase implements DelegatingToPartContext, FacadePartWithSourceFile {
private final JetFile sourceFile;
public MultifileClassPartContext(
PackageFragmentDescriptor descriptor,
CodegenContext parent,
Type multifileClassType,
Type filePartType
Type filePartType,
@NotNull JetFile sourceFile
) {
super(descriptor, parent, multifileClassType, filePartType);
this.sourceFile = sourceFile;
}
@Nullable
@@ -35,4 +41,10 @@ public class MultifileClassPartContext extends MultifileClassContextBase impleme
public Type getImplementationOwnerClassType() {
return getFilePartType();
}
@NotNull
@Override
public JetFile getSourceFile() {
return sourceFile;
}
}
@@ -20,18 +20,22 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.org.objectweb.asm.Type;
public class PackageContext extends FieldOwnerContext<PackageFragmentDescriptor> implements DelegatingToPartContext {
public class PackageContext extends FieldOwnerContext<PackageFragmentDescriptor> implements DelegatingToPartContext, FacadePartWithSourceFile {
private final Type packagePartType;
@Nullable private JetFile sourceFile;
public PackageContext(
@NotNull PackageFragmentDescriptor contextDescriptor,
@NotNull CodegenContext parent,
@Nullable Type packagePartType
@Nullable Type packagePartType,
@Nullable JetFile sourceFile
) {
super(contextDescriptor, OwnerKind.PACKAGE, parent, null, null, null);
this.packagePartType = packagePartType;
this.sourceFile = sourceFile;
}
@Override
@@ -49,4 +53,10 @@ public class PackageContext extends FieldOwnerContext<PackageFragmentDescriptor>
public Type getImplementationOwnerClassType() {
return packagePartType;
}
@Nullable
@Override
public JetFile getSourceFile() {
return sourceFile;
}
}
@@ -38,7 +38,7 @@ public class PackageFacadeContext extends PackageContext implements DelegatingFa
@NotNull Type packagePartType,
@NotNull Type publicFacadeType
) {
super(contextDescriptor, parent, packagePartType);
super(contextDescriptor, parent, packagePartType, null);
this.publicFacadeType = publicFacadeType;
}
@@ -109,7 +109,8 @@ public class InlineCodegen extends CallGenerator {
initialFrameSize = codegen.getFrameMap().getCurrentSize();
context = (MethodContext) getContext(functionDescriptor, state);
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
context = (MethodContext) getContext(functionDescriptor, state, element != null ? (JetFile) element.getContainingFile() : null);
jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
// TODO: implement AS_FUNCTION inline strategy
@@ -586,12 +587,12 @@ public class InlineCodegen extends CallGenerator {
activeLambda = null;
}
public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) {
public static CodegenContext getContext(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable JetFile sourceFile) {
if (descriptor instanceof PackageFragmentDescriptor) {
return new PackageContext((PackageFragmentDescriptor) descriptor, state.getRootContext(), null);
return new PackageContext((PackageFragmentDescriptor) descriptor, state.getRootContext(), null, sourceFile);
}
CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state);
CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state, sourceFile);
if (descriptor instanceof ClassDescriptor) {
OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION;
@@ -376,7 +376,7 @@ public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostic
PackageCodegen packageCodegen = state.getFactory().forPackage(getPackageFqName(), files);
JetFile file = classOrObject.getContainingJetFile();
Type packagePartType = FileClasses.getFileClassType(state.getFileClassesProvider(), file);
PackageContext context = state.getRootContext().intoPackagePart(packageCodegen.getPackageFragment(), packagePartType);
PackageContext context = state.getRootContext().intoPackagePart(packageCodegen.getPackageFragment(), packagePartType, file);
packageCodegen.generateClassOrObject(classOrObject, context);
state.getFactory().asList();
}
@@ -1,14 +1,14 @@
public final class FileFacadeKt {
@org.jetbrains.annotations.Nullable
static final java.lang.String nullableVal = "";
private static final java.lang.String nullableVal = "";
@org.jetbrains.annotations.Nullable
static java.lang.String nullableVar;
private static java.lang.String nullableVar;
@org.jetbrains.annotations.NotNull
static final java.lang.String notNullVal = "";
private static final java.lang.String notNullVal = "";
@org.jetbrains.annotations.NotNull
static java.lang.String notNullVar;
static final java.lang.String privateNn = "";
static final java.lang.String privateN = "";
private static java.lang.String notNullVar;
private static final java.lang.String privateNn = "";
private static final java.lang.String privateN = "";
@org.jetbrains.annotations.NotNull
public static final java.lang.String notNull(@org.jetbrains.annotations.NotNull java.lang.String a) { /* compiled code */ }
@@ -0,0 +1,18 @@
// FULL_JDK
package test
import java.lang.reflect.Modifier
import kotlin.test.assertTrue
private val prop = "O"
private fun test() = "K"
fun box(): String {
val clazz = Class.forName("test.PrivateVisibilityKt")
assertTrue(Modifier.isPrivate(clazz.getDeclaredMethod("test").modifiers), "Private top level function should be private")
assertTrue(Modifier.isPrivate(clazz.getDeclaredField("prop").modifiers), "Backing field for private top level property should be private")
return "OK"
}
@@ -23,7 +23,7 @@
@kotlin.annotation.Target @java.lang.annotation.Retention @java.lang.annotation.Target @kotlin.jvm.internal.KotlinClass Anno
@kotlin.jvm.internal.KotlinFileFacade DefaultTargetsKt {
final @Anno field p2: int
private final @Anno field p2: int
method <clinit>(): void
public final method getP(): int
public final method getP2(): int
@@ -3,4 +3,4 @@
// TESTED_OBJECT_KIND: property
// TESTED_OBJECTS: TopLevelPropertyKt, test
// IS_FULL_CONTAINING_CLASS_NAME: false
// FLAGS: ACC_DEPRECATED, ACC_FINAL, ACC_STATIC
// FLAGS: ACC_DEPRECATED, ACC_FINAL, ACC_STATIC, ACC_PRIVATE
@@ -79,7 +79,7 @@ public class PropertyGenTest extends CodegenTestCase {
Field field = fields[0];
field.setAccessible(true);
assertEquals("x", field.getName());
assertEquals(Modifier.STATIC | Modifier.FINAL, field.getModifiers());
assertEquals(Modifier.STATIC | Modifier.FINAL | Modifier.PRIVATE, field.getModifiers());
assertEquals(239, field.get(null));
}
@@ -4666,6 +4666,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("privateVisibility.kt")
public void testPrivateVisibility() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/topLevelPrivate/privateVisibility.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("syntheticAccessor.kt")
public void testSyntheticAccessor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/topLevelPrivate/syntheticAccessor.kt");