Fixed deprecated ordering and quick doc for java and compiled classes in completion

This commit is contained in:
Valentin Kipyatkov
2015-06-19 00:14:45 +03:00
parent 53688d061a
commit 8520235934
16 changed files with 97 additions and 62 deletions
@@ -30,14 +30,20 @@ public fun String.trimTrailingWhitespacesAndAddNewlineAtEOF(): String =
result -> if (result.endsWith("\n")) result else result + "\n"
}
public fun CodeInsightTestFixture.configureWithExtraFile(path: String, vararg extraNameParts: String = array(".Data")) {
public fun CodeInsightTestFixture.configureWithExtraFile(path: String, vararg extraNameParts: String) {
configureWithExtraFile(path, *extraNameParts)
}
public fun CodeInsightTestFixture.configureWithExtraFile(path: String, vararg extraNameParts: String = arrayOf(".Data"), relativePaths: Boolean = false) {
fun String.toFile(): File = if (relativePaths) File(getTestDataPath(), this) else File(this)
val noExtensionPath = FileUtil.getNameWithoutExtension(path)
val extensions = array("kt", "java")
val extensions = arrayOf("kt", "java")
val extraPaths: List<String> = extraNameParts
.flatMap { extensions.map { ext -> "$noExtensionPath$it.$ext" } }
.filter { File(it).exists() }
.filter { it.toFile().exists() }
configureByFiles(*(listOf(path) + extraPaths).copyToArray())
configureByFiles(*(listOf(path) + extraPaths).toTypedArray())
}
public fun String.trimIndent(): String {
@@ -24,6 +24,7 @@ import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementWeigher
import com.intellij.codeInsight.lookup.WeighingContext
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiDocCommentOwner
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
@@ -31,7 +32,7 @@ import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.completion.smart.NameSimilarityWeigher
import org.jetbrains.kotlin.idea.completion.smart.SMART_COMPLETION_ITEM_PRIORITY_KEY
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletionItemPriority
import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.isValidJavaFqName
@@ -89,7 +90,7 @@ private object KindWeigher : LookupElementWeigher("kotlin.kind") {
val o = element.getObject()
return when (o) {
is DeclarationDescriptorLookupObject -> {
is DeclarationLookupObject -> {
val descriptor = o.descriptor
when (descriptor) {
is VariableDescriptor -> CompoundWeight(Weight.variable, element.getUserData(CALLABLE_WEIGHT_KEY))
@@ -108,8 +109,12 @@ private object KindWeigher : LookupElementWeigher("kotlin.kind") {
private object DeprecatedWeigher : LookupElementWeigher("kotlin.deprecated") {
override fun weigh(element: LookupElement): Int {
val o = element.getObject()
return if (o is DeclarationDescriptorLookupObject && KotlinBuiltIns.isDeprecated(o.descriptor)) 1 else 0
val o = element.getObject() as? DeclarationLookupObject ?: return 0
val isDeprecated = if (o.descriptor != null)
KotlinBuiltIns.isDeprecated(o.descriptor!!)
else
(o.psiElement as PsiDocCommentOwner).isDeprecated()
return if (isDeprecated) 1 else 0
}
}
@@ -135,15 +140,14 @@ private class JetDeclarationRemotenessWeigher(private val file: JetFile) : Looku
}
override fun weigh(element: LookupElement): Weight {
val o = element.getObject()
if (o is DeclarationDescriptorLookupObject) {
val elementFile = o.psiElement?.getContainingFile()
if (elementFile is JetFile && elementFile.getOriginalFile() == file) {
return Weight.thisFile
}
val o = element.getObject() as? DeclarationLookupObject ?: return Weight.default
val elementFile = o.psiElement?.getContainingFile()
if (elementFile is JetFile && elementFile.getOriginalFile() == file) {
return Weight.thisFile
}
val qualifiedName = qualifiedName(o)
val qualifiedName = o.qualifiedName()
// Invalid name can be met for companion object descriptor: Test.MyTest.A.<no name provided>.testOther
if (qualifiedName != null && isValidJavaFqName(qualifiedName)) {
val importPath = ImportPath(qualifiedName)
@@ -161,11 +165,12 @@ private class JetDeclarationRemotenessWeigher(private val file: JetFile) : Looku
return Weight.default
}
private fun qualifiedName(lookupObject: Any): String? {
return when (lookupObject) {
is DeclarationDescriptorLookupObject -> DescriptorUtils.getFqName(lookupObject.descriptor).toString()
is PsiClass -> lookupObject.getQualifiedName()
else -> null
private fun DeclarationLookupObject.qualifiedName(): String? {
return if (descriptor != null) {
DescriptorUtils.getFqName(descriptor!!).toString()
}
else {
(psiElement as? PsiClass)?.getQualifiedName();
}
}
@@ -20,40 +20,42 @@ import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
/**
* Stores information about resolved descriptor and position of that descriptor.
* Position will be used for sorting
*/
public class DeclarationDescriptorLookupObjectImpl(
public override val descriptor: DeclarationDescriptor,
private val resolutionFacade: ResolutionFacade,
public override val psiElement: PsiElement?
): DeclarationDescriptorLookupObject {
override fun toString(): String {
return super.toString() + " " + descriptor
public class DeclarationLookupObjectImpl(
public override val descriptor: DeclarationDescriptor?,
public override val psiElement: PsiElement?,
private val resolutionFacade: ResolutionFacade
): DeclarationLookupObject {
init {
assert(descriptor != null || psiElement != null)
}
override fun toString() = super.toString() + " " + (descriptor ?: psiElement)
override fun hashCode(): Int {
return descriptor.getOriginal().hashCode()
return if (descriptor != null) descriptor.getOriginal().hashCode() else psiElement!!.hashCode()
}
override fun equals(other: Any?): Boolean {
if (this identityEquals other) return true
if (other == null || javaClass != other.javaClass) return false
val lookupObject = other as DeclarationDescriptorLookupObjectImpl
val lookupObject = other as DeclarationLookupObjectImpl
if (resolutionFacade != lookupObject.resolutionFacade) {
LOG.warn("Descriptors from different resolve sessions")
return false
}
return descriptorsEqualWithSubstitution(descriptor, lookupObject.descriptor)
return descriptorsEqualWithSubstitution(descriptor, lookupObject.descriptor) && psiElement == lookupObject.psiElement
}
companion object {
private val LOG = Logger.getInstance("#" + javaClass<DeclarationDescriptorLookupObject>().getName())
private val LOG = Logger.getInstance("#" + javaClass<DeclarationLookupObject>().getName())
}
}
@@ -98,7 +98,9 @@ public class LookupElementFactory(
}
public fun createLookupElementForJavaClass(psiClass: PsiClass): LookupElement {
var element = LookupElementBuilder.create(psiClass, psiClass.getName()).withInsertHandler(KotlinClassInsertHandler)
val lookupObject = DeclarationLookupObjectImpl(null, psiClass, resolutionFacade)
var element = LookupElementBuilder.create(lookupObject, psiClass.getName())
.withInsertHandler(KotlinClassInsertHandler)
val typeParams = psiClass.getTypeParameters()
if (typeParams.isNotEmpty()) {
@@ -149,7 +151,7 @@ public class LookupElementFactory(
val name = nameAndIconDescriptor.getName().asString()
val icon = JetDescriptorIconProvider.getIcon(nameAndIconDescriptor, iconDeclaration, Iconable.ICON_FLAG_VISIBILITY)
var element = LookupElementBuilder.create(DeclarationDescriptorLookupObjectImpl(descriptor, resolutionFacade, declaration), name)
var element = LookupElementBuilder.create(DeclarationLookupObjectImpl(descriptor, declaration, resolutionFacade), name)
.withIcon(icon)
when (descriptor) {
@@ -20,13 +20,13 @@ import com.intellij.codeInsight.completion.InsertHandler
import com.intellij.codeInsight.completion.InsertionContext
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.renderer.render
open class BaseDeclarationInsertHandler : InsertHandler<LookupElement> {
override fun handleInsert(context: InsertionContext, item: LookupElement) {
val descriptor = (item.getObject() as? DeclarationDescriptorLookupObject)?.descriptor
val descriptor = (item.getObject() as? DeclarationLookupObject)?.descriptor
if (descriptor != null) {
val name = descriptor.getName()
val nameInCode = name.render()
@@ -21,7 +21,7 @@ import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.psi.*
@@ -35,7 +35,7 @@ object CastReceiverInsertHandler : KotlinCallableInsertHandler() {
if (qualifiedExpression != null) {
val receiver = qualifiedExpression.getReceiverExpression()
val descriptor = (item.getObject() as? DeclarationDescriptorLookupObject)?.descriptor as CallableDescriptor
val descriptor = (item.getObject() as? DeclarationLookupObject)?.descriptor as CallableDescriptor
val project = context.getProject()
val thisObj = if (descriptor.getExtensionReceiverParameter() != null) descriptor.getExtensionReceiverParameter() else descriptor.getDispatchReceiverParameter()
@@ -21,7 +21,7 @@ import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.psi.PsiDocumentManager
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.completion.isAfterDot
import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.JetFile
@@ -39,7 +39,7 @@ abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler() {
val file = context.getFile()
val o = item.getObject()
if (file is JetFile && o is DeclarationDescriptorLookupObject) {
if (file is JetFile && o is DeclarationLookupObject) {
val descriptor = o.descriptor as? CallableDescriptor
if (descriptor != null) {
// for completion after dot, import insertion may be required only for extensions
@@ -23,7 +23,7 @@ import com.intellij.psi.PsiDocumentManager
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.completion.isAfterDot
import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.name.FqNameUnsafe
@@ -84,16 +84,13 @@ object KotlinClassInsertHandler : BaseDeclarationInsertHandler() {
}
private fun qualifiedNameToInsert(item: LookupElement): String {
val lookupObject = item.getObject()
return when (lookupObject) {
is DeclarationDescriptorLookupObject -> IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(lookupObject.descriptor as ClassDescriptor)
is PsiClass -> {
val qualifiedName = lookupObject.getQualifiedName()!!
if (FqNameUnsafe.isValid(qualifiedName)) FqNameUnsafe(qualifiedName).render() else qualifiedName
}
else -> error("Unknown object in LookupElement with KotlinClassInsertHandler: $lookupObject")
val lookupObject = item.getObject() as DeclarationLookupObject
if (lookupObject.descriptor != null) {
return IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(lookupObject.descriptor as ClassDescriptor)
}
else {
val qualifiedName = (lookupObject.psiElement as PsiClass).getQualifiedName()!!
return if (FqNameUnsafe.isValid(qualifiedName)) FqNameUnsafe(qualifiedName).render() else qualifiedName
}
}
}
@@ -0,0 +1,3 @@
@Deprecated
class XXXDeprecatedJavaClass {
}
@@ -0,0 +1 @@
class XXXNotDeprecated
@@ -0,0 +1,5 @@
fun test() {
val v: XXX<caret>
}
// ORDER: XXXNotDeprecated, XXXDeprecatedJavaClass
@@ -22,8 +22,9 @@ import org.jetbrains.kotlin.idea.project.TargetPlatform
import org.jetbrains.kotlin.test.JetTestUtils
import org.junit.Assert
val COMPLETION_TEST_DATA_BASE_PATH: String
get() = JetTestUtils.getHomeDirectory() + "/idea/idea-completion/testData"
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) {
testWithAutoCompleteSetting(fileText) {
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.idea.completion.test.weighers
import com.intellij.codeInsight.completion.CompletionType
import org.jetbrains.kotlin.idea.completion.test.COMPLETION_TEST_DATA_BASE_PATH
import org.jetbrains.kotlin.idea.completion.test.RELATIVE_COMPLETION_TEST_DATA_BASE_PATH
import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.JetLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor
@@ -24,10 +26,15 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.JetTestUtils
import org.jetbrains.kotlin.test.util.configureWithExtraFile
import org.junit.Assert
import java.io.File
public abstract class AbstractCompletionWeigherTest(val completionType: CompletionType) : JetLightCodeInsightFixtureTestCase() {
public abstract class AbstractCompletionWeigherTest(val completionType: CompletionType, val relativeTestDataPath: String) : JetLightCodeInsightFixtureTestCase() {
fun doTest(path: String) {
myFixture.configureWithExtraFile(path, ".Data", ".Data1", ".Data2", ".Data3")
val pathPrefix = RELATIVE_COMPLETION_TEST_DATA_BASE_PATH + "/" + relativeTestDataPath
assert(path.startsWith(pathPrefix))
val relativePath = path.removePrefix(pathPrefix)
myFixture.configureWithExtraFile(relativePath, ".Data", ".Data1", ".Data2", ".Data3", relativePaths = true)
val text = myFixture.getEditor().getDocument().getText()
@@ -38,13 +45,13 @@ public abstract class AbstractCompletionWeigherTest(val completionType: Completi
myFixture.assertPreferredCompletionItems(InTextDirectivesUtils.getPrefixedInt(text, "// SELECTED:") ?: 0, *items)
}
override fun getTestDataPath() = JetTestUtils.getHomeDirectory()
override fun getTestDataPath() = File(COMPLETION_TEST_DATA_BASE_PATH, relativeTestDataPath).getPath() + File.separator
}
public abstract class AbstractBasicCompletionWeigherTest() : AbstractCompletionWeigherTest(CompletionType.BASIC) {
public abstract class AbstractBasicCompletionWeigherTest() : AbstractCompletionWeigherTest(CompletionType.BASIC, "weighers/basic") {
override fun getProjectDescriptor() = JetLightProjectDescriptor.INSTANCE
}
public abstract class AbstractSmartCompletionWeigherTest() : AbstractCompletionWeigherTest(CompletionType.SMART) {
public abstract class AbstractSmartCompletionWeigherTest() : AbstractCompletionWeigherTest(CompletionType.SMART, "weighers/smart") {
override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
}
@@ -53,6 +53,12 @@ public class BasicCompletionWeigherTestGenerated extends AbstractBasicCompletion
doTest(fileName);
}
@TestMetadata("DeprecatedJavaClass.kt")
public void testDeprecatedJavaClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/DeprecatedJavaClass.kt");
doTest(fileName);
}
@TestMetadata("ExactMatchForKeyword.kt")
public void testExactMatchForKeyword() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/ExactMatchForKeyword.kt");
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.idea.core.completion
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
public trait DeclarationDescriptorLookupObject {
public interface DeclarationLookupObject {
public val psiElement: PsiElement?
public val descriptor: DeclarationDescriptor
public val descriptor: DeclarationDescriptor?
}
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.core.completion.DeclarationDescriptorLookupObject
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
import org.jetbrains.kotlin.idea.kdoc.KDocFinder
import org.jetbrains.kotlin.idea.kdoc.KDocRenderer
import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
@@ -75,7 +75,7 @@ public class KotlinQuickDocumentationProvider : AbstractDocumentationProvider()
}
override fun getDocumentationElementForLookupItem(psiManager: PsiManager, `object`: Any?, element: PsiElement?): PsiElement? {
if (`object` is DeclarationDescriptorLookupObject) {
if (`object` is DeclarationLookupObject) {
return `object`.psiElement
}
return null