KT UAST: always preserve receiver expression of callable reference

It seems like qualifier type and qualifier expression did not co-exist,
but that only made users (like Lint detector) deal with inconsistent
examination of both information that are sometimes available or not.

Java UAST counterpart has both information always, so no good reason to
keep such contract in Kotlin UAST.

GitOrigin-RevId: 69f96325910cf8eea056449c984151925dffcf10
This commit is contained in:
Jinseong Jeon
2024-02-15 13:22:07 -08:00
committed by intellij-monorepo-bot
parent acbc5e7d11
commit dbaaeef8dc
8 changed files with 11 additions and 19 deletions

View File

@@ -1,8 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>TC.kt</file>
<line>6</line>
<description>Parameter &lt;code&gt;s&lt;/code&gt; is not used</description>
</problem>
</problems>

View File

@@ -3,7 +3,7 @@ fun main() {
}
fun foo(i: Int,
s: String //todo wrongly marked as unused, because simple references in callables are treated as class references
s: String
) {
println("Foo $i"::toString)
println(s::toString)

View File

@@ -8,8 +8,6 @@ import com.intellij.psi.PsiType
import com.intellij.psi.ResolveResult
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.internal.getResolveResultVariants
@@ -19,21 +17,18 @@ class KotlinUCallableReferenceExpression(
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UCallableReferenceExpression, UMultiResolvable, KotlinUElementWithType {
private val qualifierExpressionPart = UastLazyPart<UExpression?>()
private val qualifierTypePart = UastLazyPart<PsiType?>()
override val qualifierExpression: UExpression?
get() {
if (qualifierType != null) return null
val receiverExpression = sourcePsi.receiverExpression ?: return null
return baseResolveProviderService.baseKotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST)
get() = qualifierExpressionPart.getOrBuild {
val receiverExpression = sourcePsi.receiverExpression ?: return@getOrBuild null
baseResolveProviderService.baseKotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST)
}
override val qualifierType: PsiType?
get() = qualifierTypePart.getOrBuild {
if (sourcePsi.receiverExpression !is KtNameReferenceExpression && sourcePsi.receiverExpression !is KtDotQualifiedExpression) {
null
} else
baseResolveProviderService.getDoubleColonReceiverType(sourcePsi, this)
baseResolveProviderService.getDoubleColonReceiverType(sourcePsi, this)
}
override val callableName: String

View File

@@ -618,9 +618,10 @@ interface FirKotlinUastResolveProviderService : BaseKotlinUastResolveProviderSer
// Again, Analysis API returns [Unit] for statements, so we need to filter out
// some cases that are not actually expression's return type.
if (ktType.isUnit) {
val parent = ktExpression.parent
// E.g., AnnotationTarget.FIELD, reference to enum class is resolved to the constructor call,
// and then returned as Unit expression type. Same for path segments in a fully qualified name
if (ktExpression.parent is KtQualifiedExpression &&
if ((parent is KtQualifiedExpression || parent is KtDoubleColonExpression) &&
(ktExpression is KtQualifiedExpression || ktExpression is KtNameReferenceExpression)
) {
return null

View File

@@ -3,6 +3,7 @@ UFile (package = )
UField (name = x)
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
UCallableReferenceExpression (name = bar)
USimpleNameReferenceExpression (identifier = Foo)
UMethod (name = getX)
UClass (name = Foo)
UMethod (name = bar)

View File

@@ -3,6 +3,7 @@ UFile (package = ) [public final class MethodReferenceKt {...]
UField (name = x) [@org.jetbrains.annotations.NotNull private static final var x: kotlin.reflect.KFunction<kotlin.Unit> = Foo::bar]
UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull]
UCallableReferenceExpression (name = bar) [Foo::bar] : PsiType:KFunction<? extends Unit>
USimpleNameReferenceExpression (identifier = Foo) [Foo]
UMethod (name = getX) [public static final fun getX() : kotlin.reflect.KFunction<kotlin.Unit> = UastEmptyExpression]
UClass (name = Foo) [public final class Foo {...}]
UMethod (name = bar) [public final fun bar() : void {...}]

View File

@@ -3,6 +3,7 @@ UFile (package = ) [public final class MethodReferenceKt {...]
UField (name = x) [@org.jetbrains.annotations.NotNull private static final var x: kotlin.reflect.KFunction<kotlin.Unit> = Foo::bar]
UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull]
UCallableReferenceExpression (name = bar) [Foo::bar] = external Foo::bar()
USimpleNameReferenceExpression (identifier = Foo) [Foo] = external Foo()
UMethod (name = getX) [public static final fun getX() : kotlin.reflect.KFunction<kotlin.Unit> = UastEmptyExpression]
UClass (name = Foo) [public final class Foo {...}]
UMethod (name = bar) [public final fun bar() : void {...}]

View File

@@ -14,13 +14,11 @@ import org.jetbrains.uast.visitor.UastVisitor
interface UCallableReferenceExpression : UReferenceExpression {
/**
* Returns the qualifier expression.
* Can be null if the [qualifierType] is known.
*/
val qualifierExpression: UExpression?
/**
* Returns the qualifier type.
* Can be null if the qualifier is an expression.
*/
val qualifierType: PsiType?