KT-6225 Completion of annotations for method parameters
#KT-6225 Fixed
This commit is contained in:
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import com.intellij.patterns.StandardPatterns
|
||||
import com.intellij.util.ProcessingContext
|
||||
import com.intellij.patterns.PatternCondition
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.isAncestor
|
||||
|
||||
class CompletionSessionConfiguration(
|
||||
val completeNonImportedDeclarations: Boolean,
|
||||
@@ -168,7 +169,7 @@ abstract class CompletionSessionBase(protected val configuration: CompletionSess
|
||||
// set is used only for completion in code fragments
|
||||
private var alreadyAddedDescriptors: Collection<DeclarationDescriptor> by Delegates.notNull()
|
||||
|
||||
fun getReferenceVariants(kindFilter: DescriptorKindFilter, shouldCastToRuntimeType: Boolean): Collection<DeclarationDescriptor> {
|
||||
protected fun getReferenceVariants(kindFilter: DescriptorKindFilter, shouldCastToRuntimeType: Boolean): Collection<DeclarationDescriptor> {
|
||||
val descriptors = referenceVariantsHelper!!.getReferenceVariants(reference!!.expression, kindFilter, shouldCastToRuntimeType, prefixMatcher.asNameFilter())
|
||||
if (!shouldCastToRuntimeType) {
|
||||
if (position.getContainingFile() is JetCodeFragment) {
|
||||
@@ -218,16 +219,21 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
override fun doComplete() {
|
||||
assert(parameters.getCompletionType() == CompletionType.BASIC)
|
||||
|
||||
if (!NamedParametersCompletion.isOnlyNamedParameterExpected(position)) {
|
||||
val completeReference = reference != null && !isOnlyKeywordCompletion()
|
||||
val onlyTypes = completeReference && shouldRunOnlyTypeCompletion()
|
||||
val completionKind = completionKind()
|
||||
|
||||
val kindFilter = if (onlyTypes)
|
||||
DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude DescriptorKindExclude.EnumEntry
|
||||
else
|
||||
DescriptorKindFilter(DescriptorKindFilter.ALL_KINDS_MASK)
|
||||
if (completionKind != CompletionKind.NAMED_PARAMETERS_ONLY) {
|
||||
val kindFilter = when (completionKind) {
|
||||
CompletionKind.TYPES ->
|
||||
DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude DescriptorKindExclude.EnumEntry
|
||||
|
||||
if (completeReference) {
|
||||
CompletionKind.ANNOTATION_TYPES ->
|
||||
DescriptorKindFilter(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK) exclude NonAnnotationClassifierExclude
|
||||
|
||||
else ->
|
||||
DescriptorKindFilter(DescriptorKindFilter.ALL_KINDS_MASK)
|
||||
}
|
||||
|
||||
if (completionKind != CompletionKind.KEYWORDS_ONLY) {
|
||||
addReferenceVariants(kindFilter, shouldCastToRuntimeType = false)
|
||||
}
|
||||
|
||||
@@ -260,51 +266,84 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration,
|
||||
}
|
||||
}
|
||||
|
||||
if (completeReference) {
|
||||
if (completionKind != CompletionKind.KEYWORDS_ONLY) {
|
||||
if (!configuration.completeNonImportedDeclarations && isNoQualifierContext()) {
|
||||
JavaCompletionContributor.advertiseSecondCompletion(project, resultSet)
|
||||
}
|
||||
|
||||
flushToResultSet()
|
||||
addNonImported(onlyTypes)
|
||||
}
|
||||
addNonImported(completionKind)
|
||||
|
||||
if (completeReference && position.getContainingFile() is JetCodeFragment) {
|
||||
flushToResultSet()
|
||||
addReferenceVariants(kindFilter, shouldCastToRuntimeType = true)
|
||||
if (position.getContainingFile() is JetCodeFragment) {
|
||||
flushToResultSet()
|
||||
addReferenceVariants(kindFilter, shouldCastToRuntimeType = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NamedParametersCompletion.complete(position, collector)
|
||||
}
|
||||
|
||||
private fun addNonImported(onlyTypes: Boolean) {
|
||||
if (shouldRunTopLevelCompletion()) {
|
||||
addAllClasses { it != ClassKind.ENUM_ENTRY }
|
||||
private object NonAnnotationClassifierExclude : DescriptorKindExclude {
|
||||
override fun matches(descriptor: DeclarationDescriptor): Boolean {
|
||||
return if (descriptor is ClassDescriptor)
|
||||
descriptor.getKind() != ClassKind.ANNOTATION_CLASS
|
||||
else
|
||||
descriptor !is ClassifierDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlyTypes) {
|
||||
private fun addNonImported(completionKind: CompletionKind) {
|
||||
if (shouldRunTopLevelCompletion()) {
|
||||
addAllClasses {
|
||||
if (completionKind != CompletionKind.ANNOTATION_TYPES)
|
||||
it != ClassKind.ENUM_ENTRY
|
||||
else
|
||||
it == ClassKind.ANNOTATION_CLASS
|
||||
}
|
||||
|
||||
if (completionKind == CompletionKind.ALL) {
|
||||
collector.addDescriptorElements(getKotlinTopLevelCallables(), suppressAutoInsertion = true)
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlyTypes && shouldRunExtensionsCompletion()) {
|
||||
if (completionKind == CompletionKind.ALL && shouldRunExtensionsCompletion()) {
|
||||
collector.addDescriptorElements(getKotlinExtensions(), suppressAutoInsertion = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isOnlyKeywordCompletion()
|
||||
= position.getStrictParentOfType<JetModifierList>() != null
|
||||
private enum class CompletionKind {
|
||||
KEYWORDS_ONLY
|
||||
NAMED_PARAMETERS_ONLY
|
||||
ALL
|
||||
TYPES
|
||||
ANNOTATION_TYPES
|
||||
}
|
||||
|
||||
private fun completionKind(): CompletionKind {
|
||||
if (NamedParametersCompletion.isOnlyNamedParameterExpected(position)) return CompletionKind.NAMED_PARAMETERS_ONLY
|
||||
|
||||
if (reference == null) return CompletionKind.KEYWORDS_ONLY
|
||||
|
||||
val modifierList = position.getStrictParentOfType<JetModifierList>()
|
||||
if (modifierList != null) {
|
||||
val valueArgList = position.getStrictParentOfType<JetValueArgumentList>()
|
||||
if (valueArgList == null || !modifierList.isAncestor(valueArgList)) {
|
||||
return CompletionKind.ANNOTATION_TYPES
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldRunOnlyTypeCompletion(): Boolean {
|
||||
// Check that completion in the type annotation context and if there's a qualified
|
||||
// expression we are at first of it
|
||||
val typeReference = position.getStrictParentOfType<JetTypeReference>()
|
||||
if (typeReference != null) {
|
||||
val firstPartReference = PsiTreeUtil.findChildOfType(typeReference, javaClass<JetSimpleNameExpression>())
|
||||
return firstPartReference == reference!!.expression
|
||||
if (firstPartReference == reference.expression) {
|
||||
return CompletionKind.TYPES
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return CompletionKind.ALL
|
||||
}
|
||||
|
||||
private fun addReferenceVariants(kindFilter: DescriptorKindFilter, shouldCastToRuntimeType: Boolean) {
|
||||
|
||||
@@ -59,6 +59,8 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.psi.JetTypeElement
|
||||
import org.jetbrains.kotlin.psi.JetAnnotationEntry
|
||||
|
||||
public class KotlinCompletionContributor : CompletionContributor() {
|
||||
|
||||
@@ -93,6 +95,7 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
||||
|
||||
else -> specialExtensionReceiverDummyIdentifier(tokenBefore)
|
||||
?: specialInTypeArgsDummyIdentifier(tokenBefore)
|
||||
?: specialInParameterListDummyIdentifier(tokenBefore)
|
||||
?: DEFAULT_DUMMY_IDENTIFIER
|
||||
}
|
||||
context.setDummyIdentifier(dummyIdentifier)
|
||||
@@ -343,4 +346,34 @@ public class KotlinCompletionContributor : CompletionContributor() {
|
||||
current = current.prevLeaf(skipEmptyElements = true) ?: return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun specialInParameterListDummyIdentifier(tokenBefore: PsiElement?): String? {
|
||||
if (tokenBefore == null) return null
|
||||
var parent = tokenBefore.getParent()
|
||||
while (parent != null) {
|
||||
if (parent is JetParameterList) {
|
||||
val balance = countParenthesisBalance(tokenBefore, parent)
|
||||
val count = if (balance > 1) balance - 1 else 0
|
||||
return CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED + ")".repeat(count) + " a: B$"
|
||||
}
|
||||
if (parent is JetTypeElement) return null
|
||||
if (parent is JetAnnotationEntry) return null
|
||||
parent = parent.getParent()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun countParenthesisBalance(at: PsiElement, container: PsiElement): Int {
|
||||
val stopAt = container.prevLeaf()
|
||||
var current: PsiElement? = at
|
||||
var balance = 0
|
||||
while (current != stopAt) {
|
||||
when (current!!.getNode().getElementType()) {
|
||||
JetTokens.LPAR -> balance++
|
||||
JetTokens.RPAR -> balance--
|
||||
}
|
||||
current = current!!.prevLeaf()
|
||||
}
|
||||
return balance
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
val v = 1
|
||||
|
||||
fun foo(<caret>) { }
|
||||
|
||||
// EXIST: inlineOptions
|
||||
// ABSENT: String
|
||||
// ABSENT: v
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo(i<caret>) { }
|
||||
|
||||
// EXIST: inlineOptions
|
||||
@@ -0,0 +1,7 @@
|
||||
val v = 1
|
||||
|
||||
fun foo(p: String, <caret>) { }
|
||||
|
||||
// EXIST: inlineOptions
|
||||
// ABSENT: String
|
||||
// ABSENT: v
|
||||
@@ -0,0 +1,7 @@
|
||||
val v = 1
|
||||
|
||||
fun foo(volatile <caret>) { }
|
||||
|
||||
// EXIST: inlineOptions
|
||||
// ABSENT: String
|
||||
// ABSENT: v
|
||||
@@ -0,0 +1,7 @@
|
||||
val v = 1
|
||||
|
||||
fun foo(<caret>
|
||||
|
||||
// EXIST: inlineOptions
|
||||
// ABSENT: String
|
||||
// ABSENT: v
|
||||
@@ -0,0 +1,7 @@
|
||||
val v = 1
|
||||
|
||||
fun foo(inlineOptions(InlineOp<caret>) { }
|
||||
|
||||
// EXIST: InlineOption
|
||||
// ABSENT: String
|
||||
// ABSENT: v
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo(koltin.<caret>) { }
|
||||
|
||||
// EXIST: inlineOptions
|
||||
// ABSENT: String
|
||||
@@ -0,0 +1,7 @@
|
||||
val v = 1
|
||||
|
||||
fun foo([<caret>) { }
|
||||
|
||||
// EXIST: inlineOptions
|
||||
// ABSENT: String
|
||||
// ABSENT: v
|
||||
@@ -0,0 +1,7 @@
|
||||
val v = 1
|
||||
|
||||
fun foo([i<caret>) { }
|
||||
|
||||
// EXIST: inlineOptions
|
||||
// ABSENT: String
|
||||
// ABSENT: v
|
||||
@@ -0,0 +1,7 @@
|
||||
val v = 1
|
||||
|
||||
fun foo(inlineOptions(<caret>) { }
|
||||
|
||||
// EXIST: InlineOption
|
||||
// EXIST: String
|
||||
// EXIST: v
|
||||
@@ -33,7 +33,7 @@ import java.util.regex.Pattern;
|
||||
public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTest {
|
||||
@TestMetadata("idea/testData/completion/basic/common")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@InnerTestClasses({Common.Extensions.class, Common.NamedParameters.class, Common.TypeArgsOrNot.class, Common.Visibility.class})
|
||||
@InnerTestClasses({Common.Annotations.class, Common.Extensions.class, Common.NamedParameters.class, Common.TypeArgsOrNot.class, Common.Visibility.class})
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Common extends AbstractJSBasicCompletionTest {
|
||||
@TestMetadata("AfterFloatOnNewLine.kt")
|
||||
@@ -892,6 +892,69 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/completion/basic/common/annotations")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Annotations extends AbstractJSBasicCompletionTest {
|
||||
public void testAllFilesPresentInAnnotations() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/completion/basic/common/annotations"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation1.kt")
|
||||
public void testParameterAnnotation1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation2.kt")
|
||||
public void testParameterAnnotation2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation3.kt")
|
||||
public void testParameterAnnotation3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation4.kt")
|
||||
public void testParameterAnnotation4() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation4.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation5.kt")
|
||||
public void testParameterAnnotation5() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation5.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation6.kt")
|
||||
public void testParameterAnnotation6() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation6.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation8.kt")
|
||||
public void testParameterAnnotation8() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation8.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation9.kt")
|
||||
public void testParameterAnnotation9() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation9.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotationArgs.kt")
|
||||
public void testParameterAnnotationArgs() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotationArgs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/completion/basic/common/extensions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.util.regex.Pattern;
|
||||
public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionTest {
|
||||
@TestMetadata("idea/testData/completion/basic/common")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@InnerTestClasses({Common.Extensions.class, Common.NamedParameters.class, Common.TypeArgsOrNot.class, Common.Visibility.class})
|
||||
@InnerTestClasses({Common.Annotations.class, Common.Extensions.class, Common.NamedParameters.class, Common.TypeArgsOrNot.class, Common.Visibility.class})
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Common extends AbstractJvmBasicCompletionTest {
|
||||
@TestMetadata("AfterFloatOnNewLine.kt")
|
||||
@@ -892,6 +892,69 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/completion/basic/common/annotations")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Annotations extends AbstractJvmBasicCompletionTest {
|
||||
public void testAllFilesPresentInAnnotations() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/completion/basic/common/annotations"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation1.kt")
|
||||
public void testParameterAnnotation1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation2.kt")
|
||||
public void testParameterAnnotation2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation3.kt")
|
||||
public void testParameterAnnotation3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation4.kt")
|
||||
public void testParameterAnnotation4() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation4.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation5.kt")
|
||||
public void testParameterAnnotation5() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation5.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation6.kt")
|
||||
public void testParameterAnnotation6() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation6.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation8.kt")
|
||||
public void testParameterAnnotation8() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation8.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotation9.kt")
|
||||
public void testParameterAnnotation9() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotation9.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ParameterAnnotationArgs.kt")
|
||||
public void testParameterAnnotationArgs() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/basic/common/annotations/ParameterAnnotationArgs.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/completion/basic/common/extensions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user