KT-4908 Smart completion does not work for arguments of function with vararg
#KT-4908 Fixed
This commit is contained in:
@@ -55,13 +55,20 @@ enum class Tail {
|
||||
ELSE
|
||||
}
|
||||
|
||||
open data class ExpectedInfo(val type: JetType, val name: String?, val tail: Tail?)
|
||||
data class ItemOptions(val starPrefix: Boolean) {
|
||||
companion object {
|
||||
val DEFAULT = ItemOptions(false)
|
||||
val STAR_PREFIX = ItemOptions(true)
|
||||
}
|
||||
}
|
||||
|
||||
class PositionalArgumentExpectedInfo(type: JetType, name: String?, tail: Tail?, val function: FunctionDescriptor, val argumentIndex: Int)
|
||||
: ExpectedInfo(type, name, tail) {
|
||||
open data class ExpectedInfo(val type: JetType, val name: String?, val tail: Tail?, val itemOptions: ItemOptions = ItemOptions.DEFAULT)
|
||||
|
||||
class PositionalArgumentExpectedInfo(type: JetType, name: String?, tail: Tail?, val function: FunctionDescriptor, val parameterIndex: Int, itemOptions: ItemOptions = ItemOptions.DEFAULT)
|
||||
: ExpectedInfo(type, name, tail, itemOptions) {
|
||||
|
||||
override fun equals(other: Any?)
|
||||
= other is PositionalArgumentExpectedInfo && super.equals(other) && function == other.function && argumentIndex == other.argumentIndex
|
||||
= other is PositionalArgumentExpectedInfo && super.equals(other) && function == other.function && parameterIndex == other.parameterIndex
|
||||
|
||||
override fun hashCode()
|
||||
= function.hashCode()
|
||||
@@ -149,8 +156,8 @@ class ExpectedInfos(
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression)
|
||||
val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for completion")
|
||||
val context = BasicCallResolutionContext.create(bindingTrace, resolutionScope, call, expectedType, dataFlowInfo,
|
||||
ContextDependency.INDEPENDENT, CheckValueArgumentsMode.ENABLED,
|
||||
CompositeChecker(listOf()), SymbolUsageValidator.Empty, AdditionalTypeChecker.Composite(listOf()), false)
|
||||
ContextDependency.INDEPENDENT, CheckValueArgumentsMode.ENABLED,
|
||||
CompositeChecker(listOf()), SymbolUsageValidator.Empty, AdditionalTypeChecker.Composite(listOf()), false)
|
||||
val callResolutionContext = context.replaceCollectAllCandidates(true)
|
||||
val callResolver = InjectorForMacros(
|
||||
callElement.getProject(),
|
||||
@@ -163,32 +170,58 @@ class ExpectedInfos(
|
||||
val status = candidate.getStatus()
|
||||
if (status == ResolutionStatus.RECEIVER_TYPE_ERROR || status == ResolutionStatus.RECEIVER_PRESENCE_ERROR) continue
|
||||
|
||||
// consider only candidates with more arguments than in the truncated call and with all arguments before the current one matched
|
||||
if (candidate.noErrorsInValueArguments() && (candidate.getCandidateDescriptor().getValueParameters().size() > argumentIndex || isFunctionLiteralArgument)) {
|
||||
val descriptor = candidate.getResultingDescriptor()
|
||||
// check that all arguments before the current one matched
|
||||
if (!candidate.noErrorsInValueArguments()) continue
|
||||
|
||||
val thisReceiver = ExpressionTypingUtils.normalizeReceiverValueForVisibility(candidate.getDispatchReceiver(), bindingContext)
|
||||
if (!Visibilities.isVisible(thisReceiver, descriptor, resolutionScope.getContainingDeclaration())) continue
|
||||
val descriptor = candidate.getResultingDescriptor()
|
||||
val parameters = descriptor.getValueParameters()
|
||||
|
||||
val parameters = descriptor.getValueParameters()
|
||||
if (isFunctionLiteralArgument && argumentIndex != parameters.lastIndex) continue
|
||||
val parameterIndex = if (isFunctionLiteralArgument) {
|
||||
if (argumentIndex != parameters.lastIndex) continue //TODO: varargs and optional parameters
|
||||
argumentIndex
|
||||
}
|
||||
else {
|
||||
val varArgIndex = parameters.indexOfFirst { it.getVarargElementType() != null }
|
||||
if (varArgIndex < 0) {
|
||||
if (parameters.size() <= argumentIndex) continue
|
||||
argumentIndex
|
||||
}
|
||||
else {
|
||||
if (argumentIndex < varArgIndex) argumentIndex else varArgIndex
|
||||
}
|
||||
}
|
||||
|
||||
val thisReceiver = ExpressionTypingUtils.normalizeReceiverValueForVisibility(candidate.getDispatchReceiver(), bindingContext)
|
||||
if (!Visibilities.isVisible(thisReceiver, descriptor, resolutionScope.getContainingDeclaration())) continue
|
||||
|
||||
val parameter = parameters[parameterIndex]
|
||||
val varargElementType = parameter.getVarargElementType()
|
||||
|
||||
val expectedName = if (descriptor.hasSynthesizedParameterNames()) null else parameter.getName().asString()
|
||||
|
||||
if (varargElementType != null) {
|
||||
expectedInfos.add(PositionalArgumentExpectedInfo(varargElementType, expectedName?.fromPlural(), null, descriptor, parameterIndex))
|
||||
|
||||
if (argumentIndex == parameterIndex) {
|
||||
val tail = if (parameterIndex == parameters.lastIndex) Tail.RPARENTH else null
|
||||
expectedInfos.add(PositionalArgumentExpectedInfo(parameter.getType(), expectedName, tail, descriptor, parameterIndex, ItemOptions.STAR_PREFIX))
|
||||
}
|
||||
}
|
||||
else {
|
||||
val tail = if (isFunctionLiteralArgument)
|
||||
null
|
||||
else if (argumentIndex == parameters.lastIndex)
|
||||
else if (parameterIndex == parameters.lastIndex)
|
||||
Tail.RPARENTH //TODO: support square brackets
|
||||
else if (parameters.drop(argumentIndex + 1).all { it.hasDefaultValue() || it.getVarargElementType() != null })
|
||||
else if (parameters.drop(parameterIndex + 1).all { it.hasDefaultValue() || it.getVarargElementType() != null })
|
||||
null
|
||||
else
|
||||
Tail.COMMA
|
||||
|
||||
val parameter = parameters[argumentIndex]
|
||||
val expectedName = if (descriptor.hasSynthesizedParameterNames()) null else parameter.getName().asString()
|
||||
val parameterType = if (useHeuristicSignatures)
|
||||
HeuristicSignatures.correctedParameterType(descriptor, argumentIndex, moduleDescriptor, callElement.getProject()) ?: parameter.getType()
|
||||
else
|
||||
parameter.getType()
|
||||
expectedInfos.add(PositionalArgumentExpectedInfo(parameterType, expectedName, tail, descriptor, argumentIndex))
|
||||
expectedInfos.add(PositionalArgumentExpectedInfo(parameterType, expectedName, tail, descriptor, parameterIndex))
|
||||
}
|
||||
}
|
||||
return expectedInfos
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ private fun needExplicitParameterTypes(context: InsertionContext, placeholderRan
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
|
||||
val file = context.getFile() as JetFile
|
||||
val expression = PsiTreeUtil.findElementOfClassAtRange(file, placeholderRange.getStartOffset(), placeholderRange.getEndOffset(), javaClass<JetExpression>())
|
||||
if (expression == null) return false
|
||||
?: return false
|
||||
|
||||
val resolutionFacade = file.getResolutionFacade()
|
||||
val bindingContext = resolutionFacade.analyze(expression, BodyResolveMode.PARTIAL)
|
||||
|
||||
+4
-4
@@ -47,15 +47,15 @@ class MultipleArgumentsItemProvider(val bindingContext: BindingContext,
|
||||
|
||||
val added = HashSet<String>()
|
||||
for (expectedInfo in expectedInfos) {
|
||||
if (expectedInfo is PositionalArgumentExpectedInfo && expectedInfo.argumentIndex == 0) {
|
||||
if (expectedInfo is PositionalArgumentExpectedInfo && expectedInfo.parameterIndex == 0) {
|
||||
val parameters = expectedInfo.function.getValueParameters()
|
||||
if (parameters.size > 1) {
|
||||
if (parameters.size() > 1) {
|
||||
val variables = ArrayList<VariableDescriptor>()
|
||||
for ((i, parameter) in parameters.withIndices()) {
|
||||
for ((i, parameter) in parameters.withIndex()) {
|
||||
val variable = variableInScope(parameter, resolutionScope) ?: break
|
||||
variables.add(variable) // TODO: cannot inline variable because of KT-5890
|
||||
|
||||
if (i > 0 && parameters.stream().drop(i + 1).all { it.hasDefaultValue() }) { // this is the last parameter or all others have default values
|
||||
if (i > 0 && parameters.asSequence().drop(i + 1).all { it.hasDefaultValue() }) { // this is the last parameter or all others have default values
|
||||
val lookupElement = createParametersLookupElement(variables)
|
||||
if (added.add(lookupElement.getLookupString())) { // check that we don't already have item with the same text
|
||||
collection.add(lookupElement)
|
||||
|
||||
@@ -17,34 +17,28 @@
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
|
||||
import com.intellij.codeInsight.completion.InsertHandler
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.completion.InsertionContext
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import java.util.HashSet
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import com.intellij.openapi.util.Key
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.completion.*
|
||||
import org.jetbrains.kotlin.idea.completion.handlers.WithTailInsertHandler
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetValueArgument
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
import org.jetbrains.kotlin.idea.util.FuzzyType
|
||||
import org.jetbrains.kotlin.idea.util.makeNotNullable
|
||||
import org.jetbrains.kotlin.idea.util.nullability
|
||||
import org.jetbrains.kotlin.idea.util.TypeNullability
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import java.util.HashSet
|
||||
|
||||
class ArtificialElementInsertHandler(
|
||||
val textBeforeCaret: String, val textAfterCaret: String, val shortenRefs: Boolean) : InsertHandler<LookupElement>{
|
||||
@@ -95,6 +89,32 @@ fun LookupElement.addTail(tail: Tail?): LookupElement {
|
||||
}
|
||||
}
|
||||
|
||||
fun LookupElement.withOptions(options: ItemOptions): LookupElement {
|
||||
var lookupElement = this
|
||||
if (options.starPrefix) {
|
||||
lookupElement = object : LookupElementDecorator<LookupElement>(this) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.setItemText("*" + presentation.getItemText())
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
getDelegate().handleInsert(context)
|
||||
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
|
||||
|
||||
val offset = context.getStartOffset()
|
||||
val token = context.getFile().findElementAt(offset)!!
|
||||
val argument = token.getStrictParentOfType<JetValueArgument>()
|
||||
if (argument != null) {
|
||||
context.getDocument().insertString(argument.getTextRange().getStartOffset(), "*")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lookupElement
|
||||
}
|
||||
|
||||
fun LookupElement.addTailAndNameSimilarity(matchedExpectedInfos: Collection<ExpectedInfo>): LookupElement {
|
||||
val lookupElement = addTail(mergeTails(matchedExpectedInfos.map { it.tail }))
|
||||
val similarity = calcNameSimilarity(lookupElement.getLookupString(), matchedExpectedInfos)
|
||||
@@ -113,14 +133,14 @@ class ExpectedInfoClassification private(val substitutor: TypeSubstitutor?, val
|
||||
}
|
||||
|
||||
fun Collection<FuzzyType>.classifyExpectedInfo(expectedInfo: ExpectedInfo): ExpectedInfoClassification {
|
||||
val stream = stream()
|
||||
val substitutor = stream.map { it.checkIsSubtypeOf(expectedInfo.type) }.firstOrNull()
|
||||
val sequence = asSequence()
|
||||
val substitutor = sequence.map { it.checkIsSubtypeOf(expectedInfo.type) }.firstOrNull()
|
||||
if (substitutor != null) {
|
||||
return ExpectedInfoClassification.matches(substitutor)
|
||||
}
|
||||
|
||||
if (stream.any { it.nullability() == TypeNullability.NULLABLE }) {
|
||||
val substitutor2 = stream.map { it.makeNotNullable().checkIsSubtypeOf(expectedInfo.type) }.firstOrNull()
|
||||
if (sequence.any { it.nullability() == TypeNullability.NULLABLE }) {
|
||||
val substitutor2 = sequence.map { it.makeNotNullable().checkIsSubtypeOf(expectedInfo.type) }.firstOrNull()
|
||||
if (substitutor2 != null) {
|
||||
return ExpectedInfoClassification.matchesIfNotNullable(substitutor2)
|
||||
}
|
||||
@@ -137,36 +157,37 @@ fun<TDescriptor: DeclarationDescriptor?> MutableCollection<LookupElement>.addLoo
|
||||
infoClassifier: (ExpectedInfo) -> ExpectedInfoClassification,
|
||||
lookupElementFactory: (TDescriptor) -> LookupElement?
|
||||
) {
|
||||
class DescriptorWrapper(val descriptor: TDescriptor) {
|
||||
override fun equals(other: Any?) = other is DescriptorWrapper && descriptorsEqualWithSubstitution(this.descriptor, other.descriptor)
|
||||
class ItemData(val descriptor: TDescriptor, val itemOptions: ItemOptions) {
|
||||
override fun equals(other: Any?)
|
||||
= other is ItemData && descriptorsEqualWithSubstitution(this.descriptor, other.descriptor) && itemOptions == other.itemOptions
|
||||
override fun hashCode() = if (this.descriptor != null) this.descriptor.getOriginal().hashCode() else 0
|
||||
}
|
||||
fun TDescriptor.wrap() = DescriptorWrapper(this)
|
||||
fun DescriptorWrapper.unwrap() = this.descriptor
|
||||
|
||||
val matchedInfos = HashMap<DescriptorWrapper, MutableList<ExpectedInfo>>()
|
||||
val makeNullableInfos = HashMap<DescriptorWrapper, MutableList<ExpectedInfo>>()
|
||||
fun ItemData.createLookupElement() = lookupElementFactory(this.descriptor)?.withOptions(this.itemOptions)
|
||||
|
||||
val matchedInfos = HashMap<ItemData, MutableList<ExpectedInfo>>()
|
||||
val makeNullableInfos = HashMap<ItemData, MutableList<ExpectedInfo>>()
|
||||
for (info in expectedInfos) {
|
||||
val classification = infoClassifier(info)
|
||||
if (classification.substitutor != null) {
|
||||
[suppress("UNCHECKED_CAST")]
|
||||
val substitutedDescriptor = descriptor?.substitute(classification.substitutor) as TDescriptor
|
||||
val map = if (classification.makeNotNullable) makeNullableInfos else matchedInfos
|
||||
map.getOrPut(substitutedDescriptor.wrap()) { ArrayList() }.add(info)
|
||||
map.getOrPut(ItemData(substitutedDescriptor, info.itemOptions)) { ArrayList() }.add(info)
|
||||
}
|
||||
}
|
||||
|
||||
if (!matchedInfos.isEmpty()) {
|
||||
for ((substitutedDescriptor, infos) in matchedInfos) {
|
||||
val lookupElement = lookupElementFactory(substitutedDescriptor.unwrap())
|
||||
for ((itemData, infos) in matchedInfos) {
|
||||
val lookupElement = itemData.createLookupElement()
|
||||
if (lookupElement != null) {
|
||||
add(lookupElement.addTailAndNameSimilarity(infos))
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ((substitutedDescriptor, infos) in makeNullableInfos) {
|
||||
addLookupElementsForNullable({ lookupElementFactory(substitutedDescriptor.unwrap()) }, infos)
|
||||
for ((itemData, infos) in makeNullableInfos) {
|
||||
addLookupElementsForNullable({ itemData.createLookupElement() }, infos)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,7 +203,7 @@ private fun lookupElementsForNullable(factory: () -> LookupElement?): Collection
|
||||
|
||||
var lookupElement = factory()
|
||||
if (lookupElement != null) {
|
||||
lookupElement = object: LookupElementDecorator<LookupElement>(lookupElement!!) {
|
||||
lookupElement = object: LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.setItemText("!! " + presentation.getItemText())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
fun List<S<caret>>foo() {}
|
||||
|
||||
// ELEMENT: String
|
||||
// TAIL_TEXT: "(kotlin)"
|
||||
// TAIL_TEXT: " (kotlin)"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
fun List<String<caret>>foo() {}
|
||||
|
||||
// ELEMENT: String
|
||||
// TAIL_TEXT: "(kotlin)"
|
||||
// TAIL_TEXT: " (kotlin)"
|
||||
|
||||
@@ -5,4 +5,4 @@ class Pair<T1, T2>
|
||||
private val v = ArrayList<Pair<Str<caret>>>
|
||||
|
||||
// ELEMENT: String
|
||||
// TAIL_TEXT: "(kotlin)"
|
||||
// TAIL_TEXT: " (kotlin)"
|
||||
|
||||
@@ -5,4 +5,4 @@ class Pair<T1, T2>
|
||||
private val v = ArrayList<Pair<String<caret>>>
|
||||
|
||||
// ELEMENT: String
|
||||
// TAIL_TEXT: "(kotlin)"
|
||||
// TAIL_TEXT: " (kotlin)"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
|
||||
|
||||
fun foo() {
|
||||
val pair = 1 <caret>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
|
||||
|
||||
fun foo() {
|
||||
val pair = 1 to <caret>
|
||||
}
|
||||
|
||||
@@ -6,3 +6,5 @@ fun foo(p: HashMap<String, List<Int>>){}
|
||||
fun f(){
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: HashMap
|
||||
|
||||
@@ -6,3 +6,5 @@ fun foo(p: HashMap<String, List<Int>>){}
|
||||
fun f(){
|
||||
foo(HashMap<String, List<Int>>())
|
||||
}
|
||||
|
||||
// ELEMENT: HashMap
|
||||
|
||||
@@ -5,3 +5,5 @@ class X<T> {
|
||||
foo(<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: HashMap
|
||||
|
||||
@@ -8,3 +8,5 @@ class X<T> {
|
||||
foo(HashMap<File, T>(<caret>))
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: HashMap
|
||||
|
||||
@@ -5,3 +5,5 @@ class X<T> {
|
||||
foo(<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: HashMap
|
||||
|
||||
@@ -9,3 +9,5 @@ class X<T> {
|
||||
foo(HashMap<T, AbstractMap<T, File>>(<caret>))
|
||||
}
|
||||
}
|
||||
|
||||
// ELEMENT: HashMap
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(s: String, optional: String = ""){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: s
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(s: String, optional: String = ""){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo(s<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: s
|
||||
@@ -2,5 +2,5 @@ fun foo(){
|
||||
val l : java.util.Calendar = <caret>
|
||||
}
|
||||
|
||||
// ELEMENT_TEXT: Calendar.getInstance
|
||||
// TAIL_TEXT: (TimeZone!)
|
||||
// ELEMENT_TEXT: "Calendar.getInstance"
|
||||
// TAIL_TEXT: "(TimeZone!) (java.util)"
|
||||
|
||||
@@ -4,5 +4,5 @@ fun foo(){
|
||||
val l : java.util.Calendar = Calendar.getInstance(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT_TEXT: Calendar.getInstance
|
||||
// TAIL_TEXT: (TimeZone!)
|
||||
// ELEMENT_TEXT: "Calendar.getInstance"
|
||||
// TAIL_TEXT: "(TimeZone!) (java.util)"
|
||||
|
||||
@@ -7,4 +7,4 @@ fun bar() {
|
||||
}
|
||||
|
||||
// ELEMENT_TEXT: "?: getString"
|
||||
// TAIL_TEXT: "(i: Int)"
|
||||
// TAIL_TEXT: "(i: Int) (<root>)"
|
||||
|
||||
@@ -7,4 +7,4 @@ fun bar() {
|
||||
}
|
||||
|
||||
// ELEMENT_TEXT: "?: getString"
|
||||
// TAIL_TEXT: "(i: Int)"
|
||||
// TAIL_TEXT: "(i: Int) (<root>)"
|
||||
|
||||
@@ -9,4 +9,4 @@ fun foo(){
|
||||
}
|
||||
|
||||
// ELEMENT_TEXT: "!! K.bar"
|
||||
// TAIL_TEXT: "()"
|
||||
// TAIL_TEXT: "() (<root>)"
|
||||
|
||||
@@ -9,4 +9,4 @@ fun foo(){
|
||||
}
|
||||
|
||||
// ELEMENT_TEXT: "!! K.bar"
|
||||
// TAIL_TEXT: "()"
|
||||
// TAIL_TEXT: "() (<root>)"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var a : Runnable = <caret>
|
||||
|
||||
// ELEMENT_TEXT: Runnable
|
||||
// TAIL_TEXT: "()"
|
||||
// TAIL_TEXT: "(function: () -> Unit) (java.lang)"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var a : Runnable = Runnable { <caret> }
|
||||
|
||||
// ELEMENT_TEXT: Runnable
|
||||
// TAIL_TEXT: "()"
|
||||
// TAIL_TEXT: "(function: () -> Unit) (java.lang)"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: s
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo(s<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: s
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo("", <caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: s
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo("", s<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: s
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String, options: Int = 0){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo("", <caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: s
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String, options: Int = 0){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo("", s<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: s
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(arr: Array<String>){
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: arr
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(arr: Array<String>){
|
||||
foo(*arr)<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: arr
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(list: List<String>){
|
||||
foo(list.<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: toTypedArray
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(list: List<String>){
|
||||
foo(*list.toTypedArray())<caret>
|
||||
}
|
||||
|
||||
// ELEMENT: toTypedArray
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String, optional: String = ""){ }
|
||||
|
||||
fun bar(arr: Array<String>){
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: arr
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String, optional: String = ""){ }
|
||||
|
||||
fun bar(arr: Array<String>){
|
||||
foo(*arr<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: arr
|
||||
@@ -0,0 +1,8 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(s: String, arr: Array<String>){
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// EXIST: s
|
||||
// EXIST: { lookupString: "arr", itemText: "*arr" }
|
||||
@@ -0,0 +1,9 @@
|
||||
fun foo(vararg strings: String){ }
|
||||
|
||||
fun bar(s: String, arr: Array<String>){
|
||||
foo("", <caret>)
|
||||
}
|
||||
|
||||
// EXIST: s
|
||||
// ABSENT: arr
|
||||
// ABSENT: *arr
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg strings: String, options: Int = 0){ }
|
||||
|
||||
fun bar(s: String){
|
||||
foo("", <caret>)
|
||||
}
|
||||
|
||||
// EXIST: s
|
||||
@@ -0,0 +1,9 @@
|
||||
fun foo(vararg args: Any){ }
|
||||
|
||||
fun bar(s: String, arr: Array<String>){
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// EXIST: s
|
||||
// EXIST: { lookupString: "arr", itemText: "arr" }
|
||||
// EXIST: { lookupString: "arr", itemText: "*arr" }
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(vararg xFooBars: String){}
|
||||
|
||||
fun g(a: String, bar: String, fooBar: String, xFooBars: Array<String>) {
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ORDER: xFooBars, fooBar, bar, a
|
||||
+24
@@ -371,6 +371,30 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg1.kt")
|
||||
public void testVararg1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/Vararg1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg2.kt")
|
||||
public void testVararg2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/Vararg2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg3.kt")
|
||||
public void testVararg3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/Vararg3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg4.kt")
|
||||
public void testVararg4() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/Vararg4.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("VariableAsFunction1.kt")
|
||||
public void testVariableAsFunction1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/VariableAsFunction1.kt");
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.idea.completion.test.handlers
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionType
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.idea.test.JetLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import java.io.File
|
||||
|
||||
@@ -61,7 +61,7 @@ public abstract class AbstractCompletionHandlerTest(private val defaultCompletio
|
||||
fixture.configureByFile(testPath)
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor() = JetLightProjectDescriptor.INSTANCE
|
||||
override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||
}
|
||||
|
||||
public abstract class AbstractBasicCompletionHandlerTest() : AbstractCompletionHandlerTest(CompletionType.BASIC)
|
||||
|
||||
+6
-6
@@ -61,7 +61,7 @@ public class BasicCompletionHandlerTest : CompletionHandlerTestBase(){
|
||||
|
||||
fun testDoNotInsertImportIfResolvedIntoJavaConstructor() = doTest()
|
||||
|
||||
fun testNonStandardArray() = doTest(2, "Array", "java.lang.reflect", '\n')
|
||||
fun testNonStandardArray() = doTest(2, "Array", " (java.lang.reflect)", '\n')
|
||||
|
||||
fun testNoParamsFunction() = doTest()
|
||||
|
||||
@@ -89,15 +89,15 @@ public class BasicCompletionHandlerTest : CompletionHandlerTestBase(){
|
||||
|
||||
fun testHigherOrderFunction() = doTest()
|
||||
|
||||
fun testInsertFqnForJavaClass() = doTest(2, "SortedSet", "java.util", '\n')
|
||||
fun testInsertFqnForJavaClass() = doTest(2, "SortedSet", "<E> (java.util)", '\n')
|
||||
|
||||
fun testHigherOrderFunctionWithArg() = doTest(2, "filterNot", null, '\n')
|
||||
|
||||
fun testHigherOrderFunctionWithArgs1() = doTest(1, "foo", "foo", " { String, Char -> ... }", '\n')
|
||||
fun testHigherOrderFunctionWithArgs1() = doTest(1, "foo", "foo", " { String, Char -> ... } (<root>)", '\n')
|
||||
|
||||
fun testHigherOrderFunctionWithArgs2() = doTest(1, "foo", "foo", "(p: (String, Char) -> Boolean)", '\n')
|
||||
fun testHigherOrderFunctionWithArgs2() = doTest(1, "foo", "foo", "(p: (String, Char) -> Boolean) (<root>)", '\n')
|
||||
|
||||
fun testHigherOrderFunctionWithArgs3() = doTest(1, "foo", "foo", " { String, Char -> ... }", '\n')
|
||||
fun testHigherOrderFunctionWithArgs3() = doTest(1, "foo", "foo", " { String, Char -> ... } (<root>)", '\n')
|
||||
|
||||
fun testForceParenthesisForTabChar() = doTest(0, "some", null, '\t')
|
||||
|
||||
@@ -170,7 +170,7 @@ public class BasicCompletionHandlerTest : CompletionHandlerTestBase(){
|
||||
fun testTypeArgOfSuper() = doTest(1, "X", null, '\n')
|
||||
|
||||
fun testKeywordClassName() = doTest(1, "class", null, '\n')
|
||||
fun testKeywordFunctionName() = doTest(1, "fun", "fun", "()", '\n')
|
||||
fun testKeywordFunctionName() = doTest(1, "fun", "fun", "() (test)", '\n')
|
||||
|
||||
fun testInfixCall() = doTest(1, "to", null, null, '\n')
|
||||
fun testInfixCallOnSpace() = doTest(1, "to", null, null, ' ')
|
||||
|
||||
+12
-8
@@ -25,9 +25,10 @@ import com.intellij.codeInsight.lookup.impl.LookupImpl
|
||||
import com.intellij.openapi.application.Result
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture
|
||||
import org.jetbrains.kotlin.idea.completion.test.ExpectedCompletionUtils
|
||||
import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.test.JetTestUtils
|
||||
import org.junit.Assert
|
||||
import kotlin.test.fail
|
||||
|
||||
public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTestCase() {
|
||||
protected val fixture: JavaCodeInsightTestFixture
|
||||
@@ -55,8 +56,7 @@ public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTe
|
||||
}
|
||||
|
||||
private fun getExistentLookupElement(lookupString: String?, itemText: String?, tailText: String?): LookupElement? {
|
||||
val lookup = LookupManager.getInstance(getProject())?.getActiveLookup() as LookupImpl?
|
||||
if (lookup == null) return null
|
||||
val lookup = LookupManager.getInstance(getProject())?.getActiveLookup() as LookupImpl? ?: return null
|
||||
val items = lookup.getItems()
|
||||
|
||||
if (lookupString == "*") {
|
||||
@@ -68,14 +68,14 @@ public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTe
|
||||
var foundElement : LookupElement? = null
|
||||
val presentation = LookupElementPresentation()
|
||||
for (lookupElement in items) {
|
||||
val lookupOk = if (lookupString != null) lookupElement.getLookupString().contains(lookupString) else true
|
||||
val lookupOk = if (lookupString != null) lookupElement.getLookupString() == lookupString else true
|
||||
|
||||
if (lookupOk) {
|
||||
lookupElement.renderElement(presentation)
|
||||
|
||||
val textOk = if (itemText != null) {
|
||||
val itemItemText = presentation.getItemText()
|
||||
itemItemText != null && itemItemText.contains(itemText)
|
||||
itemItemText != null && itemItemText == itemText
|
||||
}
|
||||
else {
|
||||
true
|
||||
@@ -84,7 +84,7 @@ public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTe
|
||||
if (textOk) {
|
||||
val tailOk = if (tailText != null) {
|
||||
val itemTailText = presentation.getTailText()
|
||||
itemTailText != null && itemTailText.contains(tailText)
|
||||
itemTailText != null && itemTailText == tailText
|
||||
}
|
||||
else {
|
||||
true
|
||||
@@ -92,7 +92,8 @@ public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTe
|
||||
|
||||
if (tailOk) {
|
||||
if (foundElement != null) {
|
||||
Assert.fail("Several elements satisfy to completion restrictions: \n $foundElement\n $lookupElement")
|
||||
val dump = ExpectedCompletionUtils.listToString(ExpectedCompletionUtils.getItemsInformation(arrayOf(foundElement, lookupElement)))
|
||||
fail("Several elements satisfy to completion restrictions:\n$dump")
|
||||
}
|
||||
|
||||
foundElement = lookupElement
|
||||
@@ -101,7 +102,10 @@ public abstract class CompletionHandlerTestBase() : JetLightCodeInsightFixtureTe
|
||||
}
|
||||
}
|
||||
|
||||
if (foundElement == null) error("No element satisfy completion restrictions")
|
||||
if (foundElement == null) {
|
||||
val dump = ExpectedCompletionUtils.listToString(ExpectedCompletionUtils.getItemsInformation(items.toTypedArray()))
|
||||
error("No element satisfy completion restrictions in:\n$dump")
|
||||
}
|
||||
return foundElement
|
||||
}
|
||||
|
||||
|
||||
+42
@@ -293,6 +293,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DefaultParams.kt")
|
||||
public void testDefaultParams() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/DefaultParams.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DoNotEraseBraceOnTab.kt")
|
||||
public void testDoNotEraseBraceOnTab() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/DoNotEraseBraceOnTab.kt");
|
||||
@@ -647,6 +653,42 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg1.kt")
|
||||
public void testVararg1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/Vararg1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg2.kt")
|
||||
public void testVararg2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/Vararg2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg3.kt")
|
||||
public void testVararg3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/Vararg3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg4.kt")
|
||||
public void testVararg4() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/Vararg4.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg5.kt")
|
||||
public void testVararg5() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/Vararg5.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Vararg6.kt")
|
||||
public void testVararg6() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/Vararg6.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("WhenElse.kt")
|
||||
public void testWhenElse() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/WhenElse.kt");
|
||||
|
||||
+6
@@ -167,6 +167,12 @@ public class SmartCompletionWeigherTestGenerated extends AbstractSmartCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NameSimilarityForVararg.kt")
|
||||
public void testNameSimilarityForVararg() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/smart/NameSimilarityForVararg.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NameSimilarityInImplicitlyTypedVarInitializer.kt")
|
||||
public void testNameSimilarityInImplicitlyTypedVarInitializer() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/smart/NameSimilarityInImplicitlyTypedVarInitializer.kt");
|
||||
|
||||
Reference in New Issue
Block a user