Refactoring: remove ProgressManager.progressIndicator usages

This commit is contained in:
Nikolay Krasko
2018-07-13 16:01:21 +03:00
parent 652d074bca
commit 3bb9288e86
20 changed files with 58 additions and 535 deletions
@@ -50,6 +50,7 @@ import org.jetbrains.kotlin.idea.refactoring.j2k
import org.jetbrains.kotlin.idea.refactoring.j2kText
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.versions.getKotlinJvmRuntimeMarkerClass
import org.jetbrains.kotlin.j2k.AfterConversionPass
import org.jetbrains.kotlin.psi.*
@@ -93,7 +94,7 @@ class KotlinCodeFragmentFactory : CodeFragmentFactory() {
semaphore.down()
val nameRef = AtomicReference<KotlinType>()
val worker = object : KotlinRuntimeTypeEvaluator(
null, expression, debuggerContext, ProgressManager.getInstance().progressIndicator!!
null, expression, debuggerContext, ProgressManager.getInstance().progressIndicatorNullable!!
) {
override fun typeCalculationFinished(type: KotlinType?) {
nameRef.set(type)
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.runInReadActionWithWriteActionPriority
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
@@ -112,7 +113,7 @@ class KotlinLanguageInjector(
return computedInjection
}
if (ApplicationManager.getApplication().isReadAccessAllowed && ProgressManager.getInstance().progressIndicator == null) {
if (ApplicationManager.getApplication().isReadAccessAllowed && ProgressManager.getInstance().progressIndicatorNullable == null) {
// The action cannot be canceled by caller and by internal checkCanceled() calls.
// Force creating new indicator that is canceled on write action start, otherwise there might be lags in typing.
runInReadActionWithWriteActionPriority(::computeAndCache) ?: kotlinCachedInjection?.baseInjection ?: ABSENT_KOTLIN_INJECTION
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.runInReadActionWithWriteActionPriority
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
@@ -98,7 +99,7 @@ class KotlinLanguageInjector(
return computedInjection
}
if (ApplicationManager.getApplication().isReadAccessAllowed && ProgressManager.getInstance().progressIndicator == null) {
if (ApplicationManager.getApplication().isReadAccessAllowed && ProgressManager.getInstance().progressIndicatorNullable == null) {
// The action cannot be canceled by caller and by internal checkCanceled() calls.
// Force creating new indicator that is canceled on write action start, otherwise there might be lags in typing.
runInReadActionWithWriteActionPriority(::computeAndCache) ?: kotlinCachedInjection?.baseInjection ?: ABSENT_KOTLIN_INJECTION
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.runInReadActionWithWriteActionPriority
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
@@ -112,7 +113,7 @@ class KotlinLanguageInjector(
return computedInjection
}
if (ApplicationManager.getApplication().isReadAccessAllowed && ProgressManager.getInstance().progressIndicator == null) {
if (ApplicationManager.getApplication().isReadAccessAllowed && ProgressManager.getInstance().progressIndicatorNullable == null) {
// The action cannot be canceled by caller and by internal checkCanceled() calls.
// Force creating new indicator that is canceled on write action start, otherwise there might be lags in typing.
runInReadActionWithWriteActionPriority(::computeAndCache) ?: kotlinCachedInjection?.baseInjection ?: ABSENT_KOTLIN_INJECTION
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
@@ -101,7 +102,10 @@ class JavaToKotlinAction : AnAction() {
var converterResult: JavaToKotlinConverter.FilesResult? = null
fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
converterResult = converter.filesToKotlin(javaFiles, J2kPostProcessor(formatCode = true), ProgressManager.getInstance().progressIndicator!!)
converterResult = converter.filesToKotlin(
javaFiles, J2kPostProcessor(formatCode = true),
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
@@ -120,7 +124,9 @@ class JavaToKotlinAction : AnAction() {
ProgressManager.getInstance().runProcessWithProgressSynchronously(
{
runReadAction {
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(ProgressManager.getInstance().progressIndicator!!)
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
},
title,
@@ -1,223 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.actions
import com.intellij.codeInsight.navigation.NavigationUtil
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.ide.scratch.ScratchFileService
import com.intellij.ide.scratch.ScratchRootType
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.ex.MessagesEx
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileVisitor
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiManager
import com.intellij.psi.search.FileTypeIndex
import com.intellij.psi.search.GlobalSearchScopesCore
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
import org.jetbrains.kotlin.psi.KtFile
import java.io.File
import java.io.IOException
import java.util.*
class JavaToKotlinAction : AnAction() {
companion object {
private fun uniqueKotlinFileName(javaFile: VirtualFile): String {
val ioFile = File(javaFile.path.replace('/', File.separatorChar))
var i = 0
while (true) {
val fileName = javaFile.nameWithoutExtension + (if (i > 0) i else "") + ".kt"
if (!ioFile.resolveSibling(fileName).exists()) return fileName
i++
}
}
val title = "Convert Java to Kotlin"
private fun saveResults(javaFiles: List<PsiJavaFile>, convertedTexts: List<String>): List<VirtualFile> {
val result = ArrayList<VirtualFile>()
for ((psiFile, text) in javaFiles.zip(convertedTexts)) {
try {
val document = PsiDocumentManager.getInstance(psiFile.project).getDocument(psiFile)
if (document == null) {
MessagesEx.error(psiFile.project, "Failed to save conversion result: couldn't find document for " + psiFile.name).showLater()
continue
}
document.replaceString(0, document.textLength, text)
FileDocumentManager.getInstance().saveDocument(document)
val virtualFile = psiFile.virtualFile
if (ScratchRootType.getInstance().containsFile(virtualFile)) {
val mapping = ScratchFileService.getInstance().scratchesMapping
mapping.setMapping(virtualFile, KotlinFileType.INSTANCE.language)
}
else {
val fileName = uniqueKotlinFileName(virtualFile)
virtualFile.rename(this, fileName)
}
}
catch (e: IOException) {
MessagesEx.error(psiFile.project, e.message ?: "").showLater()
}
}
return result
}
fun convertFiles(javaFiles: List<PsiJavaFile>, project: Project, enableExternalCodeProcessing: Boolean = true): List<KtFile> {
var converterResult: JavaToKotlinConverter.FilesResult? = null
fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
converterResult = converter.filesToKotlin(javaFiles, J2kPostProcessor(formatCode = true), ProgressManager.getInstance().progressIndicator)
}
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
::convert,
title,
true,
project)) return emptyList()
var externalCodeUpdate: (() -> Unit)? = null
if (enableExternalCodeProcessing && converterResult!!.externalCodeProcessing != null) {
val question = "Some code in the rest of your project may require corrections after performing this conversion. Do you want to find such code and correct it too?"
if (Messages.showOkCancelDialog(project, question, title, Messages.getQuestionIcon()) == Messages.OK) {
ProgressManager.getInstance().runProcessWithProgressSynchronously(
{
runReadAction {
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(ProgressManager.getInstance().progressIndicator)
}
},
title,
true,
project)
}
}
return project.executeWriteCommand("Convert files from Java to Kotlin", null) {
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project)
val newFiles = saveResults(javaFiles, converterResult!!.results)
externalCodeUpdate?.invoke()
PsiDocumentManager.getInstance(project).commitAllDocuments()
newFiles.singleOrNull()?.let {
FileEditorManager.getInstance(project).openFile(it, true)
}
newFiles.map { it.toPsiFile(project) as KtFile }
}
}
}
override fun actionPerformed(e: AnActionEvent) {
val javaFiles = selectedJavaFiles(e).filter { it.isWritable }.toList()
val project = CommonDataKeys.PROJECT.getData(e.dataContext)!!
val firstSyntaxError = javaFiles.asSequence().map { PsiTreeUtil.findChildOfType(it, PsiErrorElement::class.java) }.firstOrNull()
if (firstSyntaxError != null) {
val count = javaFiles.filter { PsiTreeUtil.hasErrorElements(it) }.count()
val question = firstSyntaxError.containingFile.name +
(if (count > 1) " and ${count - 1} more Java files" else " file") +
" contain syntax errors, the conversion result may be incorrect"
val okText = "Investigate Errors"
val cancelText = "Proceed with Conversion"
if (Messages.showOkCancelDialog(
project,
question,
title,
okText,
cancelText,
Messages.getWarningIcon()
) == Messages.OK) {
NavigationUtil.activateFileWithPsiElement(firstSyntaxError.navigationElement)
return
}
}
convertFiles(javaFiles, project)
}
override fun update(e: AnActionEvent) {
val virtualFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return
val project = e.project ?: return
e.presentation.isEnabled = isAnyJavaFileSelected(project, virtualFiles)
}
private fun isAnyJavaFileSelected(project: Project, files: Array<VirtualFile>): Boolean {
val filesScope = GlobalSearchScopesCore.directoriesScope(project, true, *files)
val potentialJavaFiles = FileTypeIndex.getFiles(JavaFileType.INSTANCE, filesScope)
if (potentialJavaFiles.isEmpty()) return false
val manager = PsiManager.getInstance(project)
return potentialJavaFiles.any { manager.findFile(it) is PsiJavaFile && it.isWritable }
}
private fun selectedJavaFiles(e: AnActionEvent): Sequence<PsiJavaFile> {
val virtualFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return sequenceOf()
val project = e.project ?: return sequenceOf()
return allJavaFiles(virtualFiles, project)
}
private fun allJavaFiles(filesOrDirs: Array<VirtualFile>, project: Project): Sequence<PsiJavaFile> {
val manager = PsiManager.getInstance(project)
return allFiles(filesOrDirs)
.asSequence()
.mapNotNull { manager.findFile(it) as? PsiJavaFile }
}
private fun allFiles(filesOrDirs: Array<VirtualFile>): Collection<VirtualFile> {
val result = ArrayList<VirtualFile>()
for (file in filesOrDirs) {
VfsUtilCore.visitChildrenRecursively(file, object : VirtualFileVisitor<Unit>() {
override fun visitFile(file: VirtualFile): Boolean {
result.add(file)
return true
}
})
}
return result
}
}
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
@@ -106,7 +107,10 @@ class JavaToKotlinAction : AnAction() {
var converterResult: JavaToKotlinConverter.FilesResult? = null
fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
converterResult = converter.filesToKotlin(javaFiles, J2kPostProcessor(formatCode = true), ProgressManager.getInstance().progressIndicator!!)
converterResult = converter.filesToKotlin(
javaFiles, J2kPostProcessor(formatCode = true),
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
@@ -125,7 +129,9 @@ class JavaToKotlinAction : AnAction() {
ProgressManager.getInstance().runProcessWithProgressSynchronously(
{
runReadAction {
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(ProgressManager.getInstance().progressIndicator!!)
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
},
title,
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
@@ -103,7 +104,10 @@ class JavaToKotlinAction : AnAction() {
var converterResult: JavaToKotlinConverter.FilesResult? = null
fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
converterResult = converter.filesToKotlin(javaFiles, J2kPostProcessor(formatCode = true), ProgressManager.getInstance().progressIndicator)
converterResult = converter.filesToKotlin(
javaFiles, J2kPostProcessor(formatCode = true),
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
@@ -122,7 +126,9 @@ class JavaToKotlinAction : AnAction() {
ProgressManager.getInstance().runProcessWithProgressSynchronously(
{
runReadAction {
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(ProgressManager.getInstance().progressIndicator)
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
},
title,
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
@@ -103,7 +104,10 @@ class JavaToKotlinAction : AnAction() {
var converterResult: JavaToKotlinConverter.FilesResult? = null
fun convert() {
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
converterResult = converter.filesToKotlin(javaFiles, J2kPostProcessor(formatCode = true), ProgressManager.getInstance().progressIndicator!!)
converterResult = converter.filesToKotlin(
javaFiles, J2kPostProcessor(formatCode = true),
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
@@ -122,7 +126,9 @@ class JavaToKotlinAction : AnAction() {
ProgressManager.getInstance().runProcessWithProgressSynchronously(
{
runReadAction {
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(ProgressManager.getInstance().progressIndicator!!)
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(
ProgressManager.getInstance().progressIndicatorNullable!!
)
}
},
title,
@@ -30,6 +30,7 @@ import com.intellij.openapi.vfs.VirtualFileVisitor
import com.intellij.psi.PsiManager
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.idea.search.usagesSearch.ExpressionsOfTypeProcessor
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtFile
@@ -57,7 +58,7 @@ class CheckComponentsUsageSearchAction : AnAction() {
.filter { it.isData() }
.toList()
val progressIndicator = ProgressManager.getInstance().progressIndicator
val progressIndicator = ProgressManager.getInstance().progressIndicatorNullable
for ((i, dataClass) in dataClasses.withIndex()) {
progressIndicator?.text = "Checking data class ${i + 1} of ${dataClasses.size}..."
progressIndicator?.text2 = dataClass.fqName?.asString() ?: ""
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
@@ -62,7 +63,7 @@ class FindImplicitNothingAction : AnAction() {
}
private fun find(files: Collection<KtFile>, project: Project) {
val progressIndicator = ProgressManager.getInstance().progressIndicator
val progressIndicator = ProgressManager.getInstance().progressIndicatorNullable
val found = ArrayList<KtCallExpression>()
for ((i, file) in files.withIndex()) {
progressIndicator?.text = "Scanning files: $i of ${files.size} file. ${found.size} occurences found"
@@ -29,6 +29,7 @@ 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.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
@@ -93,7 +94,7 @@ class KotlinOptimizeImportsRefactoringHelper : RefactoringHelper<Set<KtFile>> {
val unusedImports = LinkedHashSet<SmartPsiElementPointer<KtImportDirective>>()
val findRedundantImports = {
DumbService.getInstance(project).runReadActionInSmartMode {
val progressIndicator = ProgressManager.getInstance().progressIndicator
val progressIndicator = ProgressManager.getInstance().progressIndicatorNullable
val fileCount = operationData.size
for ((i, file) in operationData.withIndex()) {
if (!file.isValid) continue
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.idea.imports.KotlinImportOptimizer
import org.jetbrains.kotlin.idea.imports.OptimizedImportsBuilder
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
@@ -143,7 +144,7 @@ class KotlinUnusedImportInspection : AbstractKotlinInspection() {
val optimizedImports = KotlinImportOptimizer.prepareOptimizedImports(file, data) ?: return // return if already optimized
// unwrap progress indicator
val progress = generateSequence(ProgressManager.getInstance().progressIndicator) {
val progress = generateSequence(ProgressManager.getInstance().progressIndicatorNullable) {
(it as? ProgressWrapper)?.originalProgressIndicator
}.last() as DaemonProgressIndicator
val highlightingSession = HighlightingSessionImpl.getHighlightingSession(file, progress)
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -72,7 +73,7 @@ class ChangeSuspendInHierarchyFix(
private fun findAllFunctionToProcess(project: Project): Set<KtNamedFunction> {
val result = LinkedHashSet<KtNamedFunction>()
val progressIndicator = ProgressManager.getInstance().progressIndicator!!
val progressIndicator = ProgressManager.getInstance().progressIndicatorNullable!!
val function = element ?: return emptySet()
val functionDescriptor = function.unsafeResolveToDescriptor() as FunctionDescriptor
@@ -1,193 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.asJava.unwrapped
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor
import org.jetbrains.kotlin.util.findCallableMemberBySignature
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.ifEmpty
import java.util.ArrayList
import kotlin.collections.Collection
import kotlin.collections.HashMap
import kotlin.collections.LinkedHashSet
import kotlin.collections.List
import kotlin.collections.Set
import kotlin.collections.emptyList
import kotlin.collections.emptySet
import kotlin.collections.filter
import kotlin.collections.flatMap
import kotlin.collections.forEach
import kotlin.collections.getOrPut
import kotlin.collections.listOf
import kotlin.collections.mapNotNullTo
import kotlin.collections.plus
class ChangeSuspendInHierarchyFix(
element: KtNamedFunction,
private val addModifier: Boolean
) : KotlinQuickFixAction<KtNamedFunction>(element) {
override fun getFamilyName(): String {
return if (addModifier) {
"Add 'suspend' modifier to all functions in hierarchy"
} else {
"Remove 'suspend' modifier from all functions in hierarchy"
}
}
override fun getText() = familyName
override fun startInWriteAction() = false
private fun findAllFunctionToProcess(project: Project): Set<KtNamedFunction> {
val result = LinkedHashSet<KtNamedFunction>()
val progressIndicator = ProgressManager.getInstance().progressIndicator
val function = element ?: return emptySet()
val functionDescriptor = function.unsafeResolveToDescriptor() as FunctionDescriptor
val baseFunctionDescriptors = functionDescriptor.findTopMostOverriddables()
baseFunctionDescriptors.forEach { baseFunctionDescriptor ->
val baseClassDescriptor = baseFunctionDescriptor.containingDeclaration as? ClassDescriptor ?: return@forEach
val baseClass = DescriptorToSourceUtilsIde.getAnyDeclaration(project, baseClassDescriptor) ?: return@forEach
val name = (baseClass as? PsiNamedElement)?.name ?: return@forEach
progressIndicator.text = "Looking for class $name inheritors..."
val classes = listOf(baseClass) + HierarchySearchRequest(baseClass, baseClass.useScope).searchInheritors()
classes.mapNotNullTo(result) {
val subClass = it.unwrapped as? KtClassOrObject ?: return@mapNotNullTo null
val classDescriptor = subClass.unsafeResolveToDescriptor() as ClassDescriptor
val substitutor = getTypeSubstitutor(baseClassDescriptor.defaultType, classDescriptor.defaultType)
?: return@mapNotNullTo null
val signatureInSubClass = baseFunctionDescriptor.substitute(substitutor) as FunctionDescriptor
val subFunctionDescriptor = classDescriptor.findCallableMemberBySignature(signatureInSubClass, true)
?: return@mapNotNullTo null
subFunctionDescriptor.source.getPsi() as? KtNamedFunction
}
}
return result
}
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val functions = project.runSynchronouslyWithProgress("Analyzing class hierarchy...", true) {
runReadAction { findAllFunctionToProcess(project) }
} ?: return
runWriteAction {
functions.forEach {
if (addModifier) {
it.addModifier(KtTokens.SUSPEND_KEYWORD)
}
else {
it.removeModifier(KtTokens.SUSPEND_KEYWORD)
}
}
}
}
companion object : KotlinIntentionActionsFactory() {
fun FunctionDescriptor.findTopMostOverriddables(): List<FunctionDescriptor> {
val overridablesCache = HashMap<FunctionDescriptor, List<FunctionDescriptor>>()
fun FunctionDescriptor.getOverridables(): List<FunctionDescriptor> {
return overridablesCache.getOrPut(this) {
val classDescriptor = containingDeclaration as? ClassDescriptorWithResolutionScopes ?: return emptyList()
DescriptorUtils.getSuperclassDescriptors(classDescriptor).flatMap { superClassDescriptor ->
if (superClassDescriptor !is ClassDescriptorWithResolutionScopes) return@flatMap emptyList<FunctionDescriptor>()
val candidates = superClassDescriptor.unsubstitutedMemberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
val substitutor = getTypeSubstitutor(superClassDescriptor.defaultType, classDescriptor.defaultType)
?: return@flatMap emptyList<FunctionDescriptor>()
candidates.filter {
val signature = it.substitute(substitutor) as FunctionDescriptor
classDescriptor.findCallableMemberBySignature(signature, true) == this
}
}
}
}
return DFS.dfs(
listOf(this),
{ it?.getOverridables() ?: emptyList() },
object : DFS.CollectingNodeHandler<FunctionDescriptor, FunctionDescriptor, ArrayList<FunctionDescriptor>>(ArrayList()) {
override fun afterChildren(current: FunctionDescriptor) {
if (current.getOverridables().isEmpty()) {
result.add(current)
}
}
})
}
private fun Collection<DeclarationDescriptor>.getOverridables(
currentDescriptor: FunctionDescriptor
): List<DeclarationDescriptor> {
val currentClassDescriptor = currentDescriptor.containingDeclaration as? ClassDescriptor ?: return emptyList()
return filter {
if (it !is FunctionDescriptor || it == currentDescriptor) return@filter false
if (it.isSuspend == currentDescriptor.isSuspend) return@filter false
val containingClassDescriptor = it.containingDeclaration as? ClassDescriptor ?: return@filter false
if (!currentClassDescriptor.isSubclassOf(containingClassDescriptor)) return@filter false
val substitutor = getTypeSubstitutor(
containingClassDescriptor.defaultType,
currentClassDescriptor.defaultType
) ?: return@filter false
val signatureInCurrentClass = it.substitute(substitutor) ?: return@filter false
OverridingUtil.DEFAULT.isOverridableBy(signatureInCurrentClass, currentDescriptor, null).result ==
OverridingUtil.OverrideCompatibilityInfo.Result.CONFLICT
}
}
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
val currentFunction = diagnostic.psiElement as? KtNamedFunction ?: return emptyList()
val currentDescriptor = currentFunction.unsafeResolveToDescriptor() as FunctionDescriptor
Errors.CONFLICTING_OVERLOADS.cast(diagnostic).a.getOverridables(currentDescriptor).ifEmpty { return emptyList() }
return listOf(
ChangeSuspendInHierarchyFix(currentFunction, true),
ChangeSuspendInHierarchyFix(currentFunction, false)
)
}
}
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinDirecto
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.analyzeConflictsInFile
import org.jetbrains.kotlin.idea.search.projectScope
import org.jetbrains.kotlin.idea.stubindex.KotlinExactPackagesIndex
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
@@ -73,7 +74,7 @@ class KotlinAwareDelegatingMoveDestination(
}
filesToProcess.flatMap {it.declarations}.forEach { it.accept(extraElementCollector) }
val progressIndicator = ProgressManager.getInstance().progressIndicator!!
val progressIndicator = ProgressManager.getInstance().progressIndicatorNullable!!
progressIndicator.pushState()
val extraUsages = ArrayList<UsageInfo>()
@@ -1,97 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.refactoring.move.moveClassesOrPackages
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiPackage
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.refactoring.MoveDestination
import com.intellij.usageView.UsageInfo
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.idea.refactoring.move.createMoveUsageInfoIfPossible
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinDirectoryMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.analyzeConflictsInFile
import org.jetbrains.kotlin.idea.search.projectScope
import org.jetbrains.kotlin.idea.stubindex.KotlinExactPackagesIndex
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
class KotlinAwareDelegatingMoveDestination(
private val delegate: MoveDestination,
private val targetPackage: PsiPackage?,
private val targetDirectory: PsiDirectory?
) : MoveDestination by delegate {
override fun analyzeModuleConflicts(
elements: MutableCollection<PsiElement>,
conflicts: MultiMap<PsiElement, String>,
usages: Array<out UsageInfo>
) {
delegate.analyzeModuleConflicts(elements, conflicts, usages)
if (targetPackage == null || targetDirectory == null) return
val project = targetDirectory.project
val moveTarget = KotlinDirectoryMoveTarget(FqName(targetPackage.qualifiedName), targetDirectory)
val packagesIndex = KotlinExactPackagesIndex.getInstance()
val directoriesToMove = elements.flatMapTo(LinkedHashSet<PsiDirectory>()) {
(it as? PsiPackage)?.directories?.toList() ?: emptyList()
}
val projectScope = project.projectScope()
val filesToProcess = elements.flatMapTo(LinkedHashSet<KtFile>()) {
if (it is PsiPackage) packagesIndex[it.qualifiedName, project, projectScope] else emptyList()
}
val extraElementsForReferenceSearch = LinkedHashSet<PsiElement>()
val extraElementCollector = object : PsiRecursiveElementWalkingVisitor() {
override fun visitElement(element: PsiElement) {
if (element is KtNamedDeclaration && element.hasModifier(KtTokens.INTERNAL_KEYWORD)) {
element.parentsWithSelf.lastOrNull { it is KtNamedDeclaration }?.let { extraElementsForReferenceSearch += it }
stopWalking()
}
super.visitElement(element)
}
}
filesToProcess.flatMap {it.declarations}.forEach { it.accept(extraElementCollector) }
val progressIndicator = ProgressManager.getInstance().progressIndicator
progressIndicator?.pushState()
val extraUsages = ArrayList<UsageInfo>()
try {
progressIndicator.text = "Looking for Usages"
for ((index, element) in extraElementsForReferenceSearch.withIndex()) {
progressIndicator.fraction = (index + 1)/extraElementsForReferenceSearch.size.toDouble()
ReferencesSearch.search(element, projectScope).mapNotNullTo(extraUsages) { ref ->
createMoveUsageInfoIfPossible(ref, element, true, false)
}
}
}
finally {
progressIndicator?.popState()
}
filesToProcess.forEach {
analyzeConflictsInFile(it, extraUsages, moveTarget, directoriesToMove, conflicts) {}
}
}
}
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.idea.refactoring.invokeOnceOnCommandFinish
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.KotlinDirectoryMoveTarget
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.MoveKotlinDeclarationsProcessor
import org.jetbrains.kotlin.idea.refactoring.move.moveDeclarations.analyzeConflictsInFile
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
@@ -86,7 +86,7 @@ class KotlinMoveDirectoryWithClassesHelper : MoveDirectoryWithClassesHelper() {
for ((index, usageInfo) in infos.withIndex()) {
if (usageInfo !is FileUsagesWrapper) continue
ProgressManager.getInstance().progressIndicator?.text2 = "Processing ${usageInfo.psiFile.name}"
ProgressManager.getInstance().progressIndicatorNullable?.text2 = "Processing ${usageInfo.psiFile.name}"
runReadAction {
analyzeConflictsInFile(usageInfo.psiFile, usageInfo.usages, moveTarget, files, conflicts) {
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.idea.refactoring.fqName.isImported
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference.ShorteningMode
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.application.progressIndicatorNullable
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
@@ -473,7 +474,7 @@ fun postProcessMoveUsages(
val nonCodeUsages = ArrayList<NonCodeUsageInfo>()
val progressStep = 1.0/sortedUsages.size
val progressIndicator = ProgressManager.getInstance().progressIndicator
val progressIndicator = ProgressManager.getInstance().progressIndicatorNullable
progressIndicator?.text = "Updating usages..."
usageLoop@ for ((i, usage) in sortedUsages.withIndex()) {
progressIndicator?.fraction = (i + 1) * progressStep
@@ -314,7 +314,8 @@ class JavaToKotlinConverter(
}
constructor() {
val indicator = ProgressManager.getInstance().progressIndicator
@Suppress("IncompatibleAPI")
val indicator: ProgressIndicator? = ProgressManager.getInstance().progressIndicator
delegate = indicator ?: EmptyProgressIndicator()
}