Override/Implement: Implement JavaDoc/KDoc copying

#KT-8682 Fixed
 #KT-12735 Fixed
(cherry picked from commit f4486be)
This commit is contained in:
Alexey Sedunov
2016-06-20 14:41:00 +03:00
parent 3f09b7f9d5
commit ffe4e760d7
15 changed files with 112 additions and 12 deletions
+2
View File
@@ -349,11 +349,13 @@
- [`KT-11704`](https://youtrack.jetbrains.com/issue/KT-11704) Support file path references inside of Kotlin string literals - [`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-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-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 ###### 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-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-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-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-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 - [`KT-9797`](https://youtrack.jetbrains.com/issue/KT-9797) "Kotlin Bytecode" toolwindow breaks after closing
@@ -114,7 +114,7 @@ class OverridesCompletion(
// keep original modifiers // keep original modifiers
val modifierList = KtPsiFactory(context.project).createModifierList(dummyMember.modifierList!!.text) 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) prototype.modifierList!!.replace(modifierList)
val insertedMember = dummyMember.replaced(prototype) val insertedMember = dummyMember.replaced(prototype)
+1
View File
@@ -14,6 +14,7 @@
<orderEntry type="module" module-name="light-classes" /> <orderEntry type="module" module-name="light-classes" />
<orderEntry type="module" module-name="frontend.java" /> <orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="util" /> <orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="j2k" />
<orderEntry type="library" scope="PROVIDED" name="gradle-and-groovy-plugin" level="project" /> <orderEntry type="library" scope="PROVIDED" name="gradle-and-groovy-plugin" level="project" />
</component> </component>
</module> </module>
@@ -72,18 +72,22 @@ abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandle
return return
} }
val selectedElements = if (implementAll) { val copyDoc: Boolean
members val selectedElements: Collection<OverrideMemberChooserObject>
if (implementAll) {
selectedElements = members
copyDoc = false
} }
else { else {
val chooser = showOverrideImplementChooser(project, members.toTypedArray()) ?: return val chooser = showOverrideImplementChooser(project, members.toTypedArray()) ?: return
chooser.selectedElements ?: return selectedElements = chooser.selectedElements ?: return
copyDoc = chooser.isCopyJavadoc
} }
if (selectedElements.isEmpty()) return if (selectedElements.isEmpty()) return
PsiDocumentManager.getInstance(project).commitAllDocuments() PsiDocumentManager.getInstance(project).commitAllDocuments()
generateMembers(editor, classOrObject, selectedElements) generateMembers(editor, classOrObject, selectedElements, copyDoc)
} }
override fun invoke(project: Project, editor: Editor, file: PsiFile) { override fun invoke(project: Project, editor: Editor, file: PsiFile) {
@@ -93,9 +97,14 @@ abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandle
override fun startInWriteAction(): Boolean = false override fun startInWriteAction(): Boolean = false
companion object { companion object {
fun generateMembers(editor: Editor?, classOrObject: KtClassOrObject, selectedElements: Collection<OverrideMemberChooserObject>) { fun generateMembers(
editor: Editor?,
classOrObject: KtClassOrObject,
selectedElements: Collection<OverrideMemberChooserObject>,
copyDoc: Boolean
) {
val project = classOrObject.project val project = classOrObject.project
insertMembersAfter(editor, classOrObject, selectedElements.map { it.generateMember(project) }) insertMembersAfter(editor, classOrObject, selectedElements.map { it.generateMember(project, copyDoc) })
} }
} }
} }
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.generation.ClassMember
import com.intellij.codeInsight.generation.MemberChooserObject import com.intellij.codeInsight.generation.MemberChooserObject
import com.intellij.codeInsight.generation.MemberChooserObjectBase import com.intellij.codeInsight.generation.MemberChooserObjectBase
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocCommentOwner
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* 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.TemplateKind
import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject 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.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.findDocComment.findDocComment
import org.jetbrains.kotlin.renderer.* import org.jetbrains.kotlin.renderer.*
import org.jetbrains.kotlin.resolve.descriptorUtil.setSingleOverridden 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 val descriptor = immediateSuper
if (preferConstructorParameter && descriptor is PropertyDescriptor) return generateConstructorParameter(project, descriptor) if (preferConstructorParameter && descriptor is PropertyDescriptor) return generateConstructorParameter(project, descriptor)
return when (descriptor) { val newMember: KtCallableDeclaration = when (descriptor) {
is SimpleFunctionDescriptor -> generateFunction(project, descriptor, bodyType) is SimpleFunctionDescriptor -> generateFunction(project, descriptor, bodyType)
is PropertyDescriptor -> generateProperty(project, descriptor, bodyType) is PropertyDescriptor -> generateProperty(project, descriptor, bodyType)
else -> error("Unknown member to override: $descriptor") 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 { private val OVERRIDE_RENDERER = DescriptorRenderer.withOptions {
@@ -78,5 +78,5 @@ fun confirmMemberRewrite(targetClass: KtClass, vararg descriptors: FunctionDescr
fun generateFunctionSkeleton(descriptor: FunctionDescriptor, project: Project): KtNamedFunction { fun generateFunctionSkeleton(descriptor: FunctionDescriptor, project: Project): KtNamedFunction {
return OverrideMemberChooserObject return OverrideMemberChooserObject
.create(project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY) .create(project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY)
.generateMember(project) as KtNamedFunction .generateMember(project, false) as KtNamedFunction
} }
@@ -138,7 +138,7 @@ abstract class ImplementAbstractMemberIntentionBase :
descriptorToImplement, descriptorToImplement,
OverrideMemberChooserObject.BodyType.EMPTY, OverrideMemberChooserObject.BodyType.EMPTY,
preferConstructorParameters) preferConstructorParameters)
OverrideImplementMembersHandler.generateMembers(null, targetClass, chooserObject.singletonList()) OverrideImplementMembersHandler.generateMembers(null, targetClass, chooserObject.singletonList(), false)
} }
private fun implementInJavaClass(member: KtNamedDeclaration, targetClass: PsiClass) { private fun implementInJavaClass(member: KtNamedDeclaration, targetClass: PsiClass) {
@@ -0,0 +1,10 @@
package foo;
public class A {
/**
* @return TEST
*/
public int foo() {
return 1;
}
}
@@ -0,0 +1,7 @@
// COPY_DOC
import foo.A
class B : A() {
<caret>
}
@@ -0,0 +1,12 @@
// COPY_DOC
import foo.A
class B : A() {
/**
* @return TEST
*/
override fun foo(): Int {
<selection><caret>return super.foo()</selection>
}
}
+11
View File
@@ -0,0 +1,11 @@
// COPY_DOC
abstract class A {
/**
* @see TEST
*/
abstract fun foo()
}
class B : A() {
<caret>
}
@@ -0,0 +1,16 @@
// COPY_DOC
abstract class A {
/**
* @see TEST
*/
abstract fun foo()
}
class B : A() {
/**
* @see TEST
*/
override fun foo() {
<selection><caret>throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.</selection>
}
}
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.idea.test.dumpTextWithErrors
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TagsTestDataUtil import org.jetbrains.kotlin.test.TagsTestDataUtil
import org.jetbrains.kotlin.utils.rethrow import org.jetbrains.kotlin.utils.rethrow
@@ -171,8 +172,9 @@ abstract class AbstractOverrideImplementTest : KotlinLightCodeInsightFixtureTest
classOrObject: KtClassOrObject, classOrObject: KtClassOrObject,
selectedElements: List<OverrideMemberChooserObject>) { selectedElements: List<OverrideMemberChooserObject>) {
try { try {
val copyDoc = InTextDirectivesUtils.isDirectiveDefined(classOrObject.containingFile.text, "// COPY_DOC")
myFixture.project.executeWriteCommand("") { myFixture.project.executeWriteCommand("") {
OverrideImplementMembersHandler.generateMembers(myFixture.editor, classOrObject, selectedElements) OverrideImplementMembersHandler.generateMembers(myFixture.editor, classOrObject, selectedElements, copyDoc)
} }
} }
catch (throwable: Throwable) { catch (throwable: Throwable) {
@@ -235,4 +235,12 @@ class OverrideImplementTest : AbstractOverrideImplementTest() {
fun testEqualsInInterface() { fun testEqualsInInterface() {
doOverrideFileTest("equals") doOverrideFileTest("equals")
} }
fun testCopyKDoc() {
doOverrideFileTest("foo")
}
fun testConvertJavaDoc() {
doOverrideDirectoryTest("foo")
}
} }