J2K: convert protected member used outside of inheritors as public
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user