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")
|
||||
.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.psi.*
|
||||
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.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
@@ -41,7 +42,19 @@ public class AddInitKeywordFix(element: JetClassInitializer) : JetIntentionActio
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
val psiFactory = JetPsiFactory(element)
|
||||
@@ -55,39 +68,5 @@ public class AddInitKeywordFix(element: JetClassInitializer) : JetIntentionActio
|
||||
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.idea.JetBundle
|
||||
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.psi.*
|
||||
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 invoke(project: Project, editor: Editor, file: JetFile) {
|
||||
classKeywordToCompanionModifier(elem)
|
||||
changeClassKeywordToCompanionModifier(elem)
|
||||
}
|
||||
|
||||
companion object Factory : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic) =
|
||||
(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()
|
||||
if (!objectDeclaration.hasModifier(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.idea.JetBundle
|
||||
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.ShortenReferences
|
||||
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.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import java.util.ArrayList
|
||||
|
||||
public class DeprecatedLambdaSyntaxFix(element: JetFunctionLiteralExpression) : JetIntentionAction<JetFunctionLiteralExpression>(element) {
|
||||
@@ -43,64 +45,45 @@ public class DeprecatedLambdaSyntaxFix(element: JetFunctionLiteralExpression) :
|
||||
companion object Factory : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic)
|
||||
= (diagnostic.getPsiElement() as? JetFunctionLiteralExpression)?.let { DeprecatedLambdaSyntaxFix(it) }
|
||||
}
|
||||
}
|
||||
|
||||
public class DeprecatedLambdaSyntaxInWholeProjectFix(element: JetFunctionLiteralExpression) :
|
||||
JetWholeProjectModalAction<JetFunctionLiteralExpression, Collection<DeprecatedSyntaxFix>>(
|
||||
element, JetBundle.message("migrate.lambda.syntax.in.whole.project.modal.title")) {
|
||||
|
||||
override fun getText() = JetBundle.message("migrate.lambda.syntax.in.whole.project")
|
||||
override fun getFamilyName() = 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()
|
||||
public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory {
|
||||
JetWholeProjectForEachElementOfTypeFix.createByTaskFactory(
|
||||
taskFactory = fun (it: JetFunctionLiteralExpression) = fixTaskFactory(it),
|
||||
taskProcessor = { it.runFix() },
|
||||
modalTitle = JetBundle.message("migrate.lambda.syntax.in.whole.project.modal.title"),
|
||||
name = JetBundle.message("migrate.lambda.syntax.in.whole.project"),
|
||||
familyName = JetBundle.message("migrate.lambda.syntax.in.whole.project.family")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class LambdaCollectionVisitor(val lambdas: MutableCollection<DeprecatedSyntaxFix>) : JetTreeVisitor<Int>() {
|
||||
override fun visitFunctionLiteralExpression(functionLiteralExpression: JetFunctionLiteralExpression, data: Int): Void? {
|
||||
functionLiteralExpression.acceptChildren(this, data + 1)
|
||||
if (JetPsiUtil.isDeprecatedLambdaSyntax(functionLiteralExpression)) {
|
||||
lambdas.add(DeprecatedSyntaxFix.createFix(functionLiteralExpression, data))
|
||||
private fun fixTaskFactory(functionLiteralExpression: JetFunctionLiteralExpression): DeprecatedSyntaxFix? {
|
||||
return if (JetPsiUtil.isDeprecatedLambdaSyntax(functionLiteralExpression)) {
|
||||
DeprecatedSyntaxFix.createFix(functionLiteralExpression)
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
companion object Factory : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic)
|
||||
= (diagnostic.getPsiElement() as? JetFunctionLiteralExpression)?.let { DeprecatedLambdaSyntaxInWholeProjectFix(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private trait DeprecatedSyntaxFix {
|
||||
val level: Int
|
||||
|
||||
// you must run it under write action
|
||||
fun runFix()
|
||||
|
||||
internal companion object {
|
||||
fun createFix(functionLiteralExpression: JetFunctionLiteralExpression, level: Int = 0): DeprecatedSyntaxFix {
|
||||
fun createFix(functionLiteralExpression: JetFunctionLiteralExpression): DeprecatedSyntaxFix {
|
||||
val functionLiteral = functionLiteralExpression.getFunctionLiteral()
|
||||
val hasNoReturnAndReceiverType = !functionLiteral.hasDeclaredReturnType() && functionLiteral.getReceiverTypeReference() == null
|
||||
|
||||
return if (hasNoReturnAndReceiverType) DeparenthesizeParameterList(functionLiteralExpression, level)
|
||||
else LambdaToFunctionExpression(functionLiteralExpression, level)
|
||||
return if (hasNoReturnAndReceiverType) DeparenthesizeParameterList(functionLiteralExpression)
|
||||
else LambdaToFunctionExpression(functionLiteralExpression)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DeparenthesizeParameterList(
|
||||
val functionLiteralExpression: JetFunctionLiteralExpression,
|
||||
override val level: Int = 0
|
||||
val functionLiteralExpression: JetFunctionLiteralExpression
|
||||
): DeprecatedSyntaxFix {
|
||||
|
||||
override fun runFix() {
|
||||
@@ -118,8 +101,7 @@ private class DeparenthesizeParameterList(
|
||||
}
|
||||
|
||||
private class LambdaToFunctionExpression(
|
||||
val functionLiteralExpression: JetFunctionLiteralExpression,
|
||||
override val level: Int = 0
|
||||
val functionLiteralExpression: JetFunctionLiteralExpression
|
||||
): DeprecatedSyntaxFix {
|
||||
val functionLiteralArgumentName: String?
|
||||
val receiverType: String?
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
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.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
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.JetVisitor
|
||||
import org.jetbrains.kotlin.psi.JetVisitorVoid
|
||||
import org.jetbrains.kotlin.psi.psiUtil.flatMapDescendantsOfTypeVisitor
|
||||
import org.jetbrains.kotlin.utils.singletonOrEmptyList
|
||||
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 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(
|
||||
object : Task.Modal(project, title, true) {
|
||||
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)
|
||||
|
||||
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.CreateParameterByNamedArgumentActionFactory;
|
||||
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.resolve.jvm.diagnostics.ErrorsJvm;
|
||||
|
||||
@@ -236,7 +235,7 @@ public class QuickFixRegistrar {
|
||||
QuickFixes.factories.put(UNUSED_PARAMETER, ChangeFunctionSignatureFix.createFactoryForUnusedParameter());
|
||||
QuickFixes.factories.put(EXPECTED_PARAMETERS_NUMBER_MISMATCH, ChangeFunctionSignatureFix.createFactoryForParametersNumberMismatch());
|
||||
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_RETURN_TYPE_MISMATCH, ChangeTypeFix.createFactoryForExpectedReturnTypeMismatch());
|
||||
@@ -310,9 +309,9 @@ public class QuickFixRegistrar {
|
||||
QuickFixes.factories.put(UNRESOLVED_REFERENCE, CreateClassFromCallWithConstructorCalleeActionFactory.INSTANCE$);
|
||||
|
||||
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, 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$);
|
||||
|
||||
@@ -320,6 +319,6 @@ public class QuickFixRegistrar {
|
||||
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, 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
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
|
||||
inline fun <reified T : PsiElement> Diagnostic.createIntentionForFirstParentOfType(
|
||||
factory: (T) -> JetIntentionAction<T>?
|
||||
) = 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 org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetIntentionAction
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetWholeProjectModalAction
|
||||
import org.jetbrains.kotlin.idea.quickfix.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
@@ -36,50 +35,25 @@ public class ReplaceJavaClassAsAnnotationArgumentFix(
|
||||
annotationEntry: JetAnnotationEntry
|
||||
) : JetIntentionAction<JetAnnotationEntry>(annotationEntry) {
|
||||
|
||||
private val psiFactory: JetPsiFactory = JetPsiFactory(annotationEntry)
|
||||
|
||||
override fun getText() = JetBundle.message("replace.java.class.argument")
|
||||
override fun getFamilyName() = JetBundle.message("replace.java.class.argument.family")
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: JetFile?) {
|
||||
processTasks(createReplacementTasks(element), psiFactory)
|
||||
processTasks(createReplacementTasks(element))
|
||||
}
|
||||
|
||||
companion object : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic) =
|
||||
diagnostic.createIntentionForFirstParentOfType(::ReplaceJavaClassAsAnnotationArgumentFix)
|
||||
}
|
||||
}
|
||||
|
||||
public class ReplaceJavaClassAsAnnotationArgumentInWholeProjectFix(
|
||||
annotationEntry: JetAnnotationEntry
|
||||
) : JetWholeProjectModalAction<JetAnnotationEntry, Collection<ReplacementTask>>(
|
||||
annotationEntry, JetBundle.message("replace.java.class.argument.in.whole.project.modal.title")
|
||||
) {
|
||||
|
||||
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)
|
||||
|
||||
public fun createWholeProjectFixFactory(): JetSingleIntentionActionFactory = createIntentionFactory {
|
||||
JetWholeProjectForEachElementOfTypeFix.createForMultiTask(
|
||||
tasksFactory = ::createReplacementTasks,
|
||||
tasksProcessor = ::processTasks,
|
||||
modalTitle = 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")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.isJavaLangClass
|
||||
|
||||
private trait ReplacementTask
|
||||
private trait ReplacementTask {
|
||||
val element: JetElement
|
||||
}
|
||||
private class JavaClassCallReplacementTask(
|
||||
val javaClassCall: JetExpression,
|
||||
val className: String
|
||||
) : ReplacementTask
|
||||
) : ReplacementTask {
|
||||
override val element: JetElement = javaClassCall
|
||||
}
|
||||
|
||||
fun createReplacementTasks(element: JetAnnotationEntry): List<ReplacementTask> {
|
||||
val replacementTasks = arrayListOf<ReplacementTask>()
|
||||
@@ -63,7 +67,10 @@ private fun Diagnostic.isJavaLangClassArgumentInAnnotation(expression: JetCallEx
|
||||
getFactory() == ErrorsJvm.JAVA_LANG_CLASS_ARGUMENT_IN_ANNOTATION &&
|
||||
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>()
|
||||
replacementTasks.forEach {
|
||||
task ->
|
||||
|
||||
Reference in New Issue
Block a user