Refactoring
This commit is contained in:
+2
-3
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,11 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix.replaceWith
|
package org.jetbrains.kotlin.idea.replacement
|
||||||
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
||||||
import org.jetbrains.kotlin.idea.replacement.*
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
+2
-3
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -14,12 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix.replaceWith
|
package org.jetbrains.kotlin.idea.replacement
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
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.replacement.ReplacementExpression
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 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.replacement
|
||||||
|
|
||||||
|
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.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import com.intellij.psi.search.searches.ReferencesSearch
|
||||||
|
import com.intellij.util.ui.UIUtil
|
||||||
|
import org.jetbrains.kotlin.idea.core.targetDescriptors
|
||||||
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||||
|
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||||
|
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
|
||||||
|
interface UsageReplacementStrategy {
|
||||||
|
fun createReplacer(usage: KtSimpleNameExpression): (() -> KtElement)?
|
||||||
|
}
|
||||||
|
|
||||||
|
private val LOG = Logger.getInstance(UsageReplacementStrategy::class.java)
|
||||||
|
|
||||||
|
fun UsageReplacementStrategy.replaceUsagesInWholeProject(
|
||||||
|
targetPsiElement: PsiElement,
|
||||||
|
progressTitle: String,
|
||||||
|
commandName: String
|
||||||
|
) {
|
||||||
|
val project = targetPsiElement.project
|
||||||
|
ProgressManager.getInstance().run(
|
||||||
|
object : Task.Modal(project, progressTitle, true) {
|
||||||
|
override fun run(indicator: ProgressIndicator) {
|
||||||
|
val usages = runReadAction {
|
||||||
|
val searchScope = KotlinSourceFilterScope.projectSources(GlobalSearchScope.projectScope(project), project)
|
||||||
|
ReferencesSearch.search(targetPsiElement, searchScope)
|
||||||
|
.filterIsInstance<KtSimpleNameReference>()
|
||||||
|
.map { ref -> ref.expression }
|
||||||
|
}
|
||||||
|
this@replaceUsagesInWholeProject.replaceUsages(usages, project, commandName)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun UsageReplacementStrategy.replaceUsages(
|
||||||
|
usages: Collection<KtSimpleNameExpression>,
|
||||||
|
project: Project,
|
||||||
|
commandName: String
|
||||||
|
) {
|
||||||
|
UIUtil.invokeLaterIfNeeded {
|
||||||
|
project.executeWriteCommand(commandName) {
|
||||||
|
// we should delete imports later to not affect other usages
|
||||||
|
val importsToDelete = arrayListOf<KtImportDirective>()
|
||||||
|
|
||||||
|
for (usage in usages) {
|
||||||
|
try {
|
||||||
|
if (!usage.isValid) continue // TODO: nested calls
|
||||||
|
|
||||||
|
//TODO: keep the import if we don't know how to replace some of the usages
|
||||||
|
val importDirective = usage.getStrictParentOfType<KtImportDirective>()
|
||||||
|
if (importDirective != null) {
|
||||||
|
if (!importDirective.isAllUnder && importDirective.targetDescriptors().size == 1) {
|
||||||
|
importsToDelete.add(importDirective)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
createReplacer(usage)?.invoke()
|
||||||
|
}
|
||||||
|
catch (e: Throwable) {
|
||||||
|
LOG.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
importsToDelete.forEach { it.delete() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.idea.core.targetDescriptors
|
|||||||
import org.jetbrains.kotlin.idea.quickfix.CleanupFix
|
import org.jetbrains.kotlin.idea.quickfix.CleanupFix
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
||||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||||
|
import org.jetbrains.kotlin.idea.replacement.UsageReplacementStrategy
|
||||||
import org.jetbrains.kotlin.psi.KtImportDirective
|
import org.jetbrains.kotlin.psi.KtImportDirective
|
||||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||||
|
|||||||
+50
-2
@@ -20,21 +20,31 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.core.OptionalParametersHelper
|
import org.jetbrains.kotlin.idea.core.OptionalParametersHelper
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
||||||
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.idea.replacement.CallableUsageReplacementStrategy
|
||||||
|
import org.jetbrains.kotlin.idea.replacement.ClassUsageReplacementStrategy
|
||||||
|
import org.jetbrains.kotlin.idea.replacement.UsageReplacementStrategy
|
||||||
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
|
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
|
||||||
//TODO: different replacements for property accessors
|
//TODO: different replacements for property accessors
|
||||||
|
|
||||||
@@ -46,13 +56,13 @@ abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||||
val element = element ?: return false
|
val element = element ?: return false
|
||||||
if (!super.isAvailable(project, editor, file)) return false
|
if (!super.isAvailable(project, editor, file)) return false
|
||||||
val strategy = UsageReplacementStrategy.build(element, replaceWith, recheckAnnotation = true)
|
val strategy = buildUsageReplacementStrategy(element, replaceWith, recheckAnnotation = true)
|
||||||
return strategy != null && strategy.createReplacer(element) != null
|
return strategy != null && strategy.createReplacer(element) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
final override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
final override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
val element = element ?: return
|
val element = element ?: return
|
||||||
val strategy = UsageReplacementStrategy.build(element, replaceWith, recheckAnnotation = false)!!
|
val strategy = buildUsageReplacementStrategy(element, replaceWith, recheckAnnotation = false)!!
|
||||||
invoke(strategy, project, editor)
|
invoke(strategy, project, editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,5 +116,43 @@ abstract class DeprecatedSymbolUsageFixBase(
|
|||||||
val replacement = DeprecatedSymbolUsageFixBase.fetchReplaceWithPattern(descriptor, nameExpression.project) ?: return null
|
val replacement = DeprecatedSymbolUsageFixBase.fetchReplaceWithPattern(descriptor, nameExpression.project) ?: return null
|
||||||
return Data(nameExpression, replacement, descriptor)
|
return Data(nameExpression, replacement, descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buildUsageReplacementStrategy(element: KtSimpleNameExpression, replaceWith: ReplaceWith, recheckAnnotation: Boolean): UsageReplacementStrategy? {
|
||||||
|
val resolutionFacade = element.getResolutionFacade()
|
||||||
|
val bindingContext = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL)
|
||||||
|
var target = element.mainReference.resolveToDescriptors(bindingContext).singleOrNull() ?: return null
|
||||||
|
|
||||||
|
var replacePatternFromSymbol = DeprecatedSymbolUsageFixBase.fetchReplaceWithPattern(target, resolutionFacade.project)
|
||||||
|
if (replacePatternFromSymbol == null && target is ConstructorDescriptor) {
|
||||||
|
target = target.containingDeclaration
|
||||||
|
replacePatternFromSymbol = DeprecatedSymbolUsageFixBase.fetchReplaceWithPattern(target, resolutionFacade.project)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that ReplaceWith hasn't changed
|
||||||
|
if (recheckAnnotation && replacePatternFromSymbol != replaceWith) return null
|
||||||
|
|
||||||
|
when (target) {
|
||||||
|
is CallableDescriptor -> {
|
||||||
|
val resolvedCall = element.getResolvedCall(bindingContext) ?: return null
|
||||||
|
if (!resolvedCall.isReallySuccess()) return null
|
||||||
|
val replacement = ReplaceWithAnnotationAnalyzer.analyzeCallableReplacement(replaceWith, target, resolutionFacade) ?: return null
|
||||||
|
return CallableUsageReplacementStrategy(replacement)
|
||||||
|
}
|
||||||
|
|
||||||
|
is ClassDescriptor -> {
|
||||||
|
val replacementType = ReplaceWithAnnotationAnalyzer.analyzeClassReplacement(replaceWith, target, resolutionFacade)
|
||||||
|
if (replacementType != null) { //TODO: check that it's really resolved and is not an object otherwise it can be expression as well
|
||||||
|
return ClassUsageReplacementStrategy(replacementType, null, element.project)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val constructor = target.unsubstitutedPrimaryConstructor ?: return null
|
||||||
|
val replacementExpression = ReplaceWithAnnotationAnalyzer.analyzeCallableReplacement(replaceWith, constructor, resolutionFacade) ?: return null
|
||||||
|
return ClassUsageReplacementStrategy(null, replacementExpression, element.project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-61
@@ -17,28 +17,17 @@
|
|||||||
package org.jetbrains.kotlin.idea.quickfix.replaceWith
|
package org.jetbrains.kotlin.idea.quickfix.replaceWith
|
||||||
|
|
||||||
import com.intellij.codeInsight.intention.IntentionAction
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.progress.ProgressIndicator
|
|
||||||
import com.intellij.openapi.progress.ProgressManager
|
|
||||||
import com.intellij.openapi.progress.Task
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
|
||||||
import com.intellij.util.ui.UIUtil
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.idea.core.targetDescriptors
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
||||||
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
import org.jetbrains.kotlin.idea.replacement.UsageReplacementStrategy
|
||||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
import org.jetbrains.kotlin.idea.replacement.replaceUsagesInWholeProject
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
|
||||||
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.ParameterNameRenderingPolicy
|
import org.jetbrains.kotlin.renderer.ParameterNameRenderingPolicy
|
||||||
|
|
||||||
class DeprecatedSymbolUsageInWholeProjectFix(
|
class DeprecatedSymbolUsageInWholeProjectFix(
|
||||||
@@ -47,8 +36,6 @@ class DeprecatedSymbolUsageInWholeProjectFix(
|
|||||||
private val text: String
|
private val text: String
|
||||||
) : DeprecatedSymbolUsageFixBase(element, replaceWith) {
|
) : DeprecatedSymbolUsageFixBase(element, replaceWith) {
|
||||||
|
|
||||||
private val LOG = Logger.getInstance(DeprecatedSymbolUsageInWholeProjectFix::class.java)
|
|
||||||
|
|
||||||
override fun getFamilyName() = "Replace deprecated symbol usage in whole project"
|
override fun getFamilyName() = "Replace deprecated symbol usage in whole project"
|
||||||
|
|
||||||
override fun getText() = text
|
override fun getText() = text
|
||||||
@@ -62,19 +49,7 @@ class DeprecatedSymbolUsageInWholeProjectFix(
|
|||||||
|
|
||||||
override fun invoke(replacementStrategy: UsageReplacementStrategy, project: Project, editor: Editor?) {
|
override fun invoke(replacementStrategy: UsageReplacementStrategy, project: Project, editor: Editor?) {
|
||||||
val psiElement = targetPsiElement()!!
|
val psiElement = targetPsiElement()!!
|
||||||
|
replacementStrategy.replaceUsagesInWholeProject(psiElement, progressTitle = "Applying '$text'", commandName = text)
|
||||||
ProgressManager.getInstance().run(
|
|
||||||
object : Task.Modal(project, "Applying '$text'", true) {
|
|
||||||
override fun run(indicator: ProgressIndicator) {
|
|
||||||
val usages = runReadAction {
|
|
||||||
val searchScope = KotlinSourceFilterScope.projectSources(GlobalSearchScope.projectScope(project), project)
|
|
||||||
ReferencesSearch.search(psiElement, searchScope)
|
|
||||||
.filterIsInstance<KtSimpleNameReference>()
|
|
||||||
.map { ref -> ref.expression }
|
|
||||||
}
|
|
||||||
replaceUsages(project, usages, replacementStrategy)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun targetPsiElement(): KtDeclaration? {
|
private fun targetPsiElement(): KtDeclaration? {
|
||||||
@@ -87,37 +62,6 @@ class DeprecatedSymbolUsageInWholeProjectFix(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun replaceUsages(project: Project, usages: Collection<KtSimpleNameExpression>, replacementStrategy: UsageReplacementStrategy) {
|
|
||||||
UIUtil.invokeLaterIfNeeded {
|
|
||||||
project.executeWriteCommand(text) {
|
|
||||||
// we should delete imports later to not affect other usages
|
|
||||||
val importsToDelete = arrayListOf<KtImportDirective>()
|
|
||||||
|
|
||||||
for (usage in usages) {
|
|
||||||
try {
|
|
||||||
if (!usage.isValid) continue // TODO: nested calls
|
|
||||||
|
|
||||||
//TODO: keep the import if we don't know how to replace some of the usages
|
|
||||||
val importDirective = usage.getStrictParentOfType<KtImportDirective>()
|
|
||||||
if (importDirective != null) {
|
|
||||||
if (!importDirective.isAllUnder && importDirective.targetDescriptors().size == 1) {
|
|
||||||
importsToDelete.add(importDirective)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
replacementStrategy.createReplacer(usage)?.invoke()
|
|
||||||
}
|
|
||||||
catch (e: Throwable) {
|
|
||||||
LOG.error(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
importsToDelete.forEach { it.delete() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object : KotlinSingleIntentionActionFactory() {
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
//TODO: better rendering needed
|
//TODO: better rendering needed
|
||||||
private val RENDERER = DescriptorRenderer.withOptions {
|
private val RENDERER = DescriptorRenderer.withOptions {
|
||||||
@@ -136,6 +80,5 @@ class DeprecatedSymbolUsageInWholeProjectFix(
|
|||||||
val descriptorName = RENDERER.render(descriptor)
|
val descriptorName = RENDERER.render(descriptor)
|
||||||
return DeprecatedSymbolUsageInWholeProjectFix(nameExpression, replacement, "Replace usages of '$descriptorName' in whole project")
|
return DeprecatedSymbolUsageInWholeProjectFix(nameExpression, replacement, "Replace usages of '$descriptorName' in whole project")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,72 +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.quickfix.replaceWith
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
|
||||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
|
||||||
|
|
||||||
interface UsageReplacementStrategy {
|
|
||||||
fun createReplacer(usage: KtSimpleNameExpression): (() -> KtElement)?
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun build(element: KtSimpleNameExpression, replaceWith: ReplaceWith, recheckAnnotation: Boolean): UsageReplacementStrategy? {
|
|
||||||
val resolutionFacade = element.getResolutionFacade()
|
|
||||||
val bindingContext = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL)
|
|
||||||
var target = element.mainReference.resolveToDescriptors(bindingContext).singleOrNull() ?: return null
|
|
||||||
|
|
||||||
var replacePatternFromSymbol = DeprecatedSymbolUsageFixBase.fetchReplaceWithPattern(target, resolutionFacade.project)
|
|
||||||
if (replacePatternFromSymbol == null && target is ConstructorDescriptor) {
|
|
||||||
target = target.containingDeclaration
|
|
||||||
replacePatternFromSymbol = DeprecatedSymbolUsageFixBase.fetchReplaceWithPattern(target, resolutionFacade.project)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that ReplaceWith hasn't changed
|
|
||||||
if (recheckAnnotation && replacePatternFromSymbol != replaceWith) return null
|
|
||||||
|
|
||||||
when (target) {
|
|
||||||
is CallableDescriptor -> {
|
|
||||||
val resolvedCall = element.getResolvedCall(bindingContext) ?: return null
|
|
||||||
if (!resolvedCall.isReallySuccess()) return null
|
|
||||||
val replacement = ReplaceWithAnnotationAnalyzer.analyzeCallableReplacement(replaceWith, target, resolutionFacade) ?: return null
|
|
||||||
return CallableUsageReplacementStrategy(replacement)
|
|
||||||
}
|
|
||||||
|
|
||||||
is ClassDescriptor -> {
|
|
||||||
val replacementType = ReplaceWithAnnotationAnalyzer.analyzeClassReplacement(replaceWith, target, resolutionFacade)
|
|
||||||
if (replacementType != null) { //TODO: check that it's really resolved and is not an object otherwise it can be expression as well
|
|
||||||
return ClassUsageReplacementStrategy(replacementType, null, element.project)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val constructor = target.unsubstitutedPrimaryConstructor ?: return null
|
|
||||||
val replacementExpression = ReplaceWithAnnotationAnalyzer.analyzeCallableReplacement(replaceWith, constructor, resolutionFacade) ?: return null
|
|
||||||
return ClassUsageReplacementStrategy(null, replacementExpression, element.project)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user