diff --git a/ChangeLog.md b/ChangeLog.md
index 0cf5a1b24df..4f6381e64bf 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -349,11 +349,13 @@
- [`KT-11704`](https://youtrack.jetbrains.com/issue/KT-11704) Support file path references inside of Kotlin string literals
- [`KT-12076`](https://youtrack.jetbrains.com/issue/KT-12076) Kotlin Plugin update check: alwats display installed version number
- [`KT-11814`](https://youtrack.jetbrains.com/issue/KT-11814) New icon for kotlin annotation classes
+- [`KT-12735`](https://youtrack.jetbrains.com/issue/KT-12735) Convert JavaDoc to KDoc when overriding Java class member in Kotlin
###### Issues fixed
- [`KT-5960`](https://youtrack.jetbrains.com/issue/KT-5960) Can't find usages for Java methods used from Kotlin by call convention
- [`KT-8362`](https://youtrack.jetbrains.com/issue/KT-8362) "New Kotlin file": Keywords should be escaped in package name
+- [`KT-8682`](https://youtrack.jetbrains.com/issue/KT-8682) Respect "Copy JavaDoc" option in the "Override/Implement Members..." dialog
- [`KT-8817`](https://youtrack.jetbrains.com/issue/KT-8817) Fixed rename of Java getters/setters through synthetic property references in Kotlin
- [`KT-9399`](https://youtrack.jetbrains.com/issue/KT-9399) Find Usages omits Kotlin annotation parameter usage in Java source
- [`KT-9797`](https://youtrack.jetbrains.com/issue/KT-9797) "Kotlin Bytecode" toolwindow breaks after closing
diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt
index 97a90b05137..2aeb0a82a6d 100644
--- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt
+++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/OverridesCompletion.kt
@@ -114,7 +114,7 @@ class OverridesCompletion(
// keep original modifiers
val modifierList = KtPsiFactory(context.project).createModifierList(dummyMember.modifierList!!.text)
- val prototype = memberObject.generateMember(context.project)
+ val prototype = memberObject.generateMember(context.project, false)
prototype.modifierList!!.replace(modifierList)
val insertedMember = dummyMember.replaced(prototype)
diff --git a/idea/idea-core/idea-core.iml b/idea/idea-core/idea-core.iml
index 3238fb2a99b..a9a10941722 100644
--- a/idea/idea-core/idea-core.iml
+++ b/idea/idea-core/idea-core.iml
@@ -14,6 +14,7 @@
+
\ No newline at end of file
diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMembersHandler.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMembersHandler.kt
index de384c198b5..5bab68cc526 100644
--- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMembersHandler.kt
+++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMembersHandler.kt
@@ -72,18 +72,22 @@ abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandle
return
}
- val selectedElements = if (implementAll) {
- members
+ val copyDoc: Boolean
+ val selectedElements: Collection
+ if (implementAll) {
+ selectedElements = members
+ copyDoc = false
}
else {
val chooser = showOverrideImplementChooser(project, members.toTypedArray()) ?: return
- chooser.selectedElements ?: return
+ selectedElements = chooser.selectedElements ?: return
+ copyDoc = chooser.isCopyJavadoc
}
if (selectedElements.isEmpty()) return
PsiDocumentManager.getInstance(project).commitAllDocuments()
- generateMembers(editor, classOrObject, selectedElements)
+ generateMembers(editor, classOrObject, selectedElements, copyDoc)
}
override fun invoke(project: Project, editor: Editor, file: PsiFile) {
@@ -93,9 +97,14 @@ abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandle
override fun startInWriteAction(): Boolean = false
companion object {
- fun generateMembers(editor: Editor?, classOrObject: KtClassOrObject, selectedElements: Collection) {
+ fun generateMembers(
+ editor: Editor?,
+ classOrObject: KtClassOrObject,
+ selectedElements: Collection,
+ copyDoc: Boolean
+ ) {
val project = classOrObject.project
- insertMembersAfter(editor, classOrObject, selectedElements.map { it.generateMember(project) })
+ insertMembersAfter(editor, classOrObject, selectedElements.map { it.generateMember(project, copyDoc) })
}
}
}
diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt
index c7b9cc02886..860a6e8c9a3 100644
--- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt
+++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.generation.ClassMember
import com.intellij.codeInsight.generation.MemberChooserObject
import com.intellij.codeInsight.generation.MemberChooserObjectBase
import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiDocCommentOwner
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
@@ -27,8 +28,11 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.TemplateKind
import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
+import org.jetbrains.kotlin.idea.j2k.IdeaDocCommentConverter
+import org.jetbrains.kotlin.idea.kdoc.KDocElementFactory
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.findDocComment.findDocComment
import org.jetbrains.kotlin.renderer.*
import org.jetbrains.kotlin.resolve.descriptorUtil.setSingleOverridden
@@ -88,15 +92,33 @@ interface OverrideMemberChooserObject : ClassMember {
}
}
-fun OverrideMemberChooserObject.generateMember(project: Project): KtCallableDeclaration {
+fun OverrideMemberChooserObject.generateMember(project: Project, copyDoc: Boolean): KtCallableDeclaration {
val descriptor = immediateSuper
if (preferConstructorParameter && descriptor is PropertyDescriptor) return generateConstructorParameter(project, descriptor)
- return when (descriptor) {
+ val newMember: KtCallableDeclaration = when (descriptor) {
is SimpleFunctionDescriptor -> generateFunction(project, descriptor, bodyType)
is PropertyDescriptor -> generateProperty(project, descriptor, bodyType)
else -> error("Unknown member to override: $descriptor")
}
+
+ if (copyDoc) {
+ val superDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
+ val kDoc = when (superDeclaration) {
+ is KtDeclaration ->
+ findDocComment(superDeclaration)
+ is PsiDocCommentOwner -> {
+ val kDocText = superDeclaration.docComment?.let { IdeaDocCommentConverter.convertDocComment(it) }
+ if (kDocText.isNullOrEmpty()) null else KDocElementFactory(project).createKDocFromText(kDocText!!)
+ }
+ else -> null
+ }
+ if (kDoc != null) {
+ newMember.addAfter(kDoc, null)
+ }
+ }
+
+ return newMember
}
private val OVERRIDE_RENDERER = DescriptorRenderer.withOptions {
diff --git a/idea/src/org/jetbrains/kotlin/idea/j2k/IdeaDocCommentConverter.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/j2k/IdeaDocCommentConverter.kt
similarity index 100%
rename from idea/src/org/jetbrains/kotlin/idea/j2k/IdeaDocCommentConverter.kt
rename to idea/idea-core/src/org/jetbrains/kotlin/idea/j2k/IdeaDocCommentConverter.kt
diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/generate/utils.kt b/idea/src/org/jetbrains/kotlin/idea/actions/generate/utils.kt
index ddd788e7f81..49a58226e23 100644
--- a/idea/src/org/jetbrains/kotlin/idea/actions/generate/utils.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/actions/generate/utils.kt
@@ -78,5 +78,5 @@ fun confirmMemberRewrite(targetClass: KtClass, vararg descriptors: FunctionDescr
fun generateFunctionSkeleton(descriptor: FunctionDescriptor, project: Project): KtNamedFunction {
return OverrideMemberChooserObject
.create(project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY)
- .generateMember(project) as KtNamedFunction
+ .generateMember(project, false) as KtNamedFunction
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ImplementAbstractMemberIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ImplementAbstractMemberIntention.kt
index 18cf507b9ed..34fb2536d70 100644
--- a/idea/src/org/jetbrains/kotlin/idea/intentions/ImplementAbstractMemberIntention.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ImplementAbstractMemberIntention.kt
@@ -138,7 +138,7 @@ abstract class ImplementAbstractMemberIntentionBase :
descriptorToImplement,
OverrideMemberChooserObject.BodyType.EMPTY,
preferConstructorParameters)
- OverrideImplementMembersHandler.generateMembers(null, targetClass, chooserObject.singletonList())
+ OverrideImplementMembersHandler.generateMembers(null, targetClass, chooserObject.singletonList(), false)
}
private fun implementInJavaClass(member: KtNamedDeclaration, targetClass: PsiClass) {
diff --git a/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/A.java b/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/A.java
new file mode 100644
index 00000000000..70a8b8f1eb7
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/A.java
@@ -0,0 +1,10 @@
+package foo;
+
+public class A {
+ /**
+ * @return TEST
+ */
+ public int foo() {
+ return 1;
+ }
+}
diff --git a/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/Impl.kt b/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/Impl.kt
new file mode 100644
index 00000000000..2af8ba23706
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/Impl.kt
@@ -0,0 +1,7 @@
+// COPY_DOC
+
+import foo.A
+
+class B : A() {
+
+}
diff --git a/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/Impl.kt.after b/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/Impl.kt.after
new file mode 100644
index 00000000000..0bf06f98b56
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/convertJavaDoc/foo/Impl.kt.after
@@ -0,0 +1,12 @@
+// COPY_DOC
+
+import foo.A
+
+class B : A() {
+ /**
+ * @return TEST
+ */
+ override fun foo(): Int {
+ return super.foo()
+ }
+}
diff --git a/idea/testData/codeInsight/overrideImplement/copyKDoc.kt b/idea/testData/codeInsight/overrideImplement/copyKDoc.kt
new file mode 100644
index 00000000000..4e33c92f8fd
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/copyKDoc.kt
@@ -0,0 +1,11 @@
+// COPY_DOC
+abstract class A {
+ /**
+ * @see TEST
+ */
+ abstract fun foo()
+}
+
+class B : A() {
+
+}
\ No newline at end of file
diff --git a/idea/testData/codeInsight/overrideImplement/copyKDoc.kt.after b/idea/testData/codeInsight/overrideImplement/copyKDoc.kt.after
new file mode 100644
index 00000000000..c051dd27ed4
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/copyKDoc.kt.after
@@ -0,0 +1,16 @@
+// COPY_DOC
+abstract class A {
+ /**
+ * @see TEST
+ */
+ abstract fun foo()
+}
+
+class B : A() {
+ /**
+ * @see TEST
+ */
+ override fun foo() {
+ throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt
index 028ebac06f2..7377d12808b 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.idea.test.dumpTextWithErrors
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TagsTestDataUtil
import org.jetbrains.kotlin.utils.rethrow
@@ -171,8 +172,9 @@ abstract class AbstractOverrideImplementTest : KotlinLightCodeInsightFixtureTest
classOrObject: KtClassOrObject,
selectedElements: List) {
try {
+ val copyDoc = InTextDirectivesUtils.isDirectiveDefined(classOrObject.containingFile.text, "// COPY_DOC")
myFixture.project.executeWriteCommand("") {
- OverrideImplementMembersHandler.generateMembers(myFixture.editor, classOrObject, selectedElements)
+ OverrideImplementMembersHandler.generateMembers(myFixture.editor, classOrObject, selectedElements, copyDoc)
}
}
catch (throwable: Throwable) {
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.kt
index 69e950cd0b4..14f16852e59 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.kt
@@ -235,4 +235,12 @@ class OverrideImplementTest : AbstractOverrideImplementTest() {
fun testEqualsInInterface() {
doOverrideFileTest("equals")
}
+
+ fun testCopyKDoc() {
+ doOverrideFileTest("foo")
+ }
+
+ fun testConvertJavaDoc() {
+ doOverrideDirectoryTest("foo")
+ }
}