Completion: got rid of special LookupElementFactory implementation to highlight immediate members

This commit is contained in:
Valentin Kipyatkov
2014-12-01 16:22:57 +03:00
parent 66289f0b4a
commit 7c67566719
9 changed files with 101 additions and 92 deletions
@@ -31,13 +31,11 @@ import org.jetbrains.jet.plugin.caches.KotlinIndicesHelper
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
import org.jetbrains.jet.plugin.caches.resolve.ResolutionFacade
import org.jetbrains.jet.lang.resolve.BindingContext
import org.jetbrains.jet.plugin.caches.resolve.ResolutionFacade
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
class AllClassesCompletion(val parameters: CompletionParameters,
val lookupElementFactory: LookupElementFactory,
val resolutionFacade: ResolutionFacade,
val bindingContext: BindingContext,
val moduleDescriptor: ModuleDescriptor,
@@ -75,7 +73,7 @@ class AllClassesCompletion(val parameters: CompletionParameters,
else -> ClassKind.CLASS
}
if (kindFilter(kind)) {
collector.addElementWithAutoInsertionSuppressed(LookupElementFactory.DEFAULT.createLookupElementForJavaClass(psiClass))
collector.addElementWithAutoInsertionSuppressed(lookupElementFactory.createLookupElementForJavaClass(psiClass))
}
}
}
@@ -72,8 +72,8 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
protected val referenceVariantsHelper: ReferenceVariantsHelper?
= if (bindingContext != null) ReferenceVariantsHelper(bindingContext) { isVisibleDescriptor(it) } else null
protected val boldImmediateLookupElementFactory: LookupElementFactory = run {
if (jetReference != null) {
protected val lookupElementFactory: LookupElementFactory = run {
val receiverTypes = if (jetReference != null) {
val expression = jetReference.expression
val (receivers, callType) = referenceVariantsHelper!!.getReferenceVariantsReceivers(expression)
val dataFlowInfo = bindingContext!!.getDataFlowInfo(expression)
@@ -83,14 +83,15 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
if (callType == ReferenceVariantsHelper.CallType.SAFE) {
receiverTypes = receiverTypes.map { it.makeNotNullable() }
}
BoldImmediateLookupElementFactory(receiverTypes)
receiverTypes
}
else {
LookupElementFactory.DEFAULT
null
}
LookupElementFactory(receiverTypes)
}
protected val collector: LookupElementsCollector = LookupElementsCollector(prefixMatcher, parameters, resolutionFacade, boldImmediateLookupElementFactory)
protected val collector: LookupElementsCollector = LookupElementsCollector(prefixMatcher, parameters, resolutionFacade, lookupElementFactory)
protected val project: Project = position.getProject()
@@ -166,7 +167,7 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) {
AllClassesCompletion(
parameters, resolutionFacade, bindingContext!!, moduleDescriptor,
parameters, lookupElementFactory, resolutionFacade, bindingContext!!, moduleDescriptor,
searchScope, prefixMatcher, kindFilter, { isVisibleDescriptor(it) }
).collect(collector)
}
@@ -265,7 +266,7 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para
val mapper = ToFromOriginalFileMapper(parameters.getOriginalFile() as JetFile, position.getContainingFile() as JetFile, parameters.getOffset())
val completion = SmartCompletion(jetReference.expression, resolutionFacade, moduleDescriptor,
bindingContext!!, { isVisibleDescriptor(it) }, originalSearchScope,
mapper, boldImmediateLookupElementFactory)
mapper, lookupElementFactory)
val result = completion.execute()
if (result != null) {
collector.addElements(result.additionalItems)
@@ -39,13 +39,78 @@ import java.awt.Color
import org.jetbrains.jet.lang.types.TypeUtils
import com.intellij.codeInsight.lookup.DefaultLookupItemRenderer
public open class LookupElementFactory protected() {
public open fun createLookupElement(resolutionFacade: ResolutionFacade, descriptor: DeclarationDescriptor): LookupElement {
public class LookupElementFactory(
private val receiverTypes: Collection<JetType>?
) {
public fun createLookupElement(
resolutionFacade: ResolutionFacade,
descriptor: DeclarationDescriptor,
boldImmediateMembers: Boolean
): LookupElement {
val _descriptor = if (descriptor is CallableMemberDescriptor)
DescriptorUtils.unwrapFakeOverride(descriptor)
else
descriptor
return createLookupElement(resolutionFacade, _descriptor, DescriptorToSourceUtils.descriptorToDeclaration(_descriptor))
var element = createLookupElement(resolutionFacade, _descriptor, DescriptorToSourceUtils.descriptorToDeclaration(_descriptor))
if (boldImmediateMembers) {
element = element.boldIfImmediate(descriptor)
}
return element
}
private fun LookupElement.boldIfImmediate(descriptor: DeclarationDescriptor): LookupElement {
if (receiverTypes == null) return this
if (descriptor !is CallableMemberDescriptor) return this
val isReceiverNullable = receiverTypes.all { it.isNullable() }
val receiverParameter = descriptor.getExtensionReceiverParameter()
val style: Style = if (receiverParameter != null) {
val receiverParamType = receiverParameter.getType()
if (isReceiverNullable && !receiverParamType.isNullable())
Style.GRAYED
else if (receiverTypes.any { TypeUtils.equalTypes(it, receiverParamType) })
Style.BOLD
else
Style.NORMAL
}
else {
if (isReceiverNullable)
Style.GRAYED
else if (descriptor.getContainingDeclaration() is ClassifierDescriptor && descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION)
Style.BOLD
else
Style.NORMAL
}
return if (style != Style.NORMAL) {
object : LookupElementDecorator<LookupElement>(this) {
override fun renderElement(presentation: LookupElementPresentation) {
super.renderElement(presentation)
if (style == Style.BOLD) {
presentation.setItemTextBold(true)
}
else {
presentation.setItemTextForeground(Color.GRAY)
// gray all tail fragments too:
val fragments = presentation.getTailFragments()
presentation.clearTail()
for (fragment in fragments) {
presentation.appendTailText(fragment.text, true)
}
}
}
}
}
else {
this
}
}
private enum class Style {
NORMAL
BOLD
GRAYED
}
public fun createLookupElementForJavaClass(psiClass: PsiClass): LookupElement {
@@ -146,8 +211,6 @@ public open class LookupElementFactory protected() {
}
class object {
public val DEFAULT: LookupElementFactory = LookupElementFactory()
public fun getDefaultInsertHandler(descriptor: DeclarationDescriptor): InsertHandler<LookupElement> {
return when (descriptor) {
is FunctionDescriptor -> {
@@ -180,61 +243,3 @@ public open class LookupElementFactory protected() {
}
}
}
public class BoldImmediateLookupElementFactory(private val receiverTypes: Collection<JetType>) : LookupElementFactory() {
override fun createLookupElement(resolutionFacade: ResolutionFacade, descriptor: DeclarationDescriptor): LookupElement {
val element = super.createLookupElement(resolutionFacade, descriptor)
if (descriptor !is CallableMemberDescriptor) return element
val isReceiverNullable = receiverTypes.all { it.isNullable() }
val receiverParameter = descriptor.getExtensionReceiverParameter()
val style: Style = if (receiverParameter != null) {
val receiverParamType = receiverParameter.getType()
if (isReceiverNullable && !receiverParamType.isNullable())
Style.GRAYED
else if (receiverTypes.any { TypeUtils.equalTypes(it, receiverParamType) })
Style.BOLD
else
Style.NORMAL
}
else {
if (isReceiverNullable)
Style.GRAYED
else if (descriptor.getContainingDeclaration() is ClassifierDescriptor && descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION)
Style.BOLD
else
Style.NORMAL
}
return if (style != Style.NORMAL) {
object : LookupElementDecorator<LookupElement>(element) {
override fun renderElement(presentation: LookupElementPresentation) {
super.renderElement(presentation)
if (style == Style.BOLD) {
presentation.setItemTextBold(true)
}
else {
presentation.setItemTextForeground(Color.GRAY)
// gray all tail fragments too:
val fragments = presentation.getTailFragments()
presentation.clearTail()
for (fragment in fragments) {
presentation.appendTailText(fragment.text, true)
}
}
}
}
}
else {
element
}
}
private enum class Style {
NORMAL
BOLD
GRAYED
}
}
@@ -35,7 +35,7 @@ class LookupElementsCollector(
private val prefixMatcher: PrefixMatcher,
private val completionParameters: CompletionParameters,
private val resolutionFacade: ResolutionFacade,
private val boldImmediateLookupElementFactory: LookupElementFactory
private val lookupElementFactory: LookupElementFactory
) {
private val elements = ArrayList<LookupElement>()
@@ -61,11 +61,10 @@ class LookupElementsCollector(
public fun addDescriptorElements(descriptor: DeclarationDescriptor, suppressAutoInsertion: Boolean, shouldCastToRuntimeType: Boolean) {
run {
var lookupElement = boldImmediateLookupElementFactory.createLookupElement(resolutionFacade, descriptor)
var lookupElement = lookupElementFactory.createLookupElement(resolutionFacade, descriptor, true)
if (shouldCastToRuntimeType) {
lookupElement = lookupElement.shouldCastReceiver()
}
if (suppressAutoInsertion) {
addElementWithAutoInsertionSuppressed(lookupElement)
}
@@ -82,7 +81,7 @@ class LookupElementsCollector(
if (KotlinBuiltIns.isFunctionOrExtensionFunctionType(parameterType)) {
val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size()
if (parameterCount > 1) {
val lookupElement = boldImmediateLookupElementFactory.createLookupElement(resolutionFacade, descriptor)
val lookupElement = lookupElementFactory.createLookupElement(resolutionFacade, descriptor, true)
addElement(object : LookupElementDecorator<LookupElement>(lookupElement) {
override fun renderElement(presentation: LookupElementPresentation) {
super.renderElement(presentation)
@@ -52,7 +52,7 @@ object PackageDirectiveCompletion {
val variants = ReferenceVariantsHelper(bindingContext, { true }).getPackageReferenceVariants(ref.expression, prefixMatcher.asNameFilter())
for (variant in variants) {
val lookupElement = LookupElementFactory.DEFAULT.createLookupElement(resolutionFacade, variant)
val lookupElement = LookupElementFactory(null).createLookupElement(resolutionFacade, variant, false)
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
result.addElement(lookupElement)
}
@@ -47,7 +47,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
val inheritorSearchScope: GlobalSearchScope,
val toFromOriginalFileMapper: ToFromOriginalFileMapper,
val boldImmediateLookupElementFactory: LookupElementFactory) {
val lookupElementFactory: LookupElementFactory) {
private val project = expression.getProject()
public class Result(
@@ -133,7 +133,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
else -> ExpectedInfoClassification.NOT_MATCHES
}
}
result.addLookupElements(expectedInfos, classifier, { boldImmediateLookupElementFactory.createLookupElement(descriptor, resolutionFacade, bindingContext) })
result.addLookupElements(expectedInfos, classifier, { lookupElementFactory.createLookupElement(descriptor, resolutionFacade, bindingContext, true) })
if (receiver == null) {
toFunctionReferenceLookupElement(descriptor, functionExpectedInfos)?.let { result.add(it) }
@@ -145,10 +145,10 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
val additionalItems = ArrayList<LookupElement>()
val inheritanceSearchers = ArrayList<InheritanceItemsSearcher>()
if (receiver == null) {
TypeInstantiationItems(resolutionFacade, moduleDescriptor, bindingContext, visibilityFilter, toFromOriginalFileMapper, inheritorSearchScope)
TypeInstantiationItems(resolutionFacade, moduleDescriptor, bindingContext, visibilityFilter, toFromOriginalFileMapper, inheritorSearchScope, lookupElementFactory)
.addTo(additionalItems, inheritanceSearchers, expectedInfos)
StaticMembers(bindingContext, resolutionFacade).addToCollection(additionalItems, expectedInfos, expression, itemsToSkip)
StaticMembers(bindingContext, resolutionFacade, lookupElementFactory).addToCollection(additionalItems, expectedInfos, expression, itemsToSkip)
ThisItems(bindingContext).addToCollection(additionalItems, expressionWithType, expectedInfos)
@@ -262,7 +262,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
val matchedExpectedInfos = functionExpectedInfos.filter { functionType.isSubtypeOf(it.type) }
if (matchedExpectedInfos.isEmpty()) return null
var lookupElement = boldImmediateLookupElementFactory.createLookupElement(descriptor, resolutionFacade, bindingContext)
var lookupElement = lookupElementFactory.createLookupElement(descriptor, resolutionFacade, bindingContext, true)
val text = "::" + (if (descriptor is ConstructorDescriptor) descriptor.getContainingDeclaration().getName() else descriptor.getName())
lookupElement = object: LookupElementDecorator<LookupElement>(lookupElement) {
override fun getLookupString() = text
@@ -321,7 +321,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
if (jetType.isError()) return null
val classifier = jetType.getConstructor().getDeclarationDescriptor() ?: return null
val lookupElement = LookupElementFactory.DEFAULT.createLookupElement(classifier, resolutionFacade, bindingContext)
val lookupElement = lookupElementFactory.createLookupElement(classifier, resolutionFacade, bindingContext, false)
val lookupString = lookupElement.getLookupString()
val typeArgs = jetType.getArguments()
@@ -36,7 +36,11 @@ import org.jetbrains.jet.plugin.caches.resolve.ResolutionFacade
import org.jetbrains.jet.plugin.completion.LookupElementFactory
// adds java static members, enum members and members from class object
class StaticMembers(val bindingContext: BindingContext, val resolutionFacade: ResolutionFacade) {
class StaticMembers(
val bindingContext: BindingContext,
val resolutionFacade: ResolutionFacade,
val lookupElementFactory: LookupElementFactory
) {
public fun addToCollection(collection: MutableCollection<LookupElement>,
expectedInfos: Collection<ExpectedInfo>,
context: JetExpression,
@@ -101,7 +105,7 @@ class StaticMembers(val bindingContext: BindingContext, val resolutionFacade: Re
}
private fun createLookupElement(memberDescriptor: DeclarationDescriptor, classDescriptor: ClassDescriptor): LookupElement {
val lookupElement = LookupElementFactory.DEFAULT.createLookupElement(memberDescriptor, resolutionFacade, bindingContext)
val lookupElement = lookupElementFactory.createLookupElement(memberDescriptor, resolutionFacade, bindingContext, false)
val qualifierPresentation = classDescriptor.getName().asString()
val qualifierText = qualifiedNameForSourceCode(classDescriptor)
@@ -67,7 +67,8 @@ class TypeInstantiationItems(
val bindingContext: BindingContext,
val visibilityFilter: (DeclarationDescriptor) -> Boolean,
val toFromOriginalFileMapper: ToFromOriginalFileMapper,
val inheritorSearchScope: GlobalSearchScope
val inheritorSearchScope: GlobalSearchScope,
val lookupElementFactory: LookupElementFactory
) {
public fun addTo(
items: MutableCollection<LookupElement>,
@@ -132,7 +133,7 @@ class TypeInstantiationItems(
typeArgs: List<TypeProjection>,
tail: Tail?
): LookupElement? {
var lookupElement = LookupElementFactory.DEFAULT.createLookupElement(classifier, resolutionFacade, bindingContext)
var lookupElement = lookupElementFactory.createLookupElement(classifier, resolutionFacade, bindingContext, false)
if (classifier.getKind() == ClassKind.OBJECT) {
return lookupElement.addTail(tail)
@@ -259,7 +260,7 @@ class TypeInstantiationItems(
val samConstructor = scope.getFunctions(`class`.getName())
.filterIsInstance<SamConstructorDescriptor>()
.singleOrNull() ?: return
val lookupElement = LookupElementFactory.DEFAULT.createLookupElement(samConstructor, resolutionFacade, bindingContext)
val lookupElement = lookupElementFactory.createLookupElement(samConstructor, resolutionFacade, bindingContext, false)
.assignSmartCompletionPriority(SmartCompletionItemPriority.INSTANTIATION)
.addTail(tail)
collection.add(lookupElement)
@@ -189,9 +189,10 @@ fun functionType(function: FunctionDescriptor): JetType? {
fun LookupElementFactory.createLookupElement(
descriptor: DeclarationDescriptor,
resolutionFacade: ResolutionFacade,
bindingContext: BindingContext
bindingContext: BindingContext,
boldImmediateMembers: Boolean
): LookupElement {
var element = createLookupElement(resolutionFacade, descriptor)
var element = createLookupElement(resolutionFacade, descriptor, boldImmediateMembers)
if (descriptor is FunctionDescriptor && descriptor.getValueParameters().isNotEmpty()) {
element = element.keepOldArgumentListOnTab()