From 13ca110430040635b549fe7ff32e0f0e3e983713 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 27 Oct 2016 14:12:58 +0300 Subject: [PATCH] Refactoring --- .../postfix/KtPostfixTemplateProvider.kt | 81 ++++++++----------- 1 file changed, 34 insertions(+), 47 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt index 5ce10836bf5..4c0ff4215ae 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/postfix/KtPostfixTemplateProvider.kt @@ -20,10 +20,10 @@ import com.intellij.codeInsight.template.postfix.templates.* import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Document import com.intellij.openapi.editor.Editor -import com.intellij.openapi.util.Condition import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.util.PsiTreeUtil.findElementOfClassAtRange +import com.intellij.util.Function import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.idea.caches.resolve.analyze @@ -111,52 +111,43 @@ internal fun createExpressionSelector( checkCanBeUsedAsValue: Boolean = true, statementsOnly: Boolean = false, typePredicate: ((KotlinType) -> Boolean)? = null -): PostfixTemplateExpressionSelectorBase = KtExpressionPostfixTemplateSelector(statementsOnly, checkCanBeUsedAsValue, typePredicate) +): PostfixTemplateExpressionSelector = KtExpressionPostfixTemplateSelector(statementsOnly, checkCanBeUsedAsValue, typePredicate) private class KtExpressionPostfixTemplateSelector( - statementsOnly: Boolean, - checkCanBeUsedAsValue: Boolean, - typePredicate: ((KotlinType) -> Boolean)? -) : PostfixTemplateExpressionSelectorBase(createFilter(statementsOnly, checkCanBeUsedAsValue, typePredicate)) { - companion object { - private fun createFilter( - statementsOnly: Boolean, - checkCanBeUsedAsValue: Boolean, - typePredicate: ((KotlinType) -> Boolean)? - ): Condition = Condition { - if (it !is KtExpression) return@Condition false + private val statementsOnly: Boolean, + private val checkCanBeUsedAsValue: Boolean, + private val typePredicate: ((KotlinType) -> Boolean)? +) : PostfixTemplateExpressionSelector { - // Can't be independent expressions - if (it.isSelector || it.parent is KtUserType || it.isOperationReference || it is KtBlockExpression) return@Condition false + private fun filterElement(element: PsiElement): Boolean { + if (element !is KtExpression) return false - // Both KtLambdaExpression and KtFunctionLiteral have the same offset, so we add only one of them -> KtLambdaExpression - if (it is KtFunctionLiteral) return@Condition false + // Can't be independent expressions + if (element.isSelector || element.parent is KtUserType || element.isOperationReference || element is KtBlockExpression) return false - val bindingContext by lazy { it.analyze(BodyResolveMode.PARTIAL) } + // Both KtLambdaExpression and KtFunctionLiteral have the same offset, so we add only one of them -> KtLambdaExpression + if (element is KtFunctionLiteral) return false - if (statementsOnly) { - val elementToCheck = it.getQualifiedExpressionForReceiverOrThis() - if (elementToCheck.parent !is KtBlockExpression && !elementToCheck.isUsedAsStatement(bindingContext)) return@Condition false - } - if (checkCanBeUsedAsValue && !it.canBeUsedAsValue()) return@Condition false + val bindingContext by lazy { element.analyze(BodyResolveMode.PARTIAL) } - typePredicate == null || it.getType(bindingContext)?.let { typePredicate(it) } ?: false + if (statementsOnly) { + val elementToCheck = element.getQualifiedExpressionForReceiverOrThis() + if (elementToCheck.parent !is KtBlockExpression && !elementToCheck.isUsedAsStatement(bindingContext)) return false } + if (checkCanBeUsedAsValue && !element.canBeUsedAsValue()) return false - private fun KtExpression.canBeUsedAsValue() = - !KtPsiUtil.isAssignment(this) && - !this.isNamedDeclaration && - this !is KtLoopExpression && - // if's only with else may be treated as expressions - !isIfWithoutElse - - private val KtExpression.isIfWithoutElse: Boolean - get() = (this is KtIfExpression && this.elseKeyword == null) + return typePredicate == null || element.getType(bindingContext)?.let { typePredicate.invoke(it) } ?: false } - override fun getFilters(offset: Int): Condition { - return myAdditionalCondition - } + private fun KtExpression.canBeUsedAsValue() = + !KtPsiUtil.isAssignment(this) && + !this.isNamedDeclaration && + this !is KtLoopExpression && + // if's only with else may be treated as expressions + !isIfWithoutElse + + private val KtExpression.isIfWithoutElse: Boolean + get() = (this is KtIfExpression && this.elseKeyword == null) override fun getExpressions(context: PsiElement, document: Document, offset: Int): List { val originalFile = context.containingFile.originalFile @@ -175,12 +166,12 @@ private class KtExpressionPostfixTemplateSelector( val qualifiedExpressionEnd = boundElementParent.endOffset expressions .dropWhile { it != boundElementParent } - .filter { it != boundElementParent } + .drop(1) .takeWhile { it.endOffset == qualifiedExpressionEnd } .toCollection(filteredByOffset) } - val result = filteredByOffset.filter { myAdditionalCondition.value(it) } + val result = filteredByOffset.filter(this::filterElement) if (ApplicationManager.getApplication().isUnitTestMode && result.size > 1) { KtPostfixTemplateProvider.previouslySuggestedExpressions = result.map { it.text } @@ -189,15 +180,11 @@ private class KtExpressionPostfixTemplateSelector( return result } - override fun getNonFilteredExpressions( - context: PsiElement, - document: Document, - offset: Int - ) = context.parentsWithSelf - .filterIsInstance() - .takeWhile { - !it.isBlockBodyInDeclaration - }.toList() + override fun hasExpression(context: PsiElement, copyDocument: Document, newOffset: Int): Boolean { + return !getExpressions(context, copyDocument, newOffset).isEmpty() + } + + override fun getRenderer() = Function(PsiElement::getText) } private val KtExpression.isOperationReference: Boolean