Code completion: avoid duplication of elements for java classes
This commit is contained in:
@@ -34,6 +34,11 @@ import org.jetbrains.jet.plugin.completion.handlers.JetFunctionInsertHandler
|
||||
import org.jetbrains.jet.renderer.DescriptorRenderer
|
||||
import org.jetbrains.jet.plugin.completion.handlers.BaseDeclarationInsertHandler
|
||||
import org.jetbrains.jet.plugin.completion.handlers.JetPropertyInsertHandler
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.jet.asJava.KotlinLightClass
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaResolverPsiUtils
|
||||
import org.jetbrains.jet.plugin.completion.handlers.JetJavaClassInsertHandler
|
||||
import com.intellij.codeInsight.completion.JavaPsiClassReferenceElement
|
||||
|
||||
public object DescriptorLookupConverter {
|
||||
public fun createLookupElement(analyzer: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor): LookupElement {
|
||||
@@ -44,7 +49,21 @@ public object DescriptorLookupConverter {
|
||||
return createLookupElement(analyzer, _descriptor, DescriptorToSourceUtils.descriptorToDeclaration(_descriptor))
|
||||
}
|
||||
|
||||
public fun createLookupElementForJavaClass(psiClass: PsiClass): LookupElement {
|
||||
return JavaPsiClassReferenceElement(psiClass).setInsertHandler(JetJavaClassInsertHandler)
|
||||
}
|
||||
|
||||
private fun createLookupElement(analyzer: KotlinCodeAnalyzer, descriptor: DeclarationDescriptor, declaration: PsiElement?): LookupElement {
|
||||
if (descriptor is ClassifierDescriptor &&
|
||||
declaration is PsiClass &&
|
||||
declaration !is KotlinLightClass &&
|
||||
!JavaResolverPsiUtils.isCompiledKotlinClass(declaration)) {
|
||||
// for java classes we create special lookup elements
|
||||
// because they must be equal to ones created in TypesCompletion
|
||||
// otherwise we may have duplicates
|
||||
return createLookupElementForJavaClass(declaration)
|
||||
}
|
||||
|
||||
val name = descriptor.getName().asString()
|
||||
var element = LookupElementBuilder.create(DeclarationLookupObject(descriptor, analyzer, declaration), name)
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@ import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||
import org.jetbrains.jet.plugin.completion.handlers.*
|
||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
||||
import java.util.ArrayList
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor
|
||||
|
||||
class LookupElementsCollector(private val prefixMatcher: PrefixMatcher,
|
||||
private val resolveSession: ResolveSessionForBodies,
|
||||
@@ -57,12 +57,13 @@ class LookupElementsCollector(private val prefixMatcher: PrefixMatcher,
|
||||
if (!descriptorFilter(descriptor)) return
|
||||
|
||||
run {
|
||||
var lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, descriptor)
|
||||
if (suppressAutoInsertion &&
|
||||
elements.isEmpty() && isResultEmpty /* without these checks we would get duplicated items */) {
|
||||
lookupElement = lookupElement.suppressAutoInsertion()
|
||||
val lookupElement = DescriptorLookupConverter.createLookupElement(resolveSession, descriptor)
|
||||
if (suppressAutoInsertion) {
|
||||
addElementWithAutoInsertionSuppressed(lookupElement)
|
||||
}
|
||||
else {
|
||||
addElement(lookupElement)
|
||||
}
|
||||
addElement(lookupElement)
|
||||
}
|
||||
|
||||
// add special item for function with one argument of function type with more than one parameter
|
||||
@@ -96,6 +97,15 @@ class LookupElementsCollector(private val prefixMatcher: PrefixMatcher,
|
||||
}
|
||||
}
|
||||
|
||||
public fun addElementWithAutoInsertionSuppressed(element: LookupElement) {
|
||||
if (isResultEmpty && elements.isEmpty()) { /* without these checks we may get duplicated items */
|
||||
addElement(element.suppressAutoInsertion())
|
||||
}
|
||||
else {
|
||||
addElement(element)
|
||||
}
|
||||
}
|
||||
|
||||
public fun addElements(elements: Iterable<LookupElement>) {
|
||||
elements.forEach { addElement(it) }
|
||||
}
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
package org.jetbrains.jet.plugin.completion
|
||||
|
||||
import com.intellij.codeInsight.completion.*
|
||||
import com.intellij.codeInsight.lookup.LookupElement
|
||||
import com.intellij.codeInsight.lookup.LookupElementDecorator
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.util.Consumer
|
||||
import org.jetbrains.jet.asJava.KotlinLightClass
|
||||
import org.jetbrains.jet.lang.descriptors.ClassKind
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
@@ -29,7 +26,6 @@ import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||
import org.jetbrains.jet.plugin.caches.JetFromJavaDescriptorHelper
|
||||
import org.jetbrains.jet.plugin.completion.handlers.JetJavaClassInsertHandler
|
||||
import org.jetbrains.jet.plugin.project.ProjectStructureUtil
|
||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
||||
import org.jetbrains.jet.plugin.caches.KotlinIndicesHelper
|
||||
@@ -53,42 +49,26 @@ class TypesCompletion(val parameters: CompletionParameters, val resolveSession:
|
||||
/**
|
||||
* Add java elements with performing conversion to kotlin elements if necessary.
|
||||
*/
|
||||
private fun addAdaptedJavaCompletion(result: LookupElementsCollector) {
|
||||
JavaClassNameCompletionContributor.addAllClasses(parameters, true, prefixMatcher, object : Consumer<LookupElement> {
|
||||
override fun consume(lookupElement: LookupElement?) {
|
||||
if (lookupElement is JavaPsiClassReferenceElement) {
|
||||
val psiClass = lookupElement.getObject()
|
||||
|
||||
if (addJavaClassAsJetLookupElement(psiClass, result)) return
|
||||
|
||||
result.addElement(object : LookupElementDecorator<LookupElement>(lookupElement) {
|
||||
override fun handleInsert(context: InsertionContext) {
|
||||
JetJavaClassInsertHandler.handleInsert(context, lookupElement)
|
||||
}
|
||||
}.suppressAutoInsertion())
|
||||
private fun addAdaptedJavaCompletion(collector: LookupElementsCollector) {
|
||||
AllClassesGetter.processJavaClasses(parameters, prefixMatcher, true, { psiClass ->
|
||||
if (psiClass!! !is KotlinLightClass) { // Kotlin non-compiled class should have already been added as kotlin element before
|
||||
if (JavaResolverPsiUtils.isCompiledKotlinClass(psiClass)) {
|
||||
addLookupElementForCompiledKotlinClass(psiClass, collector)
|
||||
}
|
||||
else {
|
||||
collector.addElementWithAutoInsertionSuppressed(DescriptorLookupConverter.createLookupElementForJavaClass(psiClass))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun addJavaClassAsJetLookupElement(aClass: PsiClass, result: LookupElementsCollector): Boolean {
|
||||
if (aClass is KotlinLightClass) {
|
||||
// Do nothing. Kotlin not-compiled class should have already been added as kotlin element before.
|
||||
return true
|
||||
}
|
||||
|
||||
if (JavaResolverPsiUtils.isCompiledKotlinClass(aClass)) {
|
||||
if (JetFromJavaDescriptorHelper.getCompiledClassKind(aClass) != ClassKind.CLASS_OBJECT) {
|
||||
val qualifiedName = aClass.getQualifiedName()
|
||||
if (qualifiedName != null) {
|
||||
result.addDescriptorElements(ResolveSessionUtils.getClassDescriptorsByFqName(resolveSession.getModuleDescriptor(), FqName(qualifiedName)),
|
||||
suppressAutoInsertion = true)
|
||||
}
|
||||
private fun addLookupElementForCompiledKotlinClass(aClass: PsiClass, collector: LookupElementsCollector) {
|
||||
if (JetFromJavaDescriptorHelper.getCompiledClassKind(aClass) != ClassKind.CLASS_OBJECT) {
|
||||
val qualifiedName = aClass.getQualifiedName()
|
||||
if (qualifiedName != null) {
|
||||
val descriptors = ResolveSessionUtils.getClassDescriptorsByFqName(resolveSession.getModuleDescriptor(), FqName(qualifiedName))
|
||||
collector.addDescriptorElements(descriptors, suppressAutoInsertion = true)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.jetbrains.jet.plugin.quickfix.ImportInsertHelper
|
||||
* Handler for inserting java class completion.
|
||||
* - Should place import directive if necessary.
|
||||
*/
|
||||
public object JetJavaClassInsertHandler : InsertHandler<JavaPsiClassReferenceElement> {
|
||||
object JetJavaClassInsertHandler : InsertHandler<JavaPsiClassReferenceElement> {
|
||||
override fun handleInsert(context: InsertionContext, item: JavaPsiClassReferenceElement) {
|
||||
PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments()
|
||||
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@ import java.io.InputStreamReader
|
||||
|
||||
val x = InputStreamReader<caret>
|
||||
|
||||
// INVOCATION_COUNT: 1
|
||||
// INVOCATION_COUNT: 2
|
||||
// EXIST: { lookupString:"InputStreamReader", tailText:" (java.io)" }
|
||||
// NUMBER: 1
|
||||
@@ -17,13 +17,10 @@
|
||||
package org.jetbrains.jet.completion;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.test.InnerTestClasses;
|
||||
import org.jetbrains.jet.test.TestMetadata;
|
||||
import org.jetbrains.jet.JUnit3RunnerWithInners;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -846,15 +843,15 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NoClassNameDuplicationForRuntimeClass.kt")
|
||||
public void testNoClassNameDuplicationForRuntimeClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/java/NoClassNameDuplicationForRuntimeClass.kt");
|
||||
@TestMetadata("NoDuplicationForImportedJavaClass.kt")
|
||||
public void testNoDuplicationForImportedJavaClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/java/NoDuplicationForImportedJavaClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NoImportedJavaClassDuplication.kt")
|
||||
public void testNoImportedJavaClassDuplication() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/java/NoImportedJavaClassDuplication.kt");
|
||||
@TestMetadata("NoDuplicationForRuntimeClass.kt")
|
||||
public void testNoDuplicationForRuntimeClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/java/NoDuplicationForRuntimeClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
|
||||
+6
-2
@@ -17,9 +17,13 @@
|
||||
package org.jetbrains.jet.completion;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.test.TestMetadata;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.jetbrains.jet.JetTestUtils;
|
||||
import org.jetbrains.jet.test.InnerTestClasses;
|
||||
import org.jetbrains.jet.test.TestMetadata;
|
||||
import org.jetbrains.jet.JUnit3RunnerWithInners;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
Reference in New Issue
Block a user