Competion in debugger for runtime receiver type should not show members grayed

This commit is contained in:
Valentin Kipyatkov
2015-10-28 21:49:21 +03:00
parent af441d32b1
commit 4ab2019da4
27 changed files with 168 additions and 92 deletions
@@ -94,7 +94,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
private val smartCompletion = expression?.let {
SmartCompletion(
it, resolutionFacade, bindingContext, moduleDescriptor, isVisibleFilter, prefixMatcher,
GlobalSearchScope.EMPTY_SCOPE, toFromOriginalFileMapper, lookupElementFactory, callTypeAndReceiver,
GlobalSearchScope.EMPTY_SCOPE, toFromOriginalFileMapper, callTypeAndReceiver,
isJvmModule, forBasicCompletion = true
)
}
@@ -197,7 +197,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
if (completionKind != CompletionKind.NAMED_ARGUMENTS_ONLY) {
if (smartCompletion != null) {
val (additionalItems, @Suppress("UNUSED_VARIABLE") inheritanceSearcher) = smartCompletion.additionalItems()
val (additionalItems, @Suppress("UNUSED_VARIABLE") inheritanceSearcher) = smartCompletion.additionalItems(lookupElementFactory)
// all additional items should have SMART_COMPLETION_ITEM_PRIORITY_KEY to be recognized by SmartCompletionInBasicWeigher
for (item in additionalItems) {
@@ -211,8 +211,8 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
referenceVariants?.let {
val (imported, notImported) = it
collector.addDescriptorElements(imported)
collector.addDescriptorElements(notImported, notImported = true)
collector.addDescriptorElements(imported, lookupElementFactory)
collector.addDescriptorElements(notImported, lookupElementFactory, notImported = true)
}
completeKeywords()
@@ -243,10 +243,12 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
flushToResultSet()
if (position.getContainingFile() is KtCodeFragment) {
val variants = getRuntimeReceiverTypeReferenceVariants()
if (variants != null) {
collector.addDescriptorElements(variants.imported, withReceiverCast = true)
collector.addDescriptorElements(variants.notImportedExtensions, withReceiverCast = true, notImported = true)
val variantsAndFactory = getRuntimeReceiverTypeReferenceVariants()
if (variantsAndFactory != null) {
val variants = variantsAndFactory.first
val lookupElementFactory = variantsAndFactory.second
collector.addDescriptorElements(variants.imported, lookupElementFactory, withReceiverCast = true)
collector.addDescriptorElements(variants.notImportedExtensions, lookupElementFactory, withReceiverCast = true, notImported = true)
flushToResultSet()
}
}
@@ -380,7 +382,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
private fun completeNonImported() {
if (shouldCompleteTopLevelCallablesFromIndex()) {
collector.addDescriptorElements(getTopLevelCallables(), notImported = true)
collector.addDescriptorElements(getTopLevelCallables(), lookupElementFactory, notImported = true)
}
val classKindFilter: ((ClassKind) -> Boolean)?
@@ -143,7 +143,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
// LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes
protected val collector: LookupElementsCollector by lazy(LazyThreadSafetyMode.NONE) {
LookupElementsCollector(prefixMatcher, parameters, resultSet, lookupElementFactory, createSorter())
LookupElementsCollector(prefixMatcher, parameters, resultSet, createSorter())
}
protected val originalSearchScope: GlobalSearchScope = getResolveScope(parameters.getOriginalFile() as KtFile)
@@ -329,7 +329,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
return this
}
protected fun getRuntimeReceiverTypeReferenceVariants(): ReferenceVariants? {
protected fun getRuntimeReceiverTypeReferenceVariants(): Pair<ReferenceVariants, LookupElementFactory>? {
val explicitReceiver = callTypeAndReceiver.receiver as? KtExpression ?: return null
val type = bindingContext.getType(explicitReceiver) ?: return null
if (!TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, type)) return null
@@ -340,7 +340,9 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
val (variants, notImportedExtensions) = collectReferenceVariants(descriptorKindFilter!!, ExpressionReceiver(explicitReceiver, runtimeType))
val filteredVariants = filterVariantsForRuntimeReceiverType(variants, referenceVariants!!.imported)
val filteredNotImportedExtensions = filterVariantsForRuntimeReceiverType(notImportedExtensions, referenceVariants!!.notImportedExtensions)
return ReferenceVariants(filteredVariants, filteredNotImportedExtensions)
val referenceVariants = ReferenceVariants(filteredVariants, filteredNotImportedExtensions)
return Pair(referenceVariants, lookupElementFactory.copy(receiverTypes = listOf(runtimeType)))
}
private fun <TDescriptor : DeclarationDescriptor> filterVariantsForRuntimeReceiverType(
@@ -383,7 +385,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC
protected fun addClassesFromIndex(kindFilter: (ClassKind) -> Boolean) {
AllClassesCompletion(parameters, indicesHelper, prefixMatcher, resolutionFacade, kindFilter)
.collect(
{ descriptor -> collector.addDescriptorElements(descriptor, notImported = true) },
{ descriptor -> collector.addDescriptorElements(descriptor, lookupElementFactory, notImported = true) },
{ javaClass -> collector.addElement(lookupElementFactory.createLookupElementForJavaClass(javaClass), notImported = true) }
)
}
@@ -42,13 +42,14 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
data /* we need copy() */
class LookupElementFactory(
private val resolutionFacade: ResolutionFacade,
private val receiverTypes: Collection<KotlinType>?,
private val callType: CallType<*>?,
private val isInStringTemplateAfterDollar: Boolean,
public val insertHandlerProvider: InsertHandlerProvider,
contextVariablesProvider: () -> Collection<VariableDescriptor>
private val contextVariablesProvider: () -> Collection<VariableDescriptor>
) {
private val basicFactory = BasicLookupElementFactory(resolutionFacade.project, insertHandlerProvider)
@@ -31,7 +31,6 @@ class LookupElementsCollector(
private val prefixMatcher: PrefixMatcher,
private val completionParameters: CompletionParameters,
resultSet: CompletionResultSet,
private val lookupElementFactory: LookupElementFactory,
private val sorter: CompletionSorter
) {
@@ -59,24 +58,28 @@ class LookupElementsCollector(
}
public fun addDescriptorElements(descriptors: Iterable<DeclarationDescriptor>,
lookupElementFactory: LookupElementFactory,
notImported: Boolean = false,
withReceiverCast: Boolean = false
) {
for (descriptor in descriptors) {
addDescriptorElements(descriptor, notImported, withReceiverCast)
addDescriptorElements(descriptor, lookupElementFactory, notImported, withReceiverCast)
}
}
public fun addDescriptorElements(descriptor: DeclarationDescriptor, notImported: Boolean = false, withReceiverCast: Boolean = false) {
run {
var lookupElements = lookupElementFactory.createStandardLookupElementsForDescriptor(descriptor, useReceiverTypes = true)
public fun addDescriptorElements(
descriptor: DeclarationDescriptor,
lookupElementFactory: LookupElementFactory,
notImported: Boolean = false,
withReceiverCast: Boolean = false
) {
var lookupElements = lookupElementFactory.createStandardLookupElementsForDescriptor(descriptor, useReceiverTypes = true)
if (withReceiverCast) {
lookupElements = lookupElements.map { it.withReceiverCast() }
}
addElements(lookupElements, notImported)
if (withReceiverCast) {
lookupElements = lookupElements.map { it.withReceiverCast() }
}
addElements(lookupElements, notImported)
}
public fun addElement(element: LookupElement, notImported: Boolean = false) {
@@ -56,7 +56,6 @@ class SmartCompletion(
private val prefixMatcher: PrefixMatcher,
private val inheritorSearchScope: GlobalSearchScope,
private val toFromOriginalFileMapper: ToFromOriginalFileMapper,
private val lookupElementFactory: LookupElementFactory,
private val callTypeAndReceiver: CallTypeAndReceiver<*, *>,
private val isJvmModule: Boolean,
private val forBasicCompletion: Boolean = false
@@ -83,11 +82,13 @@ class SmartCompletion(
SmartCastCalculator(bindingContext, resolutionFacade.moduleDescriptor, expression, resolutionFacade)
}
public val descriptorFilter: ((DeclarationDescriptor) -> Collection<LookupElement>)?
= { descriptor: DeclarationDescriptor -> filterDescriptor(descriptor).map { postProcess(it) } }.check { expectedInfos.isNotEmpty() }
public val descriptorFilter: ((DeclarationDescriptor, LookupElementFactory) -> Collection<LookupElement>)? =
{ descriptor: DeclarationDescriptor, lookupElementFactory: LookupElementFactory ->
filterDescriptor(descriptor, lookupElementFactory).map { postProcess(it) }
}.check { expectedInfos.isNotEmpty() }
public fun additionalItems(): Pair<Collection<LookupElement>, InheritanceItemsSearcher?> {
val (items, inheritanceSearcher) = additionalItemsNoPostProcess()
public fun additionalItems(lookupElementFactory: LookupElementFactory): Pair<Collection<LookupElement>, InheritanceItemsSearcher?> {
val (items, inheritanceSearcher) = additionalItemsNoPostProcess(lookupElementFactory)
val postProcessedItems = items.map { postProcess(it) }
//TODO: could not use "let" because of KT-8754
val postProcessedSearcher = if (inheritanceSearcher != null)
@@ -152,7 +153,7 @@ class SmartCompletion(
return@lazy emptySet()
}
private fun filterDescriptor(descriptor: DeclarationDescriptor): Collection<LookupElement> {
private fun filterDescriptor(descriptor: DeclarationDescriptor, lookupElementFactory: LookupElementFactory): Collection<LookupElement> {
val callType = callTypeAndReceiver.callType
if (descriptor in descriptorsToSkip) return emptyList()
@@ -165,14 +166,14 @@ class SmartCompletion(
}
if (callTypeAndReceiver is CallTypeAndReceiver.DEFAULT) {
result.addCallableReferenceLookupElements(descriptor)
result.addCallableReferenceLookupElements(descriptor, lookupElementFactory)
}
return result
}
private fun additionalItemsNoPostProcess(): Pair<Collection<LookupElement>, InheritanceItemsSearcher?> {
val asTypePositionItems = buildForAsTypePosition()
private fun additionalItemsNoPostProcess(lookupElementFactory: LookupElementFactory): Pair<Collection<LookupElement>, InheritanceItemsSearcher?> {
val asTypePositionItems = buildForAsTypePosition(lookupElementFactory)
if (asTypePositionItems != null) {
assert(expectedInfos.isEmpty())
return Pair(asTypePositionItems, null)
@@ -320,7 +321,7 @@ class SmartCompletion(
return null
}
private fun MutableCollection<LookupElement>.addCallableReferenceLookupElements(descriptor: DeclarationDescriptor) {
private fun MutableCollection<LookupElement>.addCallableReferenceLookupElements(descriptor: DeclarationDescriptor, lookupElementFactory: LookupElementFactory) {
if (callableTypeExpectedInfo.isEmpty()) return
fun toLookupElement(descriptor: CallableDescriptor): LookupElement? {
@@ -367,7 +368,7 @@ class SmartCompletion(
}
}
private fun buildForAsTypePosition(): Collection<LookupElement>? {
private fun buildForAsTypePosition(lookupElementFactory: LookupElementFactory): Collection<LookupElement>? {
val binaryExpression = ((expression.getParent() as? KtUserType)
?.getParent() as? KtTypeReference)
?.getParent() as? KtBinaryExpressionWithTypeRHS
@@ -50,7 +50,7 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
private val smartCompletion by lazy(LazyThreadSafetyMode.NONE) {
expression?.let {
SmartCompletion(it, resolutionFacade, bindingContext, moduleDescriptor, isVisibleFilter,
prefixMatcher, originalSearchScope, toFromOriginalFileMapper, lookupElementFactory,
prefixMatcher, originalSearchScope, toFromOriginalFileMapper,
callTypeAndReceiver, isJvmModule)
}
}
@@ -67,28 +67,30 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
if (expression != null) {
addFunctionLiteralArgumentCompletions()
val (additionalItems, inheritanceSearcher) = smartCompletion!!.additionalItems()
val (additionalItems, inheritanceSearcher) = smartCompletion!!.additionalItems(lookupElementFactory)
collector.addElements(additionalItems)
if (nameExpression != null) {
val filter = smartCompletion!!.descriptorFilter
if (filter != null) {
val (imported, notImported) = referenceVariants!!
imported.forEach { collector.addElements(filter(it)) }
notImported.forEach { collector.addElements(filter(it), notImported = true) }
imported.forEach { collector.addElements(filter(it, lookupElementFactory)) }
notImported.forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
flushToResultSet()
if (shouldCompleteTopLevelCallablesFromIndex()) {
getTopLevelCallables().forEach { collector.addElements(filter(it), notImported = true) }
getTopLevelCallables().forEach { collector.addElements(filter(it, lookupElementFactory), notImported = true) }
flushToResultSet()
}
if (position.getContainingFile() is KtCodeFragment) {
val variants = getRuntimeReceiverTypeReferenceVariants()
if (variants != null) {
variants.imported.forEach { collector.addElements(filter(it).map { it.withReceiverCast() }) }
variants.notImportedExtensions.forEach { collector.addElements(filter(it).map { it.withReceiverCast() }, notImported = true) }
val variantsAndFactory = getRuntimeReceiverTypeReferenceVariants()
if (variantsAndFactory != null) {
val variants = variantsAndFactory.first
val lookupElementFactory = variantsAndFactory.second
variants.imported.forEach { collector.addElements(filter(it, lookupElementFactory).map { it.withReceiverCast() }) }
variants.notImportedExtensions.forEach { collector.addElements(filter(it, lookupElementFactory).map { it.withReceiverCast() }, notImported = true) }
flushToResultSet()
}
}
@@ -3,6 +3,7 @@ fun foo(o: Any) {
}
// INVOCATION_COUNT: 1
// EXIST: read, write
// EXIST: { itemText: "read", attributes: "bold" }
// EXIST: { itemText: "write", attributes: "bold" }
// RUNTIME_TYPE: java.util.concurrent.locks.ReentrantReadWriteLock
@@ -12,7 +12,11 @@ open class Base {
fun funInBoth() { }
}
class Derived: Base() {
open class Intermediate : Base() {
fun funInIntermediate(){}
}
class Derived : Intermediate() {
fun funInDerived() { }
override fun funWithOverride() { }
@@ -21,12 +25,13 @@ class Derived: Base() {
}
// INVOCATION_COUNT: 1
// EXIST: funInBase
// EXIST: funWithOverride
// EXIST: funWithoutOverride
// EXIST: funInDerived
// EXIST: { itemText: "funInBase", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funWithOverride", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funWithoutOverride", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funInDerived", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funInBoth", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funInBoth", tailText: "(p: Int)", attributes: "grayed" }
// EXIST: { itemText: "funInBoth", tailText: "(p: Int)", attributes: "bold" }
// EXIST: { itemText: "funInIntermediate", tailText: "()", attributes: "" }
// NOTHING_ELSE
@@ -0,0 +1,41 @@
fun main(args: Array<String>) {
val b: Base = Derived()
<caret>val a = 1
}
open class Base {
fun funInBase(): Int = 0
open fun funWithOverride(): Int = 0
open fun funWithoutOverride(): Int = 0
fun funInBoth(): Int = 0
}
open class Intermediate : Base() {
fun funInIntermediate() = 0
}
class Derived : Intermediate() {
fun funInDerived(): Int = 0
override fun funWithOverride(): Int = 0
fun funInBoth(p: Int): Int = 0
fun funWrongType(): String = ""
}
// COMPLETION_TYPE: SMART
// INVOCATION_COUNT: 1
// EXIST: { itemText: "funInBase", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funWithOverride", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funWithoutOverride", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funInDerived", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funInBoth", tailText: "()", attributes: "bold" }
// EXIST: { itemText: "funInBoth", tailText: "(p: Int)", attributes: "bold" }
// EXIST: { itemText: "funInIntermediate", tailText: "()", attributes: "" }
// NOTHING_ELSE
// RUNTIME_TYPE: Derived
@@ -0,0 +1 @@
"".substring(b.fun<caret>)
@@ -24,6 +24,5 @@ public abstract class AbstractCompiledKotlinInJavaCompletionTest : JetFixtureCom
override fun getPlatform() = JvmPlatform
override fun getProjectDescriptor() = JdkAndMockLibraryProjectDescriptor(COMPLETION_TEST_DATA_BASE_PATH + "/injava/mockLib", false)
override fun complete(invocationCount: Int) = myFixture.complete(CompletionType.BASIC, invocationCount)
override fun defaultCompletionType() = CompletionType.BASIC
}
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.testFramework.LightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.js.KotlinJavaScriptLibraryManager;
import org.jetbrains.kotlin.idea.test.KotlinStdJSProjectDescriptor;
import org.jetbrains.kotlin.js.resolve.JsPlatform;
@@ -44,8 +45,9 @@ public abstract class AbstractJSBasicCompletionTest extends JetFixtureCompletion
KotlinJavaScriptLibraryManager.getInstance(getProject()).syncUpdateProjectLibrary();
}
@NotNull
@Override
protected LookupElement[] complete(int invocationCount) {
return myFixture.complete(CompletionType.BASIC, invocationCount);
protected CompletionType defaultCompletionType() {
return CompletionType.BASIC;
}
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.idea.completion.test;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.testFramework.LightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor;
@@ -37,8 +36,9 @@ public abstract class AbstractJvmBasicCompletionTest extends JetFixtureCompletio
return JvmPlatform.INSTANCE$;
}
@NotNull
@Override
protected LookupElement[] complete(int invocationCount) {
return myFixture.complete(CompletionType.BASIC, invocationCount);
protected CompletionType defaultCompletionType() {
return CompletionType.BASIC;
}
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.idea.completion.test;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.testFramework.LightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor;
@@ -37,8 +36,9 @@ public abstract class AbstractJvmSmartCompletionTest extends JetFixtureCompletio
return JvmPlatform.INSTANCE$;
}
@NotNull
@Override
protected LookupElement[] complete(int invocationCount) {
return myFixture.complete(CompletionType.SMART, invocationCount);
protected CompletionType defaultCompletionType() {
return CompletionType.SMART;
}
}
@@ -33,6 +33,5 @@ public abstract class AbstractJvmWithLibBasicCompletionTest : JetFixtureCompleti
}
override fun getPlatform() = JvmPlatform
override fun complete(invocationCount: Int) = myFixture.complete(CompletionType.BASIC, invocationCount)
override fun defaultCompletionType() = CompletionType.BASIC
}
@@ -25,9 +25,11 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
public abstract class AbstractKeywordCompletionTest : JetFixtureCompletionBaseTestCase() {
override fun getPlatform() = JvmPlatform
override fun complete(invocationCount: Int): Array<LookupElement>? {
val items = myFixture.complete(CompletionType.BASIC) ?: return null
return items.filter { it.getObject() is KeywordLookupObject }.toTypedArray()
override fun defaultCompletionType() = CompletionType.BASIC
override fun complete(completionType: CompletionType, invocationCount: Int): Array<LookupElement>? {
val items = myFixture.complete(completionType) ?: return null
return items.filter { it.`object` is KeywordLookupObject }.toTypedArray()
}
override fun getProjectDescriptor() = JetLightProjectDescriptor.INSTANCE
@@ -43,6 +43,5 @@ public abstract class AbstractKotlinSourceInJavaCompletionTest : JetFixtureCompl
}
override fun getProjectDescriptor() = LightCodeInsightFixtureTestCase.JAVA_LATEST
override fun complete(invocationCount: Int) = myFixture.complete(CompletionType.BASIC, invocationCount)
override fun defaultCompletionType() = CompletionType.BASIC
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.completion.test
import com.intellij.codeInsight.completion.CompletionType
import org.jetbrains.kotlin.idea.test.AstAccessControl
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
@@ -24,10 +25,11 @@ public abstract class AbstractMultiFileJvmBasicCompletionTest : KotlinCompletion
configureByFile(getTestName(false) + ".kt", "")
val shouldFail = testPath.contains("NoSpecifiedType")
AstAccessControl.testWithControlledAccessToAst(shouldFail, getFile().getVirtualFile(), getProject(), getTestRootDisposable(), {
testCompletion(getFile().getText(), JvmPlatform, { invocationCount ->
testCompletion(getFile().getText(), JvmPlatform, { completionType, invocationCount ->
setType(completionType)
complete(invocationCount)
myItems
}, 0)
}, CompletionType.BASIC, 0)
})
}
@@ -29,10 +29,11 @@ public abstract class AbstractMultiFileSmartCompletionTest : KotlinCompletionTes
protected fun doTest(testPath: String) {
configureByFile(getTestName(false) + ".kt", "")
AstAccessControl.testWithControlledAccessToAst(false, getFile().getVirtualFile(), getProject(), getTestRootDisposable(), {
testCompletion(getFile().getText(), JvmPlatform, { invocationCount ->
testCompletion(getFile().getText(), JvmPlatform, { completionType, invocationCount ->
setType(completionType)
complete(invocationCount)
myItems
}, 1)
}, CompletionType.SMART, 1)
})
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.completion.test
import com.intellij.codeInsight.CodeInsightSettings
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInsight.lookup.LookupElement
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.test.JetTestUtils
@@ -26,10 +27,11 @@ val RELATIVE_COMPLETION_TEST_DATA_BASE_PATH = "idea/idea-completion/testData"
val COMPLETION_TEST_DATA_BASE_PATH = JetTestUtils.getHomeDirectory() + "/" + RELATIVE_COMPLETION_TEST_DATA_BASE_PATH
fun testCompletion(fileText: String, platform: TargetPlatform?, complete: (Int) -> Array<LookupElement>?, defaultInvocationCount: Int = 0) {
fun testCompletion(fileText: String, platform: TargetPlatform?, complete: (CompletionType, Int) -> Array<LookupElement>?, defaultCompletionType: CompletionType = CompletionType.BASIC, defaultInvocationCount: Int = 0) {
testWithAutoCompleteSetting(fileText) {
val completionType = ExpectedCompletionUtils.getCompletionType(fileText) ?: defaultCompletionType
val invocationCount = ExpectedCompletionUtils.getInvocationCount(fileText) ?: defaultInvocationCount
val items = complete(invocationCount) ?: emptyArray()
val items = complete(completionType, invocationCount) ?: emptyArray()
ExpectedCompletionUtils.assertDirectivesValid(fileText)
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList
import com.google.gson.JsonNull
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementPresentation
import com.intellij.codeInsight.lookup.impl.LookupCellRenderer
@@ -113,6 +114,8 @@ public object ExpectedCompletionUtils {
public val RUNTIME_TYPE: String = "RUNTIME_TYPE:"
private val COMPLETION_TYPE_PREFIX = "COMPLETION_TYPE:"
public val KNOWN_PREFIXES: List<String> = ImmutableList.of(
EXIST_LINE_PREFIX,
ABSENT_LINE_PREFIX,
@@ -128,6 +131,7 @@ public object ExpectedCompletionUtils {
AUTOCOMPLETE_SETTING_PREFIX,
NOTHING_ELSE_PREFIX,
RUNTIME_TYPE,
COMPLETION_TYPE_PREFIX,
AstAccessControl.ALLOW_AST_ACCESS_DIRECTIVE)
public fun itemsShouldExist(fileText: String, platform: TargetPlatform?): Array<CompletionProposal> {
@@ -186,6 +190,16 @@ public object ExpectedCompletionUtils {
return InTextDirectivesUtils.getPrefixedInt(fileText, INVOCATION_COUNT_PREFIX)
}
public fun getCompletionType(fileText: String): CompletionType? {
val completionTypeString = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_TYPE_PREFIX)
return when (completionTypeString) {
"BASIC" -> CompletionType.BASIC
"SMART" -> CompletionType.SMART
null -> null
else -> error("Unknown completion type: $completionTypeString")
}
}
public fun getAutocompleteSetting(fileText: String): Boolean? {
return InTextDirectivesUtils.getPrefixedBoolean(fileText, AUTOCOMPLETE_SETTING_PREFIX)
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.completion.test
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker
@@ -26,15 +27,17 @@ import java.io.File
public abstract class JetFixtureCompletionBaseTestCase : JetLightCodeInsightFixtureTestCase() {
public abstract fun getPlatform(): TargetPlatform
protected abstract fun complete(invocationCount: Int): Array<LookupElement>?
protected open fun complete(completionType: CompletionType, invocationCount: Int): Array<LookupElement>?
= myFixture.complete(completionType, invocationCount)
protected abstract fun defaultCompletionType(): CompletionType
protected open fun defaultInvocationCount(): Int = 0
public open fun doTest(testPath: String) {
setUpFixture(testPath)
val fileText = FileUtil.loadFile(File(testPath), true)
testCompletion(fileText, getPlatform(), { complete(it) }, defaultInvocationCount())
testCompletion(fileText, getPlatform(), { completionType, count -> complete(completionType, count) }, defaultCompletionType(), defaultInvocationCount())
}
protected open fun setUpFixture(testPath: String) {
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.completion.test.handlers
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import org.jetbrains.kotlin.idea.completion.test.ExpectedCompletionUtils
import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.test.InTextDirectivesUtils
@@ -31,7 +32,6 @@ public abstract class AbstractCompletionHandlerTest(private val defaultCompletio
private val ELEMENT_TEXT_PREFIX = "ELEMENT_TEXT:"
private val TAIL_TEXT_PREFIX = "TAIL_TEXT:"
private val COMPLETION_CHAR_PREFIX = "CHAR:"
private val COMPLETION_TYPE_PREFIX = "COMPLETION_TYPE:"
private val CODE_STYLE_SETTING_PREFIX = "CODE_STYLE_SETTING:"
protected open fun doTest(testPath: String) {
@@ -54,13 +54,7 @@ public abstract class AbstractCompletionHandlerTest(private val defaultCompletio
else -> completionCharString.singleOrNull() ?: error("Incorrect completion char: \"$completionCharString\"")
}
val completionTypeString = InTextDirectivesUtils.findStringWithPrefixes(fileText, COMPLETION_TYPE_PREFIX)
val completionType = when (completionTypeString) {
"BASIC" -> CompletionType.BASIC
"SMART" -> CompletionType.SMART
null -> defaultCompletionType
else -> error("Unknown completion type: $completionTypeString")
}
val completionType = ExpectedCompletionUtils.getCompletionType(fileText) ?: defaultCompletionType
val codeStyleSettings = JetCodeStyleSettings.getInstance(getProject())
for (line in InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, CODE_STYLE_SETTING_PREFIX)) {
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.JetTestUtils
import java.io.File
import kotlin.test.fail
public abstract class AbstractCodeFragmentHighlightingTest : AbstractJetPsiCheckerTest() {
override fun doTest(filePath: String) {
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.idea.debugger.evaluate
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.roots.OrderRootType
@@ -68,9 +67,7 @@ public class CodeFragmentCompletionInLibraryTest : AbstractJvmBasicCompletionTes
private fun testCompletionInLibraryCodeFragment(fragmentText: String, vararg completionDirectives: String) {
setupFixtureByCodeFragment(fragmentText)
val directives = completionDirectives.map { "//$it" }.joinToString(separator = "\n")
testCompletion(directives, JvmPlatform, {
myFixture.complete(CompletionType.BASIC)
})
testCompletion(directives, JvmPlatform, { completionType, count -> myFixture.complete(completionType, count) })
}
private fun setupFixtureByCodeFragment(fragmentText: String) {
@@ -126,5 +126,11 @@ public class CodeFragmentCompletionTestGenerated extends AbstractCodeFragmentCom
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/codeFragments/runtimeType/runtimeCast.kt");
doTest(fileName);
}
@TestMetadata("smartCompletion.kt")
public void testSmartCompletion() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/codeFragments/runtimeType/smartCompletion.kt");
doTest(fileName);
}
}
}
@@ -48,9 +48,7 @@ public abstract class AbstractAndroidCompletionTest : KotlinAndroidTestCase() {
val virtualFile = myFixture.copyFileToProject(path + getTestName(true) + ".kt", "src/" + getTestName(true) + ".kt");
myFixture.configureFromExistingVirtualFile(virtualFile)
val fileText = FileUtil.loadFile(File(path + getTestName(true) + ".kt"), true)
testCompletion(fileText, JvmPlatform, {
count -> myFixture.complete(completionType())
})
testCompletion(fileText, JvmPlatform, { completionType, count -> myFixture.complete(completionType, count) })
}