KT-4908 Smart completion does not work for arguments of function with vararg

#KT-4908 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-05-06 18:33:52 +03:00
parent 4c315b6219
commit 2adf0a3e9a
49 changed files with 369 additions and 93 deletions
@@ -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
@@ -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)
@@ -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
@@ -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");
@@ -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)
@@ -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, ' ')
@@ -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
}
@@ -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");
@@ -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");