diff --git a/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt index 402023715f4..25aaf632abd 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/CodeConverter.kt @@ -83,7 +83,7 @@ class CodeConverter( val explicitType = type.takeIf { settings.specifyLocalVariableTypeByDefault || converter.shouldDeclareVariableType(variable, type, isVal) } return LocalVariable(variable.declarationIdentifier(), converter.convertAnnotations(variable), - converter.convertModifiers(variable, false), + converter.convertModifiers(variable, false, false), explicitType, convertExpression(variable.initializer, variable.type), isVal).assignPrototype(variable) diff --git a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt index 41b5180e64c..3164ba59118 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt @@ -162,7 +162,7 @@ class Converter private constructor( } val annotations = convertAnnotations(psiClass) - var modifiers = convertModifiers(psiClass, false) + var modifiers = convertModifiers(psiClass, false, false) val typeParameters = convertTypeParameterList(psiClass.typeParameterList) val extendsTypes = convertToNotNullableTypes(psiClass.extendsList) val implementsTypes = convertToNotNullableTypes(psiClass.implementsList) @@ -222,7 +222,7 @@ class Converter private constructor( settings.openByDefault || referenceSearcher.hasInheritors(psiClass) } - private fun shouldConvertIntoObject(psiClass: PsiClass): Boolean { + fun shouldConvertIntoObject(psiClass: PsiClass): Boolean { val methods = psiClass.methods val fields = psiClass.fields val classes = psiClass.innerClasses @@ -295,7 +295,7 @@ class Converter private constructor( return Class(psiClass.declarationIdentifier(), convertAnnotations(psiClass), - convertModifiers(psiClass, false).with(Modifier.ANNOTATION).without(Modifier.ABSTRACT), + convertModifiers(psiClass, false, false).with(Modifier.ANNOTATION).without(Modifier.ABSTRACT), TypeParameterList.Empty, listOf(), null, @@ -305,7 +305,7 @@ class Converter private constructor( fun convertInitializer(initializer: PsiClassInitializer): Initializer { return Initializer(deferredElement { codeConverter -> codeConverter.convertBlock(initializer.body) }, - convertModifiers(initializer, false)).assignPrototype(initializer) + convertModifiers(initializer, false, false)).assignPrototype(initializer) } fun convertProperty(propertyInfo: PropertyInfo, classKind: ClassKind): Member { @@ -544,7 +544,7 @@ class Converter private constructor( val annotations = convertAnnotations(method) + convertThrows(method) - var modifiers = convertModifiers(method, classKind.isOpen()) + var modifiers = convertModifiers(method, classKind.isOpen(), classKind == ClassKind.OBJECT) val statementsToInsert = ArrayList() for (parameter in method.parameterList.parameters) { @@ -735,7 +735,7 @@ class Converter private constructor( return Identifier(identifier.text!!).assignPrototype(identifier) } - fun convertModifiers(owner: PsiModifierListOwner, isMethodInOpenClass: Boolean): Modifiers { + fun convertModifiers(owner: PsiModifierListOwner, isMethodInOpenClass: Boolean, isInObject: Boolean): Modifiers { var modifiers = Modifiers(MODIFIERS_MAP.filter { owner.hasModifierProperty(it.first) }.map { it.second }) .assignPrototype(owner.modifierList, CommentsAndSpacesInheritance.NO_SPACES) @@ -752,10 +752,14 @@ class Converter private constructor( if (owner.hasModifierProperty(PsiModifier.NATIVE)) modifiers = modifiers.with(Modifier.EXTERNAL) - modifiers = modifiers.adaptForContainingClassVisibility(owner.containingClass).adaptProtectedVisibility(owner) + modifiers = modifiers.adaptForObject(isInObject) + .adaptForContainingClassVisibility(owner.containingClass) + .adaptProtectedVisibility(owner) } else if (owner is PsiField) { - modifiers = modifiers.adaptForContainingClassVisibility(owner.containingClass).adaptProtectedVisibility(owner) + modifiers = modifiers.adaptForObject(isInObject) + .adaptForContainingClassVisibility(owner.containingClass) + .adaptProtectedVisibility(owner) } else if (owner is PsiClass && owner.scope is PsiMethod) { // Local class should not have visibility modifiers @@ -765,6 +769,12 @@ class Converter private constructor( return modifiers } + private fun Modifiers.adaptForObject(isInObject: Boolean): Modifiers { + if (!isInObject) return this + if (!modifiers.contains(Modifier.PROTECTED)) return this + return without(Modifier.PROTECTED).with(Modifier.INTERNAL) + } + // to convert package local members in package local class into public member (when it's not override, open or abstract) private fun Modifiers.adaptForContainingClassVisibility(containingClass: PsiClass?): Modifiers { if (containingClass == null || !containingClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) return this diff --git a/j2k/src/org/jetbrains/kotlin/j2k/propertyDetection.kt b/j2k/src/org/jetbrains/kotlin/j2k/propertyDetection.kt index 16f5ccb7b43..5da7d32b66d 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/propertyDetection.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/propertyDetection.kt @@ -85,7 +85,8 @@ class PropertyInfo( companion object { fun fromFieldWithNoAccessors(field: PsiField, converter: Converter): PropertyInfo { val isVar = field.isVar(converter.referenceSearcher) - val modifiers = converter.convertModifiers(field, false) + val isInObject = field.containingClass?.let { converter.shouldConvertIntoObject(it) } == true + val modifiers = converter.convertModifiers(field, false, isInObject) return PropertyInfo(field.declarationIdentifier(), isVar, field.type, field, null, null, false, false, modifiers, null, null) } } @@ -221,9 +222,9 @@ private class PropertyDetector( val propertyAccess = modifiers.accessModifier() val setterAccess = if (setterInfo != null) - converter.convertModifiers(setterInfo.method, false).accessModifier() + converter.convertModifiers(setterInfo.method, false, false).accessModifier() else if (field != null && field.isVar(converter.referenceSearcher)) - converter.convertModifiers(field, false).accessModifier() + converter.convertModifiers(field, false, false).accessModifier() else propertyAccess val specialSetterAccess = setterAccess?.takeIf { it != propertyAccess } @@ -366,9 +367,9 @@ private class PropertyDetector( } private fun convertModifiers(field: PsiField?, getMethod: PsiMethod?, setMethod: PsiMethod?, isOverride: Boolean): Modifiers { - val fieldModifiers = field?.let { converter.convertModifiers(it, false) } ?: Modifiers.Empty - val getterModifiers = getMethod?.let { converter.convertModifiers(it, isOpenClass) } ?: Modifiers.Empty - val setterModifiers = setMethod?.let { converter.convertModifiers(it, isOpenClass) } ?: Modifiers.Empty + val fieldModifiers = field?.let { converter.convertModifiers(it, false, false) } ?: Modifiers.Empty + val getterModifiers = getMethod?.let { converter.convertModifiers(it, isOpenClass, false) } ?: Modifiers.Empty + val setterModifiers = setMethod?.let { converter.convertModifiers(it, isOpenClass, false) } ?: Modifiers.Empty val modifiers = ArrayList() diff --git a/j2k/testData/fileOrElement/class/utilityClass4.java b/j2k/testData/fileOrElement/class/utilityClass4.java new file mode 100644 index 00000000000..d13cdff53ae --- /dev/null +++ b/j2k/testData/fileOrElement/class/utilityClass4.java @@ -0,0 +1,11 @@ +class Util { + public static final String publicStr = ""; + protected static final String protectedStr = ""; + static final String packageStr = ""; + private static final String privateStr = ""; + + public static void publicMethod() {} + protected static void protectedMethod() {} + static void packageMethod() {} + private static void privateMethod() {} +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/class/utilityClass4.kt b/j2k/testData/fileOrElement/class/utilityClass4.kt new file mode 100644 index 00000000000..12e23fcc7e4 --- /dev/null +++ b/j2k/testData/fileOrElement/class/utilityClass4.kt @@ -0,0 +1,11 @@ +internal object Util { + val publicStr = "" + val protectedStr = "" + val packageStr = "" + private val privateStr = "" + + fun publicMethod() {} + fun protectedMethod() {} + fun packageMethod() {} + private fun privateMethod() {} +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/class/utilityClass5.java b/j2k/testData/fileOrElement/class/utilityClass5.java new file mode 100644 index 00000000000..466c6cf5937 --- /dev/null +++ b/j2k/testData/fileOrElement/class/utilityClass5.java @@ -0,0 +1,11 @@ +public class Util { + public static final String publicStr = ""; + protected static final String protectedStr = ""; + static final String packageStr = ""; + private static final String privateStr = ""; + + public static void publicMethod() {} + protected static void protectedMethod() {} + static void packageMethod() {} + private static void privateMethod() {} +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/class/utilityClass5.kt b/j2k/testData/fileOrElement/class/utilityClass5.kt new file mode 100644 index 00000000000..60ec0e4b9ba --- /dev/null +++ b/j2k/testData/fileOrElement/class/utilityClass5.kt @@ -0,0 +1,11 @@ +object Util { + val publicStr = "" + internal val protectedStr = "" + internal val packageStr = "" + private val privateStr = "" + + fun publicMethod() {} + internal fun protectedMethod() {} + internal fun packageMethod() {} + private fun privateMethod() {} +} \ No newline at end of file diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java index 2b80a7c9ba3..db54343c21b 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -1018,6 +1018,18 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/class/utilityClass3.java"); doTest(fileName); } + + @TestMetadata("utilityClass4.java") + public void testUtilityClass4() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/class/utilityClass4.java"); + doTest(fileName); + } + + @TestMetadata("utilityClass5.java") + public void testUtilityClass5() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/class/utilityClass5.java"); + doTest(fileName); + } } @TestMetadata("j2k/testData/fileOrElement/classExpression") diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java index 38718ed5ff2..a8be43da6c4 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java @@ -1018,6 +1018,18 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/class/utilityClass3.java"); doTest(fileName); } + + @TestMetadata("utilityClass4.java") + public void testUtilityClass4() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/class/utilityClass4.java"); + doTest(fileName); + } + + @TestMetadata("utilityClass5.java") + public void testUtilityClass5() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/class/utilityClass5.java"); + doTest(fileName); + } } @TestMetadata("j2k/testData/fileOrElement/classExpression")