From 30cbec3fc87ea83335ab61481da66404c2f1c864 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Sat, 10 Oct 2015 01:40:44 +0300 Subject: [PATCH] Refactoring --- .idea/dictionaries/valentin.xml | 1 + .../quickfix/replaceWith/CallKindHandler.kt | 62 +++++++++++++++++++ .../CallableUsageReplacementStrategy.kt | 47 +++++++------- 3 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallKindHandler.kt diff --git a/.idea/dictionaries/valentin.xml b/.idea/dictionaries/valentin.xml index 8615d4e262c..990faa769a7 100644 --- a/.idea/dictionaries/valentin.xml +++ b/.idea/dictionaries/valentin.xml @@ -9,6 +9,7 @@ inserter negatable pparent + precheck prioritizer processings rbrace diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallKindHandler.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallKindHandler.kt new file mode 100644 index 00000000000..ebd4b0418a7 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallKindHandler.kt @@ -0,0 +1,62 @@ +/* + * 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.idea.core.replaced +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis + +internal interface CallKindHandler { + val elementToReplace: JetElement + + fun precheckReplacementPattern(pattern: ReplaceWithAnnotationAnalyzer.ReplacementExpression): Boolean + + fun wrapGeneratedExpression(expression: JetExpression): JetElement + + fun unwrapResult(result: JetElement): JetElement +} + +internal class CallExpressionHandler(callElement: JetExpression) : CallKindHandler { + override val elementToReplace = callElement.getQualifiedExpressionForSelectorOrThis() + + override fun precheckReplacementPattern(pattern: ReplaceWithAnnotationAnalyzer.ReplacementExpression) = true + + override fun wrapGeneratedExpression(expression: JetExpression) = expression + + override fun unwrapResult(result: JetElement) = result +} + +internal class AnnotationEntryHandler(annotationEntry: JetAnnotationEntry) : CallKindHandler { + override val elementToReplace = annotationEntry + + override fun precheckReplacementPattern(pattern: ReplaceWithAnnotationAnalyzer.ReplacementExpression): Boolean { + //TODO + return true + } + + //TODO: how to prohibit wrapping replacement expression into anything? + + override fun wrapGeneratedExpression(expression: JetExpression): JetAnnotationEntry { + return createByPattern("@Dummy($0)", expression) { JetPsiFactory(expression).createAnnotationEntry(it) } + } + + override fun unwrapResult(result: JetElement): JetAnnotationEntry { + result as JetAnnotationEntry + val text = result.valueArguments.single().getArgumentExpression()!!.text + return result.replaced(JetPsiFactory(result).createAnnotationEntry("@" + text)) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt index f67836f815c..7590fcd7c84 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/CallableUsageReplacementStrategy.kt @@ -60,9 +60,23 @@ class CallableUsageReplacementStrategy( val bindingContext = usage.analyze(BodyResolveMode.PARTIAL) val resolvedCall = usage.getResolvedCall(bindingContext) ?: return null if (!resolvedCall.isReallySuccess()) return null + + val callElement = resolvedCall.call.callElement + val callTypeHandler = callTypeHandler(callElement) ?: return null + + if (!callTypeHandler.precheckReplacementPattern(replacement)) return null + return { // copy replacement expression because it is modified by performCallReplacement - performCallReplacement(usage, bindingContext, resolvedCall, replacement.copy()) + performCallReplacement(usage, bindingContext, resolvedCall, callElement, callTypeHandler, replacement.copy()) + } + } + + private fun callTypeHandler(callElement: JetElement): CallKindHandler? { + return when (callElement) { + is JetExpression -> CallExpressionHandler(callElement) + is JetAnnotationEntry -> AnnotationEntryHandler(callElement) + else -> null } } } @@ -71,15 +85,16 @@ private fun performCallReplacement( element: JetSimpleNameExpression, bindingContext: BindingContext, resolvedCall: ResolvedCall, + callElement: JetElement, + callKindHandler: CallKindHandler, replacement: ReplaceWithAnnotationAnalyzer.ReplacementExpression ): JetElement { val project = element.project val psiFactory = JetPsiFactory(project) val descriptor = resolvedCall.resultingDescriptor - val callElement = resolvedCall.call.callElement val qualifiedExpression = callElement.getQualifiedExpressionForSelector() - val elementToBeReplaced = qualifiedExpression ?: callElement + val elementToBeReplaced = callKindHandler.elementToReplace val commentSaver = CommentSaver(elementToBeReplaced, saveLineBreaks = true) @@ -137,7 +152,8 @@ private fun performCallReplacement( } } - var result = elementToBeReplaced.replaceCallElement(wrapper.expression) + val wrappedExpression = callKindHandler.wrapGeneratedExpression(wrapper.expression) + var result = elementToBeReplaced.replace(wrappedExpression) as JetElement val file = result.getContainingJetFile() replacement.fqNamesToImport @@ -153,27 +169,8 @@ private fun performCallReplacement( commentSaver.restore(resultRange) - var resultElement = resultRange.last as JetElement - - if (resultElement is JetAnnotationEntry) { // unwrap "@Dummy(...)" - val text = resultElement.valueArguments.single().getArgumentExpression()!!.text - resultElement = resultElement.replaced(JetPsiFactory(project).createAnnotationEntry("@" + text)) //TODO: what if it does not work? - } - - return resultElement -} - -private fun JetElement.replaceCallElement(generatedExpression: JetExpression): JetElement { - when (this) { - is JetExpression -> return replace(generatedExpression) as JetExpression - - is JetAnnotationEntry -> { - val dummyAnnotation = createByPattern("@Dummy($0)", generatedExpression) { JetPsiFactory(project).createAnnotationEntry(it) } - return replace(dummyAnnotation) as JetElement - } - - else -> throw UnsupportedOperationException() //TODO: check it before!! - } + @Suppress("UNCHECKED_CAST") + return callKindHandler.unwrapResult(resultRange.last as JetElement) } private fun ConstructedExpressionWrapper.processValueParameterUsages(