Completion to insert type arguments for a call when they are likely required
This commit is contained in:
+3
@@ -103,6 +103,9 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
)
|
||||
}
|
||||
|
||||
override val expectedInfos: Collection<ExpectedInfo>
|
||||
get() = smartCompletion?.expectedInfos ?: emptyList()
|
||||
|
||||
private fun calcCompletionKind(): CompletionKind {
|
||||
if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(position)) {
|
||||
return CompletionKind.NAMED_ARGUMENTS_ONLY
|
||||
|
||||
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
@@ -142,10 +143,11 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
protected val receiversData: ReferenceVariantsHelper.ReceiversData? = nameExpression?.let { referenceVariantsHelper.getReferenceVariantsReceivers(it) }
|
||||
|
||||
protected val lookupElementFactory: LookupElementFactory = run {
|
||||
var receiverTypes = emptyList<JetType>()
|
||||
if (receiversData != null) {
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfo(expression)
|
||||
|
||||
var receiverTypes = receiversData.receivers.flatMap { receiverValue ->
|
||||
receiverTypes = receiversData.receivers.flatMap { receiverValue ->
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
|
||||
if (dataFlowValue.isPredictable) { // we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed
|
||||
resolutionFacade.frontendService<SmartCastManager>()
|
||||
@@ -159,12 +161,9 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
if (receiversData.callType == CallType.SAFE) {
|
||||
receiverTypes = receiverTypes.map { it.makeNotNullable() }
|
||||
}
|
||||
}
|
||||
|
||||
LookupElementFactory(resolutionFacade, receiverTypes)
|
||||
}
|
||||
else {
|
||||
LookupElementFactory(resolutionFacade, emptyList())
|
||||
}
|
||||
LookupElementFactory(resolutionFacade, receiverTypes, { expectedInfos })
|
||||
}
|
||||
|
||||
private val collectorContext = if (expression?.getParent() is JetSimpleNameStringTemplateEntry)
|
||||
@@ -230,6 +229,8 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
|
||||
|
||||
protected abstract val descriptorKindFilter: DescriptorKindFilter?
|
||||
|
||||
protected abstract val expectedInfos: Collection<ExpectedInfo>
|
||||
|
||||
protected open fun createSorter(): CompletionSorter {
|
||||
var sorter = CompletionSorter.defaultSorter(parameters, prefixMatcher)!!
|
||||
|
||||
|
||||
+1
@@ -65,6 +65,7 @@ object KDocNameCompletionProvider: CompletionProvider<CompletionParameters>() {
|
||||
class KDocNameCompletionSession(parameters: CompletionParameters,
|
||||
resultSet: CompletionResultSet): CompletionSession(CompletionSessionConfiguration(parameters), parameters, resultSet) {
|
||||
override val descriptorKindFilter: DescriptorKindFilter? get() = null
|
||||
override val expectedInfos: Collection<ExpectedInfo> get() = emptyList()
|
||||
|
||||
override fun doComplete() {
|
||||
val position = parameters.getPosition().getParentOfType<KDocName>(false) ?: return
|
||||
|
||||
@@ -77,7 +77,7 @@ object KeywordCompletion {
|
||||
.withInsertHandler(if (keywordToken !in FUNCTION_KEYWORDS)
|
||||
KotlinKeywordInsertHandler
|
||||
else
|
||||
KotlinFunctionInsertHandler.NO_PARAMETERS_HANDLER)
|
||||
KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = false))
|
||||
consumer(element)
|
||||
}
|
||||
}
|
||||
|
||||
+69
-25
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.*
|
||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||
import org.jetbrains.kotlin.idea.util.fuzzyReturnType
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -42,6 +43,8 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObject {
|
||||
override val psiElement: PsiElement? get() = null
|
||||
@@ -59,8 +62,11 @@ public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObj
|
||||
|
||||
public class LookupElementFactory(
|
||||
private val resolutionFacade: ResolutionFacade,
|
||||
private val receiverTypes: Collection<JetType>
|
||||
private val receiverTypes: Collection<JetType>,
|
||||
expectedInfosCalculator: () -> Collection<ExpectedInfo>
|
||||
) {
|
||||
private val expectedInfos by lazy { expectedInfosCalculator() }
|
||||
|
||||
public fun createLookupElement(
|
||||
descriptor: DeclarationDescriptor,
|
||||
boldImmediateMembers: Boolean,
|
||||
@@ -368,36 +374,74 @@ public class LookupElementFactory(
|
||||
return typeParameter.containingDeclaration == original
|
||||
}
|
||||
|
||||
companion object {
|
||||
public fun getDefaultInsertHandler(descriptor: DeclarationDescriptor): InsertHandler<LookupElement> {
|
||||
return when (descriptor) {
|
||||
is FunctionDescriptor -> {
|
||||
val parameters = descriptor.getValueParameters()
|
||||
when (parameters.size()) {
|
||||
0 -> KotlinFunctionInsertHandler.NO_PARAMETERS_HANDLER
|
||||
public fun getDefaultInsertHandler(descriptor: DeclarationDescriptor): InsertHandler<LookupElement> {
|
||||
return when (descriptor) {
|
||||
is FunctionDescriptor -> {
|
||||
val needTypeArguments = needTypeArguments(descriptor)
|
||||
val parameters = descriptor.valueParameters
|
||||
when (parameters.size()) {
|
||||
0 -> KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = false)
|
||||
|
||||
1 -> {
|
||||
val parameterType = parameters.single().getType()
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
|
||||
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
||||
if (parameterCount <= 1) {
|
||||
// otherwise additional item with lambda template is to be added
|
||||
return KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, GenerateLambdaInfo(parameterType, false))
|
||||
}
|
||||
1 -> {
|
||||
val parameterType = parameters.single().getType()
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) {
|
||||
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
|
||||
if (parameterCount <= 1) {
|
||||
// otherwise additional item with lambda template is to be added
|
||||
return KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true, lambdaInfo = GenerateLambdaInfo(parameterType, false))
|
||||
}
|
||||
KotlinFunctionInsertHandler.WITH_PARAMETERS_HANDLER
|
||||
}
|
||||
|
||||
else -> KotlinFunctionInsertHandler.WITH_PARAMETERS_HANDLER
|
||||
KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true)
|
||||
}
|
||||
|
||||
else -> KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true)
|
||||
}
|
||||
|
||||
is PropertyDescriptor -> KotlinPropertyInsertHandler
|
||||
|
||||
is ClassifierDescriptor -> KotlinClassifierInsertHandler
|
||||
|
||||
else -> BaseDeclarationInsertHandler()
|
||||
}
|
||||
|
||||
is PropertyDescriptor -> KotlinPropertyInsertHandler
|
||||
|
||||
is ClassifierDescriptor -> KotlinClassifierInsertHandler
|
||||
|
||||
else -> BaseDeclarationInsertHandler()
|
||||
}
|
||||
}
|
||||
|
||||
private fun needTypeArguments(function: FunctionDescriptor): Boolean {
|
||||
if (function.typeParameters.isEmpty()) return false
|
||||
|
||||
val originalFunction = function.original
|
||||
val typeParameters = originalFunction.typeParameters
|
||||
|
||||
val potentiallyInferred = HashSet<TypeParameterDescriptor>()
|
||||
|
||||
fun addPotentiallyInferred(type: JetType) {
|
||||
val descriptor = type.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||
if (descriptor != null && descriptor in typeParameters) {
|
||||
potentiallyInferred.add(descriptor)
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(type) && KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(type).size() <= 1) {
|
||||
// do not rely on inference from input of function type with one or no arguments - use only return type of functional type
|
||||
addPotentiallyInferred(KotlinBuiltIns.getReturnTypeFromFunctionType(type))
|
||||
return
|
||||
}
|
||||
|
||||
for (argument in type.arguments) {
|
||||
if (!argument.isStarProjection) { // otherwise we can fall into infinite recursion
|
||||
addPotentiallyInferred(argument.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
originalFunction.extensionReceiverParameter?.type?.let { addPotentiallyInferred(it) }
|
||||
originalFunction.valueParameters.forEach { addPotentiallyInferred(it.type) }
|
||||
|
||||
val returnType = originalFunction.returnType
|
||||
// check that there is an expected type and return value from the function can potentially match it
|
||||
if (returnType != null && expectedInfos.any { it.fuzzyType?.checkIsSuperTypeOf(originalFunction.fuzzyReturnType()!!) != null }) {
|
||||
addPotentiallyInferred(returnType)
|
||||
}
|
||||
|
||||
return originalFunction.typeParameters.any { it !in potentiallyInferred }
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -138,6 +138,8 @@ class LookupElementsCollector(
|
||||
|
||||
private fun addSpecialFunctionDescriptorElement(descriptor: FunctionDescriptor, parameterType: JetType) {
|
||||
var lookupElement = lookupElementFactory.createLookupElement(descriptor, true)
|
||||
val needTypeArguments = (lookupElementFactory.getDefaultInsertHandler(descriptor) as KotlinFunctionInsertHandler).needTypeArguments
|
||||
val lambdaInfo = GenerateLambdaInfo(parameterType, true)
|
||||
|
||||
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
@@ -150,7 +152,7 @@ class LookupElementsCollector(
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, GenerateLambdaInfo(parameterType, true)).handleInsert(context, this)
|
||||
KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true, lambdaInfo = lambdaInfo).handleInsert(context, this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ object PackageDirectiveCompletion {
|
||||
|
||||
val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, { true }).getPackageReferenceVariants(expression, prefixMatcher.asNameFilter())
|
||||
for (variant in variants) {
|
||||
val lookupElement = LookupElementFactory(resolutionFacade, listOf()).createLookupElement(variant, false)
|
||||
val lookupElement = LookupElementFactory(resolutionFacade, emptyList(), { emptyList() }).createLookupElement(variant, false)
|
||||
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
|
||||
result.addElement(lookupElement)
|
||||
}
|
||||
|
||||
+39
-34
@@ -35,24 +35,18 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
|
||||
enum class CaretPosition {
|
||||
IN_BRACKETS,
|
||||
AFTER_BRACKETS
|
||||
}
|
||||
|
||||
data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean)
|
||||
|
||||
class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : KotlinCallableInsertHandler() {
|
||||
init {
|
||||
if (caretPosition == CaretPosition.AFTER_BRACKETS && lambdaInfo != null) {
|
||||
throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with lambdaInfo != null combination is not supported")
|
||||
}
|
||||
}
|
||||
class KotlinFunctionInsertHandler(
|
||||
val needTypeArguments: Boolean,
|
||||
val needValueArguments: Boolean,
|
||||
val lambdaInfo: GenerateLambdaInfo? = null
|
||||
) : KotlinCallableInsertHandler() {
|
||||
|
||||
public override fun handleInsert(context: InsertionContext, item: LookupElement) {
|
||||
super.handleInsert(context, item)
|
||||
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject())
|
||||
val psiDocumentManager = PsiDocumentManager.getInstance(context.project)
|
||||
psiDocumentManager.commitAllDocuments()
|
||||
psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument())
|
||||
|
||||
@@ -88,31 +82,46 @@ class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaIn
|
||||
context.setAddCompletionChar(false)
|
||||
}
|
||||
|
||||
var offset = context.getTailOffset()
|
||||
val document = context.getDocument()
|
||||
val chars = document.getCharsSequence()
|
||||
var offset = context.tailOffset
|
||||
val document = context.document
|
||||
val editor = context.editor
|
||||
val project = context.project
|
||||
val chars = document.charsSequence
|
||||
|
||||
val insertLambda = lambdaInfo != null && completionChar != '(' && !(completionChar == '\t' && chars.isCharAt(offset, '('))
|
||||
|
||||
val openingBracket = if (insertLambda) '{' else '('
|
||||
val closingBracket = if (insertLambda) '}' else ')'
|
||||
|
||||
var insertTypeArguments = needTypeArguments && (completionChar == '\n' || completionChar == '\r')
|
||||
|
||||
if (completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
||||
val offset1 = chars.skipSpaces(offset)
|
||||
if (offset1 < chars.length()) {
|
||||
if (chars[offset1] == '<') {
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document)
|
||||
val token = context.getFile().findElementAt(offset1)!!
|
||||
if (token.getNode().getElementType() == JetTokens.LT) {
|
||||
val parent = token.getParent()
|
||||
if (parent is JetTypeArgumentList && parent.getText().indexOf('\n') < 0/* if type argument list is on multiple lines this is more likely wrong parsing*/) {
|
||||
offset = parent.endOffset
|
||||
insertTypeArguments = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (insertLambda && lambdaInfo!!.explicitParameters) {
|
||||
insertTypeArguments = false
|
||||
}
|
||||
|
||||
if (insertTypeArguments) {
|
||||
document.insertString(offset, "<>")
|
||||
editor.caretModel.moveToOffset(offset + 1)
|
||||
offset += 2
|
||||
}
|
||||
|
||||
var openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset)
|
||||
var closeBracketOffset = openingBracketOffset?.let { chars.indexOfSkippingSpace(closingBracket, it + 1) }
|
||||
var inBracketsShift = 0
|
||||
@@ -127,7 +136,7 @@ class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaIn
|
||||
context.setAddCompletionChar(false)
|
||||
}
|
||||
|
||||
if (isInsertSpacesInOneLineFunctionEnabled(context.getProject())) {
|
||||
if (isInsertSpacesInOneLineFunctionEnabled(project)) {
|
||||
document.insertString(offset, " { }")
|
||||
inBracketsShift = 1
|
||||
}
|
||||
@@ -138,22 +147,23 @@ class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaIn
|
||||
else {
|
||||
document.insertString(offset, "()")
|
||||
}
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document)
|
||||
|
||||
openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset)!!
|
||||
closeBracketOffset = chars.indexOfSkippingSpace(closingBracket, openingBracketOffset + 1)!!
|
||||
}
|
||||
|
||||
val editor = context.getEditor()
|
||||
if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == null) {
|
||||
editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift)
|
||||
AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement)
|
||||
}
|
||||
else {
|
||||
editor.getCaretModel().moveToOffset(closeBracketOffset + 1)
|
||||
if (!insertTypeArguments) {
|
||||
if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == null) {
|
||||
editor.caretModel.moveToOffset(openingBracketOffset + 1 + inBracketsShift)
|
||||
AutoPopupController.getInstance(project)?.autoPopupParameterInfo(editor, offsetElement)
|
||||
}
|
||||
else {
|
||||
editor.caretModel.moveToOffset(closeBracketOffset + 1)
|
||||
}
|
||||
}
|
||||
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document)
|
||||
PsiDocumentManager.getInstance(project).commitDocument(document)
|
||||
|
||||
if (insertLambda && lambdaInfo!!.explicitParameters) {
|
||||
insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset!! + 1), lambdaInfo!!.lambdaType)
|
||||
@@ -163,14 +173,9 @@ class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaIn
|
||||
private fun shouldPlaceCaretInBrackets(completionChar: Char): Boolean {
|
||||
if (completionChar == ',' || completionChar == '.' || completionChar == '=') return false
|
||||
if (completionChar == '(') return true
|
||||
return caretPosition == CaretPosition.IN_BRACKETS
|
||||
return needValueArguments
|
||||
}
|
||||
|
||||
companion object {
|
||||
public val NO_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, null)
|
||||
public val WITH_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, null)
|
||||
|
||||
private fun isInsertSpacesInOneLineFunctionEnabled(project: Project)
|
||||
= CodeStyleSettingsManager.getSettings(project).getCustomSettings(javaClass<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
||||
}
|
||||
private fun isInsertSpacesInOneLineFunctionEnabled(project: Project)
|
||||
= CodeStyleSettingsManager.getSettings(project).getCustomSettings(javaClass<JetCodeStyleSettings>())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD
|
||||
}
|
||||
+13
-7
@@ -38,6 +38,17 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
|
||||
// we do not include SAM-constructors because they are handled separately and adding them requires iterating of java classes
|
||||
override val descriptorKindFilter = DescriptorKindFilter.VALUES exclude SamConstructorDescriptorKindExclude
|
||||
|
||||
private val smartCompletion by lazy {
|
||||
expression?.let {
|
||||
SmartCompletion(it, resolutionFacade,
|
||||
bindingContext, isVisibleFilter, inDescriptor, prefixMatcher, originalSearchScope,
|
||||
toFromOriginalFileMapper, lookupElementFactory)
|
||||
}
|
||||
}
|
||||
|
||||
override val expectedInfos: Collection<ExpectedInfo>
|
||||
get() = smartCompletion?.expectedInfos ?: emptyList()
|
||||
|
||||
override fun doComplete() {
|
||||
if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(position)) {
|
||||
NamedArgumentCompletion.complete(position, collector, bindingContext)
|
||||
@@ -47,16 +58,11 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
|
||||
if (expression != null) {
|
||||
addFunctionLiteralArgumentCompletions()
|
||||
|
||||
val completion = SmartCompletion(
|
||||
expression, resolutionFacade, bindingContext, isVisibleFilter, inDescriptor,
|
||||
prefixMatcher, originalSearchScope, toFromOriginalFileMapper, lookupElementFactory
|
||||
)
|
||||
|
||||
val (additionalItems, inheritanceSearcher) = completion.additionalItems()
|
||||
val (additionalItems, inheritanceSearcher) = smartCompletion!!.additionalItems()
|
||||
collector.addElements(additionalItems)
|
||||
|
||||
if (nameExpression != null) {
|
||||
val filter = completion.descriptorFilter
|
||||
val filter = smartCompletion!!.descriptorFilter
|
||||
if (filter != null) {
|
||||
referenceVariants.forEach { collector.addElements(filter(it)) }
|
||||
flushToResultSet()
|
||||
|
||||
+4
-5
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.CaretPosition
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMethodsHandler
|
||||
import org.jetbrains.kotlin.idea.core.psiClassToDescriptor
|
||||
@@ -185,9 +184,9 @@ class TypeInstantiationItems(
|
||||
}
|
||||
|
||||
val baseInsertHandler = when (visibleConstructors.size()) {
|
||||
0 -> KotlinFunctionInsertHandler.NO_PARAMETERS_HANDLER
|
||||
1 -> LookupElementFactory.getDefaultInsertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler
|
||||
else -> KotlinFunctionInsertHandler.WITH_PARAMETERS_HANDLER
|
||||
0 -> KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = false)
|
||||
1 -> lookupElementFactory.getDefaultInsertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler
|
||||
else -> KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = true)
|
||||
}
|
||||
|
||||
insertHandler = object : InsertHandler<LookupElement> {
|
||||
@@ -200,7 +199,7 @@ class TypeInstantiationItems(
|
||||
shortenReferences(context, context.getStartOffset(), context.getTailOffset())
|
||||
}
|
||||
}
|
||||
if (baseInsertHandler.caretPosition == CaretPosition.IN_BRACKETS) {
|
||||
if (baseInsertHandler.needValueArguments) {
|
||||
lookupElement = lookupElement.keepOldArgumentListOnTab()
|
||||
}
|
||||
if (baseInsertHandler.lambdaInfo != null) {
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.foo(): String { }
|
||||
|
||||
fun f(list: List<Any>): String {
|
||||
return list.<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.foo(): String { }
|
||||
|
||||
fun f(list: List<Any>): String {
|
||||
return list.foo<<caret>>()
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.myFilterIsInstance(): Collection<T> { }
|
||||
|
||||
fun foo(list: List<Any>): String {
|
||||
return list.<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: myFilterIsInstance
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.myFilterIsInstance(): Collection<T> { }
|
||||
|
||||
fun foo(list: List<Any>): String {
|
||||
return list.myFilterIsInstance<<caret>>()
|
||||
}
|
||||
|
||||
// ELEMENT: myFilterIsInstance
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fun <T> foo(p : (T, Int) -> Boolean){}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
fo<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
// TAIL_TEXT: " { T, Int -> ... } (p: (T, Int) -> Boolean) (<root>)"
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
fun <T> foo(p : (T, Int) -> Boolean){}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
foo { t, i -> <caret> }
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
// TAIL_TEXT: " { T, Int -> ... } (p: (T, Int) -> Boolean) (<root>)"
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fun <T1, T2> T1.foo(handler: (T2) -> Boolean) {}
|
||||
|
||||
fun f() {
|
||||
"".<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
fun <T1, T2> T1.foo(handler: (T2) -> Boolean) {}
|
||||
|
||||
fun f() {
|
||||
"".foo<<caret>> { }
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fun f(list: List<String>) {
|
||||
list.<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: map
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
fun f(list: List<String>) {
|
||||
list.map { <caret> }
|
||||
}
|
||||
|
||||
// ELEMENT: map
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.myFirstIsInstance(): T { }
|
||||
|
||||
fun foo(list: List<Any>): String {
|
||||
return list.<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: myFirstIsInstance
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.myFirstIsInstance(): T { }
|
||||
|
||||
fun foo(list: List<Any>): String {
|
||||
return list.myFirstIsInstance()<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: myFirstIsInstance
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
fun <T1, reified T2> foo(t: T1): T1 {}
|
||||
|
||||
fun f() {
|
||||
<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fun <T1, reified T2> foo(t: T1): T1 {}
|
||||
|
||||
fun f() {
|
||||
foo<<caret>>()
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
@@ -0,0 +1,9 @@
|
||||
inline fun <reified R> Iterable<*>.myFilterIsInstance(): List<R> {
|
||||
return filterIsInstanceTo(ArrayList<R>())
|
||||
}
|
||||
|
||||
fun foo(list: List<Any>) {
|
||||
list.<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: myFilterIsInstance
|
||||
@@ -0,0 +1,9 @@
|
||||
inline fun <reified R> Iterable<*>.myFilterIsInstance(): List<R> {
|
||||
return filterIsInstanceTo(ArrayList<R>())
|
||||
}
|
||||
|
||||
fun foo(list: List<Any>) {
|
||||
list.myFilterIsInstance<<caret>>()
|
||||
}
|
||||
|
||||
// ELEMENT: myFilterIsInstance
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
fun <T1, T2> T1.foo(t: T2): T2 = t
|
||||
|
||||
fun foo() {
|
||||
"".<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
fun <T1, T2> T1.foo(t: T2): T2 = t
|
||||
|
||||
fun foo() {
|
||||
"".foo(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.foo(): List<T> { }
|
||||
|
||||
fun f(list: List<Any>): Collection<String> {
|
||||
return list.<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.foo(): List<T> { }
|
||||
|
||||
fun f(list: List<Any>): Collection<String> {
|
||||
return list.foo()<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.foo(): String { }
|
||||
|
||||
fun f(list: List<Any>): String {
|
||||
return list.<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
@@ -0,0 +1,7 @@
|
||||
public inline fun <reified T> Iterable<*>.foo(): String { }
|
||||
|
||||
fun f(list: List<Any>): String {
|
||||
return list.foo<<caret>>()
|
||||
}
|
||||
|
||||
// ELEMENT: foo
|
||||
+63
@@ -400,4 +400,67 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class TypeArgsForCall extends AbstractBasicCompletionHandlerTest {
|
||||
public void testAllFilesPresentInTypeArgsForCall() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/basic/typeArgsForCall"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ExpectedTypeDoesNotHelp.kt")
|
||||
public void testExpectedTypeDoesNotHelp() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ExpectedTypeDoesNotHelp2.kt")
|
||||
public void testExpectedTypeDoesNotHelp2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ExplicitLambdaSignature.kt")
|
||||
public void testExplicitLambdaSignature() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FunctionTypeParameter1.kt")
|
||||
public void testFunctionTypeParameter1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FunctionTypeParameter2.kt")
|
||||
public void testFunctionTypeParameter2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("HasExpectedType.kt")
|
||||
public void testHasExpectedType() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NotAllTypeArgumentsFromParameters.kt")
|
||||
public void testNotAllTypeArgumentsFromParameters() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeArgumentsFromParameters.kt")
|
||||
public void testTypeArgumentsFromParameters() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -311,6 +311,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DoNotInsertTypeArguments.kt")
|
||||
public void testDoNotInsertTypeArguments() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DoNotReplaceOnEnter.kt")
|
||||
public void testDoNotReplaceOnEnter() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/DoNotReplaceOnEnter.kt");
|
||||
@@ -413,6 +419,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("InsertTypeArguments.kt")
|
||||
public void testInsertTypeArguments() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("JavaEnumMemberInsertsImport.kt")
|
||||
public void testJavaEnumMemberInsertsImport() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/JavaEnumMemberInsertsImport.kt");
|
||||
|
||||
Reference in New Issue
Block a user