KT-1018: better handling of property visibility

This commit is contained in:
Alex Tkachman
2012-01-20 14:21:38 +01:00
parent b4b1ec1bb5
commit 35a1240dc7
7 changed files with 84 additions and 44 deletions
@@ -965,14 +965,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
final boolean directToField = expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL ;
JetExpression r = getReceiverForSelector(expression);
final boolean isSuper = r instanceof JetSuperExpression;
if(propertyDescriptor.getVisibility() == Visibility.PRIVATE && context.getClassOrNamespaceDescriptor() != propertyDescriptor.getContainingDeclaration()) {
DeclarationDescriptor enclosed = propertyDescriptor.getContainingDeclaration();
if(enclosed != null && enclosed != context.getThisDescriptor()) {
CodegenContext c = context;
while(c.getContextDescriptor() != enclosed) {
c = c.getParentContext();
if(propertyDescriptor.getVisibility() == Visibility.PRIVATE && !CodegenUtil.isClassObject(propertyDescriptor.getContainingDeclaration())) {
if(context.getClassOrNamespaceDescriptor() != propertyDescriptor.getContainingDeclaration()) {
DeclarationDescriptor enclosed = propertyDescriptor.getContainingDeclaration();
if(enclosed != null && enclosed != context.getThisDescriptor()) {
CodegenContext c = context;
while(c.getContextDescriptor() != enclosed) {
c = c.getParentContext();
}
propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor);
}
propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor);
}
}
final StackValue.Property iValue = intermediateValueForProperty(propertyDescriptor, directToField, isSuper ? (JetSuperExpression)r : null);
@@ -1080,12 +1082,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
else {
owner = typeMapper.getOwner(functionDescriptor, OwnerKind.IMPLEMENTATION);
if (containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.TRAIT) {
isInterface = true;
}
else {
isInterface = false;
}
isInterface = CodegenUtil.isInterface(containingDeclaration);
}
v.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, owner, functionDescriptor.getName(), typeMapper.mapSignature(functionDescriptor.getName(),functionDescriptor).getAsmMethod().getDescriptor());
@@ -684,18 +684,26 @@ public class JetTypeMapper {
return new CallableMethod(owner, method, INVOKESPECIAL);
}
static int getAccessModifiers(JetDeclaration p, int defaultFlags) {
int flags = 0;
if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
flags |= ACC_PUBLIC;
static int getAccessModifiers(DeclarationDescriptorWithVisibility p, int defaultFlags) {
DeclarationDescriptor declaration = p.getContainingDeclaration();
if(CodegenUtil.isInterface(declaration)) {
return ACC_PUBLIC;
}
else if (p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
flags |= ACC_PRIVATE;
if (p.getVisibility() == Visibility.PUBLIC) {
return ACC_PUBLIC;
}
else if (p.getVisibility() == Visibility.PROTECTED) {
return ACC_PROTECTED;
}
else if (p.getVisibility() == Visibility.PRIVATE) {
if(CodegenUtil.isClassObject(declaration)) {
return defaultFlags;
}
return ACC_PRIVATE;
}
else {
flags |= defaultFlags;
return defaultFlags;
}
return flags;
}
String classNameForAnonymousClass(JetExpression expression) {
@@ -3,10 +3,7 @@ package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
@@ -70,7 +67,7 @@ public class PropertyCodegen {
}
int modifiers;
if (kind == OwnerKind.NAMESPACE) {
int access = isExternallyAccessible(p) ? Opcodes.ACC_PUBLIC : Opcodes.ACC_PRIVATE;
int access = JetTypeMapper.getAccessModifiers(propertyDescriptor, 0);
modifiers = access | Opcodes.ACC_STATIC;
}
else {
@@ -90,17 +87,17 @@ public class PropertyCodegen {
JvmPropertyAccessorSignature signature = state.getTypeMapper().mapGetterSignature(propertyDescriptor, kind);
functionCodegen.generateMethod(getter, signature.getJvmMethodSignature(), true, signature.getPropertyTypeKotlinSignature(), propertyDescriptor.getGetter());
}
else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultGetter(p, getter);
else if (isExternallyAccessible(propertyDescriptor)) {
generateDefaultGetter(p);
}
}
else if (isExternallyAccessible(p)) {
generateDefaultGetter(p, p);
else if (isExternallyAccessible(propertyDescriptor)) {
generateDefaultGetter(p);
}
}
private static boolean isExternallyAccessible(JetProperty p) {
return !p.hasModifier(JetTokens.PRIVATE_KEYWORD);
private static boolean isExternallyAccessible(PropertyDescriptor p) {
return p.getVisibility() != Visibility.PRIVATE || CodegenUtil.isClassObject(p.getContainingDeclaration());
}
private void generateSetter(JetProperty p, PropertyDescriptor propertyDescriptor) {
@@ -112,18 +109,18 @@ public class PropertyCodegen {
JvmPropertyAccessorSignature signature = state.getTypeMapper().mapSetterSignature(propertyDescriptor, kind);
functionCodegen.generateMethod(setter, signature.getJvmMethodSignature(), true, signature.getPropertyTypeKotlinSignature(), setterDescriptor);
}
else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultSetter(p, setter);
else if (isExternallyAccessible(propertyDescriptor)) {
generateDefaultSetter(p);
}
}
else if (isExternallyAccessible(p) && p.isVar()) {
generateDefaultSetter(p, p);
else if (isExternallyAccessible(propertyDescriptor) && propertyDescriptor.isVar()) {
generateDefaultSetter(p);
}
}
private void generateDefaultGetter(JetProperty p, JetDeclaration declaration) {
private void generateDefaultGetter(JetProperty p) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, p);
int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC);
int flags = JetTypeMapper.getAccessModifiers(propertyDescriptor, 0);
generateDefaultGetter(propertyDescriptor, flags, p);
}
@@ -176,9 +173,13 @@ public class PropertyCodegen {
aw.visitEnd();
}
private void generateDefaultSetter(JetProperty p, JetDeclaration declaration) {
private void generateDefaultSetter(JetProperty p) {
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) state.getBindingContext().get(BindingContext.VARIABLE, p);
int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC);
assert propertyDescriptor != null;
int modifiers = JetTypeMapper.getAccessModifiers(propertyDescriptor, 0);
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
int flags = setter == null ? modifiers : JetTypeMapper.getAccessModifiers(setter, modifiers);
generateDefaultSetter(propertyDescriptor, flags, p);
}
@@ -0,0 +1,12 @@
public class StockMarketTableModel() {
public fun getColumnCount() : Int {
return COLUMN_TITLES?.size.sure()
}
class object {
private val COLUMN_TITLES : Array<Int?> = Array<Int?>(10)
}
}
fun box() : String = if(StockMarketTableModel().getColumnCount()==10) "OK" else "fail"
@@ -8,7 +8,7 @@ trait M {
}
class N() : M {
override var backingB : Int = 0
public override var backingB : Int = 0
val a : Int
get() {
@@ -199,7 +199,7 @@ public class ClassGenTest extends CodegenTestCase {
public void testKt508 () throws Exception {
loadFile("regressions/kt508.jet");
// System.out.println(generateToText());
System.out.println(generateToText());
blackBox();
}
@@ -245,4 +245,8 @@ public class ClassGenTest extends CodegenTestCase {
public void testKt940 () throws Exception {
blackBoxFile("regressions/kt940.kt");
}
public void testKt1018 () throws Exception {
blackBoxFile("regressions/kt1018.kt");
}
}
@@ -50,7 +50,7 @@ public class PropertyGenTest extends CodegenTestCase {
assertNotNull(findMethodByName(aClass, "setFoo"));
}
public void testPropertyInNamespace() throws Exception {
public void testPrivatePropertyInNamespace() throws Exception {
loadText("private val x = 239");
final Class nsClass = generateNamespaceClass();
final Field[] fields = nsClass.getDeclaredFields();
@@ -62,6 +62,18 @@ public class PropertyGenTest extends CodegenTestCase {
assertEquals(239, field.get(null));
}
public void testProtectedPropertyInNamespace() throws Exception {
loadText("protected val x : Int = 239");
final Class nsClass = generateNamespaceClass();
final Field[] fields = nsClass.getDeclaredFields();
assertEquals(1, fields.length);
final Field field = fields[0];
field.setAccessible(true);
assertEquals("x", field.getName());
assertEquals(Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL, field.getModifiers());
assertEquals(239, field.get(null));
}
public void testFieldPropertyAccess() throws Exception {
loadFile("properties/fieldPropertyAccess.jet");
// System.out.println(generateToText());
@@ -96,12 +108,16 @@ public class PropertyGenTest extends CodegenTestCase {
}
public void testAccessorsWithoutBody() throws Exception {
loadText("class AccessorsWithoutBody() { public var foo: Int = 349\n get\n private set\n fun setter() { foo = 610; } } ");
loadText("class AccessorsWithoutBody() { protected var foo: Int = 349\n get\n private set\n fun setter() { foo = 610; } } ");
System.out.println(generateToText());
final Class aClass = loadImplementationClass(generateClassesInFile(), "AccessorsWithoutBody");
final Object instance = aClass.newInstance();
final Method getFoo = findMethodByName(aClass, "getFoo");
getFoo.setAccessible(true);
assertTrue((getFoo.getModifiers() & Modifier.PROTECTED) != 0);
assertEquals(349, getFoo.invoke(instance));
final Method setFoo = findMethodByName(aClass, "setFoo");
setFoo.setAccessible(true);
assertTrue((setFoo.getModifiers() & Modifier.PRIVATE) != 0);
final Method setter = findMethodByName(aClass, "setter");
setter.invoke(instance);
@@ -111,6 +127,7 @@ public class PropertyGenTest extends CodegenTestCase {
public void testInitializersForNamespaceProperties() throws Exception {
loadText("val x = System.currentTimeMillis()");
final Method method = generateFunction("getX");
method.setAccessible(true);
assertIsCurrentTime((Long) method.invoke(null));
}
@@ -144,6 +161,7 @@ public class PropertyGenTest extends CodegenTestCase {
public void testKt160() throws Exception {
loadText("internal val s = java.lang.Double.toString(1.0)");
final Method method = generateFunction("getS");
method.setAccessible(true);
assertEquals(method.invoke(null), "1.0");
}
}