Use lookup elements from completion for variables in live templates

This commit is contained in:
Valentin Kipyatkov
2015-11-19 19:03:02 +03:00
parent f44bbfe4cd
commit 606a34283d
3 changed files with 14 additions and 21 deletions
@@ -18,5 +18,6 @@
<orderEntry type="module" module-name="idea" scope="RUNTIME" /> <orderEntry type="module" module-name="idea" scope="RUNTIME" />
<orderEntry type="library" scope="RUNTIME" name="junit-plugin" level="project" /> <orderEntry type="library" scope="RUNTIME" name="junit-plugin" level="project" />
<orderEntry type="module" module-name="compiler-tests" scope="TEST" /> <orderEntry type="module" module-name="compiler-tests" scope="TEST" />
<orderEntry type="module" module-name="idea-completion" />
</component> </component>
</module> </module>
@@ -17,34 +17,31 @@
package org.jetbrains.kotlin.idea.liveTemplates.macro package org.jetbrains.kotlin.idea.liveTemplates.macro
import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.template.*
import com.intellij.codeInsight.template.Expression
import com.intellij.codeInsight.template.ExpressionContext
import com.intellij.codeInsight.template.Macro
import com.intellij.codeInsight.template.Result
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.UserDataHolder import com.intellij.openapi.util.UserDataHolder
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiNamedElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.completion.BasicLookupElementFactory
import org.jetbrains.kotlin.idea.completion.InsertHandlerProvider
import org.jetbrains.kotlin.idea.core.isVisible import org.jetbrains.kotlin.idea.core.isVisible
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.util.slicedMap.UserDataHolderImpl import org.jetbrains.kotlin.util.slicedMap.UserDataHolderImpl
import java.util.*
abstract class BaseKotlinVariableMacro : Macro() { abstract class BaseKotlinVariableMacro : Macro() {
private fun getVariables(params: Array<Expression>, context: ExpressionContext): Collection<PsiNamedElement> { private fun getVariables(params: Array<Expression>, context: ExpressionContext): Collection<VariableDescriptor> {
if (params.size != 0) return emptyList() if (params.size != 0) return emptyList()
val project = context.project val project = context.project
@@ -67,16 +64,10 @@ abstract class BaseKotlinVariableMacro : Macro() {
initUserData(userData, contextElement, bindingContext) initUserData(userData, contextElement, bindingContext)
val helper = ReferenceVariantsHelper(bindingContext, resolutionFacade, resolutionFacade.moduleDescriptor, ::isVisible) val helper = ReferenceVariantsHelper(bindingContext, resolutionFacade, resolutionFacade.moduleDescriptor, ::isVisible)
val variants = helper return helper
.getReferenceVariants(contextElement, CallTypeAndReceiver.DEFAULT, DescriptorKindFilter.VARIABLES, { true }) .getReferenceVariants(contextElement, CallTypeAndReceiver.DEFAULT, DescriptorKindFilter.VARIABLES, { true })
.filter { isSuitable(it as VariableDescriptor, project, userData) } .map { it as VariableDescriptor }
.filter { isSuitable(it, project, userData) }
val declarations = ArrayList<PsiNamedElement>()
for (descriptor in variants) {
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? PsiNamedElement ?: continue
declarations.add(declaration)
}
return declarations
} }
protected open fun initUserData(userData: UserDataHolder, contextElement: KtElement, bindingContext: BindingContext) { protected open fun initUserData(userData: UserDataHolder, contextElement: KtElement, bindingContext: BindingContext) {
@@ -90,12 +81,13 @@ abstract class BaseKotlinVariableMacro : Macro() {
override fun calculateResult(params: Array<Expression>, context: ExpressionContext): Result? { override fun calculateResult(params: Array<Expression>, context: ExpressionContext): Result? {
val vars = getVariables(params, context) val vars = getVariables(params, context)
if (vars.isEmpty()) return null if (vars.isEmpty()) return null
return KotlinPsiElementResult(vars.first()) return vars.firstOrNull()?.let { TextResult(it.name.render()) }
} }
override fun calculateLookupItems(params: Array<Expression>, context: ExpressionContext): Array<LookupElement>? { override fun calculateLookupItems(params: Array<Expression>, context: ExpressionContext): Array<LookupElement>? {
val vars = getVariables(params, context) val vars = getVariables(params, context)
if (vars.size < 2) return null if (vars.size < 2) return null
return vars.map { LookupElementBuilder.create(it) }.toTypedArray() val lookupElementFactory = BasicLookupElementFactory(context.project, InsertHandlerProvider(CallType.DEFAULT, { emptyList() }))
return vars.map { lookupElementFactory.createLookupElement(it) }.toTypedArray()
} }
} }
@@ -85,7 +85,7 @@ class LiveTemplatesTest : KotlinLightCodeInsightFixtureTestCase() {
fun testSoutv() { fun testSoutv() {
start() start()
assertStringItems("args", "x", "y") assertStringItems("ASSERTIONS_ENABLED", "args", "defaultBlockSize", "defaultBufferSize", "minimumBlockSize", "x", "y")
typeAndNextTab("y") typeAndNextTab("y")
checkAfter() checkAfter()