Refactor KotlinShortenReferencesRefactringHelper

Rename refactoring helper and its infrastructure
Add support for different request types
This commit is contained in:
Alexey Sedunov
2017-03-22 17:45:15 +03:00
parent dc04b200b6
commit b3274acfc0
9 changed files with 44 additions and 40 deletions
@@ -31,50 +31,54 @@ import org.jetbrains.kotlin.psi.CopyableUserDataProperty
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import java.util.*
class ShorteningRequest(val pointer: SmartPsiElementPointer<KtElement>, val options: Options)
interface DelayedRefactoringRequest
private var Project.elementsToShorten: MutableSet<ShorteningRequest>?
by UserDataProperty(Key.create("ELEMENTS_TO_SHORTEN_KEY"))
class ShorteningRequest(val pointer: SmartPsiElementPointer<KtElement>, val options: Options) : DelayedRefactoringRequest
private var Project.delayedRefactoringRequests: MutableSet<DelayedRefactoringRequest>?
by UserDataProperty(Key.create("DELAYED_REFACTORING_REQUESTS"))
/*
* When one refactoring invokes another this value must be set to false so that shortening wait-set is not cleared
* and previously collected references are processed correctly. Afterwards it must be reset to original value
*/
var Project.ensureElementsToShortenIsEmptyBeforeRefactoring: Boolean
by NotNullableUserDataProperty(Key.create("ENSURE_ELEMENTS_TO_SHORTEN_IS_EMPTY"), true)
var Project.ensureNoRefactoringRequestsBeforeRefactoring: Boolean
by NotNullableUserDataProperty(Key.create("ENSURE_NO_REFACTORING_REQUESTS_BEFORE_REFACTORING"), true)
fun Project.runWithElementsToShortenIsEmptyIgnored(action: () -> Unit) {
val ensureElementsToShortenIsEmpty = ensureElementsToShortenIsEmptyBeforeRefactoring
fun Project.runRefactoringAndKeepDelayedRequests(action: () -> Unit) {
val ensureNoRefactoringRequests = ensureNoRefactoringRequestsBeforeRefactoring
try {
ensureElementsToShortenIsEmptyBeforeRefactoring = false
ensureNoRefactoringRequestsBeforeRefactoring = false
action()
} finally {
ensureElementsToShortenIsEmptyBeforeRefactoring = ensureElementsToShortenIsEmpty
ensureNoRefactoringRequestsBeforeRefactoring = ensureNoRefactoringRequests
}
}
private fun Project.getOrCreateElementsToShorten(): MutableSet<ShorteningRequest> {
var elements = elementsToShorten
if (elements == null) {
elements = LinkedHashSet()
elementsToShorten = elements
private fun Project.getOrCreateRefactoringRequests(): MutableSet<DelayedRefactoringRequest> {
var requests = delayedRefactoringRequests
if (requests == null) {
requests = LinkedHashSet()
delayedRefactoringRequests = requests
}
return elements
return requests
}
fun KtElement.addToShorteningWaitSet(options: Options = Options.DEFAULT) {
assert(ApplicationManager.getApplication()!!.isWriteAccessAllowed) { "Write access needed" }
val project = project
val elementPointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(this)
project.getOrCreateElementsToShorten().add(ShorteningRequest(elementPointer, options))
project.getOrCreateRefactoringRequests().add(ShorteningRequest(elementPointer, options))
}
fun performDelayedShortening(project: Project) {
project.elementsToShorten?.let { requests ->
project.elementsToShorten = null
val elementToOptions = requests.mapNotNull { req -> req.pointer.element?.let { it to req.options } }.toMap()
fun performDelayedRefactoringRequests(project: Project) {
project.delayedRefactoringRequests?.let { requests ->
project.delayedRefactoringRequests = null
val shorteningRequests = requests.filterIsInstance<ShorteningRequest>()
val elementToOptions = shorteningRequests.mapNotNull { req -> req.pointer.element?.let { it to req.options } }.toMap()
val elements = elementToOptions.keys
//TODO: this is not correct because it should not shorten deep into the elements!
ShortenReferences({ elementToOptions[it] ?: Options.DEFAULT }).process(elements)
@@ -83,11 +87,11 @@ fun performDelayedShortening(project: Project) {
private val LOG = Logger.getInstance(Project::class.java.canonicalName)
fun prepareElementsToShorten(project: Project) {
val elementsToShorten = project.elementsToShorten
if (project.ensureElementsToShortenIsEmptyBeforeRefactoring && elementsToShorten != null && !elementsToShorten.isEmpty()) {
fun prepareDelayedRequests(project: Project) {
val requests = project.delayedRefactoringRequests
if (project.ensureNoRefactoringRequestsBeforeRefactoring && requests != null && !requests.isEmpty()) {
LOG.warn("Waiting set for reference shortening is not empty")
project.elementsToShorten = null
project.delayedRefactoringRequests = null
}
}
+1 -1
View File
@@ -357,7 +357,7 @@
implementationClass="org.jetbrains.kotlin.idea.codeInsight.surroundWith.statement.KotlinStatementSurroundDescriptor"/>
<lang.unwrapDescriptor language="kotlin" implementationClass="org.jetbrains.kotlin.idea.codeInsight.unwrap.KotlinUnwrapDescriptor"/>
<quoteHandler fileType="Kotlin" className="org.jetbrains.kotlin.idea.editor.KotlinQuoteHandler"/>
<refactoring.helper implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinShortenReferencesRefactoringHelper"/>
<refactoring.helper implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinRefactoringHelperForDelayedRequests"/>
<refactoring.helper implementation="org.jetbrains.kotlin.idea.codeInsight.KotlinOptimizeImportsRefactoringHelper"/>
<refactoring.moveHandler
id="kotlin.moveFilesOrDirectories"
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedShortening
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.conversion.copy.end
import org.jetbrains.kotlin.idea.conversion.copy.range
import org.jetbrains.kotlin.idea.conversion.copy.start
@@ -334,7 +334,7 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor<KotlinReference
val reference = pointer.element!!.mainReference
reference.bindToFqName(fqName, KtSimpleNameReference.ShorteningMode.DELAYED_SHORTENING)
}
performDelayedShortening(file.project)
performDelayedRefactoringRequests(file.project)
}
private fun KotlinReferenceData.Kind.isExtension()
@@ -24,16 +24,16 @@ import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.codeInsight.shorten.*
import org.jetbrains.kotlin.idea.util.application.runWriteAction
class KotlinShortenReferencesRefactoringHelper: RefactoringHelper<Any> {
class KotlinRefactoringHelperForDelayedRequests : RefactoringHelper<Any> {
override fun prepareOperation(usages: Array<out UsageInfo>?): Any? {
if (usages != null && usages.isNotEmpty()) {
val project = usages[0].project
prepareElementsToShorten(project)
prepareDelayedRequests(project)
}
return null
}
override fun performOperation(project: Project, operationData: Any?) {
runWriteAction { performDelayedShortening(project) }
runWriteAction { performDelayedRefactoringRequests(project) }
}
}
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.codeInsight.shorten.runWithElementsToShortenIsEmptyIgnored
import org.jetbrains.kotlin.idea.codeInsight.shorten.runRefactoringAndKeepDelayedRequests
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.appendElement
@@ -201,7 +201,7 @@ object InitializePropertyQuickFixFactory : KotlinIntentionActionsFactory() {
}
}
project.runWithElementsToShortenIsEmptyIgnored {
project.runRefactoringAndKeepDelayedRequests {
processConstructors(project, propertyDescriptor, constructorDescriptors.iterator())
}
}
@@ -37,7 +37,7 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedShortening
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded
@@ -212,7 +212,7 @@ class KotlinInlineValHandler : InlineActionHandler() {
highlightElements(project, editor, inlinedExpressions)
}
}
performDelayedShortening(project)
performDelayedRefactoringRequests(project)
}
}
@@ -37,7 +37,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedShortening
import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.refactoring.introduce.insertDeclaration
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
@@ -320,7 +320,7 @@ class ExtractSuperRefactoring(
extractInfo.docPolicy
).moveMembersToBase()
performDelayedShortening(project)
performDelayedRefactoringRequests(project)
}
}
}
@@ -20,7 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDirectory
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.codeInsight.shorten.runWithElementsToShortenIsEmptyIgnored
import org.jetbrains.kotlin.idea.codeInsight.shorten.runRefactoringAndKeepDelayedRequests
import org.jetbrains.kotlin.idea.refactoring.move.ContainerChangeInfo
import org.jetbrains.kotlin.idea.refactoring.move.ContainerInfo
import org.jetbrains.kotlin.idea.refactoring.move.getInternalReferencesToUpdateOnPackageNameChange
@@ -69,7 +69,7 @@ class KotlinChangePackageRefactoring(val file: KtFile) {
project.executeWriteCommand("Change file's package to '${newFqName.asString()}'") {
packageDirective.fqName = newFqName.quoteIfNeeded()
postProcessMoveUsages(internalUsages)
project.runWithElementsToShortenIsEmptyIgnored { declarationProcessor.execute(declarationUsages) }
project.runRefactoringAndKeepDelayedRequests { declarationProcessor.execute(declarationUsages) }
}
}
}
@@ -24,7 +24,7 @@ import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler
import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFilesOrDirectoriesUtil
import com.intellij.usageView.UsageInfo
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.codeInsight.shorten.runWithElementsToShortenIsEmptyIgnored
import org.jetbrains.kotlin.idea.codeInsight.shorten.runRefactoringAndKeepDelayedRequests
import org.jetbrains.kotlin.idea.core.getPackage
import org.jetbrains.kotlin.idea.core.packageMatchesDirectory
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
@@ -145,7 +145,7 @@ class MoveKotlinFileHandler : MoveFileHandler() {
fun retargetUsages(usageInfos: List<UsageInfo>?, moveDeclarationsProcessor: MoveKotlinDeclarationsProcessor) {
postProcessMoveUsages(usageInfos?.firstIsInstanceOrNull<InternalUsagesWrapper>()?.usages ?: emptyList())
moveDeclarationsProcessor.project.runWithElementsToShortenIsEmptyIgnored {
moveDeclarationsProcessor.project.runRefactoringAndKeepDelayedRequests {
usageInfos?.let { moveDeclarationsProcessor.execute(it) }
}
}