Move remove redundant imports to bg thread

#KT-24122 Fixed
This commit is contained in:
Vladimir Dolzhenko
2020-02-04 15:58:10 +01:00
parent fef2e06db4
commit dd0613bc7a
@@ -16,8 +16,11 @@
package org.jetbrains.kotlin.idea.codeInsight
import com.intellij.openapi.application.invokeLater
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
@@ -26,81 +29,66 @@ import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.refactoring.RefactoringHelper
import com.intellij.usageView.UsageInfo
import com.intellij.util.IncorrectOperationException
import com.intellij.util.SequentialModalProgressTask
import com.intellij.util.SequentialTask
import org.jetbrains.kotlin.idea.inspections.KotlinUnusedImportInspection
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
// Based on com.intellij.refactoring.OptimizeImportsRefactoringHelper
class KotlinOptimizeImportsRefactoringHelper : RefactoringHelper<Set<KtFile>> {
internal class CollectUnusedImportsTask(
private val task: SequentialModalProgressTask,
internal open class CollectUnusedImportsTask(
project: Project,
private val dumbService: DumbService,
private val unusedImports: MutableSet<SmartPsiElementPointer<KtImportDirective>>,
operationData: Set<KtFile>
) : SequentialTask {
private val myTotalCount = operationData.size
private val operationIterator = operationData.withIndex().iterator()
private val operationData: Set<KtFile>
) : Task.Backgroundable(project, COLLECT_UNUSED_IMPORTS_TITLE, false) {
override fun prepare() {}
override fun run(indicator: ProgressIndicator) {
val myTotalCount = operationData.size
for ((counter, file) in operationData.withIndex()) {
if (!file.isValid) return
val virtualFile = file.virtualFile ?: return
override fun stop() {}
with(indicator) {
text2 = virtualFile.presentableUrl
fraction = counter.toDouble() / myTotalCount
}
override fun isDone(): Boolean = !operationIterator.hasNext()
override fun iteration(): Boolean {
val (counter, file) = operationIterator.next()
if (!file.isValid) return isDone
val virtualFile = file.virtualFile ?: return isDone
with(task.indicator) {
text2 = virtualFile.presentableUrl
fraction = counter.toDouble() / myTotalCount
dumbService.runReadActionInSmartMode {
KotlinUnusedImportInspection.analyzeImports(file)?.unusedImports?.mapTo(unusedImports) { it.createSmartPointer() }
}
}
dumbService.runReadActionInSmartMode {
KotlinUnusedImportInspection.analyzeImports(file)?.unusedImports?.mapTo(unusedImports) { it.createSmartPointer() }
}
return isDone
}
}
internal class OptimizeImportsTask(
private val task: SequentialModalProgressTask,
pointers: Set<SmartPsiElementPointer<KtImportDirective>>
) : SequentialTask {
private val pointerIterator = pointers.withIndex().iterator()
private val myTotal: Int = pointers.size
project: Project,
private val pointers: Set<SmartPsiElementPointer<KtImportDirective>>
) : Task.Modal(project, REMOVING_REDUNDANT_IMPORTS_TITLE, false) {
override fun prepare() {}
override fun run(indicator: ProgressIndicator) {
val myTotal: Int = pointers.size
for ((counter, pointer) in pointers.withIndex()) {
indicator.fraction = counter.toDouble() / myTotal
override fun isDone() = !pointerIterator.hasNext()
override fun iteration(): Boolean {
val (counter, pointer) = pointerIterator.next()
task.indicator?.fraction = counter.toDouble() / myTotal
val directive = pointer.element
if (directive?.isValid == true) {
task.indicator?.text2 = directive.containingFile.virtualFile.presentableUrl
runWriteAction {
try {
directive.delete()
} catch (e: IncorrectOperationException) {
LOG.error(e)
val directive = pointer.element
if (directive?.isValid == true) {
val presentableUrl = directive.containingFile.virtualFile.presentableUrl
indicator.text2 = presentableUrl
invokeLater {
project.executeWriteCommand("delete $presentableUrl") {
try {
directive.delete()
} catch (e: IncorrectOperationException) {
LOG.error(e)
}
}
}
}
}
return isDone
}
override fun stop() {}
companion object {
private val LOG = Logger.getInstance("#" + OptimizeImportsTask::class.java.name)
}
@@ -112,38 +100,30 @@ class KotlinOptimizeImportsRefactoringHelper : RefactoringHelper<Set<KtFile>> {
}
override fun prepareOperation(usages: Array<UsageInfo>): Set<KtFile> {
return usages.mapNotNullTo(LinkedHashSet<KtFile>()) {
return usages.mapNotNullTo(LinkedHashSet()) {
if (!it.isNonCodeUsage) it.file as? KtFile else null
}
}
override fun performOperation(project: Project, operationData: Set<KtFile>) {
if (operationData.isEmpty()) return
CodeStyleManager.getInstance(project).performActionWithFormatterDisabled {
PsiDocumentManager.getInstance(project).commitAllDocuments()
}
if (operationData.isEmpty()) return
val unusedImports = mutableSetOf<SmartPsiElementPointer<KtImportDirective>>()
val progressManager = ProgressManager.getInstance()
val dumbService = DumbService.getInstance(project)
val collectTask = object : SequentialModalProgressTask(project, COLLECT_UNUSED_IMPORTS_TITLE, false) {
val collectTask = object : CollectUnusedImportsTask(project, dumbService, unusedImports, operationData) {
override fun onSuccess() {
val progressTask = SequentialModalProgressTask(project, REMOVING_REDUNDANT_IMPORTS_TITLE, false)
with(progressTask) {
setMinIterationTime(200)
setTask(OptimizeImportsTask(this, unusedImports))
}
val progressTask = OptimizeImportsTask(project, unusedImports)
progressManager.run(progressTask)
}
}
with(collectTask) {
setMinIterationTime(200)
setTask(CollectUnusedImportsTask(this, dumbService, unusedImports, operationData))
}
progressManager.run(collectTask)
}
}