Smart completion for "ClassName::class" and "ClassName::class.java" when specific KClass or Class expected
This commit is contained in:
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.completion.smart
|
||||
|
||||
import com.intellij.codeInsight.completion.InsertionContext
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.idea.completion.ExpectedInfo
|
||||
import org.jetbrains.kotlin.idea.completion.LookupElementFactory
|
||||
import org.jetbrains.kotlin.idea.completion.createLookupElementForType
|
||||
import org.jetbrains.kotlin.idea.completion.fuzzyType
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.quickfix.moveCaret
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.util.*
|
||||
|
||||
object ClassLiteralItems {
|
||||
public fun addToCollection(
|
||||
collection: MutableCollection<LookupElement>,
|
||||
expectedInfos: Collection<ExpectedInfo>,
|
||||
lookupElementFactory: LookupElementFactory,
|
||||
isJvmModule: Boolean
|
||||
) {
|
||||
val typeAndSuffixToExpectedInfos = LinkedHashMap<Pair<JetType, String>, MutableList<ExpectedInfo>>()
|
||||
|
||||
for (expectedInfo in expectedInfos) {
|
||||
val fuzzyType = expectedInfo.fuzzyType ?: continue
|
||||
if (fuzzyType.freeParameters.isNotEmpty()) continue
|
||||
val typeConstructor = fuzzyType.type.constructor
|
||||
val klass = typeConstructor.declarationDescriptor as? ClassDescriptor ?: continue
|
||||
val typeArgument = fuzzyType.type.arguments.singleOrNull() ?: continue
|
||||
if (typeArgument.projectionKind != Variance.INVARIANT) continue
|
||||
|
||||
if (KotlinBuiltIns.isKClass(klass)) {
|
||||
typeAndSuffixToExpectedInfos.getOrPut(typeArgument.type to "::class") { ArrayList() }.add(expectedInfo)
|
||||
}
|
||||
|
||||
if (isJvmModule && klass.importableFqName?.asString() == "java.lang.Class") {
|
||||
typeAndSuffixToExpectedInfos.getOrPut(typeArgument.type to "::class.java") { ArrayList() }.add(expectedInfo)
|
||||
}
|
||||
}
|
||||
|
||||
for ((pair, matchedExpectedInfos) in typeAndSuffixToExpectedInfos) {
|
||||
val (type, suffix) = pair
|
||||
var lookupElement = lookupElementFactory.createLookupElementForType(type) ?: continue
|
||||
val text = lookupElement.lookupString + suffix
|
||||
lookupElement = object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun getLookupString() = text
|
||||
override fun getAllLookupStrings() = setOf(lookupString)
|
||||
|
||||
override fun renderElement(presentation: LookupElementPresentation) {
|
||||
super.renderElement(presentation)
|
||||
presentation.itemText = text
|
||||
}
|
||||
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
super.handleInsert(context)
|
||||
val offset = context.tailOffset
|
||||
context.document.insertString(offset, suffix)
|
||||
context.editor.moveCaret(offset + suffix.length())
|
||||
}
|
||||
}
|
||||
lookupElement.assignSmartCompletionPriority(SmartCompletionItemPriority.CLASS_LITERAL)
|
||||
lookupElement = lookupElement.addTailAndNameSimilarity(matchedExpectedInfos, emptyList())
|
||||
collection.add(lookupElement)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,6 +207,8 @@ class SmartCompletion(
|
||||
StaticMembers(bindingContext, lookupElementFactory).addToCollection(items, expectedInfos, expression, descriptorsToSkip)
|
||||
}
|
||||
|
||||
ClassLiteralItems.addToCollection(items, expectedInfos, lookupElementFactory, isJvmModule)
|
||||
|
||||
if (!forBasicCompletion) {
|
||||
LambdaItems.addToCollection(items, expectedInfos)
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
open class A<T : Any>(val javaClass: Class<T>?)
|
||||
|
||||
class B : A<java.io.File>(<caret>)
|
||||
|
||||
// ELEMENT: "File::class.java"
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.io.File
|
||||
|
||||
open class A<T : Any>(val javaClass: Class<T>?)
|
||||
|
||||
class B : A<java.io.File>(File::class.java)<caret>
|
||||
|
||||
// ELEMENT: "File::class.java"
|
||||
@@ -0,0 +1,7 @@
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
open class A<T : Any>(val kClass: KClass<T>?)
|
||||
|
||||
class B : A<java.io.File>(<caret>)
|
||||
|
||||
// ELEMENT: "File::class"
|
||||
@@ -0,0 +1,8 @@
|
||||
import java.io.File
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
open class A<T : Any>(val kClass: KClass<T>?)
|
||||
|
||||
class B : A<java.io.File>(File::class)<caret>
|
||||
|
||||
// ELEMENT: "File::class"
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
open class A<T : Any>(val javaClass: Class<T>)
|
||||
|
||||
class B : A<String>(<caret>)
|
||||
|
||||
// EXIST_JAVA_ONLY: { lookupString: "String::class.java", itemText: "String::class.java", attributes: "" }
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
open class A<T : Any>(val kClass: KClass<T>)
|
||||
|
||||
class B : A<String>(<caret>)
|
||||
|
||||
// EXIST: { lookupString: "String::class", itemText: "String::class", attributes: "" }
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
fun <T : Any> foo(kClass: KClass<T>){}
|
||||
fun <T : Any> foo(kClass: KClass<T>?, p: Int){}
|
||||
|
||||
fun f() {
|
||||
foo<Int>(<caret>)
|
||||
}
|
||||
|
||||
// WITH_ORDER
|
||||
// EXIST: { lookupString: "Int::class", itemText: "Int::class", attributes: "" }
|
||||
// EXIST: { lookupString: "object" }
|
||||
// EXIST: null
|
||||
// NOTHING_ELSE
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
interface I
|
||||
|
||||
fun foo(kClass: KClass<out I>){}
|
||||
fun foo(kClass: KClass<in I>, p: Int){}
|
||||
fun foo(kClass: KClass<*>, c: Char){}
|
||||
fun <T : Any> foo(kClass: KClass<T>, d: Double){}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ABSENT: "I::class"
|
||||
// ABSENT: "Any::class"
|
||||
// ABSENT: "T::class"
|
||||
+24
@@ -625,6 +625,24 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConcreteJavaClassExpected.kt")
|
||||
public void testConcreteJavaClassExpected() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/callableReference/ConcreteJavaClassExpected.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConcreteKClassExpected.kt")
|
||||
public void testConcreteKClassExpected() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/callableReference/ConcreteKClassExpected.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConcreteKClassExpectedNoDuplicates.kt")
|
||||
public void testConcreteKClassExpectedNoDuplicates() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/callableReference/ConcreteKClassExpectedNoDuplicates.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("EmptyQualifier1.kt")
|
||||
public void testEmptyQualifier1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/callableReference/EmptyQualifier1.kt");
|
||||
@@ -703,6 +721,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NonConcreteKClassExpected.kt")
|
||||
public void testNonConcreteKClassExpected() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/callableReference/NonConcreteKClassExpected.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NonEmptyQualifier1.kt")
|
||||
public void testNonEmptyQualifier1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/smart/callableReference/NonEmptyQualifier1.kt");
|
||||
|
||||
+12
@@ -263,6 +263,18 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConcreteJavaClass.kt")
|
||||
public void testConcreteJavaClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/ConcreteJavaClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConcreteKClass.kt")
|
||||
public void testConcreteKClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/ConcreteKClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("Constructor.kt")
|
||||
public void testConstructor() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/Constructor.kt");
|
||||
|
||||
Reference in New Issue
Block a user