diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionStatistician.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionStatistician.kt deleted file mode 100644 index cb4438c92e8..00000000000 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionStatistician.kt +++ /dev/null @@ -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) - } - } -} \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Statisticians.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Statisticians.kt new file mode 100644 index 00000000000..1b369d34848 --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Statisticians.kt @@ -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") + } +} diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 8a9a1426bf8..101b768faad 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -320,8 +320,6 @@ - - @@ -330,6 +328,9 @@ + + + ) : QuestionAction { - private val prioritizer = Prioritizer(element.getContainingJetFile()) + private val file = element.getContainingJetFile() + private val prioritizer = Prioritizer(file) private inner class Variant( val fqName: FqName, @@ -145,7 +149,9 @@ public class KotlinAddImportAction( project.executeWriteCommand(QuickFixBundle.message("add.import")) { 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 // 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) { @@ -159,36 +165,28 @@ public class KotlinAddImportAction( private class Prioritizer(private val file: JetFile) { private val classifier = ImportableFqNameClassifier(file) - private val currentModule = ModuleUtilCore.findModuleForPsiElement(file) + private val proximityComparator = PsiProximityComparator(file) - private enum class Location { - currentModule, - project, - libraries, - unknown - } + private inner class Priority(private val fqName: FqName, private val descriptor: DeclarationDescriptor) : Comparable { + private val isDeprecated = KotlinBuiltIns.isDeprecated(descriptor) + private val classification = classifier.classify(fqName, false) + private val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor) - private class Priority(private val priority1: ImportableFqNameClassifier.Classification, private val priority2: Location) : Comparable { 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 - 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 { - 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 - } - } + fun priority(fqName: FqName, descriptor: DeclarationDescriptor) = Priority(fqName, descriptor) } } diff --git a/idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.after.kt b/idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.after.kt similarity index 84% rename from idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.after.kt rename to idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.after.kt index f6586d4bcd9..a23aba8fc78 100644 --- a/idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.after.kt +++ b/idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.after.kt @@ -3,7 +3,7 @@ import java.util.* import dependency.* -import dependency.Date +import java.util.Date fun foo(d: Date) { } diff --git a/idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.before.Dependency.kt b/idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.before.Dependency.kt similarity index 100% rename from idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.before.Dependency.kt rename to idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.before.Dependency.kt diff --git a/idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.before.Main.kt b/idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.before.Main.kt similarity index 100% rename from idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.before.Main.kt rename to idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.before.Main.kt diff --git a/idea/testData/quickfix/autoImports/libraryClassJsRuntime.kt b/idea/testData/quickfix/autoImports/libraryClassJsRuntime.kt deleted file mode 100644 index d085e1a51a4..00000000000 --- a/idea/testData/quickfix/autoImports/libraryClassJsRuntime.kt +++ /dev/null @@ -1,8 +0,0 @@ -// "Import" "true" -// ERROR: Please specify constructor invocation; classifier 'HTMLStyleElement' does not have a companion object - -package test - -fun foo() { - HTMLStyleElement -} diff --git a/idea/testData/quickfix/autoImports/libraryClassJsRuntime.kt.after b/idea/testData/quickfix/autoImports/libraryClassJsRuntime.kt.after deleted file mode 100644 index 165319aee97..00000000000 --- a/idea/testData/quickfix/autoImports/libraryClassJsRuntime.kt.after +++ /dev/null @@ -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 -} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index fecee50e22d..fc8542a1afd 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -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); } - @TestMetadata("ambiguousNamePreferFromProject.before.Main.kt") - public void testAmbiguousNamePreferFromProject() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/ambiguousNamePreferFromProject.before.Main.kt"); + @TestMetadata("ambiguousNamePreferFromJdk.before.Main.kt") + public void testAmbiguousNamePreferFromJdk() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/ambiguousNamePreferFromJdk.before.Main.kt"); doTestWithExtraFile(fileName); } diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 72f636dbf1d..e59f81e3eb8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -361,12 +361,6 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { 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") public void testLibraryPropertyJsRuntime() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/libraryPropertyJsRuntime.kt");