Completion: bold members from immediate class

This commit is contained in:
Valentin Kipyatkov
2014-11-14 23:06:09 +03:00
parent 79cfe2bac4
commit d061c3d771
21 changed files with 251 additions and 24 deletions
@@ -18,6 +18,8 @@ package org.jetbrains.jet.lang.resolve.calls.smartcasts;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetExpression;
@@ -65,6 +67,26 @@ public class SmartCastUtils {
return variants;
}
@NotNull
public static List<JetType> getSmartCastVariantsWithLessSpecificExcluded(
@NotNull ReceiverValue receiverToCast,
@NotNull BindingContext bindingContext,
@NotNull DataFlowInfo dataFlowInfo
) {
final List<JetType> variants = getSmartCastVariants(receiverToCast, bindingContext, dataFlowInfo);
return KotlinPackage.filter(variants, new Function1<JetType, Boolean>() {
@Override
public Boolean invoke(final JetType type) {
return !KotlinPackage.any(variants, new Function1<JetType, Boolean>() {
@Override
public Boolean invoke(JetType another) {
return another != type && JetTypeChecker.DEFAULT.isSubtypeOf(another, type);
}
});
}
});
}
/**
* @return variants @param receiverToCast may be cast to according to @param dataFlowInfo, @param receiverToCast itself is NOT included
*/
@@ -80,7 +80,7 @@ public object TipsManager{
val dataFlowInfo = context.getDataFlowInfo(expression)
val mask = kindFilter.withoutKinds(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK).exclude(DescriptorKindExclude.Extensions)
for (variant in SmartCastUtils.getSmartCastVariants(receiverValue, context, dataFlowInfo)) {
for (variant in SmartCastUtils.getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, dataFlowInfo)) {
variant.getMemberScope().getDescriptorsFiltered(mask, nameFilter).filterTo(descriptors, ::filterIfInfix)
}
@@ -35,19 +35,25 @@ import org.jetbrains.jet.lang.resolve.java.JavaResolverUtils
import com.intellij.codeInsight.completion.JavaPsiClassReferenceElement
public object KotlinLookupElementFactory {
public fun createLookupElement(analyzer: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor): LookupElement {
public fun createLookupElement(analyzer: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor, boldImmediateMembers: Boolean): LookupElement {
val _descriptor = if (descriptor is CallableMemberDescriptor)
DescriptorUtils.unwrapFakeOverride(descriptor)
else
descriptor
return createLookupElement(analyzer, _descriptor, DescriptorToSourceUtils.descriptorToDeclaration(_descriptor))
val bold = boldImmediateMembers && descriptor is CallableMemberDescriptor && descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION
return createLookupElement(analyzer, _descriptor, DescriptorToSourceUtils.descriptorToDeclaration(_descriptor), bold)
}
public fun createLookupElementForJavaClass(psiClass: PsiClass): LookupElement {
return JavaPsiClassReferenceElement(psiClass).setInsertHandler(KotlinClassInsertHandler)
}
private fun createLookupElement(analyzer: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor, declaration: PsiElement?): LookupElement {
private fun createLookupElement(
analyzer: KotlinCodeAnalyzer,
descriptor: DeclarationDescriptor,
declaration: PsiElement?,
bold: Boolean
): LookupElement {
if (descriptor is ClassifierDescriptor &&
declaration is PsiClass &&
declaration !is KotlinLightClass &&
@@ -92,6 +98,10 @@ public object KotlinLookupElementFactory {
element = element.withStrikeoutness(true)
}
if (bold) {
element = element.withBoldness(true)
}
val insertHandler = getDefaultInsertHandler(descriptor)
element = element.withInsertHandler(insertHandler)
@@ -59,7 +59,7 @@ class LookupElementsCollector(
public fun addDescriptorElements(descriptor: DeclarationDescriptor, suppressAutoInsertion: Boolean) {
run {
val lookupElement = KotlinLookupElementFactory.createLookupElement(resolveSession, descriptor)
val lookupElement = KotlinLookupElementFactory.createLookupElement(resolveSession, descriptor, true)
if (suppressAutoInsertion) {
addElementWithAutoInsertionSuppressed(lookupElement)
}
@@ -76,7 +76,7 @@ class LookupElementsCollector(
if (KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(parameterType)) {
val parameterCount = KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(parameterType).size()
if (parameterCount > 1) {
val lookupElement = KotlinLookupElementFactory.createLookupElement(resolveSession, descriptor)
val lookupElement = KotlinLookupElementFactory.createLookupElement(resolveSession, descriptor, true)
addElement(object : LookupElementDecorator<LookupElement>(lookupElement) {
override fun renderElement(presentation: LookupElementPresentation) {
super.renderElement(presentation)
@@ -55,7 +55,7 @@ object PackageDirectiveCompletion {
val variants = TipsManager.getPackageReferenceVariants(ref.expression, bindingContext, prefixMatcher.asNameFilter())
for (variant in variants) {
val lookupElement = KotlinLookupElementFactory.createLookupElement(resolveSession, variant)
val lookupElement = KotlinLookupElementFactory.createLookupElement(resolveSession, variant, false)
if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) {
result.addElement(lookupElement)
}
@@ -117,7 +117,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
else -> ExpectedInfoClassification.NOT_MATCHES
}
}
result.addLookupElements(expectedInfos, classifier, { createLookupElement(descriptor, resolveSession, bindingContext) })
result.addLookupElements(expectedInfos, classifier, { createLookupElement(descriptor, resolveSession, bindingContext, true) })
if (receiver == null) {
toFunctionReferenceLookupElement(descriptor, functionExpectedInfos)?.let { result.add(it) }
@@ -237,7 +237,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
val matchedExpectedInfos = functionExpectedInfos.filter { functionType.isSubtypeOf(it.type) }
if (matchedExpectedInfos.isEmpty()) return null
var lookupElement = createLookupElement(descriptor, resolveSession, bindingContext)
var lookupElement = createLookupElement(descriptor, resolveSession, bindingContext, true)
val text = "::" + (if (descriptor is ConstructorDescriptor) descriptor.getContainingDeclaration().getName() else descriptor.getName())
lookupElement = object: LookupElementDecorator<LookupElement>(lookupElement) {
override fun getLookupString() = text
@@ -296,7 +296,7 @@ class SmartCompletion(val expression: JetSimpleNameExpression,
if (jetType.isError()) return null
val classifier = jetType.getConstructor().getDeclarationDescriptor() ?: return null
val lookupElement = createLookupElement(classifier, resolveSession, bindingContext)
val lookupElement = createLookupElement(classifier, resolveSession, bindingContext, false)
val lookupString = lookupElement.getLookupString()
val typeArgs = jetType.getArguments()
@@ -105,7 +105,7 @@ class StaticMembers(val bindingContext: BindingContext, val resolveSession: Reso
}
private fun createLookupElement(memberDescriptor: DeclarationDescriptor, classDescriptor: ClassDescriptor): LookupElement {
val lookupElement = createLookupElement(memberDescriptor, resolveSession, bindingContext)
val lookupElement = createLookupElement(memberDescriptor, resolveSession, bindingContext, false)
val qualifierPresentation = classDescriptor.getName().asString()
val qualifierText = qualifiedNameForSourceCode(classDescriptor)
@@ -67,7 +67,7 @@ class TypeInstantiationItems(val resolveSession: ResolveSessionForBodies, val bi
}
if (allConstructors.isNotEmpty() && visibleConstructors.isEmpty()) return
var lookupElement = createLookupElement(classifier, resolveSession, bindingContext)
var lookupElement = createLookupElement(classifier, resolveSession, bindingContext, false)
var lookupString = lookupElement.getLookupString()
var allLookupStrings = setOf(lookupString)
@@ -164,7 +164,7 @@ class TypeInstantiationItems(val resolveSession: ResolveSessionForBodies, val bi
val samConstructor = scope.getFunctions(`class`.getName())
.filterIsInstance(javaClass<SamConstructorDescriptor>())
.singleOrNull() ?: return
val lookupElement = createLookupElement(samConstructor, resolveSession, bindingContext)
val lookupElement = createLookupElement(samConstructor, resolveSession, bindingContext, false)
.assignSmartCompletionPriority(SmartCompletionItemPriority.INSTANTIATION)
.addTail(tail)
collection.add(lookupElement)
@@ -186,8 +186,13 @@ fun functionType(function: FunctionDescriptor): JetType? {
function.getReturnType() ?: return null)
}
fun createLookupElement(descriptor: DeclarationDescriptor, resolveSession: ResolveSessionForBodies, bindingContext: BindingContext): LookupElement {
var element = KotlinLookupElementFactory.createLookupElement(resolveSession, descriptor)
fun createLookupElement(
descriptor: DeclarationDescriptor,
resolveSession: ResolveSessionForBodies,
bindingContext: BindingContext,
boldImmediateMembers: Boolean
): LookupElement {
var element = KotlinLookupElementFactory.createLookupElement(resolveSession, descriptor, boldImmediateMembers)
if (descriptor is FunctionDescriptor && descriptor.getValueParameters().isNotEmpty()) {
element = element.keepOldArgumentListOnTab()
@@ -0,0 +1,23 @@
trait T {
fun fromTrait(){}
}
abstract class Base : T {
fun fromBase(){}
}
class Derived : Base() {
override fun fromTrait() { }
fun fromDerived(){}
}
fun foo(d: Derived) {
d.<caret>
}
// EXIST: { itemText: "fromTrait", attributes: "bold" }
// EXIST: { itemText: "fromDerived", attributes: "bold" }
// EXIST: { itemText: "fromBase", attributes: "" }
// EXIST: { itemText: "hashCode", attributes: "" }
// EXIST: { itemText: "equals", attributes: "" }
@@ -0,0 +1,25 @@
trait T {
fun fromTrait(){}
}
abstract class Base : T {
fun fromBase(){}
}
class Derived : Base() {
override fun fromTrait() { }
fun fromDerived(){}
}
fun foo(o: Any) {
if (o is Derived) {
o.<caret>
}
}
// EXIST: { itemText: "fromTrait", attributes: "bold" }
// EXIST: { itemText: "fromDerived", attributes: "bold" }
// EXIST: { itemText: "fromBase", attributes: "" }
// EXIST: { itemText: "hashCode", attributes: "" }
// EXIST: { itemText: "equals", attributes: "" }
@@ -0,0 +1,14 @@
trait T {
fun f(){}
}
fun foo(o: T) {
if (o is Runnable) {
o.<caret>
}
}
// EXIST: { itemText: "run", attributes: "bold" }
// EXIST: { itemText: "f", attributes: "bold" }
// EXIST: { itemText: "hashCode", attributes: "" }
// EXIST: { itemText: "equals", attributes: "" }
@@ -0,0 +1,16 @@
trait T {
fun foo1(){}
fun foo2(){}
}
class B(worker: T) : T by worker {
override fun foo1() { }
}
fun foo(b: B) {
b.<caret>
}
// EXIST: { itemText: "foo1", attributes: "bold" }
// EXIST: { itemText: "foo2", attributes: "" }
// EXIST: { itemText: "equals", attributes: "" }
@@ -0,0 +1,24 @@
trait T {
fun fromTrait(){}
}
abstract class Base : T {
fun fromBase(){}
}
class Derived : Base() {
override fun fromTrait() { }
fun fromDerived(){}
fun foo(d: Derived) {
<caret>
}
}
// EXIST: { itemText: "foo", attributes: "bold" }
// EXIST: { itemText: "fromTrait", attributes: "bold" }
// EXIST: { itemText: "fromDerived", attributes: "bold" }
// EXIST: { itemText: "fromBase", attributes: "" }
// EXIST: { itemText: "hashCode", attributes: "" }
// EXIST: { itemText: "equals", attributes: "" }
@@ -14,10 +14,10 @@ fun foo(){
val k : K = <caret>
}
// EXIST: { lookupString:"foo", itemText:"K.foo", tailText:" (sample)", typeText:"K" }
// EXIST: { lookupString:"bar", itemText:"K.bar", tailText:"() (sample)", typeText:"K" }
// EXIST: { lookupString:"foo", itemText:"K.foo", tailText:" (sample)", typeText:"K", attributes:"" }
// EXIST: { lookupString:"bar", itemText:"K.bar", tailText:"() (sample)", typeText:"K", attributes:"" }
// ABSENT: { itemText: "K.x" }
// ABSENT: { itemText:"K.kk" }
// EXIST: { lookupString:"kk", itemText:"!! K.kk", tailText:" (sample)", typeText:"K?" }
// EXIST: { lookupString:"kk", itemText:"?: K.kk", tailText:" (sample)", typeText:"K?" }
// EXIST: { lookupString:"kk", itemText:"!! K.kk", tailText:" (sample)", typeText:"K?", attributes:"" }
// EXIST: { lookupString:"kk", itemText:"?: K.kk", tailText:" (sample)", typeText:"K?", attributes:"" }
// ABSENT: { itemText: "K.privateVal" }
@@ -0,0 +1,22 @@
trait T {
fun fromTrait() = ""
}
abstract class Base : T {
fun fromBase() = ""
}
class Derived : Base() {
override fun fromTrait() = ""
val fromDerived: String = ""
}
fun foo(d: Derived): String {
return d.<caret>
}
// EXIST: { itemText: "fromTrait", attributes: "bold" }
// EXIST: { itemText: "fromDerived", attributes: "bold" }
// EXIST: { itemText: "fromBase", attributes: "" }
// EXIST: { itemText: "toString", attributes: "" }
@@ -2,5 +2,5 @@ fun foo(){
var l : java.util.Locale = <caret>
}
// EXIST: { lookupString:"ENGLISH", itemText:"Locale.ENGLISH", tailText:" (java.util)", typeText:"Locale!" }
// EXIST: { lookupString:"FRENCH", itemText:"Locale.FRENCH", tailText:" (java.util)", typeText:"Locale!" }
// EXIST: { lookupString:"ENGLISH", itemText:"Locale.ENGLISH", tailText:" (java.util)", typeText:"Locale!", attributes:"" }
// EXIST: { lookupString:"FRENCH", itemText:"Locale.FRENCH", tailText:" (java.util)", typeText:"Locale!", attributes:"" }
@@ -2,6 +2,6 @@ fun foo(){
val l : java.util.Calendar = <caret>
}
// EXIST: { lookupString:"getInstance", itemText:"Calendar.getInstance", tailText:"() (java.util)", typeText:"Calendar!" }
// EXIST: { lookupString:"getInstance", itemText:"Calendar.getInstance", tailText:"(TimeZone!) (java.util)", typeText:"Calendar!" }
// EXIST: { lookupString:"getInstance", itemText:"Calendar.getInstance", tailText:"(TimeZone!, Locale!) (java.util)", typeText:"Calendar!" }
// EXIST: { lookupString:"getInstance", itemText:"Calendar.getInstance", tailText:"() (java.util)", typeText:"Calendar!", attributes:"" }
// EXIST: { lookupString:"getInstance", itemText:"Calendar.getInstance", tailText:"(TimeZone!) (java.util)", typeText:"Calendar!", attributes:"" }
// EXIST: { lookupString:"getInstance", itemText:"Calendar.getInstance", tailText:"(TimeZone!, Locale!) (java.util)", typeText:"Calendar!", attributes:"" }
@@ -304,6 +304,36 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
doTest(fileName);
}
@TestMetadata("ImmediateMembers1.kt")
public void testImmediateMembers1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers1.kt");
doTest(fileName);
}
@TestMetadata("ImmediateMembers2.kt")
public void testImmediateMembers2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers2.kt");
doTest(fileName);
}
@TestMetadata("ImmediateMembers3.kt")
public void testImmediateMembers3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers3.kt");
doTest(fileName);
}
@TestMetadata("ImmediateMembers4.kt")
public void testImmediateMembers4() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers4.kt");
doTest(fileName);
}
@TestMetadata("ImmediateMembers5.kt")
public void testImmediateMembers5() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers5.kt");
doTest(fileName);
}
@TestMetadata("ImportedEnumMembers.kt")
public void testImportedEnumMembers() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImportedEnumMembers.kt");
@@ -304,6 +304,36 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest(fileName);
}
@TestMetadata("ImmediateMembers1.kt")
public void testImmediateMembers1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers1.kt");
doTest(fileName);
}
@TestMetadata("ImmediateMembers2.kt")
public void testImmediateMembers2() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers2.kt");
doTest(fileName);
}
@TestMetadata("ImmediateMembers3.kt")
public void testImmediateMembers3() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers3.kt");
doTest(fileName);
}
@TestMetadata("ImmediateMembers4.kt")
public void testImmediateMembers4() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers4.kt");
doTest(fileName);
}
@TestMetadata("ImmediateMembers5.kt")
public void testImmediateMembers5() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImmediateMembers5.kt");
doTest(fileName);
}
@TestMetadata("ImportedEnumMembers.kt")
public void testImportedEnumMembers() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/ImportedEnumMembers.kt");
@@ -300,6 +300,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName);
}
@TestMetadata("ImmediateMembers.kt")
public void testImmediateMembers() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/ImmediateMembers.kt");
doTest(fileName);
}
@TestMetadata("ImplicitlyTypedFunBody.kt")
public void testImplicitlyTypedFunBody() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/smart/ImplicitlyTypedFunBody.kt");