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