Fix J2K to apply post convert intentions on EDT only

#KT-16754 fixed
This commit is contained in:
Simon Ogorodnik
2017-03-29 22:23:00 +03:00
parent 6cbeffe4b2
commit 8bd23d71a7
6 changed files with 69 additions and 39 deletions
@@ -58,10 +58,6 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
abstract fun applyTo(element: TElement, editor: Editor?)
protected fun <R> runInWriteActionOrHere(inWriteAction: Boolean = true, action: () -> R): R =
if (inWriteAction) runWriteAction(action)
else run(action)
private fun getTarget(editor: Editor, file: PsiFile): TElement? {
val offset = editor.caretModel.offset
val leaf1 = file.findElementAt(offset)
@@ -21,12 +21,15 @@ import com.intellij.codeInsight.editorActions.TextBlockTransferableData
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.ThrowableComputable
import com.intellij.psi.*
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.idea.actions.JavaToKotlinAction
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.codeInsight.KotlinCopyPasteReferenceProcessor
import org.jetbrains.kotlin.idea.codeInsight.KotlinReferenceData
@@ -34,6 +37,7 @@ import org.jetbrains.kotlin.idea.editor.KotlinEditorOptions
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.j2k.AfterConversionPass
import org.jetbrains.kotlin.j2k.ConverterSettings
@@ -212,7 +216,17 @@ internal fun ElementAndTextList.convertCodeToKotlin(project: Project): Conversio
)
val inputElements = this.toList().filterIsInstance<PsiElement>()
val results = converter.elementsToKotlin(inputElements).results
val results =
ProgressManager.getInstance().runProcessWithProgressSynchronously(
ThrowableComputable<JavaToKotlinConverter.Result, Exception> {
runReadAction { converter.elementsToKotlin(inputElements) }
},
JavaToKotlinAction.title,
false,
project
).results
val importsToAdd = LinkedHashSet<FqName>()
var resultIndex = 0
@@ -41,12 +41,10 @@ class IfThenToElvisInspection : IntentionBasedInspection<KtIfExpression>(
{ it -> it.isUsedAsExpression(it.analyze(BodyResolveMode.PARTIAL)) }
)
class IfThenToElvisIntention(private val fromJ2K: Boolean) : SelfTargetingOffsetIndependentIntention<KtIfExpression>(
class IfThenToElvisIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(
KtIfExpression::class.java,
"Replace 'if' expression with elvis expression"
) {
@Suppress("unused")
constructor(): this(fromJ2K = false)
private fun KtExpression.clausesReplaceableByElvis(firstClause: KtExpression, secondClause: KtExpression, context: BindingContext) =
!firstClause.isNullOrBlockExpression() &&
@@ -147,7 +145,7 @@ class IfThenToElvisIntention(private val fromJ2K: Boolean) : SelfTargetingOffset
it.typeReference!!)
}
val checkedExpression = condition.checkedExpression()!!
val elvis = runInWriteActionOrHere(inWriteAction = !fromJ2K) {
val elvis = runWriteAction {
val replacedLeft = if (left.evaluatesTo(checkedExpression)) {
if (condition is KtIsExpression) newReceiver!! else left
}
@@ -21,16 +21,15 @@ import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.intentions.SelfTargetingOffsetIndependentIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.*
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
class IfThenToSafeAccessInspection : IntentionBasedInspection<KtIfExpression>(IfThenToSafeAccessIntention::class)
class IfThenToSafeAccessIntention(private val fromJ2K: Boolean) : SelfTargetingOffsetIndependentIntention<KtIfExpression>(
class IfThenToSafeAccessIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(
KtIfExpression::class.java, "Replace 'if' expression with safe access expression"
) {
@Suppress("unused")
constructor(): this(fromJ2K = false)
override fun isApplicableTo(element: KtIfExpression): Boolean {
val condition = element.condition as? KtBinaryExpression ?: return false
@@ -70,9 +69,7 @@ class IfThenToSafeAccessIntention(private val fromJ2K: Boolean) : SelfTargetingO
}
val newExpr = KtPsiFactory(element).createExpressionByPattern("$0?.$1", receiverExpression, selectorExpression) as KtSafeQualifiedExpression
val safeAccessExpr = runInWriteActionOrHere(inWriteAction = !fromJ2K) {
element.replaced(newExpr)
}
val safeAccessExpr = runWriteAction { element.replaced(newExpr) }
if (editor != null) {
safeAccessExpr.inlineReceiverIfApplicableWithPrompt(editor)
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.ReplaceGetOrSetI
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
import org.jetbrains.kotlin.idea.quickfix.RemoveUselessCastFix
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
@@ -69,8 +70,8 @@ object J2KPostProcessingRegistrar {
_processings.add(RemoveRedundantCastToNullableProcessing())
registerIntentionBasedProcessing(ConvertToExpressionBodyIntention(convertEmptyToUnit = false)) { it is KtPropertyAccessor }
registerIntentionBasedProcessing(IfThenToSafeAccessIntention(fromJ2K = true))
registerIntentionBasedProcessing(IfThenToElvisIntention(fromJ2K = true))
registerIntentionBasedProcessing(IfThenToSafeAccessIntention())
registerIntentionBasedProcessing(IfThenToElvisIntention())
registerIntentionBasedProcessing(FoldInitializerAndIfToElvisIntention())
registerIntentionBasedProcessing(SimplifyNegatedBinaryExpressionIntention())
registerIntentionBasedProcessing(ReplaceGetOrSetIntention(), additionalChecker = ReplaceGetOrSetInspection.additionalChecker)
@@ -136,7 +137,12 @@ object J2KPostProcessingRegistrar {
if (!additionalChecker(tElement)) return null
return {
if (intention.applicabilityRange(tElement) != null) { // check availability of the intention again because something could change
intention.applyTo(element, null)
val apply = { intention.applyTo(element, null) }
if (intention.startInWriteAction())
runWriteAction(apply)
else
apply()
}
}
}
@@ -16,15 +16,21 @@
package org.jetbrains.kotlin.idea.j2k
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementVisitor
import com.intellij.psi.codeStyle.CodeStyleManager
import kotlinx.coroutines.experimental.run
import kotlinx.coroutines.experimental.runBlocking
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.conversion.copy.range
import org.jetbrains.kotlin.idea.core.util.EDT
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.j2k.PostProcessor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtElement
@@ -35,8 +41,12 @@ import java.util.*
class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
override fun insertImport(file: KtFile, fqName: FqName) {
val descriptors = file.resolveImportReference(fqName)
descriptors.firstOrNull()?.let { ImportInsertHelper.getInstance(file.project).importDescriptor(file, it) }
ApplicationManager.getApplication().invokeAndWait {
runWriteAction {
val descriptors = file.resolveImportReference(fqName)
descriptors.firstOrNull()?.let { ImportInsertHelper.getInstance(file.project).importDescriptor(file, it) }
}
}
}
private enum class RangeFilterResult {
@@ -45,39 +55,48 @@ class J2kPostProcessor(private val formatCode: Boolean) : PostProcessor {
PROCESS
}
override fun doAdditionalProcessing(file: KtFile, rangeMarker: RangeMarker?) {
var elementToActions = collectAvailableActions(file, rangeMarker)
while (elementToActions.isNotEmpty()) {
override fun doAdditionalProcessing(file: KtFile, rangeMarker: RangeMarker?) = runBlocking {
do {
var modificationStamp: Long? = file.modificationStamp
val elementToActions = runReadAction {
collectAvailableActions(file, rangeMarker)
}
for ((element, action, _) in elementToActions) {
if (element.isValid) {
action()
}
else {
modificationStamp = null
run(EDT) {
for ((element, action, _) in elementToActions) {
if (element.isValid) {
action()
}
else {
modificationStamp = null
}
}
}
if (modificationStamp == file.modificationStamp) break
elementToActions = collectAvailableActions(file, rangeMarker)
}
while (elementToActions.isNotEmpty())
if (formatCode) {
val codeStyleManager = CodeStyleManager.getInstance(file.project)
if (rangeMarker != null) {
if (rangeMarker.isValid) {
codeStyleManager.reformatRange(file, rangeMarker.startOffset, rangeMarker.endOffset)
run(EDT) {
runWriteAction {
val codeStyleManager = CodeStyleManager.getInstance(file.project)
if (rangeMarker != null) {
if (rangeMarker.isValid) {
codeStyleManager.reformatRange(file, rangeMarker.startOffset, rangeMarker.endOffset)
}
}
else {
codeStyleManager.reformat(file)
}
Unit
}
}
else {
codeStyleManager.reformat(file)
}
}
}
private data class ActionData(val element: KtElement, val action: () -> Unit, val priority: Int)
private fun collectAvailableActions(file: KtFile, rangeMarker: RangeMarker?): List<ActionData> {