[kotlin] Do not show parameter hints on argument for Java parameter with a "named argument" comment

#KTIJ-29299 Fixed

GitOrigin-RevId: 8ebf80a4fcc0b40ad104c669670ef9184482495a
This commit is contained in:
Vladimir Dolzhenko
2024-04-03 20:07:27 +02:00
committed by intellij-monorepo-bot
parent 0b75360e40
commit 89eee1e509
4 changed files with 47 additions and 17 deletions

View File

@@ -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<PsiComment>()
.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<SmartPsiElementPointer<KtValueArgument>, 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<KtValueArgument> =
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

View File

@@ -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
}
}

View File

@@ -1,20 +1,20 @@
fun javaParameters() {
val some = SomeClass()
some.invokeMe(/* in */ /*<# [javaParameters.dependency.java:50]index|: #>*/<hint text="index:"/>0, /* name = */ "me")
some.invokeMe(/* index = */ /*<# [javaParameters.dependency.java:50]index|: #>*/0, /* na = */ /*<# [javaParameters.dependency.java:61]name|: #>*/<hint text="name:"/>"me")
some.invokeMe(/*<# [javaParameters.dependency.java:50]index|: #>*/<hint text="index:"/>0, <hint text="name:"/>"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|: #>*/<hint text="...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|: #>*/<hint text="...variables:"/>123)
some.sameFirstParamNameAndVararg(/*<# [javaParameters.dependency.java:294]sameFirstParamNameAndVararg|: #>*/"no hint param name equals method name", /*<# …|[javaParameters.dependency.java:330]variables|: #>*/>123)
}

View File

@@ -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 = */ <hint text="...args:"/>"a", "b")
some.singleParamDslWithSameParamName("no hint param name equals method name")