From 7c8fdc42b478c7fa471121f10d3aa72b74285c15 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Tue, 18 Oct 2016 12:17:11 +0300 Subject: [PATCH] Fix for KT-12892 J2K: Wrong placing of comments when constructor converted to primary constructor & `init` --- .../kotlin/j2k/ClassBodyConverter.kt | 13 +++++++----- j2k/src/org/jetbrains/kotlin/j2k/Converter.kt | 16 +++++++++++++-- .../org/jetbrains/kotlin/j2k/ast/ClassBody.kt | 1 + .../jetbrains/kotlin/j2k/ast/Constructors.kt | 8 +++++--- .../comments/commentsForConstructors.java | 20 +++++++++++++++++++ .../comments/commentsForConstructors.kt | 20 ++++++++++++++++++- .../docComments/primaryConstructorDoc.java | 18 +++++++++++++++++ .../docComments/primaryConstructorDoc.kt | 15 ++++++++++++++ ...otlinConverterForWebDemoTestGenerated.java | 6 ++++++ ...otlinConverterSingleFileTestGenerated.java | 6 ++++++ 10 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 j2k/testData/fileOrElement/docComments/primaryConstructorDoc.java create mode 100644 j2k/testData/fileOrElement/docComments/primaryConstructorDoc.kt diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ClassBodyConverter.kt b/j2k/src/org/jetbrains/kotlin/j2k/ClassBodyConverter.kt index fc9347b4037..c45ec06b4aa 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ClassBodyConverter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ClassBodyConverter.kt @@ -106,7 +106,7 @@ class ClassBodyConverter(private val psiClass: PsiClass, } } - return ClassBody(null, null, convertedMembers.values.toList(), emptyList(), lBrace, rBrace, classKind) + return ClassBody(null, null, null, convertedMembers.values.toList(), emptyList(), lBrace, rBrace, classKind) } val useCompanionObject = shouldGenerateCompanionObject(convertedMembers) @@ -114,11 +114,13 @@ class ClassBodyConverter(private val psiClass: PsiClass, val members = ArrayList() val companionObjectMembers = ArrayList() var primaryConstructorSignature: PrimaryConstructorSignature? = null + var primaryConstructor: PrimaryConstructor? = null for ((psiMember, member) in convertedMembers) { if (member is PrimaryConstructor) { + primaryConstructor = member assert(primaryConstructorSignature == null) - primaryConstructorSignature = member.createSignature(converter) - members.add(member.initializer()) + primaryConstructorSignature = primaryConstructor.createSignature(converter) + members.add(primaryConstructor.initializer) } else if (useCompanionObject && member !is Class && psiMember !is PsiEnumConstant && psiMember.hasModifierProperty(PsiModifier.STATIC)) { companionObjectMembers.add(member) @@ -131,7 +133,8 @@ class ClassBodyConverter(private val psiClass: PsiClass, } } - if (primaryConstructorSignature != null + if (primaryConstructor != null + && primaryConstructorSignature != null && classKind != ClassKind.ANONYMOUS_OBJECT && primaryConstructorSignature.annotations.isEmpty && primaryConstructorSignature.accessModifier == null @@ -141,7 +144,7 @@ class ClassBodyConverter(private val psiClass: PsiClass, primaryConstructorSignature = null // no "()" after class name is needed in this case } - return ClassBody(primaryConstructorSignature, constructorConverter?.baseClassParams, members, companionObjectMembers, lBrace, rBrace, classKind) + return ClassBody(primaryConstructor, primaryConstructorSignature, constructorConverter?.baseClassParams, members, companionObjectMembers, lBrace, rBrace, classKind) } private fun convertMember( diff --git a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt index f6c2b2268f2..8bad25e8aeb 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/Converter.kt @@ -175,7 +175,7 @@ class Converter private constructor( val implementsTypes = convertToNotNullableTypes(psiClass.implementsListTypes) val name = psiClass.declarationIdentifier() - return when { + val converted = when { psiClass.isInterface -> { val classBody = ClassBodyConverter(psiClass, ClassKind.INTERFACE, this).convertBody() Interface(name, annotations, modifiers, typeParameters, extendsTypes, implementsTypes, classBody) @@ -208,6 +208,18 @@ class Converter private constructor( } } }.assignPrototype(psiClass) + + if (converted.body.primaryConstructorSignature == null) + addPostUnfoldDeferredElementsAction { + val primaryConstructor = converted.body.primaryConstructor + if (primaryConstructor != null) { + if (primaryConstructor.initializer.isEmpty) + converted.prototypes = converted.prototypes!! + primaryConstructor.prototypes!! + else + primaryConstructor.initializer.assignPrototypesFrom(primaryConstructor, CommentsAndSpacesInheritance.NO_SPACES) + } + } + return converted } fun needOpenModifier(psiClass: PsiClass): Boolean { @@ -285,7 +297,7 @@ class Converter private constructor( // to convert fields and nested types - they are not allowed in Kotlin but we convert them and let user refactor code var classBody = ClassBodyConverter(psiClass, ClassKind.ANNOTATION_CLASS, this).convertBody() - classBody = ClassBody(constructorSignature, classBody.baseClassParams, classBody.members, + classBody = ClassBody(null, constructorSignature, classBody.baseClassParams, classBody.members, classBody.companionObjectMembers, classBody.lBrace, classBody.rBrace, classBody.classKind) return Class(psiClass.declarationIdentifier(), diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/ClassBody.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/ClassBody.kt index 03222ac6030..70d2dd453cc 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/ClassBody.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/ClassBody.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.j2k.append abstract class Member(var annotations: Annotations, val modifiers: Modifiers) : Element() class ClassBody ( + val primaryConstructor: PrimaryConstructor?, val primaryConstructorSignature: PrimaryConstructorSignature?, val baseClassParams: List>?, val members: List, diff --git a/j2k/src/org/jetbrains/kotlin/j2k/ast/Constructors.kt b/j2k/src/org/jetbrains/kotlin/j2k/ast/Constructors.kt index 85baf591cf6..09da9c18acb 100644 --- a/j2k/src/org/jetbrains/kotlin/j2k/ast/Constructors.kt +++ b/j2k/src/org/jetbrains/kotlin/j2k/ast/Constructors.kt @@ -39,10 +39,12 @@ class PrimaryConstructor( override fun generateCode(builder: CodeBuilder) { throw IncorrectOperationException() } - fun initializer(): Initializer - = Initializer(body!!, Modifiers.Empty).assignPrototypesFrom(this, CommentsAndSpacesInheritance(commentsBefore = false)) + // Should be lazy, to defer `assignPrototypesFrom(this,...)` a bit, + // cause when `PrimaryConstructor` created prototypes not yet assigned + val initializer: Initializer by + lazy { Initializer(body, Modifiers.Empty).assignPrototypesFrom(this, CommentsAndSpacesInheritance(commentsBefore = false)) } - fun createSignature(converter: Converter): PrimaryConstructorSignature { + fun createSignature(converter: Converter): PrimaryConstructorSignature? { val signature = PrimaryConstructorSignature(annotations, modifiers, parameterList) // assign prototypes later because we don't know yet whether the body is empty or not diff --git a/j2k/testData/fileOrElement/comments/commentsForConstructors.java b/j2k/testData/fileOrElement/comments/commentsForConstructors.java index 00e5dc30b39..34b4db9c95f 100644 --- a/j2k/testData/fileOrElement/comments/commentsForConstructors.java +++ b/j2k/testData/fileOrElement/comments/commentsForConstructors.java @@ -26,4 +26,24 @@ class B { } // end of constructor body void foo(){} +} + +class CtorComment { + public String myA; + + /* + * The magic of comments + */ + // single line magic comments + public CtorComment() { + myA = "a"; + } +} + +class CtorComment2 { + /* + * The magic of comments + */ + // single line magic comments + public CtorComment() {} } \ No newline at end of file diff --git a/j2k/testData/fileOrElement/comments/commentsForConstructors.kt b/j2k/testData/fileOrElement/comments/commentsForConstructors.kt index 981712fb82f..bac40ad44de 100644 --- a/j2k/testData/fileOrElement/comments/commentsForConstructors.kt +++ b/j2k/testData/fileOrElement/comments/commentsForConstructors.kt @@ -18,4 +18,22 @@ internal class B// this constructor will disappear fun foo() { } -} \ No newline at end of file +} + +internal class CtorComment { + var myA: String + + /* + * The magic of comments + */ + // single line magic comments + init { + myA = "a" + } +} + +/* + * The magic of comments + */ +// single line magic comments +internal class CtorComment2 \ No newline at end of file diff --git a/j2k/testData/fileOrElement/docComments/primaryConstructorDoc.java b/j2k/testData/fileOrElement/docComments/primaryConstructorDoc.java new file mode 100644 index 00000000000..3b4a7ddaf67 --- /dev/null +++ b/j2k/testData/fileOrElement/docComments/primaryConstructorDoc.java @@ -0,0 +1,18 @@ +class CtorComment { + public String myA; + + /** + * This constructor is especially useful + */ + public CtorComment() { + myA = "str"; + } +} + +class CtorComment2 { + + /** + * This constructor is especially useful + */ + public CtorComment() {} +} \ No newline at end of file diff --git a/j2k/testData/fileOrElement/docComments/primaryConstructorDoc.kt b/j2k/testData/fileOrElement/docComments/primaryConstructorDoc.kt new file mode 100644 index 00000000000..7457f103983 --- /dev/null +++ b/j2k/testData/fileOrElement/docComments/primaryConstructorDoc.kt @@ -0,0 +1,15 @@ +internal class CtorComment { + var myA: String + + /** + * This constructor is especially useful + */ + init { + myA = "str" + } +} + +/** + * This constructor is especially useful + */ +internal class CtorComment2 \ 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 78ab0401923..4c5cfbf964e 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterForWebDemoTestGenerated.java @@ -1807,6 +1807,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("primaryConstructorDoc.java") + public void testPrimaryConstructorDoc() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/docComments/primaryConstructorDoc.java"); + doTest(fileName); + } + @TestMetadata("quoted.java") public void testQuoted() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/docComments/quoted.java"); diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java index 19a057c0c1f..aafd482e3ba 100644 --- a/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java +++ b/j2k/tests/org/jetbrains/kotlin/j2k/JavaToKotlinConverterSingleFileTestGenerated.java @@ -1807,6 +1807,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo doTest(fileName); } + @TestMetadata("primaryConstructorDoc.java") + public void testPrimaryConstructorDoc() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/docComments/primaryConstructorDoc.java"); + doTest(fileName); + } + @TestMetadata("quoted.java") public void testQuoted() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/docComments/quoted.java");