diff --git a/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/codeinsights/impl/base/JavaArgumentNameCommentUtils.kt b/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/codeinsights/impl/base/JavaArgumentNameCommentUtils.kt index 2ea01086e6e9..1ce04c2e25a2 100644 --- a/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/codeinsights/impl/base/JavaArgumentNameCommentUtils.kt +++ b/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/codeinsights/impl/base/JavaArgumentNameCommentUtils.kt @@ -7,6 +7,7 @@ import com.intellij.psi.SmartPsiElementPointer import com.intellij.psi.createSmartPointer import com.intellij.psi.util.elementType import com.intellij.psi.util.siblings +import org.jetbrains.annotations.ApiStatus import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.calls.successfulFunctionCallOrNull import org.jetbrains.kotlin.analysis.api.calls.symbol @@ -34,7 +35,11 @@ fun KtValueArgument.getBlockCommentWithName(): PsiComment? = .filterIsInstance() .firstOrNull { it.elementType == KtTokens.BLOCK_COMMENT && it.text.removeSuffix("*/").trim().endsWith("=") } -class ArgumentNameCommentInfo(val argumentName: Name, val comment: String) +@ApiStatus.Internal +class ArgumentNameCommentInfo(val argumentName: Name, val comment: String) { + @ApiStatus.Internal + constructor(symbol: KtValueParameterSymbol): this(symbol.name, symbol.toArgumentNameComment()) +} typealias NameCommentsByArgument = Map, ArgumentNameCommentInfo> @@ -62,7 +67,7 @@ fun getArgumentNameComments(element: KtCallElement): NameCommentsByArgument? { // subsequent varargs. .takeWhileInclusive { !it.second.isVararg } .associate { (argument, symbol) -> - argument.createSmartPointer() to ArgumentNameCommentInfo(symbol.name, symbol.toArgumentNameComment()) + argument.createSmartPointer() to ArgumentNameCommentInfo(symbol) } } @@ -72,6 +77,7 @@ private fun KtCallElement.getNonLambdaArguments(): List = private fun KtValueParameterSymbol.toArgumentNameComment(): String = canonicalArgumentNameComment(if (isVararg) "...$name" else name.toString()) +@ApiStatus.Internal fun PsiComment.isExpectedArgumentNameComment(info: ArgumentNameCommentInfo): Boolean { if (this.elementType != KtTokens.BLOCK_COMMENT) return false val parameterName = text diff --git a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/hints/KtParameterHintsProvider.kt b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/hints/KtParameterHintsProvider.kt index 88313110fd2c..d84bf78bf80d 100644 --- a/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/hints/KtParameterHintsProvider.kt +++ b/plugins/kotlin/code-insight/kotlin.code-insight.k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/hints/KtParameterHintsProvider.kt @@ -8,13 +8,17 @@ import com.intellij.codeInsight.hints.declarative.PsiPointerInlayActionNavigatio import com.intellij.codeInsight.hints.declarative.PsiPointerInlayActionPayload import com.intellij.codeInsight.hints.filtering.Matcher import com.intellij.codeInsight.hints.filtering.MatcherConstructor +import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement +import com.intellij.psi.PsiWhiteSpace import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.analyze import org.jetbrains.kotlin.analysis.api.calls.singleFunctionCallOrNull import org.jetbrains.kotlin.analysis.api.calls.symbol import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol +import org.jetbrains.kotlin.idea.codeinsights.impl.base.ArgumentNameCommentInfo +import org.jetbrains.kotlin.idea.codeinsights.impl.base.isExpectedArgumentNameComment import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtCallElement import org.jetbrains.kotlin.psi.KtValueArgument @@ -106,8 +110,8 @@ class KtParameterHintsProvider : AbstractKtInlayHintsProvider() { if (argument.getArgumentName()?.asName != name) break continue } - // avoid cases like "`value:` value" - if (argument.text == name.asString()) continue + + if (argument.isArgumentNamed(symbol)) continue name.takeUnless(Name::isSpecial)?.asString()?.let { stringName -> sink.addPresentation(InlineInlayPosition(argument.startOffset, true), hasBackground = true) { @@ -124,4 +128,24 @@ class KtParameterHintsProvider : AbstractKtInlayHintsProvider() { } } } + + private fun KtValueArgument.isArgumentNamed(symbol: KtValueParameterSymbol): Boolean { + // avoid cases like "`value:` value" + if (this.text == symbol.name.asString()) return true + + // avoid cases like "/* value = */ value" + var sibling: PsiElement? = this.prevSibling + while (sibling != null) { + when(sibling) { + is PsiComment -> { + val argumentNameCommentInfo = ArgumentNameCommentInfo(symbol) + return sibling.isExpectedArgumentNameComment(argumentNameCommentInfo) + } + !is PsiWhiteSpace -> break + } + sibling = sibling.prevSibling + } + + return false + } } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/codeInsight/hints/arguments/javaParameters.k2.kt b/plugins/kotlin/idea/tests/testData/codeInsight/hints/arguments/javaParameters.k2.kt index a2972eae222e..3ba6369e5f37 100644 --- a/plugins/kotlin/idea/tests/testData/codeInsight/hints/arguments/javaParameters.k2.kt +++ b/plugins/kotlin/idea/tests/testData/codeInsight/hints/arguments/javaParameters.k2.kt @@ -1,20 +1,20 @@ fun javaParameters() { val some = SomeClass() - some.invokeMe(/* in */ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* name = */ "me") - some.invokeMe(/* index = */ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* na = */ /*<# [javaParameters.dependency.java:61]name|: #>*/"me") - some.invokeMe(/*<# [javaParameters.dependency.java:50]index|: #>*/0, "me") - some.invokeMe(/* index = */ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* name = */ /*<# [javaParameters.dependency.java:61]name|: #>*/"me") + some.invokeMe(/* in */ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* name = */ "me") + some.invokeMe(/* index = */ 0, /* na = */ /*<# [javaParameters.dependency.java:61]name|: #>*/"me") + some.invokeMe(/*<# [javaParameters.dependency.java:50]index|: #>*/0, /*<# [javaParameters.dependency.java:61]name|: #>*/"me") + some.invokeMe(/* index = */ 0, /* name = */ "me") - some.invokeMe(/*index = */ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* name = */ /*<# [javaParameters.dependency.java:61]name|: #>*/"me") - some.invokeMe(/* index= */ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* name = */ /*<# [javaParameters.dependency.java:61]name|: #>*/"me") - some.invokeMe(/* index=*/ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* name = */ /*<# [javaParameters.dependency.java:61]name|: #>*/"me") - some.invokeMe(/* index =*/ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* name = */ /*<# [javaParameters.dependency.java:61]name|: #>*/"me") - some.invokeMe(/* index = */ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* name = */ /*<# [javaParameters.dependency.java:61]name|: #>*/"me") + some.invokeMe(/*index = */ 0, /* name = */ "me") + some.invokeMe(/* index= */ 0, /* name = */ "me") + some.invokeMe(/* index=*/ 0, /* name = */"me") + some.invokeMe(/* index =*/ 0, /* name = */ "me") + some.invokeMe(/* index = */ 0, /* name = */ "me") - some.doNotInvokeMe(/* index = */ /*<# [javaParameters.dependency.java:114]index|: #>*/0, /* ...args = */ /*<# …|[javaParameters.dependency.java:125]args|: #>*/"a", "b") - some.doNotInvokeMe(/* index = */ /*<# [javaParameters.dependency.java:114]index|: #>*/0, /* ...names = */ /*<# …|[javaParameters.dependency.java:125]args|: #>*/"a", "b") + some.doNotInvokeMe(/* index= */ 0, /* ...args= */ "a", "b") + some.doNotInvokeMe(/* index = */ 0, /* ...names = */ /*<# …|[javaParameters.dependency.java:125]args|: #>*/"a", "b") some.singleParamDslWithSameParamName(/*<# [javaParameters.dependency.java:200]singleParamDslWithSameParamNam...|: #>*/"no hint param name equals method name") some.sameFirstParamNameAndVararg(/*<# [javaParameters.dependency.java:294]sameFirstParamNameAndVararg|: #>*/"no hint param name equals method name") - some.sameFirstParamNameAndVararg(/*<# [javaParameters.dependency.java:294]sameFirstParamNameAndVararg|: #>*/"no hint param name equals method name", /*<# …|[javaParameters.dependency.java:330]variables|: #>*/123) + some.sameFirstParamNameAndVararg(/*<# [javaParameters.dependency.java:294]sameFirstParamNameAndVararg|: #>*/"no hint param name equals method name", /*<# …|[javaParameters.dependency.java:330]variables|: #>*/>123) } \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/codeInsight/hints/arguments/javaParameters.kt b/plugins/kotlin/idea/tests/testData/codeInsight/hints/arguments/javaParameters.kt index 3627f9747644..c380a7d1c2d6 100644 --- a/plugins/kotlin/idea/tests/testData/codeInsight/hints/arguments/javaParameters.kt +++ b/plugins/kotlin/idea/tests/testData/codeInsight/hints/arguments/javaParameters.kt @@ -11,7 +11,7 @@ fun javaParameters() { some.invokeMe(/* index =*/ 0, /* name = */ "me") some.invokeMe(/* index = */ 0, /* name = */ "me") - some.doNotInvokeMe(/* index = */ 0, /* ...args = */ "a", "b") + some.doNotInvokeMe(/* index= */ 0, /* ...args= */ "a", "b") some.doNotInvokeMe(/* index = */ 0, /* ...names = */ "a", "b") some.singleParamDslWithSameParamName("no hint param name equals method name")