Completion: insert cast to runtime type for receiver in code fragments
This commit is contained in:
+19
-2
@@ -33,6 +33,9 @@ import org.jetbrains.jet.lang.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.jet.lang.resolve.scopes.DescriptorKindExclude
|
||||
import org.jetbrains.jet.plugin.util.extensionsUtils.isExtensionCallable
|
||||
import org.jetbrains.jet.lang.types.JetType
|
||||
import org.jetbrains.jet.lang.types.TypeUtils
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
||||
|
||||
public class ReferenceVariantsHelper(
|
||||
private val context: BindingContext,
|
||||
@@ -42,14 +45,16 @@ public class ReferenceVariantsHelper(
|
||||
public fun getReferenceVariants(
|
||||
expression: JetSimpleNameExpression,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
shouldCastToRuntimeType: Boolean,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> {
|
||||
return getReferenceVariantsNoVisibilityFilter(expression, kindFilter, nameFilter).filter(visibilityFilter)
|
||||
return getReferenceVariantsNoVisibilityFilter(expression, kindFilter, shouldCastToRuntimeType, nameFilter).filter(visibilityFilter)
|
||||
}
|
||||
|
||||
private fun getReferenceVariantsNoVisibilityFilter(
|
||||
expression: JetSimpleNameExpression,
|
||||
kindFilter: DescriptorKindFilter,
|
||||
shouldCastToRuntimeType: Boolean,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> {
|
||||
val parent = expression.getParent()
|
||||
@@ -75,7 +80,10 @@ public class ReferenceVariantsHelper(
|
||||
qualifier.scope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter).filterTo(descriptors, ::filterIfInfix)
|
||||
}
|
||||
|
||||
val expressionType = context[BindingContext.EXPRESSION_TYPE, receiverExpression]
|
||||
val expressionType = if (shouldCastToRuntimeType)
|
||||
getQualifierRuntimeType(receiverExpression)
|
||||
else
|
||||
context[BindingContext.EXPRESSION_TYPE, receiverExpression]
|
||||
if (expressionType != null && !expressionType.isError()) {
|
||||
val receiverValue = ExpressionReceiver(receiverExpression, expressionType)
|
||||
val dataFlowInfo = context.getDataFlowInfo(expression)
|
||||
@@ -124,6 +132,15 @@ public class ReferenceVariantsHelper(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getQualifierRuntimeType(receiver: JetExpression): JetType? {
|
||||
val type = context[BindingContext.EXPRESSION_TYPE, receiver]
|
||||
if (TypeUtils.canHaveSubtypes(JetTypeChecker.DEFAULT, type)) {
|
||||
val evaluator = receiver.getContainingFile().getCopyableUserData(JetCodeFragment.RUNTIME_TYPE_EVALUATOR)
|
||||
return evaluator?.invoke(receiver)
|
||||
}
|
||||
return type
|
||||
}
|
||||
|
||||
private fun getReferenceVariantsReceiver(expression: JetSimpleNameExpression): JetExpression? {
|
||||
val parent = expression.getParent()
|
||||
val inPositionForCompletionWithReceiver = parent is JetCallExpression
|
||||
|
||||
@@ -121,8 +121,8 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
|
||||
|
||||
protected abstract fun doComplete()
|
||||
|
||||
protected fun getReferenceVariants(kindFilter: DescriptorKindFilter): Collection<DeclarationDescriptor>
|
||||
= referenceVariantsHelper!!.getReferenceVariants(jetReference!!.expression, kindFilter, prefixMatcher.asNameFilter())
|
||||
protected fun getReferenceVariants(kindFilter: DescriptorKindFilter, shouldCastToRuntimeType: Boolean): Collection<DeclarationDescriptor>
|
||||
= referenceVariantsHelper!!.getReferenceVariants(jetReference!!.expression, kindFilter, shouldCastToRuntimeType, prefixMatcher.asNameFilter())
|
||||
|
||||
protected fun shouldRunTopLevelCompletion(): Boolean
|
||||
= configuration.completeNonImportedDeclarations && isNoQualifierContext()
|
||||
@@ -161,11 +161,12 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
val completeReference = jetReference != null && !isOnlyKeywordCompletion()
|
||||
val onlyTypes = completeReference && shouldRunOnlyTypeCompletion()
|
||||
|
||||
val kindMask = if (onlyTypes)
|
||||
DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK
|
||||
else
|
||||
DescriptorKindFilter.ALL_KINDS_MASK
|
||||
|
||||
if (completeReference) {
|
||||
val kindMask = if (onlyTypes)
|
||||
DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK
|
||||
else
|
||||
DescriptorKindFilter.ALL_KINDS_MASK
|
||||
addReferenceVariants(DescriptorKindFilter(kindMask))
|
||||
|
||||
if (onlyTypes) {
|
||||
@@ -183,6 +184,11 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
flushToResultSet()
|
||||
addNonImported(onlyTypes)
|
||||
}
|
||||
|
||||
if (completeReference && position.getContainingFile() is JetCodeFragment) {
|
||||
flushToResultSet()
|
||||
addReferenceVariants(DescriptorKindFilter(kindMask), true)
|
||||
}
|
||||
}
|
||||
|
||||
NamedParametersCompletion.complete(position, collector)
|
||||
@@ -217,8 +223,11 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
return false
|
||||
}
|
||||
|
||||
private fun addReferenceVariants(kindFilter: DescriptorKindFilter) {
|
||||
collector.addDescriptorElements(getReferenceVariants(kindFilter), suppressAutoInsertion = false)
|
||||
private fun addReferenceVariants(kindFilter: DescriptorKindFilter, shouldCastToRuntimeType: Boolean = false) {
|
||||
collector.addDescriptorElements(
|
||||
getReferenceVariants(kindFilter, shouldCastToRuntimeType),
|
||||
suppressAutoInsertion = false,
|
||||
shouldCastToRuntimeType = shouldCastToRuntimeType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,11 +249,16 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
|
||||
|
||||
val filter = result.declarationFilter
|
||||
if (filter != null) {
|
||||
getReferenceVariants(DESCRIPTOR_KIND_MASK).forEach { collector.addElements(filter(it)) }
|
||||
getReferenceVariants(DESCRIPTOR_KIND_MASK, false).forEach { collector.addElements(filter(it)) }
|
||||
flushToResultSet()
|
||||
|
||||
processNonImported { collector.addElements(filter(it)) }
|
||||
flushToResultSet()
|
||||
|
||||
if (position.getContainingFile() is JetCodeFragment) {
|
||||
getReferenceVariants(DESCRIPTOR_KIND_MASK, true).forEach { collector.addElementsWithReceiverCast(filter(it)) }
|
||||
flushToResultSet()
|
||||
}
|
||||
}
|
||||
|
||||
result.inheritanceSearcher?.search({ prefixMatcher.prefixMatches(it) }) {
|
||||
|
||||
@@ -31,6 +31,10 @@ import org.jetbrains.jet.plugin.util.IdeDescriptorRenderers
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
||||
import org.jetbrains.jet.lang.resolve.name.Name
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.codeInsight.completion.InsertionContext
|
||||
import org.jetbrains.jet.plugin.completion.handlers.CastReceiverInsertHandler
|
||||
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor
|
||||
|
||||
enum class ItemPriority {
|
||||
MULTIPLE_ARGUMENTS_ITEM
|
||||
@@ -47,6 +51,15 @@ fun LookupElement.assignPriority(priority: ItemPriority): LookupElement {
|
||||
|
||||
fun LookupElement.suppressAutoInsertion() = AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(this)
|
||||
|
||||
fun LookupElement.shouldCastReceiver(): LookupElement {
|
||||
return object: LookupElementDecorator<LookupElement>(this) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
super.handleInsert(context)
|
||||
CastReceiverInsertHandler.handleInsert(context, getDelegate())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY = Key<Unit>("KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY")
|
||||
|
||||
fun LookupElement.keepOldArgumentListOnTab(): LookupElement {
|
||||
@@ -65,7 +78,7 @@ fun rethrowWithCancelIndicator(exception: ProcessCanceledException): ProcessCanc
|
||||
return exception
|
||||
}
|
||||
|
||||
fun qualifiedNameForSourceCode(descriptor: ClassDescriptor): String? {
|
||||
fun qualifiedNameForSourceCode(descriptor: ClassifierDescriptor): String? {
|
||||
val name = descriptor.getName()
|
||||
if (name.isSpecial()) return null
|
||||
val nameString = IdeDescriptorRenderers.SOURCE_CODE.renderName(name)
|
||||
|
||||
@@ -51,16 +51,21 @@ class LookupElementsCollector(
|
||||
private set
|
||||
|
||||
public fun addDescriptorElements(descriptors: Iterable<DeclarationDescriptor>,
|
||||
suppressAutoInsertion: Boolean // auto-insertion suppression is used for elements that require adding an import
|
||||
suppressAutoInsertion: Boolean, // auto-insertion suppression is used for elements that require adding an import
|
||||
shouldCastToRuntimeType: Boolean = false
|
||||
) {
|
||||
for (descriptor in descriptors) {
|
||||
addDescriptorElements(descriptor, suppressAutoInsertion)
|
||||
addDescriptorElements(descriptor, suppressAutoInsertion, shouldCastToRuntimeType)
|
||||
}
|
||||
}
|
||||
|
||||
public fun addDescriptorElements(descriptor: DeclarationDescriptor, suppressAutoInsertion: Boolean) {
|
||||
public fun addDescriptorElements(descriptor: DeclarationDescriptor, suppressAutoInsertion: Boolean, shouldCastToRuntimeType: Boolean) {
|
||||
run {
|
||||
val lookupElement = boldImmediateLookupElementFactory.createLookupElement(resolutionFacade, descriptor)
|
||||
var lookupElement = boldImmediateLookupElementFactory.createLookupElement(resolutionFacade, descriptor)
|
||||
if (shouldCastToRuntimeType) {
|
||||
lookupElement = lookupElement.shouldCastReceiver()
|
||||
}
|
||||
|
||||
if (suppressAutoInsertion) {
|
||||
addElementWithAutoInsertionSuppressed(lookupElement)
|
||||
}
|
||||
@@ -136,4 +141,8 @@ class LookupElementsCollector(
|
||||
public fun addElements(elements: Iterable<LookupElement>) {
|
||||
elements.forEach { addElement(it) }
|
||||
}
|
||||
|
||||
public fun addElementsWithReceiverCast(elements: Iterable<LookupElement>) {
|
||||
elements.forEach { addElement(it.shouldCastReceiver()) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,15 @@ import org.jetbrains.jet.plugin.completion.DeclarationDescriptorLookupObject
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpression
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
||||
import org.jetbrains.jet.lang.psi.JetPsiFactory
|
||||
import org.jetbrains.jet.lang.psi.JetParenthesizedExpression
|
||||
import org.jetbrains.jet.lang.psi.JetBinaryExpressionWithTypeRHS
|
||||
import org.jetbrains.jet.lang.psi.JetExpression
|
||||
import org.jetbrains.jet.plugin.codeInsight.ShortenReferences
|
||||
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.getStrictParentOfType
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.jet.plugin.completion.qualifiedNameForSourceCode
|
||||
|
||||
public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler() {
|
||||
public override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
@@ -211,4 +219,34 @@ public class KotlinFunctionInsertHandler(val caretPosition : CaretPosition, val
|
||||
= CodeStyleSettingsManager.getSettings(project)
|
||||
.getCustomSettings(javaClass<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
||||
}
|
||||
}
|
||||
|
||||
object CastReceiverInsertHandler : KotlinCallableInsertHandler() {
|
||||
override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
super.handleInsert(context, item)
|
||||
|
||||
val expression = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), javaClass<JetSimpleNameExpression>(), false)
|
||||
val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, javaClass<JetQualifiedExpression>(), true)
|
||||
if (qualifiedExpression != null) {
|
||||
val receiver = qualifiedExpression.getReceiverExpression()
|
||||
|
||||
val descriptor = (item.getObject() as? DeclarationDescriptorLookupObject)?.descriptor as CallableDescriptor
|
||||
val project = context.getProject()
|
||||
|
||||
val thisObj = if (descriptor.getExtensionReceiverParameter() != null) descriptor.getExtensionReceiverParameter() else descriptor.getDispatchReceiverParameter()
|
||||
val fqName = qualifiedNameForSourceCode(thisObj.getType().getConstructor().getDeclarationDescriptor())
|
||||
|
||||
val parentCast = JetPsiFactory(project).createExpression("(expr as $fqName)") as JetParenthesizedExpression
|
||||
val cast = parentCast.getExpression() as JetBinaryExpressionWithTypeRHS
|
||||
cast.getLeft().replace(receiver)
|
||||
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument())
|
||||
|
||||
val expr = receiver.replace(parentCast) as JetParenthesizedExpression
|
||||
|
||||
ShortenReferences.process((expr.getExpression() as JetBinaryExpressionWithTypeRHS).getRight())
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -410,7 +410,7 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith
|
||||
};
|
||||
Collection<DeclarationDescriptor> variants = new ReferenceVariantsHelper(bindingContext, visibilityFilter).getReferenceVariants(
|
||||
callNameExpression, new DescriptorKindFilter(DescriptorKindFilter.FUNCTIONS_MASK | DescriptorKindFilter.CLASSIFIERS_MASK,
|
||||
Collections.<DescriptorKindExclude>emptyList()), nameFilter);
|
||||
Collections.<DescriptorKindExclude>emptyList()), false, nameFilter);
|
||||
|
||||
Collection<Pair<? extends DeclarationDescriptor, ResolutionFacade>> itemsToShow = new ArrayList<Pair<? extends DeclarationDescriptor, ResolutionFacade>>();
|
||||
for (DeclarationDescriptor variant : variants) {
|
||||
|
||||
Reference in New Issue
Block a user