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