diff --git a/idea/ide-common/src/org/jetbrains/jet/plugin/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/jet/plugin/codeInsight/ReferenceVariantsHelper.kt index a7af3ed1ac0..f62a3c0d64e 100644 --- a/idea/ide-common/src/org/jetbrains/jet/plugin/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/jet/plugin/codeInsight/ReferenceVariantsHelper.kt @@ -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 { - 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 { 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 diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt index 653fb644928..e32a63d1d5c 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt @@ -121,8 +121,8 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess protected abstract fun doComplete() - protected fun getReferenceVariants(kindFilter: DescriptorKindFilter): Collection - = referenceVariantsHelper!!.getReferenceVariants(jetReference!!.expression, kindFilter, prefixMatcher.asNameFilter()) + protected fun getReferenceVariants(kindFilter: DescriptorKindFilter, shouldCastToRuntimeType: Boolean): Collection + = 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) }) { diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt index 255b3118600..b051eae8e16 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt @@ -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(this) { + override fun handleInsert(context: InsertionContext) { + super.handleInsert(context) + CastReceiverInsertHandler.handleInsert(context, getDelegate()) + } + } +} + val KEEP_OLD_ARGUMENT_LIST_ON_TAB_KEY = Key("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) diff --git a/idea/src/org/jetbrains/jet/plugin/completion/LookupElementsCollector.kt b/idea/src/org/jetbrains/jet/plugin/completion/LookupElementsCollector.kt index 42c5e30aaeb..4da20a09e5b 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/LookupElementsCollector.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/LookupElementsCollector.kt @@ -51,16 +51,21 @@ class LookupElementsCollector( private set public fun addDescriptorElements(descriptors: Iterable, - 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) { elements.forEach { addElement(it) } } + + public fun addElementsWithReceiverCast(elements: Iterable) { + elements.forEach { addElement(it.shouldCastReceiver()) } + } } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt b/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt index f2ee68b58bc..b383795d0af 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt @@ -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())!!.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(), false) + val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, javaClass(), 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()) + } + } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/parameterInfo/JetFunctionParameterInfoHandler.java b/idea/src/org/jetbrains/jet/plugin/parameterInfo/JetFunctionParameterInfoHandler.java index 11b72a48b37..1732c8acb92 100644 --- a/idea/src/org/jetbrains/jet/plugin/parameterInfo/JetFunctionParameterInfoHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/parameterInfo/JetFunctionParameterInfoHandler.java @@ -410,7 +410,7 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith }; Collection variants = new ReferenceVariantsHelper(bindingContext, visibilityFilter).getReferenceVariants( callNameExpression, new DescriptorKindFilter(DescriptorKindFilter.FUNCTIONS_MASK | DescriptorKindFilter.CLASSIFIERS_MASK, - Collections.emptyList()), nameFilter); + Collections.emptyList()), false, nameFilter); Collection> itemsToShow = new ArrayList>(); for (DeclarationDescriptor variant : variants) {