From 6468530a36e782a7737e0da1cc4da8b15ea84e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E5=85=B8=E5=85=B8?= <413153189@qq.com> Date: Tue, 25 Jun 2024 16:23:07 +0800 Subject: [PATCH] release 1.0.3 --- .github/workflows/build.yml | 2 +- CHANGELOG.md | 5 + build.gradle.kts | 3 +- .../annotator/FixBeanProperties.kt | 115 ++++++++++++++++++ .../annotator/RemoveAllNullType.kt | 72 +++++++++++ .../GenerateModuleConfigurationDialog.kt | 8 +- .../dd_kotlin_util/help/KtPropertyHelper.kt | 26 ++++ .../itbug/dd_kotlin_util/help/KtTypeHelper.kt | 30 +++++ .../shop/itbug/dd_kotlin_util/icons/DDIcon.kt | 12 ++ .../intention/FixBeanProperties.kt | 31 +++++ .../dd_kotlin_util/util/MyKtPsiFactory.kt | 40 ++++++ .../dd_kotlin_util/util/PsiElementUtil.kt | 13 ++ .../resources/META-INF/entity_actions.xml | 12 -- src/main/resources/META-INF/plugin.xml | 15 ++- src/main/resources/icons/fix.svg | 1 + .../FixBeanProperties/description.html | 27 ++++ 16 files changed, 388 insertions(+), 24 deletions(-) create mode 100644 src/main/kotlin/shop/itbug/dd_kotlin_util/annotator/FixBeanProperties.kt create mode 100644 src/main/kotlin/shop/itbug/dd_kotlin_util/annotator/RemoveAllNullType.kt create mode 100644 src/main/kotlin/shop/itbug/dd_kotlin_util/help/KtPropertyHelper.kt create mode 100644 src/main/kotlin/shop/itbug/dd_kotlin_util/help/KtTypeHelper.kt create mode 100644 src/main/kotlin/shop/itbug/dd_kotlin_util/icons/DDIcon.kt create mode 100644 src/main/kotlin/shop/itbug/dd_kotlin_util/intention/FixBeanProperties.kt create mode 100644 src/main/kotlin/shop/itbug/dd_kotlin_util/util/MyKtPsiFactory.kt create mode 100644 src/main/kotlin/shop/itbug/dd_kotlin_util/util/PsiElementUtil.kt delete mode 100644 src/main/resources/META-INF/entity_actions.xml create mode 100644 src/main/resources/icons/fix.svg create mode 100644 src/main/resources/intentionDescriptions/FixBeanProperties/description.html diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e3eb03d..937a71d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: # 准备插件并将其发布到 JetBrains Marketplace 存储库 release: - name: Publish Plugin + name: 准备插件并将其发布到 JetBrains Marketplace 存储库 runs-on: ubuntu-latest permissions: contents: write diff --git a/CHANGELOG.md b/CHANGELOG.md index f1791ef..a015578 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [1.0.3] - 2024-06-25 + +- 添加java转kotlin自动修复功能,@Autowired,和 @Resource, ?? -> lateinit var +- 添加kotlin接口和class可空转不可空一键修复功能 + ## [1.0.1] - 2024-05-25 diff --git a/build.gradle.kts b/build.gradle.kts index c9f3980..dc83df9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,10 +11,9 @@ plugins { } group = "shop.itbug" -version = "1.0.1" +version = "1.0.3" repositories { - mavenLocal() mavenCentral() } diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/annotator/FixBeanProperties.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/annotator/FixBeanProperties.kt new file mode 100644 index 0000000..65d3db9 --- /dev/null +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/annotator/FixBeanProperties.kt @@ -0,0 +1,115 @@ +package shop.itbug.dd_kotlin_util.annotator + +import com.intellij.codeInsight.intention.impl.BaseIntentionAction +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Iconable +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiReference +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.search.LocalSearchScope +import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.psi.util.elementType +import com.intellij.psi.util.lastLeaf +import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.psi.KtOperationReferenceExpression +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.psiUtil.prevLeaf +import shop.itbug.dd_kotlin_util.help.helper +import shop.itbug.dd_kotlin_util.icons.DDIcon +import shop.itbug.dd_kotlin_util.util.MyKtPsiFactory +import shop.itbug.dd_kotlin_util.util.filterByType +import shop.itbug.dd_kotlin_util.util.findByTypeAndText +import javax.swing.Icon + +class FixBeanProperties : Annotator, DumbAware { + + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + if (element !is KtProperty) return + if (!element.helper.isNullableType()) return + if (!element.helper.isAutowiredOrResource()) return + holder.newAnnotation(HighlightSeverity.WARNING, "Change to lateinit var").range(element).withFix(MyFix(element)) + .create() + } + + + private class MyFix(val element: KtProperty) : BaseIntentionAction(), Iconable { + override fun getFamilyName(): String { + return "Change to lateinit var" + } + + override fun getText(): String { + return familyName + } + + override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean { + return true + } + + override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { + val factory = KtPsiFactory(project) + val myFactory = MyKtPsiFactory(project) + //1. 去除问号 + element.typeReference?.let { + val newEle = factory.createType(it.text.removeSuffix("?")) + it.replace(newEle) + } + + // 2. 删除null和null前面的=号 + val nullPsi = element.children.find { it.elementType == KtNodeTypes.NULL } + nullPsi?.let { + it.prevLeaf { p -> p.text == "=" }?.delete() + it.delete() + } + + + // 3替换val + element.filterByType().find { it.text == "val" }?.let { + val lateinitPsi = myFactory.createLateinit() + + /// 添加lateinit + val ws = factory.createWhiteSpace(" ") + element.modifierList?.let { modis -> + modis.addAfter(ws, modis.lastLeaf()) + modis.addAfter(lateinitPsi, modis.lastLeaf()) + } + + ///替换var + val valPsi = element.findByTypeAndText("val") + val newVar = factory.createVarKeyword() + valPsi?.replace(newVar) // val 替换为 var + + } + + + //======= 修复双!!号 + if (file != null) { + val find: MutableCollection = + ReferencesSearch.search(element, LocalSearchScope(file)).findAll() + find.forEach { ele -> + when (val e = ele.element.nextSibling) { + is KtOperationReferenceExpression -> { + if (e.text == "!!") { + val newPsi = myFactory.createNameReferenceExpression(element.nameIdentifier?.text ?: "") + ele.element.parent.replace(newPsi) + } + } + } + } + } + + } + + override fun getIcon(flags: Int): Icon { + return DDIcon.FixIcon + } + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/annotator/RemoveAllNullType.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/annotator/RemoveAllNullType.kt new file mode 100644 index 0000000..e8b391d --- /dev/null +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/annotator/RemoveAllNullType.kt @@ -0,0 +1,72 @@ +package shop.itbug.dd_kotlin_util.annotator + +import com.intellij.codeInsight.intention.impl.BaseIntentionAction +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Iconable +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.psi.KtClass +import org.jetbrains.kotlin.psi.KtSuperTypeListEntry +import shop.itbug.dd_kotlin_util.help.helper +import shop.itbug.dd_kotlin_util.icons.DDIcon +import javax.swing.Icon + + +///将接口定义的函数列表里面可空的类型全部设置为不可空类型 +class RemoveAllNullType : Annotator, DumbAware, Iconable { + + override fun getIcon(flags: Int): Icon { + return DDIcon.FixIcon + } + + override fun annotate(element: PsiElement, holder: AnnotationHolder) { + if (element is KtClass) { + println("name psi : ${element.nameIdentifier?.text}") + val namePsi = element.nameIdentifier ?: return + holder.newAnnotation(HighlightSeverity.INFORMATION,"Set all nullable types to non-nullable") + .range(namePsi) + .withFix(Fix(element)) + .create() + } + } + + private class Fix(val ktClass: KtClass): BaseIntentionAction(),Iconable { + override fun getFamilyName(): String { + return "Set all nullable types to non-nullable" + } + + override fun getText(): String { + return familyName + } + + override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean { + return true + } + + override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { + val functions = ktClass.body?.functions ?: emptyList() + functions.forEach { + it.valueParameterList?.parameters?.forEach { prop -> + prop.typeReference?.helper?.nullableRemove() + } + it.typeReference?.helper?.nullableRemove() + } + + ktClass.superTypeListEntries.forEach { type: KtSuperTypeListEntry -> + type.typeReference?.helper?.nullableRemove() + } + + } + + override fun getIcon(flags: Int): Icon { + return DDIcon.FixIcon + } + + + } +} \ No newline at end of file diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/dialog/GenerateModuleConfigurationDialog.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/dialog/GenerateModuleConfigurationDialog.kt index bc00346..62da0ea 100644 --- a/src/main/kotlin/shop/itbug/dd_kotlin_util/dialog/GenerateModuleConfigurationDialog.kt +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/dialog/GenerateModuleConfigurationDialog.kt @@ -38,13 +38,7 @@ class GenerateModuleConfigurationDialog(private val project: Project, event: AnA override fun createCenterPanel(): JComponent { contentPanel = panel { row("类名") { - textField().bindText(configuration::className).validationInfo { - val empty = it.text.isEmpty() - if (empty) { - this.error("") - } - this.warning("").withOKEnabled() - } + textField().bindText(configuration::className) } row("包名") { textField().bindText(configuration::packageName) diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/help/KtPropertyHelper.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/help/KtPropertyHelper.kt new file mode 100644 index 0000000..c123cd7 --- /dev/null +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/help/KtPropertyHelper.kt @@ -0,0 +1,26 @@ +package shop.itbug.dd_kotlin_util.help + +import org.jetbrains.kotlin.psi.KtNullableType +import org.jetbrains.kotlin.psi.KtProperty + +val KtProperty.helper: KtPropertyHelper get() = KtPropertyHelper(this) +///帮助类 +class KtPropertyHelper(private val element: KtProperty) { + + + + + ///是否有[name]注解 + fun hasAnnotation(name: String): Boolean { + return element.modifierList?.annotationEntries?.any { it.shortName?.asString() == name } == true + } + + + fun isAutowired() = hasAnnotation("Autowired") + fun isResource() = hasAnnotation("Resource") + fun isAutowiredOrResource() = isAutowired() || isResource() + + /// + fun isNullableType() = element.typeReference?.typeElement is KtNullableType + +} \ No newline at end of file diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/help/KtTypeHelper.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/help/KtTypeHelper.kt new file mode 100644 index 0000000..d738bc2 --- /dev/null +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/help/KtTypeHelper.kt @@ -0,0 +1,30 @@ +package shop.itbug.dd_kotlin_util.help + +import org.jetbrains.kotlin.psi.KtNullableType +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.KtTypeReference +import org.jetbrains.kotlin.psi.KtUserType + +val KtTypeReference.helper: KtTypeHelper get() = KtTypeHelper(this) + +///类型转换帮助类 +class KtTypeHelper(private val element: KtTypeReference) { + private val factory = KtPsiFactory(element.project) + + //可空替换为不可空 + fun nullableRemove() { + when (val ele = element.firstChild) { + is KtNullableType -> { + val typeText = ele.firstChild.text + val newType = factory.createType(typeText) + element.replace(newType) + } + + is KtUserType -> { + ele.typeArgumentsAsTypes.forEach { ref: KtTypeReference -> + ref.helper.nullableRemove() + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/icons/DDIcon.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/icons/DDIcon.kt new file mode 100644 index 0000000..e1db27d --- /dev/null +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/icons/DDIcon.kt @@ -0,0 +1,12 @@ +package shop.itbug.dd_kotlin_util.icons + +import com.intellij.openapi.util.IconLoader +import javax.swing.Icon + +object DDIcon { + val FixIcon = getIconName("fix") + private fun getIconName(iconName: String): Icon { + return IconLoader.getIcon("/icons/$iconName.svg",DDIcon::class.java) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/intention/FixBeanProperties.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/intention/FixBeanProperties.kt new file mode 100644 index 0000000..22dccf9 --- /dev/null +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/intention/FixBeanProperties.kt @@ -0,0 +1,31 @@ +package shop.itbug.dd_kotlin_util.intention + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Iconable +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtTypeReference +import shop.itbug.dd_kotlin_util.help.helper +import shop.itbug.dd_kotlin_util.icons.DDIcon +import javax.swing.Icon + +class FixBeanProperties: PsiElementBaseIntentionAction(),IntentionAction,DumbAware,Iconable { + + override fun getIcon(flags: Int): Icon = DDIcon.FixIcon + + override fun getFamilyName(): String = "Change to latevar init" + + override fun getText(): String = getFamilyName() + + override fun isAvailable(project: Project, editor: Editor?, element: PsiElement): Boolean { + println(element::class.java) + return element is KtTypeReference && (element.parent is KtProperty && (element.parent as KtProperty).helper.isAutowiredOrResource() && (element.parent as KtProperty).helper.isNullableType()) + } + + override fun invoke(project: Project, editor: Editor?, element: PsiElement) { + } +} \ No newline at end of file diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/util/MyKtPsiFactory.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/util/MyKtPsiFactory.kt new file mode 100644 index 0000000..6aee340 --- /dev/null +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/util/MyKtPsiFactory.kt @@ -0,0 +1,40 @@ +package shop.itbug.dd_kotlin_util.util + +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.util.firstLeaf +import org.jetbrains.kotlin.psi.KtDotQualifiedExpression +import org.jetbrains.kotlin.psi.KtNameReferenceExpression +import org.jetbrains.kotlin.psi.KtPsiFactory + + +class Test { + val test: String = "" + fun test(){ + test.plus("") + } +} + +class MyKtPsiFactory(val project: Project) { + + private var factory = KtPsiFactory(project) + + + fun createLateinit(): PsiElement { + return factory.createParameter("lateinit var test: String").modifierList!!.firstLeaf() + } + + fun createNameReferenceExpression(name: String): KtNameReferenceExpression { + val clazz = factory.createClass(""" + class Test { + val $name: String = "" + fun test(){ + $name.plus("") + } + } + """.trimIndent()) + return clazz.body?.functions?.first()?.bodyBlockExpression?.filterByType()?.first()?.firstChild as KtNameReferenceExpression + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/shop/itbug/dd_kotlin_util/util/PsiElementUtil.kt b/src/main/kotlin/shop/itbug/dd_kotlin_util/util/PsiElementUtil.kt new file mode 100644 index 0000000..2b42ddc --- /dev/null +++ b/src/main/kotlin/shop/itbug/dd_kotlin_util/util/PsiElementUtil.kt @@ -0,0 +1,13 @@ +package shop.itbug.dd_kotlin_util.util + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil + + +inline fun PsiElement.filterByType(): List { + return PsiTreeUtil.findChildrenOfAnyType(this, T::class.java).toList() +} + +inline fun PsiElement.findByTypeAndText(text: String): T? { + return filterByType().find { it.text == text } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/entity_actions.xml b/src/main/resources/META-INF/entity_actions.xml deleted file mode 100644 index bb6e721..0000000 --- a/src/main/resources/META-INF/entity_actions.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 250426e..53d43b8 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -6,10 +6,11 @@ This Kotlin plugin tool is a powerful development aid crafted for swift batch code generation of Spring Boot JPA, Controller, Service, and more. Whether you're building large-scale projects or prototyping rapidly, it saves developers significant time and effort. Additionally, it offers the functionality to seamlessly convert Kotlin code into TypeScript, streamlining code conversion for projects employing front-end and back-end separation. With its intuitive interface and flexible configuration options, this plugin tool becomes an indispensable asset in your Kotlin development arsenal. ]]> com.intellij.modules.platform - org.jetbrains.kotlin JavaScript - org.jetbrains.kotlin + org.jetbrains.kotlin + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/icons/fix.svg b/src/main/resources/icons/fix.svg new file mode 100644 index 0000000..4e56052 --- /dev/null +++ b/src/main/resources/icons/fix.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/intentionDescriptions/FixBeanProperties/description.html b/src/main/resources/intentionDescriptions/FixBeanProperties/description.html new file mode 100644 index 0000000..2449107 --- /dev/null +++ b/src/main/resources/intentionDescriptions/FixBeanProperties/description.html @@ -0,0 +1,27 @@ + + +Write your description here. +Start the description with a verb in 3rd person singular, like reports, detects, highlights. +In the first sentence, briefly explain what exactly the inspection helps you detect. +Make sure the sentence is not very long and complicated. +

+ The first sentence must be in a dedicated paragraph separated from the rest of the text. This will make the + description easier to read. + Make sure the description doesn’t just repeat the inspection title. +

+

+ See https://jetbrains.design/intellij/text/inspections/#descriptions for more information. +

+

+ Embed code snippets: +

+

+// automatically highlighted according to inspection registration 'language' attribute
+
+ +

Text after this comment will only be shown in the settings of the inspection.

+ +

To open related settings directly from the description, add a link with `settings://$` optionally followed by `?$` to + pre-select a UI element.

+ + \ No newline at end of file