Better sorting of variants in add import popup
This commit is contained in:
-50
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.completion.CompletionLocation
|
|
||||||
import com.intellij.codeInsight.completion.CompletionStatistician
|
|
||||||
import com.intellij.codeInsight.lookup.LookupElement
|
|
||||||
import com.intellij.psi.statistics.StatisticsInfo
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
|
||||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
|
||||||
|
|
||||||
public class KotlinCompletionStatistician : CompletionStatistician() {
|
|
||||||
override fun serialize(element: LookupElement, location: CompletionLocation): StatisticsInfo? {
|
|
||||||
val o = (element.`object` as? DeclarationLookupObject) ?: return null
|
|
||||||
|
|
||||||
if (o.descriptor != null) {
|
|
||||||
val container = o.descriptor!!.containingDeclaration
|
|
||||||
val containerFqName = when (container) {
|
|
||||||
is ClassDescriptor -> container.importableFqName?.asString()
|
|
||||||
is PackageFragmentDescriptor -> container.fqName.asString()
|
|
||||||
is ModuleDescriptor -> ""
|
|
||||||
else -> null
|
|
||||||
} ?: return StatisticsInfo.EMPTY
|
|
||||||
val signature = DescriptorRenderer.COMPACT.render(o.descriptor!!) //TODO: more compact presentation
|
|
||||||
return StatisticsInfo(containerFqName, signature)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val fqName = o.importableFqName ?: return StatisticsInfo.EMPTY
|
|
||||||
return StatisticsInfo(fqName.parent().asString(), fqName.shortName().identifier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.completion.CompletionLocation
|
||||||
|
import com.intellij.codeInsight.completion.CompletionStatistician
|
||||||
|
import com.intellij.codeInsight.lookup.LookupElement
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.statistics.StatisticsInfo
|
||||||
|
import com.intellij.psi.util.ProximityLocation
|
||||||
|
import com.intellij.psi.util.proximity.ProximityStatistician
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject
|
||||||
|
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||||
|
import org.jetbrains.kotlin.psi.JetDeclaration
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
|
||||||
|
class KotlinCompletionStatistician : CompletionStatistician() {
|
||||||
|
override fun serialize(element: LookupElement, location: CompletionLocation): StatisticsInfo? {
|
||||||
|
val o = (element.`object` as? DeclarationLookupObject) ?: return null
|
||||||
|
|
||||||
|
if (o.descriptor != null) {
|
||||||
|
return KotlinStatisticsInfo.forDescriptor(o.descriptor!!)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val fqName = o.importableFqName ?: return StatisticsInfo.EMPTY
|
||||||
|
return StatisticsInfo("", fqName.asString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinProximityStatistician : ProximityStatistician() {
|
||||||
|
override fun serialize(element: PsiElement, location: ProximityLocation): StatisticsInfo? {
|
||||||
|
if (element !is JetDeclaration) return null
|
||||||
|
val descriptor = element.resolveToDescriptor()
|
||||||
|
return KotlinStatisticsInfo.forDescriptor(descriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object KotlinStatisticsInfo {
|
||||||
|
fun forDescriptor(descriptor: DeclarationDescriptor): StatisticsInfo {
|
||||||
|
val container = descriptor.containingDeclaration
|
||||||
|
val containerFqName = when (container) {
|
||||||
|
is ClassDescriptor -> container.importableFqName?.asString()
|
||||||
|
is PackageFragmentDescriptor -> container.fqName.asString()
|
||||||
|
is ModuleDescriptor -> ""
|
||||||
|
else -> null
|
||||||
|
} ?: return StatisticsInfo.EMPTY
|
||||||
|
val signature = DescriptorRenderer.COMPACT.render(descriptor) //TODO: more compact presentation
|
||||||
|
return StatisticsInfo("", "$containerFqName###$signature")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -320,8 +320,6 @@
|
|||||||
<completion.contributor language="jet"
|
<completion.contributor language="jet"
|
||||||
implementationClass="org.jetbrains.kotlin.idea.completion.KDocCompletionContributor"/>
|
implementationClass="org.jetbrains.kotlin.idea.completion.KDocCompletionContributor"/>
|
||||||
|
|
||||||
<statistician key="completion" implementationClass="org.jetbrains.kotlin.idea.completion.KotlinCompletionStatistician"/>
|
|
||||||
|
|
||||||
<completion.confidence language="jet" implementationClass="com.intellij.codeInsight.completion.UnfocusedNameIdentifier"/>
|
<completion.confidence language="jet" implementationClass="com.intellij.codeInsight.completion.UnfocusedNameIdentifier"/>
|
||||||
<completion.confidence language="jet"
|
<completion.confidence language="jet"
|
||||||
implementationClass="org.jetbrains.kotlin.idea.completion.confidence.UnfocusedPossibleFunctionParameter"/>
|
implementationClass="org.jetbrains.kotlin.idea.completion.confidence.UnfocusedPossibleFunctionParameter"/>
|
||||||
@@ -330,6 +328,9 @@
|
|||||||
<lookup.charFilter implementation="org.jetbrains.kotlin.idea.completion.KotlinCompletionCharFilter"/>
|
<lookup.charFilter implementation="org.jetbrains.kotlin.idea.completion.KotlinCompletionCharFilter"/>
|
||||||
<lookup.actionProvider implementation="org.jetbrains.kotlin.idea.completion.KotlinExcludeFromCompletionLookupActionProvider"/>
|
<lookup.actionProvider implementation="org.jetbrains.kotlin.idea.completion.KotlinExcludeFromCompletionLookupActionProvider"/>
|
||||||
|
|
||||||
|
<statistician key="completion" implementationClass="org.jetbrains.kotlin.idea.completion.KotlinCompletionStatistician"/>
|
||||||
|
<statistician key="proximity" implementationClass="org.jetbrains.kotlin.idea.completion.KotlinProximityStatistician"/>
|
||||||
|
|
||||||
<psi.referenceContributor language="jet" implementation="org.jetbrains.kotlin.idea.references.JetReferenceContributor"/>
|
<psi.referenceContributor language="jet" implementation="org.jetbrains.kotlin.idea.references.JetReferenceContributor"/>
|
||||||
|
|
||||||
<renamePsiElementProcessor id="KotlinClass"
|
<renamePsiElementProcessor id="KotlinClass"
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ import com.intellij.openapi.ui.popup.JBPopupFactory
|
|||||||
import com.intellij.openapi.ui.popup.PopupStep
|
import com.intellij.openapi.ui.popup.PopupStep
|
||||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
|
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.statistics.StatisticsManager
|
||||||
|
import com.intellij.psi.util.ProximityLocation
|
||||||
|
import com.intellij.psi.util.proximity.PsiProximityComparator
|
||||||
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
||||||
@@ -38,7 +42,6 @@ import org.jetbrains.kotlin.idea.imports.importableFqName
|
|||||||
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
|
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
|
||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
|
||||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
@@ -56,7 +59,8 @@ public class KotlinAddImportAction(
|
|||||||
candidates: Collection<DeclarationDescriptor>
|
candidates: Collection<DeclarationDescriptor>
|
||||||
) : QuestionAction {
|
) : QuestionAction {
|
||||||
|
|
||||||
private val prioritizer = Prioritizer(element.getContainingJetFile())
|
private val file = element.getContainingJetFile()
|
||||||
|
private val prioritizer = Prioritizer(file)
|
||||||
|
|
||||||
private inner class Variant(
|
private inner class Variant(
|
||||||
val fqName: FqName,
|
val fqName: FqName,
|
||||||
@@ -145,7 +149,9 @@ public class KotlinAddImportAction(
|
|||||||
project.executeWriteCommand(QuickFixBundle.message("add.import")) {
|
project.executeWriteCommand(QuickFixBundle.message("add.import")) {
|
||||||
if (!element.isValid()) return@executeWriteCommand
|
if (!element.isValid()) return@executeWriteCommand
|
||||||
|
|
||||||
val file = element.getContainingFile() as JetFile
|
val location = ProximityLocation(file, ModuleUtilCore.findModuleForPsiElement(file))
|
||||||
|
StatisticsManager.getInstance().incUseCount(PsiProximityComparator.STATISTICS_KEY, selectedVariant.declarationToImport, location)
|
||||||
|
|
||||||
val descriptor = selectedVariant.descriptorToImport
|
val descriptor = selectedVariant.descriptorToImport
|
||||||
// for class or package we use ShortenReferences because we not necessary insert an import but may want to insert partly qualified name
|
// for class or package we use ShortenReferences because we not necessary insert an import but may want to insert partly qualified name
|
||||||
if (descriptor is ClassDescriptor || descriptor is PackageViewDescriptor) {
|
if (descriptor is ClassDescriptor || descriptor is PackageViewDescriptor) {
|
||||||
@@ -159,36 +165,28 @@ public class KotlinAddImportAction(
|
|||||||
|
|
||||||
private class Prioritizer(private val file: JetFile) {
|
private class Prioritizer(private val file: JetFile) {
|
||||||
private val classifier = ImportableFqNameClassifier(file)
|
private val classifier = ImportableFqNameClassifier(file)
|
||||||
private val currentModule = ModuleUtilCore.findModuleForPsiElement(file)
|
private val proximityComparator = PsiProximityComparator(file)
|
||||||
|
|
||||||
private enum class Location {
|
private inner class Priority(private val fqName: FqName, private val descriptor: DeclarationDescriptor) : Comparable<Priority> {
|
||||||
currentModule,
|
private val isDeprecated = KotlinBuiltIns.isDeprecated(descriptor)
|
||||||
project,
|
private val classification = classifier.classify(fqName, false)
|
||||||
libraries,
|
private val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor)
|
||||||
unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Priority(private val priority1: ImportableFqNameClassifier.Classification, private val priority2: Location) : Comparable<Priority> {
|
|
||||||
override fun compareTo(other: Priority): Int {
|
override fun compareTo(other: Priority): Int {
|
||||||
val c1 = priority1.compareTo(other.priority1)
|
if (isDeprecated != other.isDeprecated) {
|
||||||
|
return if (isDeprecated) +1 else -1
|
||||||
|
}
|
||||||
|
|
||||||
|
val c1 = classification.compareTo(other.classification)
|
||||||
if (c1 != 0) return c1
|
if (c1 != 0) return c1
|
||||||
return priority2.compareTo(other.priority2)
|
|
||||||
|
val c2 = proximityComparator.compare(declaration, other.declaration)
|
||||||
|
if (c2 != 0) return c2
|
||||||
|
|
||||||
|
return fqName.asString().compareTo(other.fqName.asString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun priority(fqName: FqName, descriptor: DeclarationDescriptor): Priority {
|
fun priority(fqName: FqName, descriptor: DeclarationDescriptor) = Priority(fqName, descriptor)
|
||||||
val classification = classifier.classify(fqName, false)
|
|
||||||
val location = location(descriptor)
|
|
||||||
return Priority(classification, location)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun location(descriptor: DeclarationDescriptor): Location {
|
|
||||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor) ?: return Location.unknown
|
|
||||||
return when {
|
|
||||||
ModuleUtilCore.findModuleForPsiElement(declaration) == currentModule -> Location.currentModule
|
|
||||||
ProjectRootsUtil.isInProjectSource(declaration) -> Location.project
|
|
||||||
else -> Location.libraries
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import dependency.*
|
import dependency.*
|
||||||
import dependency.Date
|
import java.util.Date
|
||||||
|
|
||||||
fun foo(d: Date<caret>) {
|
fun foo(d: Date<caret>) {
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// "Import" "true"
|
|
||||||
// ERROR: Please specify constructor invocation; classifier 'HTMLStyleElement' does not have a companion object
|
|
||||||
|
|
||||||
package test
|
|
||||||
|
|
||||||
fun foo() {
|
|
||||||
<caret>HTMLStyleElement
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// "Import" "true"
|
|
||||||
// ERROR: Please specify constructor invocation; classifier 'HTMLStyleElement' does not have a companion object
|
|
||||||
|
|
||||||
package test
|
|
||||||
|
|
||||||
import kotlin.js.dom.html.HTMLStyleElement
|
|
||||||
|
|
||||||
fun foo() {
|
|
||||||
HTMLStyleElement
|
|
||||||
}
|
|
||||||
@@ -53,9 +53,9 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/autoImports"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/autoImports"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("ambiguousNamePreferFromProject.before.Main.kt")
|
@TestMetadata("ambiguousNamePreferFromJdk.before.Main.kt")
|
||||||
public void testAmbiguousNamePreferFromProject() throws Exception {
|
public void testAmbiguousNamePreferFromJdk() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.before.Main.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.before.Main.kt");
|
||||||
doTestWithExtraFile(fileName);
|
doTestWithExtraFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -361,12 +361,6 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("libraryClassJsRuntime.kt")
|
|
||||||
public void testLibraryClassJsRuntime() throws Exception {
|
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/libraryClassJsRuntime.kt");
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("libraryPropertyJsRuntime.kt")
|
@TestMetadata("libraryPropertyJsRuntime.kt")
|
||||||
public void testLibraryPropertyJsRuntime() throws Exception {
|
public void testLibraryPropertyJsRuntime() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/libraryPropertyJsRuntime.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/libraryPropertyJsRuntime.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user