J2K: convert protected member used outside of inheritors as public

This commit is contained in:
Natalia Ukhorskaya
2016-02-19 13:58:40 +03:00
parent 52be775f28
commit 7d594970ff
27 changed files with 503 additions and 3 deletions
+3
View File
@@ -6,3 +6,6 @@
### JS
- Safe calls (`x?.let { it }`) are now inlined
### Tools. J2K
- Protected members used outside of inheritors are converted as public
+32 -2
View File
@@ -665,10 +665,10 @@ class Converter private constructor(
modifiers = modifiers.with(Modifier.OPEN)
}
modifiers = modifiers.adaptForContainingClassVisibility(owner.containingClass)
modifiers = modifiers.adaptForContainingClassVisibility(owner.containingClass).adaptProtectedVisibility(owner)
}
else if (owner is PsiField) {
modifiers = modifiers.adaptForContainingClassVisibility(owner.containingClass)
modifiers = modifiers.adaptForContainingClassVisibility(owner.containingClass).adaptProtectedVisibility(owner)
}
else if (owner is PsiClass && owner.scope is PsiMethod) {
// Local class should not have visibility modifiers
@@ -685,6 +685,36 @@ class Converter private constructor(
return without(Modifier.INTERNAL).with(Modifier.PUBLIC)
}
private fun Modifiers.adaptProtectedVisibility(member: PsiMember): Modifiers {
if (!member.hasModifierProperty(PsiModifier.PROTECTED)) return this
val originalClass = member.containingClass ?: return this
// Search for usages only in Java because java-protected member cannot be used in Kotlin from same package
val usages = referenceSearcher.findUsagesForExternalCodeProcessing(member, true, false)
for (usage in usages) {
val element = usage.element
var allowProtected = false
var parent: PsiElement? = element
while (parent != null) {
if (parent is PsiClass && allowProtected(parent, originalClass)) {
allowProtected = true
break
}
parent = parent.parent
}
if (!allowProtected) {
return without(Modifier.PROTECTED).with(Modifier.PUBLIC)
}
}
return this
}
private fun allowProtected(containingClass: PsiClass, originalClass: PsiClass): Boolean {
return originalClass == containingClass || containingClass.isInheritor(originalClass, true)
}
fun convertAnonymousClassBody(anonymousClass: PsiAnonymousClass): AnonymousClassBody {
return AnonymousClassBody(ClassBodyConverter(anonymousClass, ClassKind.ANONYMOUS_OBJECT, this).convertBody(),
anonymousClass.baseClassType.resolve()?.isInterface ?: false).assignPrototype(anonymousClass)
@@ -72,5 +72,5 @@ object EmptyReferenceSearcher: ReferenceSearcher {
override fun hasInheritors(`class`: PsiClass) = false
override fun hasOverrides(method: PsiMethod) = false
override fun findUsagesForExternalCodeProcessing(element: PsiElement, searchJava: Boolean, searchKotlin: Boolean): Collection<PsiReference>
= throw UnsupportedOperationException()
= emptyList()
}
+11
View File
@@ -82,6 +82,17 @@ fun PsiElement.getContainingMethod(): PsiMethod? {
return null
}
fun PsiElement.getContainingClass(): PsiClass? {
var context = context
while (context != null) {
val _context = context
if (_context is PsiClass) return _context
if (_context is PsiMember) return _context.containingClass
context = _context.context
}
return null
}
fun PsiElement.getContainingConstructor(): PsiMethod? {
val method = getContainingMethod()
return if (method?.isConstructor == true) method else null
@@ -0,0 +1,26 @@
package test;
public abstract class Base {
protected int field;
public Base(int value) {
field = value;
}
}
public class Derived extends Base {
public Derived(int value) {
super(value);
}
private View usage = new View() {
@Override
void click() {
int activity = field;
}
}
}
abstract class View {
abstract void click();
}
@@ -0,0 +1,16 @@
package test
abstract class Base(protected var field: Int)
class Derived(value: Int) : Base(value) {
private val usage = object : View() {
override fun click() {
val activity = field
}
}
}
internal abstract class View {
internal abstract fun click()
}
@@ -0,0 +1,21 @@
package test;
public class BaseInheritorSamePackage {
protected BaseInheritorSamePackage() {
}
protected void foo() {
}
protected int i = 1;
}
class DerivedInheritorSamePackage extends BaseInheritorSamePackage {
public void usage1() {
BaseInheritorSamePackage base = new BaseInheritorSamePackage();
base.foo();
int i = base.i;
}
}
@@ -0,0 +1,18 @@
package test
open class BaseInheritorSamePackage protected constructor() {
protected fun foo() {
}
protected var i = 1
}
internal class DerivedInheritorSamePackage : BaseInheritorSamePackage() {
fun usage1() {
val base = BaseInheritorSamePackage()
base.foo()
val i = base.i
}
}
@@ -0,0 +1,13 @@
package test;
public class BaseProtectedConstructor {
protected BaseSamePackage() {
}
}
class DerivedSamePackage extends BaseProtectedConstructor {
DerivedSamePackage() {
super();
}
}
@@ -0,0 +1,5 @@
package test
open class BaseProtectedConstructor protected constructor()
internal class DerivedSamePackage : BaseProtectedConstructor()
@@ -0,0 +1,21 @@
package test;
public class BaseSamePackage {
protected BaseSamePackage() {
}
protected void foo() {
}
protected int i = 1;
}
class DerivedSamePackage {
public void usage1() {
BaseSamePackage base = new BaseSamePackage();
base.foo();
int i = base.i;
}
}
@@ -0,0 +1,18 @@
package test
class BaseSamePackage {
fun foo() {
}
var i = 1
}
internal class DerivedSamePackage {
fun usage1() {
val base = BaseSamePackage()
base.foo()
val i = base.i
}
}
@@ -0,0 +1,16 @@
package test;
public class BaseProtectedConstructor {
protected void foo() {
}
}
class MiddleSamePackage extends BaseProtectedConstructor {
}
class DerivedSamePackage extends MiddleSamePackage {
void usage() {
foo();
}
}
@@ -0,0 +1,15 @@
package test
open class BaseProtectedConstructor {
protected fun foo() {
}
}
internal open class MiddleSamePackage : BaseProtectedConstructor()
internal class DerivedSamePackage : MiddleSamePackage() {
fun usage() {
foo()
}
}
@@ -0,0 +1,21 @@
package test;
class BaseSuperSamePackage {
public void usage1() {
DerivedSuperSamePackage derived = new DerivedSuperSamePackage();
derived.foo();
int i = derived.i;
}
}
class DerivedSuperSamePackage extends BaseSuperSamePackage {
protected DerivedSuperSamePackage() {
}
protected void foo() {
}
protected int i = 1;
}
@@ -0,0 +1,18 @@
package test
internal open class BaseSuperSamePackage {
fun usage1() {
val derived = DerivedSuperSamePackage()
derived.foo()
val i = derived.i
}
}
internal class DerivedSuperSamePackage : BaseSuperSamePackage() {
fun foo() {
}
var i = 1
}
+35
View File
@@ -0,0 +1,35 @@
package test;
public class BaseProtectedConstructor {
protected void usageInConstructor() {
}
protected int usageInPropertyInitializer() {
return 1;
}
protected void usageInStaticInit() {
}
protected void usageInMethod() {
}
}
class DerivedSamePackage {
DerivedSamePackage() {
new BaseProtectedConstructor().usageInConstructor();
}
private int i = new BaseProtectedConstructor().usageInPropertyInitializer();
static {
new BaseProtectedConstructor().usageInStaticInit();
}
void usage() {
new BaseProtectedConstructor().usageInMethod();
}
}
+38
View File
@@ -0,0 +1,38 @@
package test
class BaseProtectedConstructor {
fun usageInConstructor() {
}
fun usageInPropertyInitializer(): Int {
return 1
}
fun usageInStaticInit() {
}
fun usageInMethod() {
}
}
internal class DerivedSamePackage {
init {
BaseProtectedConstructor().usageInConstructor()
}
private val i = BaseProtectedConstructor().usageInPropertyInitializer()
fun usage() {
BaseProtectedConstructor().usageInMethod()
}
companion object {
init {
BaseProtectedConstructor().usageInStaticInit()
}
}
}
@@ -0,0 +1,13 @@
package test;
public class BaseOtherPackage {
protected BaseOtherPackage() {
}
protected void foo() {
}
protected int i = 1;
}
@@ -0,0 +1,10 @@
package test
open class BaseOtherPackage protected constructor() {
protected fun foo() {
}
protected var i = 1
}
@@ -0,0 +1,11 @@
package test2;
import test.*;
public class DerivedOtherPackage extends BaseOtherPackage {
public void usage1() {
BaseOtherPackage base = new BaseOtherPackage();
base.foo();
int i = base.i;
}
}
@@ -0,0 +1,11 @@
package test2
import test.*
class DerivedOtherPackage : BaseOtherPackage() {
fun usage1() {
val base = BaseOtherPackage()
base.foo()
val i = base.i
}
}
@@ -0,0 +1,11 @@
package test3
import test.*
class DerivedOtherPackageKotlin : BaseOtherPackage() {
fun usage1() {
val base = BaseOtherPackage()
base.foo()
val i = base.i
}
}
@@ -0,0 +1,11 @@
package test3
import test.*
class DerivedOtherPackageKotlin : BaseOtherPackage() {
fun usage1() {
val base = BaseOtherPackage()
base.foo()
val i = base.i
}
}
@@ -3821,6 +3821,57 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
}
}
@TestMetadata("j2k/testData/fileOrElement/protected")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Protected extends AbstractJavaToKotlinConverterForWebDemoTest {
public void testAllFilesPresentInProtected() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/protected"), Pattern.compile("^(.+)\\.java$"), true);
}
@TestMetadata("constructorProperty.java")
public void testConstructorProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/constructorProperty.java");
doTest(fileName);
}
@TestMetadata("inheritorsSamePackage.java")
public void testInheritorsSamePackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/inheritorsSamePackage.java");
doTest(fileName);
}
@TestMetadata("onlyProtectedConstructor.java")
public void testOnlyProtectedConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/onlyProtectedConstructor.java");
doTest(fileName);
}
@TestMetadata("protectedInSamePackage.java")
public void testProtectedInSamePackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/protectedInSamePackage.java");
doTest(fileName);
}
@TestMetadata("severalInheritors.java")
public void testSeveralInheritors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/severalInheritors.java");
doTest(fileName);
}
@TestMetadata("superInSamePackage.java")
public void testSuperInSamePackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/superInSamePackage.java");
doTest(fileName);
}
@TestMetadata("usages.java")
public void testUsages() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/usages.java");
doTest(fileName);
}
}
@TestMetadata("j2k/testData/fileOrElement/rawGenerics")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -47,6 +47,12 @@ public class JavaToKotlinConverterMultiFileTestGenerated extends AbstractJavaToK
doTest(fileName);
}
@TestMetadata("ProtectedVisibility")
public void testProtectedVisibility() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/multiFile/ProtectedVisibility/");
doTest(fileName);
}
@TestMetadata("ToCompanionObject")
public void testToCompanionObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/multiFile/ToCompanionObject/");
@@ -3821,6 +3821,57 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
}
}
@TestMetadata("j2k/testData/fileOrElement/protected")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Protected extends AbstractJavaToKotlinConverterSingleFileTest {
public void testAllFilesPresentInProtected() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("j2k/testData/fileOrElement/protected"), Pattern.compile("^(.+)\\.java$"), true);
}
@TestMetadata("constructorProperty.java")
public void testConstructorProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/constructorProperty.java");
doTest(fileName);
}
@TestMetadata("inheritorsSamePackage.java")
public void testInheritorsSamePackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/inheritorsSamePackage.java");
doTest(fileName);
}
@TestMetadata("onlyProtectedConstructor.java")
public void testOnlyProtectedConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/onlyProtectedConstructor.java");
doTest(fileName);
}
@TestMetadata("protectedInSamePackage.java")
public void testProtectedInSamePackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/protectedInSamePackage.java");
doTest(fileName);
}
@TestMetadata("severalInheritors.java")
public void testSeveralInheritors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/severalInheritors.java");
doTest(fileName);
}
@TestMetadata("superInSamePackage.java")
public void testSuperInSamePackage() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/superInSamePackage.java");
doTest(fileName);
}
@TestMetadata("usages.java")
public void testUsages() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/protected/usages.java");
doTest(fileName);
}
}
@TestMetadata("j2k/testData/fileOrElement/rawGenerics")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)