mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
[kotlin] Do not duplicate parameter info type annotation
#KTIJ-31759 Fixed GitOrigin-RevId: 599c7f06a4e0a18d3daa930d7b199142d63108af
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1a4a0b51b3
commit
4d8f67c14a
@@ -0,0 +1,25 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.base.analysis.api.utils
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotated
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotationValue
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames
|
||||
|
||||
@ApiStatus.Internal
|
||||
fun KaAnnotationValue.isApplicableTargetSet(expectedTargetCallableId: CallableId): Boolean {
|
||||
return when (this) {
|
||||
is KaAnnotationValue.ArrayValue -> values.any { it.isApplicableTargetSet(expectedTargetCallableId) }
|
||||
is KaAnnotationValue.EnumEntryValue -> callableId == expectedTargetCallableId
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun KaAnnotated.hasApplicableAllowedTarget(annotationValueFilter: (KaAnnotationValue) -> Boolean): Boolean =
|
||||
annotations
|
||||
.firstOrNull { it.classId == StandardClassIds.Annotations.Target }
|
||||
?.arguments
|
||||
?.filter { it.name == ParameterNames.targetAllowedTargets }
|
||||
?.any { annotationValueFilter(it.expression) } ?: false
|
||||
@@ -13,12 +13,14 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiType
|
||||
import com.intellij.psi.SmartPointerManager
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisFromWriteAction
|
||||
import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisOnEdt
|
||||
import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisFromWriteAction
|
||||
@@ -26,16 +28,16 @@ import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisOnEdt
|
||||
import org.jetbrains.kotlin.analysis.api.renderer.types.impl.KaTypeRendererForSource
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KaAnnotatedSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaTypeNullability
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.idea.base.analysis.api.utils.hasApplicableAllowedTarget
|
||||
import org.jetbrains.kotlin.idea.base.analysis.api.utils.isApplicableTargetSet
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.ShortenReferencesFacility
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageUtil
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -223,33 +225,15 @@ object K2CreatePropertyFromUsageBuilder {
|
||||
allowAnalysisOnEdt {
|
||||
analyze(declaration) {
|
||||
val symbol = findClass(classId) as? KaAnnotatedSymbol ?: return false
|
||||
val annotationValues =
|
||||
symbol.annotations
|
||||
.firstOrNull { it.classId?.asSingleFqName() == StandardNames.FqNames.target }
|
||||
?.arguments
|
||||
?.filter { it.name == ParameterNames.targetAllowedTargets }
|
||||
?.map { it.expression }
|
||||
?: return false
|
||||
for(value in annotationValues) {
|
||||
if (value.isApplicableTargetSet(expectedTargetCallableId)) {
|
||||
return true
|
||||
}
|
||||
return symbol.hasApplicableAllowedTarget {
|
||||
it.isApplicableTargetSet(expectedTargetCallableId)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun KaAnnotationValue.isApplicableTargetSet(expectedTargetCallableId: CallableId): Boolean {
|
||||
return when (this) {
|
||||
is KaAnnotationValue.ArrayValue -> values.any { it.isApplicableTargetSet(expectedTargetCallableId) }
|
||||
is KaAnnotationValue.EnumEntryValue -> callableId == expectedTargetCallableId
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private val fieldAnnotationTargetCallableId: CallableId =
|
||||
CallableId(StandardClassIds.AnnotationTarget, Name.identifier(KotlinTarget.FIELD.name))
|
||||
|
||||
|
||||
@@ -13,21 +13,24 @@ import com.intellij.ui.JBColor
|
||||
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
|
||||
import org.jetbrains.kotlin.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotation
|
||||
import org.jetbrains.kotlin.analysis.api.components.KaSubtypingErrorTypePolicy
|
||||
import org.jetbrains.kotlin.analysis.api.renderer.types.impl.KaTypeRendererForSource
|
||||
import org.jetbrains.kotlin.analysis.api.signatures.KaVariableSignature
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaClassSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaValueParameterSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaErrorType
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.idea.base.analysis.api.utils.CallParameterInfoProvider
|
||||
import org.jetbrains.kotlin.idea.base.analysis.api.utils.collectCallCandidates
|
||||
import org.jetbrains.kotlin.idea.base.analysis.api.utils.defaultValue
|
||||
import org.jetbrains.kotlin.idea.base.analysis.api.utils.*
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.parameterInfo.KotlinParameterInfoBase
|
||||
import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.NULLABILITY_ANNOTATIONS
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.allChildren
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
@@ -40,21 +43,21 @@ class KotlinHighLevelFunctionParameterInfoHandler :
|
||||
KotlinHighLevelParameterInfoWithCallHandlerBase<KtValueArgumentList, KtValueArgument>(
|
||||
KtValueArgumentList::class, KtValueArgument::class
|
||||
) {
|
||||
override fun getActualParameters(arguments: KtValueArgumentList) = arguments.arguments.toTypedArray()
|
||||
override fun getActualParameters(arguments: KtValueArgumentList): Array<KtValueArgument?> = arguments.arguments.toTypedArray()
|
||||
|
||||
override fun getActualParametersRBraceType(): KtSingleValueToken = KtTokens.RPAR
|
||||
|
||||
override fun getArgumentListAllowedParentClasses() = setOf(KtCallElement::class.java)
|
||||
override fun getArgumentListAllowedParentClasses(): Set<Class<KtCallElement>> = setOf(KtCallElement::class.java)
|
||||
}
|
||||
|
||||
class KotlinHighLevelLambdaParameterInfoHandler :
|
||||
KotlinHighLevelParameterInfoWithCallHandlerBase<KtLambdaArgument, KtLambdaArgument>(KtLambdaArgument::class, KtLambdaArgument::class) {
|
||||
|
||||
override fun getActualParameters(lambdaArgument: KtLambdaArgument) = arrayOf(lambdaArgument)
|
||||
override fun getActualParameters(lambdaArgument: KtLambdaArgument): Array<KtLambdaArgument> = arrayOf(lambdaArgument)
|
||||
|
||||
override fun getActualParametersRBraceType(): KtSingleValueToken = KtTokens.RBRACE
|
||||
|
||||
override fun getArgumentListAllowedParentClasses() = setOf(KtLambdaArgument::class.java)
|
||||
override fun getArgumentListAllowedParentClasses(): Set<Class<KtLambdaArgument>> = setOf(KtLambdaArgument::class.java)
|
||||
|
||||
override fun getCurrentArgumentIndex(context: UpdateParameterInfoContext, argumentList: KtLambdaArgument): Int {
|
||||
val size = (argumentList.parent as? KtCallElement)?.valueArguments?.size ?: 1
|
||||
@@ -65,7 +68,7 @@ class KotlinHighLevelLambdaParameterInfoHandler :
|
||||
class KotlinHighLevelArrayAccessParameterInfoHandler :
|
||||
KotlinHighLevelParameterInfoWithCallHandlerBase<KtContainerNode, KtExpression>(KtContainerNode::class, KtExpression::class) {
|
||||
|
||||
override fun getArgumentListAllowedParentClasses() = setOf(KtArrayAccessExpression::class.java)
|
||||
override fun getArgumentListAllowedParentClasses(): Set<Class<KtArrayAccessExpression>> = setOf(KtArrayAccessExpression::class.java)
|
||||
|
||||
override fun getActualParameters(containerNode: KtContainerNode): Array<out KtExpression> =
|
||||
containerNode.allChildren.filterIsInstance<KtExpression>().toList().toTypedArray()
|
||||
@@ -93,13 +96,16 @@ abstract class KotlinHighLevelParameterInfoWithCallHandlerBase<TArgumentList : K
|
||||
)
|
||||
|
||||
private const val SINGLE_LINE_PARAMETERS_COUNT = 3
|
||||
|
||||
private val ANNOTATION_TARGET_TYPE = CallableId(StandardClassIds.AnnotationTarget, Name.identifier(AnnotationTarget.TYPE.name))
|
||||
private val ANNOTATION_TARGET_VALUE_PARAMETER = CallableId(StandardClassIds.AnnotationTarget, Name.identifier(AnnotationTarget.VALUE_PARAMETER.name))
|
||||
}
|
||||
|
||||
override fun getActualParameterDelimiterType(): KtSingleValueToken = KtTokens.COMMA
|
||||
|
||||
override fun getArgListStopSearchClasses(): Set<Class<out KtElement>> = STOP_SEARCH_CLASSES
|
||||
|
||||
override fun getArgumentListClass() = argumentListClass.java
|
||||
override fun getArgumentListClass(): Class<TArgumentList> = argumentListClass.java
|
||||
|
||||
override fun showParameterInfo(element: TArgumentList, context: CreateParameterInfoContext) {
|
||||
context.showHint(element, element.textRange.startOffset, this)
|
||||
@@ -261,7 +267,8 @@ abstract class KotlinHighLevelParameterInfoWithCallHandlerBase<TArgumentList : K
|
||||
parameter.symbol.annotations
|
||||
.filter {
|
||||
// For primary constructor parameters, the annotation use site must be "param" or unspecified.
|
||||
it.useSiteTarget == null || it.useSiteTarget == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER
|
||||
(it.useSiteTarget == null || it.useSiteTarget == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER) &&
|
||||
!it.isAnnotatedWithTypeUseOnly()
|
||||
}
|
||||
.mapNotNull { it.classId?.asSingleFqName() }
|
||||
.filter { it !in NULLABILITY_ANNOTATIONS }
|
||||
@@ -286,6 +293,14 @@ abstract class KotlinHighLevelParameterInfoWithCallHandlerBase<TArgumentList : K
|
||||
}
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
private fun KaAnnotation.isAnnotatedWithTypeUseOnly(): Boolean =
|
||||
(constructorSymbol?.containingSymbol as? KaClassSymbol)
|
||||
?.hasApplicableAllowedTarget {
|
||||
it.isApplicableTargetSet(ANNOTATION_TARGET_TYPE) &&
|
||||
!it.isApplicableTargetSet(ANNOTATION_TARGET_VALUE_PARAMETER)
|
||||
} ?: false
|
||||
|
||||
private fun calculateHighlightParameterIndex(
|
||||
arguments: List<KtExpression?>,
|
||||
currentArgumentIndex: Int,
|
||||
@@ -542,4 +557,4 @@ abstract class KotlinHighLevelParameterInfoWithCallHandlerBase<TArgumentList : K
|
||||
data class CandidateInfo(
|
||||
var callInfo: CallInfo? = null // Populated in updateParameterInfo()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.kotlin.idea.fir.parameterInfo
|
||||
|
||||
import org.jetbrains.kotlin.idea.base.test.IgnoreTests
|
||||
import org.jetbrains.kotlin.idea.fir.invalidateCaches
|
||||
import org.jetbrains.kotlin.idea.parameterInfo.AbstractParameterInfoTest
|
||||
import org.jetbrains.kotlin.idea.test.runAll
|
||||
import java.nio.file.Paths
|
||||
|
||||
abstract class AbstractFirParameterInfoTest : AbstractParameterInfoTest() {
|
||||
|
||||
@@ -15,10 +13,4 @@ abstract class AbstractFirParameterInfoTest : AbstractParameterInfoTest() {
|
||||
{ super.tearDown() },
|
||||
)
|
||||
}
|
||||
|
||||
override fun doTest(fileName: String) {
|
||||
IgnoreTests.runTestIfNotDisabledByFileDirective(Paths.get(fileName), IgnoreTests.DIRECTIVES.IGNORE_K2) {
|
||||
super.doTest(fileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -771,4 +771,23 @@ public abstract class FirParameterInfoTestGenerated extends AbstractFirParameter
|
||||
runTest("../../idea/tests/testData/parameterInfo/withLib3/useJavaSAMFromLib.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../idea/tests/testData/parameterInfo/withLib4")
|
||||
public static class WithLib4 extends AbstractFirParameterInfoTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("annotationWithTypeUse.kt")
|
||||
public void testAnnotationWithTypeUse() throws Exception {
|
||||
runTest("../../idea/tests/testData/parameterInfo/withLib4/annotationWithTypeUse.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.intellij.util.PathUtil
|
||||
import com.intellij.util.ThrowableRunnable
|
||||
import org.jetbrains.kotlin.executeOnPooledThreadInReadAction
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.base.test.IgnoreTests
|
||||
import org.jetbrains.kotlin.idea.base.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.idea.test.*
|
||||
import org.jetbrains.kotlin.idea.test.util.slashedPath
|
||||
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.allChildren
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
import java.nio.file.Paths
|
||||
|
||||
abstract class AbstractParameterInfoTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
private var mockLibraryFacility: MockLibraryFacility? = null
|
||||
@@ -46,7 +48,16 @@ abstract class AbstractParameterInfoTest : KotlinLightCodeInsightFixtureTestCase
|
||||
ThrowableRunnable { super.tearDown() },
|
||||
)
|
||||
|
||||
protected open fun doTest(fileName: String) {
|
||||
protected fun doTest(fileName: String) {
|
||||
IgnoreTests.runTestIfNotDisabledByFileDirective(
|
||||
Paths.get(fileName),
|
||||
IgnoreTests.DIRECTIVES.of(pluginMode)
|
||||
) {
|
||||
doActualTest(fileName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doActualTest(fileName: String) {
|
||||
val prefix = FileUtil.getNameWithoutExtension(PathUtil.getFileName(fileName))
|
||||
val mainFile = File(FileUtil.toSystemDependentName(fileName))
|
||||
mainFile.parentFile
|
||||
|
||||
@@ -752,4 +752,23 @@ public abstract class ParameterInfoTestGenerated extends AbstractParameterInfoTe
|
||||
runTest("testData/parameterInfo/withLib3/useJavaSAMFromLib.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("testData/parameterInfo/withLib4")
|
||||
public static class WithLib4 extends AbstractParameterInfoTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K1;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("annotationWithTypeUse.kt")
|
||||
public void testAnnotationWithTypeUse() throws Exception {
|
||||
runTest("testData/parameterInfo/withLib4/annotationWithTypeUse.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// IGNORE_K1
|
||||
package test
|
||||
|
||||
import p.ABC
|
||||
|
||||
fun foo() {
|
||||
ABC(<caret>)
|
||||
}
|
||||
|
||||
/*
|
||||
Text: (<highlight>title: @Ann String!</highlight>), Disabled: false, Strikeout: false, Green: true
|
||||
*/
|
||||
@@ -0,0 +1,5 @@
|
||||
package p;
|
||||
|
||||
public class ABC {
|
||||
public ABC(@Ann String title){}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package p;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.TYPE_USE})
|
||||
public @interface Ann {
|
||||
}
|
||||
@@ -198,7 +198,7 @@ private fun assembleWorkspace(): TWorkspace = workspace(KotlinPluginMode.K2) {
|
||||
testClass<AbstractFirParameterInfoTest> {
|
||||
model(
|
||||
"parameterInfo", pattern = Patterns.forRegex("^([\\w\\-_]+)\\.(kt|java)$"), isRecursive = true,
|
||||
excludedDirectories = listOf("withLib1/sharedLib", "withLib2/sharedLib", "withLib3/sharedLib")
|
||||
excludedDirectories = listOf("withLib1/sharedLib", "withLib2/sharedLib", "withLib3/sharedLib", "withLib4/sharedLib")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user