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