Better imported/non-imported items sorting in completion

This commit is contained in:
Valentin Kipyatkov
2014-12-01 13:59:26 +03:00
parent 94b7945cd8
commit 6ddedb7825
8 changed files with 89 additions and 18 deletions
@@ -25,18 +25,14 @@ public fun String.trimTrailingWhitespacesAndAddNewlineAtEOF(): String =
result -> if (result.endsWith("\n")) result else result + "\n"
}
public fun CodeInsightTestFixture.configureWithExtraFile(path: String, extraNamePart: String = ".Data") {
public fun CodeInsightTestFixture.configureWithExtraFile(path: String, vararg extraNameParts: String = array(".Data")) {
val noExtensionPath = FileUtil.getNameWithoutExtension(path)
val extraPath = array("kt", "java").stream()
.map { ext -> "$noExtensionPath$extraNamePart.$ext" }
.firstOrNull { extraPath -> File(extraPath).exists() }
val extensions = array("kt", "java")
val extraPaths: List<String> = extraNameParts
.flatMap { extensions.map { ext -> "$noExtensionPath$it.$ext" } }
.filter { File(it).exists() }
if (extraPath != null) {
configureByFiles(path, extraPath)
}
else {
configureByFile(path)
}
configureByFiles(*(listOf(path) + extraPaths).copyToArray())
}
public fun String.trimIndent(): String {
@@ -38,6 +38,8 @@ import org.jetbrains.jet.plugin.completion.smart.NameSimilarityWeigher
import org.jetbrains.jet.plugin.completion.smart.SMART_COMPLETION_ITEM_PRIORITY_KEY
import org.jetbrains.jet.plugin.completion.smart.SmartCompletionItemPriority
import com.intellij.psi.PsiClass
import java.util.HashSet
import org.jetbrains.jet.lang.resolve.name.FqName
public fun CompletionResultSet.addKotlinSorting(parameters: CompletionParameters): CompletionResultSet {
var sorter = CompletionSorter.defaultSorter(parameters, getPrefixMatcher())!!
@@ -109,11 +111,15 @@ private object PreferMatchingItemWeigher : LookupElementWeigher("kotlin.preferMa
}
private class JetDeclarationRemotenessWeigher(private val file: JetFile) : LookupElementWeigher("kotlin.declarationRemoteness") {
private val importCache = ImportCache()
private enum class Weight {
kotlinDefaultImport
thisFile
imported
preciseImport
allUnderImport
default
hasImportFromSamePackage
notImported
}
@@ -126,25 +132,52 @@ private class JetDeclarationRemotenessWeigher(private val file: JetFile) : Looku
}
}
val fqName = fqName(o)
val qualifiedName = qualifiedName(o)
// Invalid name can be met for class object descriptor: Test.MyTest.A.<no name provided>.testOther
if (fqName != null && isValidJavaFqName(fqName)) {
val importPath = ImportPath(fqName)
if (qualifiedName != null && isValidJavaFqName(qualifiedName)) {
val importPath = ImportPath(qualifiedName)
val fqName = importPath.fqnPart()
return when {
ImportInsertHelper.getInstance().needImport(importPath, file) -> Weight.notImported
ImportInsertHelper.getInstance().isImportedWithDefault(importPath, file) -> Weight.kotlinDefaultImport
else -> Weight.imported
importCache.isImportedWithPreciseImport(fqName) -> Weight.preciseImport
importCache.isImportedWithAllUnderImport(fqName) -> Weight.allUnderImport
importCache.hasPreciseImportFromPackage(fqName.parent()) -> Weight.hasImportFromSamePackage
else -> Weight.notImported
}
}
return Weight.default
}
private fun fqName(lookupObject: Any): String? {
private fun qualifiedName(lookupObject: Any): String? {
return when (lookupObject) {
is DeclarationDescriptorLookupObject -> DescriptorUtils.getFqName(lookupObject.descriptor).toString()
is PsiClass -> lookupObject.getQualifiedName()
else -> null
}
}
private inner class ImportCache {
private val preciseImports = HashSet<FqName>()
private val preciseImportPackages = HashSet<FqName>()
private val allUnderImports = HashSet<FqName>()
;{
for (import in file.getImportDirectives()) {
val importPath = import.getImportPath() ?: continue
val fqName = importPath.fqnPart()
if (importPath.isAllUnder()) {
allUnderImports.add(fqName)
}
else {
preciseImports.add(fqName)
preciseImportPackages.add(fqName.parent())
}
}
}
fun isImportedWithPreciseImport(name: FqName) = name in preciseImports
fun isImportedWithAllUnderImport(name: FqName) = name.parent() in allUnderImports
fun hasPreciseImportFromPackage(packageName: FqName) = packageName in preciseImportPackages
}
}
@@ -0,0 +1,4 @@
package ppp1
class MyClass1
class MyClass2
@@ -0,0 +1,4 @@
package ppp2
class MyClass3
class MyClass4
@@ -0,0 +1,4 @@
package ppp3
class MyClass5
class MyClass6
@@ -0,0 +1,24 @@
import ppp1.*
import ppp3.MyClass6
val v = My<caret>
// INVOCATION_COUNT: 2
/* explicitly imported */
// ORDER: MyClass6
/* imported with * */
// ORDER: MyClass1
/* imported with * */
// ORDER: MyClass2
/* another class from the same package imported */
// ORDER: MyClass5
/* not imported */
// ORDER: MyClass3
/* not imported */
// ORDER: MyClass4
@@ -28,7 +28,7 @@ import org.jetbrains.jet.plugin.JetWithJdkAndRuntimeLightProjectDescriptor
public abstract class AbstractCompletionWeigherTest(val completionType: CompletionType, val relativeTestDataPath: String) : JetLightCodeInsightFixtureTestCase() {
fun doTest(path: String) {
myFixture.configureWithExtraFile(path)
myFixture.configureWithExtraFile(path, ".Data", ".Data1", ".Data2", ".Data3")
val text = myFixture.getEditor().getDocument().getText()
@@ -59,6 +59,12 @@ public class BasicCompletionWeigherTestGenerated extends AbstractBasicCompletion
doTest(fileName);
}
@TestMetadata("ImportedOrder.kt")
public void testImportedOrder() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/weighers/basic/ImportedOrder.kt");
doTest(fileName);
}
@TestMetadata("KeywordsLast.kt")
public void testKeywordsLast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/weighers/basic/KeywordsLast.kt");