Refactor migrational intentions

- Make them independent on element
- Extract common parts into JetWholeProjectModalByTaskCollectionAction class
This commit is contained in:
Denis Zharkov
2015-04-21 17:38:01 +03:00
parent ef79b260f4
commit fef568dbf0
9 changed files with 188 additions and 159 deletions
@@ -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)
}
@@ -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 ->