Refactor migrational intentions
- Make them independent on element - Extract common parts into JetWholeProjectModalByTaskCollectionAction class
This commit is contained in:
@@ -512,3 +512,22 @@ public fun PsiElement.getElementTextWithContext(): String {
|
|||||||
.insert(0, "File name: ${getContainingFile().getName()}\n")
|
.insert(0, "File name: ${getContainingFile().getName()}\n")
|
||||||
.toString()
|
.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calls `block` on each descendant of T type
|
||||||
|
// Note, that calls happen in order of DFS-exit, so deeper nodes are applied earlier
|
||||||
|
inline fun <reified T : JetElement> forEachDescendantOfTypeVisitor(
|
||||||
|
inlineOptions(InlineOption.ONLY_LOCAL_RETURN) block: (T) -> Unit
|
||||||
|
): JetVisitorVoid =
|
||||||
|
object : JetTreeVisitorVoid() {
|
||||||
|
override fun visitJetElement(element: JetElement) {
|
||||||
|
super.visitJetElement(element)
|
||||||
|
if (element is T) {
|
||||||
|
block(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : JetElement, R> flatMapDescendantsOfTypeVisitor(
|
||||||
|
accumulator: MutableCollection<R>,
|
||||||
|
inlineOptions(InlineOption.ONLY_LOCAL_RETURN) map: (T) -> Collection<R>
|
||||||
|
): JetVisitorVoid = forEachDescendantOfTypeVisitor<T> { accumulator.addAll(map(it)) }
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.intellij.openapi.project.*
|
|||||||
import com.intellij.openapi.editor.*
|
import com.intellij.openapi.editor.*
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType
|
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
@@ -41,7 +42,19 @@ public class AddInitKeywordFix(element: JetClassInitializer) : JetIntentionActio
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object Factory : JetSingleIntentionActionFactory() {
|
companion object Factory : JetSingleIntentionActionFactory() {
|
||||||
fun addInitKeyword(element: JetClassInitializer) {
|
override fun createAction(diagnostic: Diagnostic) = diagnostic.createIntentionForFirstParentOfType(::AddInitKeywordFix)
|
||||||
|
|
||||||
|
public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory {
|
||||||
|
JetWholeProjectForEachElementOfTypeFix.createByPredicate<JetClassInitializer>(
|
||||||
|
predicate = { !it.hasInitKeyword() },
|
||||||
|
taskProcessor = { addInitKeyword(it) },
|
||||||
|
modalTitle = JetBundle.message("add.init.keyword.in.whole.project.modal.title"),
|
||||||
|
name = JetBundle.message("add.init.keyword.in.whole.project"),
|
||||||
|
familyName = JetBundle.message("add.init.keyword.in.whole.project.family")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addInitKeyword(element: JetClassInitializer) {
|
||||||
if (element.hasInitKeyword()) return
|
if (element.hasInitKeyword()) return
|
||||||
|
|
||||||
val psiFactory = JetPsiFactory(element)
|
val psiFactory = JetPsiFactory(element)
|
||||||
@@ -55,39 +68,5 @@ public class AddInitKeywordFix(element: JetClassInitializer) : JetIntentionActio
|
|||||||
prevLeaf!!.delete()
|
prevLeaf!!.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun createAction(diagnostic: Diagnostic) = diagnostic.createIntentionForFirstParentOfType(::AddInitKeywordFix)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AddInitKeywordFixInWholeProjectFix(elem: JetClassInitializer)
|
|
||||||
: JetWholeProjectModalAction<JetClassInitializer, Collection<JetClassInitializer>>(
|
|
||||||
elem, JetBundle.message("add.init.keyword.in.whole.project.modal.title")) {
|
|
||||||
override fun getText(): String = JetBundle.message("add.init.keyword.in.whole.project")
|
|
||||||
|
|
||||||
override fun getFamilyName(): String = JetBundle.message("add.init.keyword.in.whole.project.family")
|
|
||||||
|
|
||||||
override fun collectDataForFile(project: Project, file: JetFile): Collection<JetClassInitializer>? {
|
|
||||||
val classInitializers = ArrayList<JetClassInitializer>()
|
|
||||||
file.accept(AddInitKeywordVisitor(classInitializers))
|
|
||||||
|
|
||||||
return if (classInitializers.isEmpty()) null else classInitializers
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun applyChangesForFile(project: Project, file: JetFile, data: Collection<JetClassInitializer>) {
|
|
||||||
data.forEach { AddInitKeywordFix.addInitKeyword(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class AddInitKeywordVisitor(val classInitializers: MutableCollection<JetClassInitializer>) : JetTreeVisitorVoid() {
|
|
||||||
override fun visitAnonymousInitializer(initializer: JetClassInitializer) {
|
|
||||||
initializer.acceptChildren(this)
|
|
||||||
if (!initializer.hasInitKeyword()) {
|
|
||||||
classInitializers.add(initializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object Factory : JetSingleIntentionActionFactory() {
|
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
|
||||||
diagnostic.createIntentionForFirstParentOfType(::AddInitKeywordFixInWholeProjectFix)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project
|
|||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.JetBundle
|
import org.jetbrains.kotlin.idea.JetBundle
|
||||||
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionFactory
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
@@ -31,14 +32,24 @@ public class ClassObjectToCompanionObjectFix(private val elem: JetObjectDeclarat
|
|||||||
override fun getFamilyName(): String = JetBundle.message("migrate.class.object.to.companion.family")
|
override fun getFamilyName(): String = JetBundle.message("migrate.class.object.to.companion.family")
|
||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor, file: JetFile) {
|
override fun invoke(project: Project, editor: Editor, file: JetFile) {
|
||||||
classKeywordToCompanionModifier(elem)
|
changeClassKeywordToCompanionModifier(elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object Factory : JetSingleIntentionActionFactory() {
|
companion object Factory : JetSingleIntentionActionFactory() {
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
override fun createAction(diagnostic: Diagnostic) =
|
||||||
(diagnostic.getPsiElement() as? JetObjectDeclaration)?.let { ClassObjectToCompanionObjectFix(it) }
|
(diagnostic.getPsiElement() as? JetObjectDeclaration)?.let { ClassObjectToCompanionObjectFix(it) }
|
||||||
|
|
||||||
fun classKeywordToCompanionModifier(objectDeclaration: JetObjectDeclaration) {
|
public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory {
|
||||||
|
JetWholeProjectForEachElementOfTypeFix.createByPredicate<JetObjectDeclaration>(
|
||||||
|
predicate = { it.getClassKeyword() != null },
|
||||||
|
taskProcessor = { changeClassKeywordToCompanionModifier(it) },
|
||||||
|
modalTitle = JetBundle.message("migrate.class.object.to.companion.in.whole.project.modal.title"),
|
||||||
|
name = JetBundle.message("migrate.class.object.to.companion.in.whole.project"),
|
||||||
|
familyName = JetBundle.message("migrate.class.object.to.companion.in.whole.project.family")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeClassKeywordToCompanionModifier(objectDeclaration: JetObjectDeclaration) {
|
||||||
objectDeclaration.getClassKeyword()?.delete()
|
objectDeclaration.getClassKeyword()?.delete()
|
||||||
if (!objectDeclaration.hasModifier(JetTokens.COMPANION_KEYWORD)) {
|
if (!objectDeclaration.hasModifier(JetTokens.COMPANION_KEYWORD)) {
|
||||||
objectDeclaration.addModifier(JetTokens.COMPANION_KEYWORD)
|
objectDeclaration.addModifier(JetTokens.COMPANION_KEYWORD)
|
||||||
@@ -46,36 +57,3 @@ public class ClassObjectToCompanionObjectFix(private val elem: JetObjectDeclarat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ClassObjectToCompanionObjectInWholeProjectFix(private val elem: JetObjectDeclaration)
|
|
||||||
: JetWholeProjectModalAction<JetObjectDeclaration, Collection<JetObjectDeclaration>>(
|
|
||||||
elem, JetBundle.message("migrate.class.object.to.companion.in.whole.project.modal.title")) {
|
|
||||||
override fun getText(): String = JetBundle.message("migrate.class.object.to.companion.in.whole.project")
|
|
||||||
|
|
||||||
override fun getFamilyName(): String = JetBundle.message("migrate.class.object.to.companion.in.whole.project.family")
|
|
||||||
|
|
||||||
override fun collectDataForFile(project: Project, file: JetFile): Collection<JetObjectDeclaration>? {
|
|
||||||
val classObjects = ArrayList<JetObjectDeclaration>()
|
|
||||||
file.accept(ClassObjectToCompanionObjectVisitor(classObjects))
|
|
||||||
|
|
||||||
return if (classObjects.isEmpty()) null else classObjects
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun applyChangesForFile(project: Project, file: JetFile, data: Collection<JetObjectDeclaration>) {
|
|
||||||
data.forEach { ClassObjectToCompanionObjectFix.classKeywordToCompanionModifier(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ClassObjectToCompanionObjectVisitor(val classObjects: MutableCollection<JetObjectDeclaration>) : JetTreeVisitorVoid() {
|
|
||||||
override fun visitObjectDeclaration(objectDeclaration: JetObjectDeclaration) {
|
|
||||||
objectDeclaration.acceptChildren(this)
|
|
||||||
if (objectDeclaration.getClassKeyword() != null) {
|
|
||||||
classObjects.add(objectDeclaration)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object Factory : JetSingleIntentionActionFactory() {
|
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
|
||||||
(diagnostic.getPsiElement() as? JetObjectDeclaration)?.let { ClassObjectToCompanionObjectInWholeProjectFix(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
|
|||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
|
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
|
||||||
import org.jetbrains.kotlin.idea.JetBundle
|
import org.jetbrains.kotlin.idea.JetBundle
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionFactory
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.util.psiModificationUtil.getFunctionLiteralArgumentName
|
import org.jetbrains.kotlin.idea.util.psiModificationUtil.getFunctionLiteralArgumentName
|
||||||
@@ -30,6 +31,7 @@ import org.jetbrains.kotlin.idea.util.psiModificationUtil.moveInsideParenthesesA
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.utils.sure
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
public class DeprecatedLambdaSyntaxFix(element: JetFunctionLiteralExpression) : JetIntentionAction<JetFunctionLiteralExpression>(element) {
|
public class DeprecatedLambdaSyntaxFix(element: JetFunctionLiteralExpression) : JetIntentionAction<JetFunctionLiteralExpression>(element) {
|
||||||
@@ -43,64 +45,45 @@ public class DeprecatedLambdaSyntaxFix(element: JetFunctionLiteralExpression) :
|
|||||||
companion object Factory : JetSingleIntentionActionFactory() {
|
companion object Factory : JetSingleIntentionActionFactory() {
|
||||||
override fun createAction(diagnostic: Diagnostic)
|
override fun createAction(diagnostic: Diagnostic)
|
||||||
= (diagnostic.getPsiElement() as? JetFunctionLiteralExpression)?.let { DeprecatedLambdaSyntaxFix(it) }
|
= (diagnostic.getPsiElement() as? JetFunctionLiteralExpression)?.let { DeprecatedLambdaSyntaxFix(it) }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DeprecatedLambdaSyntaxInWholeProjectFix(element: JetFunctionLiteralExpression) :
|
public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory {
|
||||||
JetWholeProjectModalAction<JetFunctionLiteralExpression, Collection<DeprecatedSyntaxFix>>(
|
JetWholeProjectForEachElementOfTypeFix.createByTaskFactory(
|
||||||
element, JetBundle.message("migrate.lambda.syntax.in.whole.project.modal.title")) {
|
taskFactory = fun (it: JetFunctionLiteralExpression) = fixTaskFactory(it),
|
||||||
|
taskProcessor = { it.runFix() },
|
||||||
override fun getText() = JetBundle.message("migrate.lambda.syntax.in.whole.project")
|
modalTitle = JetBundle.message("migrate.lambda.syntax.in.whole.project.modal.title"),
|
||||||
override fun getFamilyName() = JetBundle.message("migrate.lambda.syntax.in.whole.project.family")
|
name = JetBundle.message("migrate.lambda.syntax.in.whole.project"),
|
||||||
|
familyName = JetBundle.message("migrate.lambda.syntax.in.whole.project.family")
|
||||||
override fun collectDataForFile(project: Project, file: JetFile): Collection<DeprecatedSyntaxFix>? {
|
)
|
||||||
val lambdas = ArrayList<DeprecatedSyntaxFix>()
|
|
||||||
file.accept(LambdaCollectionVisitor(lambdas), 0)
|
|
||||||
return lambdas.sortBy { -it.level }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun applyChangesForFile(project: Project, file: JetFile, data: Collection<DeprecatedSyntaxFix>) {
|
|
||||||
data.forEach {
|
|
||||||
it.runFix()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class LambdaCollectionVisitor(val lambdas: MutableCollection<DeprecatedSyntaxFix>) : JetTreeVisitor<Int>() {
|
private fun fixTaskFactory(functionLiteralExpression: JetFunctionLiteralExpression): DeprecatedSyntaxFix? {
|
||||||
override fun visitFunctionLiteralExpression(functionLiteralExpression: JetFunctionLiteralExpression, data: Int): Void? {
|
return if (JetPsiUtil.isDeprecatedLambdaSyntax(functionLiteralExpression)) {
|
||||||
functionLiteralExpression.acceptChildren(this, data + 1)
|
DeprecatedSyntaxFix.createFix(functionLiteralExpression)
|
||||||
if (JetPsiUtil.isDeprecatedLambdaSyntax(functionLiteralExpression)) {
|
}
|
||||||
lambdas.add(DeprecatedSyntaxFix.createFix(functionLiteralExpression, data))
|
else {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object Factory : JetSingleIntentionActionFactory() {
|
|
||||||
override fun createAction(diagnostic: Diagnostic)
|
|
||||||
= (diagnostic.getPsiElement() as? JetFunctionLiteralExpression)?.let { DeprecatedLambdaSyntaxInWholeProjectFix(it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private trait DeprecatedSyntaxFix {
|
private trait DeprecatedSyntaxFix {
|
||||||
val level: Int
|
|
||||||
|
|
||||||
// you must run it under write action
|
// you must run it under write action
|
||||||
fun runFix()
|
fun runFix()
|
||||||
|
|
||||||
internal companion object {
|
internal companion object {
|
||||||
fun createFix(functionLiteralExpression: JetFunctionLiteralExpression, level: Int = 0): DeprecatedSyntaxFix {
|
fun createFix(functionLiteralExpression: JetFunctionLiteralExpression): DeprecatedSyntaxFix {
|
||||||
val functionLiteral = functionLiteralExpression.getFunctionLiteral()
|
val functionLiteral = functionLiteralExpression.getFunctionLiteral()
|
||||||
val hasNoReturnAndReceiverType = !functionLiteral.hasDeclaredReturnType() && functionLiteral.getReceiverTypeReference() == null
|
val hasNoReturnAndReceiverType = !functionLiteral.hasDeclaredReturnType() && functionLiteral.getReceiverTypeReference() == null
|
||||||
|
|
||||||
return if (hasNoReturnAndReceiverType) DeparenthesizeParameterList(functionLiteralExpression, level)
|
return if (hasNoReturnAndReceiverType) DeparenthesizeParameterList(functionLiteralExpression)
|
||||||
else LambdaToFunctionExpression(functionLiteralExpression, level)
|
else LambdaToFunctionExpression(functionLiteralExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DeparenthesizeParameterList(
|
private class DeparenthesizeParameterList(
|
||||||
val functionLiteralExpression: JetFunctionLiteralExpression,
|
val functionLiteralExpression: JetFunctionLiteralExpression
|
||||||
override val level: Int = 0
|
|
||||||
): DeprecatedSyntaxFix {
|
): DeprecatedSyntaxFix {
|
||||||
|
|
||||||
override fun runFix() {
|
override fun runFix() {
|
||||||
@@ -118,8 +101,7 @@ private class DeparenthesizeParameterList(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class LambdaToFunctionExpression(
|
private class LambdaToFunctionExpression(
|
||||||
val functionLiteralExpression: JetFunctionLiteralExpression,
|
val functionLiteralExpression: JetFunctionLiteralExpression
|
||||||
override val level: Int = 0
|
|
||||||
): DeprecatedSyntaxFix {
|
): DeprecatedSyntaxFix {
|
||||||
val functionLiteralArgumentName: String?
|
val functionLiteralArgumentName: String?
|
||||||
val receiverType: String?
|
val receiverType: String?
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
@@ -25,18 +26,28 @@ import com.intellij.openapi.progress.ProgressManager
|
|||||||
import com.intellij.openapi.progress.Task
|
import com.intellij.openapi.progress.Task
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.util.ui.UIUtil
|
import com.intellij.util.ui.UIUtil
|
||||||
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
||||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
|
import org.jetbrains.kotlin.psi.JetElement
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
|
import org.jetbrains.kotlin.psi.JetVisitor
|
||||||
|
import org.jetbrains.kotlin.psi.JetVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.flatMapDescendantsOfTypeVisitor
|
||||||
|
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
|
|
||||||
public abstract class JetWholeProjectModalAction<T : PsiElement, D: Any>(element: T, val title: String) : JetIntentionAction<T>(element) {
|
public abstract class JetWholeProjectModalAction<D: Any>(val title: String) : IntentionAction {
|
||||||
override final fun startInWriteAction() = false
|
override final fun startInWriteAction() = false
|
||||||
|
|
||||||
override final fun invoke(project: Project, editor: Editor, file: JetFile) =
|
override final fun invoke(project: Project, editor: Editor?, file: PsiFile?) = invoke(project)
|
||||||
|
|
||||||
|
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?) = true
|
||||||
|
|
||||||
|
private fun invoke(project: Project) =
|
||||||
ProgressManager.getInstance().run(
|
ProgressManager.getInstance().run(
|
||||||
object : Task.Modal(project, title, true) {
|
object : Task.Modal(project, title, true) {
|
||||||
override fun run(indicator: ProgressIndicator) {
|
override fun run(indicator: ProgressIndicator) {
|
||||||
@@ -84,7 +95,78 @@ public abstract class JetWholeProjectModalAction<T : PsiElement, D: Any>(element
|
|||||||
protected abstract fun applyChangesForFile(project: Project, file: JetFile, data: D)
|
protected abstract fun applyChangesForFile(project: Project, file: JetFile, data: D)
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
val LOG = Logger.getInstance(javaClass<JetWholeProjectModalAction<*, *>>());
|
val LOG = Logger.getInstance(javaClass<JetWholeProjectModalAction<*>>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class JetWholeProjectModalByCollectionAction<T : Any>(modalTitle: String)
|
||||||
|
: JetWholeProjectModalAction<Collection<T>>(modalTitle) {
|
||||||
|
override fun collectDataForFile(project: Project, file: JetFile): Collection<T>? {
|
||||||
|
val accumulator = arrayListOf<T>()
|
||||||
|
collectTasksForFile(project, file, accumulator)
|
||||||
|
return accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun collectTasksForFile(project: Project, file: JetFile, accumulator: MutableCollection<T>)
|
||||||
|
}
|
||||||
|
|
||||||
|
class JetWholeProjectForEachElementOfTypeFix<T> private (
|
||||||
|
val collectingVisitorFactory: (MutableCollection<T>) -> JetVisitorVoid,
|
||||||
|
val tasksProcessor: (Collection<T>) -> Unit,
|
||||||
|
modalTitle: String,
|
||||||
|
val name: String,
|
||||||
|
val familyNameText: String
|
||||||
|
) : JetWholeProjectModalByCollectionAction<T>(modalTitle) {
|
||||||
|
|
||||||
|
override fun getFamilyName() = familyNameText
|
||||||
|
override fun getText() = name
|
||||||
|
|
||||||
|
override fun collectTasksForFile(project: Project, file: JetFile, accumulator: MutableCollection<T>) {
|
||||||
|
file.accept(collectingVisitorFactory(accumulator))
|
||||||
|
}
|
||||||
|
override fun applyChangesForFile(project: Project, file: JetFile, data: Collection<T>) = tasksProcessor(data)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
inline fun <reified E : JetElement> createByPredicate(
|
||||||
|
inlineOptions(InlineOption.ONLY_LOCAL_RETURN) predicate: (E) -> Boolean,
|
||||||
|
inlineOptions(InlineOption.ONLY_LOCAL_RETURN) taskProcessor: (E) -> Unit,
|
||||||
|
modalTitle: String,
|
||||||
|
name: String,
|
||||||
|
familyName: String
|
||||||
|
) = createByTaskFactory<E, E>(
|
||||||
|
taskFactory = { if (predicate(it)) it else null },
|
||||||
|
taskProcessor = taskProcessor,
|
||||||
|
modalTitle = modalTitle,
|
||||||
|
name = name,
|
||||||
|
familyName = familyName
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified E : JetElement, D : Any> createByTaskFactory(
|
||||||
|
inlineOptions(InlineOption.ONLY_LOCAL_RETURN) taskFactory: (E) -> D?,
|
||||||
|
inlineOptions(InlineOption.ONLY_LOCAL_RETURN) taskProcessor: (D) -> Unit,
|
||||||
|
modalTitle: String,
|
||||||
|
name: String,
|
||||||
|
familyName: String
|
||||||
|
) = createForMultiTask<E, D>(
|
||||||
|
tasksFactory = { taskFactory(it).singletonOrEmptyList() },
|
||||||
|
tasksProcessor = { it.forEach(taskProcessor) },
|
||||||
|
modalTitle = modalTitle,
|
||||||
|
name = name,
|
||||||
|
familyName = familyName
|
||||||
|
)
|
||||||
|
|
||||||
|
inline fun <reified E : JetElement, D> createForMultiTask(
|
||||||
|
inlineOptions(InlineOption.ONLY_LOCAL_RETURN) tasksFactory: (E) -> Collection<D>,
|
||||||
|
noinline tasksProcessor: (Collection<D>) -> Unit,
|
||||||
|
modalTitle: String,
|
||||||
|
name: String,
|
||||||
|
familyName: String
|
||||||
|
) = JetWholeProjectForEachElementOfTypeFix(
|
||||||
|
collectingVisitorFactory = { accumulator -> flatMapDescendantsOfTypeVisitor(accumulator, tasksFactory) },
|
||||||
|
tasksProcessor = tasksProcessor,
|
||||||
|
modalTitle = modalTitle,
|
||||||
|
name = name,
|
||||||
|
familyNameText = familyName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateL
|
|||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterActionFactory;
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterActionFactory;
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory;
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createVariable.CreateParameterByNamedArgumentActionFactory;
|
||||||
import org.jetbrains.kotlin.idea.quickfix.replaceJavaClass.ReplaceJavaClassAsAnnotationArgumentFix;
|
import org.jetbrains.kotlin.idea.quickfix.replaceJavaClass.ReplaceJavaClassAsAnnotationArgumentFix;
|
||||||
import org.jetbrains.kotlin.idea.quickfix.replaceJavaClass.ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix;
|
|
||||||
import org.jetbrains.kotlin.psi.JetClass;
|
import org.jetbrains.kotlin.psi.JetClass;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm;
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm;
|
||||||
|
|
||||||
@@ -236,7 +235,7 @@ public class QuickFixRegistrar {
|
|||||||
QuickFixes.factories.put(UNUSED_PARAMETER, ChangeFunctionSignatureFix.createFactoryForUnusedParameter());
|
QuickFixes.factories.put(UNUSED_PARAMETER, ChangeFunctionSignatureFix.createFactoryForUnusedParameter());
|
||||||
QuickFixes.factories.put(EXPECTED_PARAMETERS_NUMBER_MISMATCH, ChangeFunctionSignatureFix.createFactoryForParametersNumberMismatch());
|
QuickFixes.factories.put(EXPECTED_PARAMETERS_NUMBER_MISMATCH, ChangeFunctionSignatureFix.createFactoryForParametersNumberMismatch());
|
||||||
QuickFixes.factories.put(DEPRECATED_LAMBDA_SYNTAX, DeprecatedLambdaSyntaxFix.Factory);
|
QuickFixes.factories.put(DEPRECATED_LAMBDA_SYNTAX, DeprecatedLambdaSyntaxFix.Factory);
|
||||||
QuickFixes.factories.put(DEPRECATED_LAMBDA_SYNTAX, DeprecatedLambdaSyntaxInWholeProjectFix.Factory);
|
QuickFixes.factories.put(DEPRECATED_LAMBDA_SYNTAX, DeprecatedLambdaSyntaxFix.Factory.createWholeProjectFixFactory());
|
||||||
|
|
||||||
QuickFixes.factories.put(EXPECTED_PARAMETER_TYPE_MISMATCH, ChangeTypeFix.createFactoryForExpectedParameterTypeMismatch());
|
QuickFixes.factories.put(EXPECTED_PARAMETER_TYPE_MISMATCH, ChangeTypeFix.createFactoryForExpectedParameterTypeMismatch());
|
||||||
QuickFixes.factories.put(EXPECTED_RETURN_TYPE_MISMATCH, ChangeTypeFix.createFactoryForExpectedReturnTypeMismatch());
|
QuickFixes.factories.put(EXPECTED_RETURN_TYPE_MISMATCH, ChangeTypeFix.createFactoryForExpectedReturnTypeMismatch());
|
||||||
@@ -310,9 +309,9 @@ public class QuickFixRegistrar {
|
|||||||
QuickFixes.factories.put(UNRESOLVED_REFERENCE, CreateClassFromCallWithConstructorCalleeActionFactory.INSTANCE$);
|
QuickFixes.factories.put(UNRESOLVED_REFERENCE, CreateClassFromCallWithConstructorCalleeActionFactory.INSTANCE$);
|
||||||
|
|
||||||
QuickFixes.factories.put(DEPRECATED_CLASS_OBJECT_SYNTAX, ClassObjectToCompanionObjectFix.Factory);
|
QuickFixes.factories.put(DEPRECATED_CLASS_OBJECT_SYNTAX, ClassObjectToCompanionObjectFix.Factory);
|
||||||
QuickFixes.factories.put(DEPRECATED_CLASS_OBJECT_SYNTAX, ClassObjectToCompanionObjectInWholeProjectFix.Factory);
|
QuickFixes.factories.put(DEPRECATED_CLASS_OBJECT_SYNTAX, ClassObjectToCompanionObjectFix.Factory.createWholeProjectFixFactory());
|
||||||
QuickFixes.factories.put(INIT_KEYWORD_BEFORE_CLASS_INITIALIZER_EXPECTED, AddInitKeywordFix.Factory);
|
QuickFixes.factories.put(INIT_KEYWORD_BEFORE_CLASS_INITIALIZER_EXPECTED, AddInitKeywordFix.Factory);
|
||||||
QuickFixes.factories.put(INIT_KEYWORD_BEFORE_CLASS_INITIALIZER_EXPECTED, AddInitKeywordFixInWholeProjectFix.Factory);
|
QuickFixes.factories.put(INIT_KEYWORD_BEFORE_CLASS_INITIALIZER_EXPECTED, AddInitKeywordFix.Factory.createWholeProjectFixFactory());
|
||||||
|
|
||||||
QuickFixes.factories.put(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, InsertDelegationCallQuickfix.InsertThisDelegationCallFactory.INSTANCE$);
|
QuickFixes.factories.put(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, InsertDelegationCallQuickfix.InsertThisDelegationCallFactory.INSTANCE$);
|
||||||
|
|
||||||
@@ -320,6 +319,6 @@ public class QuickFixRegistrar {
|
|||||||
QuickFixes.factories.put(EXPLICIT_DELEGATION_CALL_REQUIRED, InsertDelegationCallQuickfix.InsertSuperDelegationCallFactory.INSTANCE$);
|
QuickFixes.factories.put(EXPLICIT_DELEGATION_CALL_REQUIRED, InsertDelegationCallQuickfix.InsertSuperDelegationCallFactory.INSTANCE$);
|
||||||
|
|
||||||
QuickFixes.factories.put(ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION, ReplaceJavaClassAsAnnotationArgumentFix.Companion);
|
QuickFixes.factories.put(ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION, ReplaceJavaClassAsAnnotationArgumentFix.Companion);
|
||||||
QuickFixes.factories.put(ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION, ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix.Companion);
|
QuickFixes.factories.put(ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION, ReplaceJavaClassAsAnnotationArgumentFix.Companion.createWholeProjectFixFactory());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix.quickfixUtil
|
package org.jetbrains.kotlin.idea.quickfix.quickfixUtil
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
|
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
|
||||||
inline fun <reified T : PsiElement> Diagnostic.createIntentionForFirstParentOfType(
|
inline fun <reified T : PsiElement> Diagnostic.createIntentionForFirstParentOfType(
|
||||||
factory: (T) -> JetIntentionAction<T>?
|
factory: (T) -> JetIntentionAction<T>?
|
||||||
) = getPsiElement().getNonStrictParentOfType<T>()?.let(factory)
|
) = getPsiElement().getNonStrictParentOfType<T>()?.let(factory)
|
||||||
|
|
||||||
|
|
||||||
|
inline fun createIntentionFactory(
|
||||||
|
inlineOptions(InlineOption.ONLY_LOCAL_RETURN) factory: (Diagnostic) -> IntentionAction?
|
||||||
|
) = object : JetSingleIntentionActionFactory() {
|
||||||
|
override fun createAction(diagnostic: Diagnostic) = factory(diagnostic)
|
||||||
|
}
|
||||||
|
|||||||
+13
-39
@@ -22,9 +22,8 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.JetBundle
|
import org.jetbrains.kotlin.idea.JetBundle
|
||||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
|
import org.jetbrains.kotlin.idea.quickfix.*
|
||||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.JetWholeProjectModalAction
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType
|
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||||
@@ -36,50 +35,25 @@ public class ReplaceJavaClassAsAnnotationArgumentFix(
|
|||||||
annotationEntry: JetAnnotationEntry
|
annotationEntry: JetAnnotationEntry
|
||||||
) : JetIntentionAction<JetAnnotationEntry>(annotationEntry) {
|
) : JetIntentionAction<JetAnnotationEntry>(annotationEntry) {
|
||||||
|
|
||||||
private val psiFactory: JetPsiFactory = JetPsiFactory(annotationEntry)
|
|
||||||
|
|
||||||
override fun getText() = JetBundle.message("replace.java.class.argument")
|
override fun getText() = JetBundle.message("replace.java.class.argument")
|
||||||
override fun getFamilyName() = JetBundle.message("replace.java.class.argument.family")
|
override fun getFamilyName() = JetBundle.message("replace.java.class.argument.family")
|
||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor?, file: JetFile?) {
|
override fun invoke(project: Project, editor: Editor?, file: JetFile?) {
|
||||||
processTasks(createReplacementTasks(element), psiFactory)
|
processTasks(createReplacementTasks(element))
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : JetSingleIntentionActionFactory() {
|
companion object : JetSingleIntentionActionFactory() {
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
override fun createAction(diagnostic: Diagnostic) =
|
||||||
diagnostic.createIntentionForFirstParentOfType(::ReplaceJavaClassAsAnnotationArgumentFix)
|
diagnostic.createIntentionForFirstParentOfType(::ReplaceJavaClassAsAnnotationArgumentFix)
|
||||||
}
|
|
||||||
}
|
public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory {
|
||||||
|
JetWholeProjectForEachElementOfTypeFix.createForMultiTask(
|
||||||
public class ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix(
|
tasksFactory = ::createReplacementTasks,
|
||||||
annotationEntry: JetAnnotationEntry
|
tasksProcessor = ::processTasks,
|
||||||
) : JetWholeProjectModalAction<JetAnnotationEntry, Collection<ReplacementTask>>(
|
modalTitle = JetBundle.message("replace.java.class.argument.in.whole.project.modal.title"),
|
||||||
annotationEntry, JetBundle.message("replace.java.class.argument.in.whole.project.modal.title")
|
name = JetBundle.message("replace.java.class.argument.in.whole.project"),
|
||||||
) {
|
familyName = JetBundle.message("replace.java.class.argument.in.whole.project.family")
|
||||||
|
)
|
||||||
private val psiFactory: JetPsiFactory = JetPsiFactory(annotationEntry)
|
}
|
||||||
|
|
||||||
override fun getText() = JetBundle.message("replace.java.class.argument.in.whole.project")
|
|
||||||
override fun getFamilyName() = JetBundle.message("replace.java.class.argument.in.whole.project.family")
|
|
||||||
|
|
||||||
override fun collectDataForFile(project: Project, file: JetFile): Collection<ReplacementTask>? {
|
|
||||||
val result = arrayListOf<ReplacementTask>()
|
|
||||||
|
|
||||||
file.accept(object : JetTreeVisitorVoid() {
|
|
||||||
override fun visitAnnotationEntry(annotationEntry: JetAnnotationEntry) {
|
|
||||||
result.addAll(createReplacementTasks(annotationEntry))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun applyChangesForFile(project: Project, file: JetFile, data: Collection<ReplacementTask>) {
|
|
||||||
processTasks(data, psiFactory)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object : JetSingleIntentionActionFactory() {
|
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
|
||||||
diagnostic.createIntentionForFirstParentOfType<JetAnnotationEntry>(::ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,15 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.isArrayOfJavaLangClass
|
import org.jetbrains.kotlin.types.typeUtil.isArrayOfJavaLangClass
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isJavaLangClass
|
import org.jetbrains.kotlin.types.typeUtil.isJavaLangClass
|
||||||
|
|
||||||
private trait ReplacementTask
|
private trait ReplacementTask {
|
||||||
|
val element: JetElement
|
||||||
|
}
|
||||||
private class JavaClassCallReplacementTask(
|
private class JavaClassCallReplacementTask(
|
||||||
val javaClassCall: JetExpression,
|
val javaClassCall: JetExpression,
|
||||||
val className: String
|
val className: String
|
||||||
) : ReplacementTask
|
) : ReplacementTask {
|
||||||
|
override val element: JetElement = javaClassCall
|
||||||
|
}
|
||||||
|
|
||||||
fun createReplacementTasks(element: JetAnnotationEntry): List<ReplacementTask> {
|
fun createReplacementTasks(element: JetAnnotationEntry): List<ReplacementTask> {
|
||||||
val replacementTasks = arrayListOf<ReplacementTask>()
|
val replacementTasks = arrayListOf<ReplacementTask>()
|
||||||
@@ -63,7 +67,10 @@ private fun Diagnostic.isJavaLangClassArgumentInAnnotation(expression: JetCallEx
|
|||||||
getFactory() == ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION &&
|
getFactory() == ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION &&
|
||||||
getPsiElement().isAncestor(expression)
|
getPsiElement().isAncestor(expression)
|
||||||
|
|
||||||
fun processTasks(replacementTasks: Collection<ReplacementTask>, psiFactory: JetPsiFactory) {
|
fun processTasks(replacementTasks: Collection<ReplacementTask>) {
|
||||||
|
val element = replacementTasks.firstOrNull()?.element ?: return
|
||||||
|
val psiFactory = JetPsiFactory(element)
|
||||||
|
|
||||||
val elementsToShorten = arrayListOf<JetElement>()
|
val elementsToShorten = arrayListOf<JetElement>()
|
||||||
replacementTasks.forEach {
|
replacementTasks.forEach {
|
||||||
task ->
|
task ->
|
||||||
|
|||||||
Reference in New Issue
Block a user