From 2999d0bd4b6e0edd95e04c550ccdc5ee62cfc96d Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 8 Jun 2021 22:58:43 -0700 Subject: [PATCH] FIR/UAST: commonize double colon expressions --- .../api/components/KtPsiTypeProvider.kt | 8 ++- .../fir/components/KtFirPsiTypeProvider.kt | 27 +++++++++- .../BaseKotlinUastResolveProviderService.kt | 3 ++ .../KotlinUCallableReferenceExpression.kt | 21 ++------ .../KotlinUClassLiteralExpression.kt | 28 ++++++++++ .../uast/kotlin/FirKotlinConverter.kt | 2 + .../FirKotlinUastResolveProviderService.kt | 7 +++ .../MethodReference.log.fir.txt | 2 +- .../MethodReference.render.fir.txt | 2 +- .../legacyTypes/MethodReference.types.fir.txt | 4 +- .../MethodReference.values.fir.txt | 4 +- .../testData/type/classLiteral.kt | 15 ++++++ .../testData/type/classLiteral.types.fe10.txt | 53 +++++++++++++++++++ .../testData/type/classLiteral.types.fir.txt | 32 +++++++++++ .../kotlin/FE1UastTypesTestGenerated.java | 5 ++ .../uast/test/kotlin/FirUastResolveApiTest.kt | 30 +++++++++++ .../kotlin/FirUastTypesTestGenerated.java | 5 ++ .../org/jetbrains/uast/test/kotlin/utils.kt | 14 +++++ .../KotlinUastResolveProviderService.kt | 8 +++ .../KotlinUClassLiteralExpression.kt | 41 -------------- 20 files changed, 244 insertions(+), 67 deletions(-) rename plugins/{uast-kotlin => uast-kotlin-base}/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt (57%) create mode 100644 plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/expressions/KotlinUClassLiteralExpression.kt create mode 100644 plugins/uast-kotlin-fir/testData/type/classLiteral.kt create mode 100644 plugins/uast-kotlin-fir/testData/type/classLiteral.types.fe10.txt create mode 100644 plugins/uast-kotlin-fir/testData/type/classLiteral.types.fir.txt create mode 100644 plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/utils.kt delete mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUClassLiteralExpression.kt diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtPsiTypeProvider.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtPsiTypeProvider.kt index 3d369dc1466..96a17ffbd66 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtPsiTypeProvider.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/components/KtPsiTypeProvider.kt @@ -7,13 +7,17 @@ package org.jetbrains.kotlin.idea.frontend.api.components import com.intellij.psi.PsiType import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.psi.KtDoubleColonExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtTypeReference abstract class KtPsiTypeProvider : KtAnalysisSessionComponent() { abstract fun getPsiTypeForKtExpression(expression: KtExpression, mode: TypeMappingMode): PsiType - abstract fun getPsiTypeForKtTypeReference(ktTypeReference: KtTypeReference, mode: TypeMappingMode): PsiType + abstract fun getPsiTypeForReceiverOfDoubleColonExpression( + ktDoubleColonExpression: KtDoubleColonExpression, + mode: TypeMappingMode + ): PsiType? } interface KtPsiTypeProviderMixIn : KtAnalysisSessionMixIn { @@ -23,4 +27,6 @@ interface KtPsiTypeProviderMixIn : KtAnalysisSessionMixIn { fun KtTypeReference.getPsiType(mode: TypeMappingMode = TypeMappingMode.DEFAULT): PsiType = analysisSession.psiTypeProvider.getPsiTypeForKtTypeReference(this, mode) + fun KtDoubleColonExpression.getReceiverPsiType(mode: TypeMappingMode = TypeMappingMode.DEFAULT): PsiType? = + analysisSession.psiTypeProvider.getPsiTypeForReceiverOfDoubleColonExpression(this, mode) } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt index 3703d8cb58e..bb61b176ff8 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirPsiTypeProvider.kt @@ -6,11 +6,12 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components import com.intellij.psi.PsiType +import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.expressions.FirGetClassCall import org.jetbrains.kotlin.fir.expressions.FirStatement import org.jetbrains.kotlin.fir.references.FirNamedReference -import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.coneType +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.idea.fir.low.level.api.api.getOrBuildFir import org.jetbrains.kotlin.idea.frontend.api.components.KtPsiTypeProvider import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession @@ -18,6 +19,8 @@ import org.jetbrains.kotlin.idea.frontend.api.fir.utils.getReferencedElementType import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.name.StandardClassIds +import org.jetbrains.kotlin.psi.KtDoubleColonExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtTypeReference @@ -47,4 +50,24 @@ internal class KtFirPsiTypeProvider( else -> error("Unexpected ${fir::class}") } } + + override fun getPsiTypeForReceiverOfDoubleColonExpression( + ktDoubleColonExpression: KtDoubleColonExpression, + mode: TypeMappingMode + ): PsiType? = withValidityAssertion { + val receiver = ktDoubleColonExpression.receiverExpression ?: return null + when (val fir = ktDoubleColonExpression.getOrBuildFir(firResolveState)) { + is FirGetClassCall -> + fir.typeRef.coneType.getReceiverOfReflectionType()?.asPsiType(mode, receiver) + is FirCallableReferenceAccess -> + fir.typeRef.coneType.getReceiverOfReflectionType()?.asPsiType(mode, receiver) + else -> error("Unexpected ${fir::class}") + } + } + + private fun ConeKotlinType.getReceiverOfReflectionType(): ConeKotlinType? { + if (this !is ConeClassLikeType) return null + if (lookupTag.classId.packageFqName != StandardClassIds.BASE_REFLECT_PACKAGE) return null + return typeArguments.firstOrNull()?.type + } } diff --git a/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/BaseKotlinUastResolveProviderService.kt b/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/BaseKotlinUastResolveProviderService.kt index fa60f07fea8..bb9bfb5ef12 100644 --- a/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/BaseKotlinUastResolveProviderService.kt +++ b/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/BaseKotlinUastResolveProviderService.kt @@ -7,6 +7,7 @@ package org.jetbrains.uast.kotlin import com.intellij.psi.PsiElement import com.intellij.psi.PsiType +import org.jetbrains.kotlin.psi.KtDoubleColonExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtTypeReference import org.jetbrains.uast.UElement @@ -25,6 +26,8 @@ interface BaseKotlinUastResolveProviderService { fun resolveToType(ktTypeReference: KtTypeReference, source: UElement): PsiType? + fun getDoubleColonReceiverType(ktDoubleColonExpression: KtDoubleColonExpression, source: UElement): PsiType? + fun getExpressionType(uExpression: UExpression): PsiType? fun evaluate(uExpression: UExpression): Any? diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt b/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt similarity index 57% rename from plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt rename to plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt index 177f3f3d823..efc5f0f97bd 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt +++ b/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.uast.kotlin @@ -20,7 +9,6 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiNamedElement import com.intellij.psi.ResolveResult import org.jetbrains.kotlin.psi.KtCallableReferenceExpression -import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS import org.jetbrains.uast.* import org.jetbrains.uast.kotlin.internal.getResolveResultVariants @@ -32,12 +20,11 @@ class KotlinUCallableReferenceExpression( get() { if (qualifierType != null) return null val receiverExpression = sourcePsi.receiverExpression ?: return null - return KotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST) + return baseResolveProviderService.baseKotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST) } override val qualifierType by lz { - val ktType = sourcePsi.analyze()[DOUBLE_COLON_LHS, sourcePsi.receiverExpression]?.type ?: return@lz null - ktType.toPsiType(this, sourcePsi, boxed = true) + baseResolveProviderService.getDoubleColonReceiverType(sourcePsi, this) } override val callableName: String diff --git a/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/expressions/KotlinUClassLiteralExpression.kt b/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/expressions/KotlinUClassLiteralExpression.kt new file mode 100644 index 00000000000..f3de623cc88 --- /dev/null +++ b/plugins/uast-kotlin-base/src/org/jetbrains/uast/kotlin/expressions/KotlinUClassLiteralExpression.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.uast.kotlin + +import org.jetbrains.kotlin.psi.KtClassLiteralExpression +import org.jetbrains.uast.DEFAULT_EXPRESSION_TYPES_LIST +import org.jetbrains.uast.UClassLiteralExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UExpression + +class KotlinUClassLiteralExpression( + override val sourcePsi: KtClassLiteralExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UClassLiteralExpression, KotlinUElementWithType { + override val type by lz { + baseResolveProviderService.getDoubleColonReceiverType(sourcePsi, this) + } + + override val expression: UExpression? + get() { + if (type != null) return null + val receiverExpression = sourcePsi.receiverExpression ?: return null + return baseResolveProviderService.baseKotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST) + } +} diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt index 4fc7c40716f..918df967dda 100644 --- a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinConverter.kt @@ -309,6 +309,8 @@ internal object FirKotlinConverter : BaseKotlinConverter { is KtArrayAccessExpression -> expr(build(::FirKotlinUArrayAccessExpression)) + is KtCallableReferenceExpression -> expr(build(::KotlinUCallableReferenceExpression)) + is KtClassLiteralExpression -> expr(build(::KotlinUClassLiteralExpression)) is KtDotQualifiedExpression -> expr(build(::KotlinUQualifiedReferenceExpression)) is KtSimpleNameExpression -> expr(build(::FirKotlinUSimpleReferenceExpression)) diff --git a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt index 06ea4d7bdb0..02588a3082b 100644 --- a/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt +++ b/plugins/uast-kotlin-fir/src/org/jetbrains/uast/kotlin/FirKotlinUastResolveProviderService.kt @@ -10,6 +10,7 @@ import com.intellij.psi.PsiType import org.jetbrains.kotlin.idea.frontend.api.analyseForUast import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.psi.KtDoubleColonExpression import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtReferenceExpression import org.jetbrains.kotlin.psi.KtTypeReference @@ -42,6 +43,12 @@ interface FirKotlinUastResolveProviderService : BaseKotlinUastResolveProviderSer } } + override fun getDoubleColonReceiverType(ktDoubleColonExpression: KtDoubleColonExpression, source: UElement): PsiType? { + analyseForUast(ktDoubleColonExpression) { + return ktDoubleColonExpression.getReceiverPsiType(TypeMappingMode.DEFAULT_UAST) + } + } + override fun getExpressionType(uExpression: UExpression): PsiType? { val ktExpression = uExpression.sourcePsi as? KtExpression ?: return null analyseForUast(ktExpression) { diff --git a/plugins/uast-kotlin-fir/testData/legacyRenderLog/MethodReference.log.fir.txt b/plugins/uast-kotlin-fir/testData/legacyRenderLog/MethodReference.log.fir.txt index 1a4721c309b..2669df54079 100644 --- a/plugins/uast-kotlin-fir/testData/legacyRenderLog/MethodReference.log.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyRenderLog/MethodReference.log.fir.txt @@ -1,7 +1,7 @@ UFile (package = ) UClass (name = MethodReferenceKt) UField (name = x) - [!] UnknownKotlinExpression (CALLABLE_REFERENCE_EXPRESSION) + UCallableReferenceExpression (name = bar) UMethod (name = getX) UClass (name = Foo) UMethod (name = Foo) diff --git a/plugins/uast-kotlin-fir/testData/legacyRenderLog/MethodReference.render.fir.txt b/plugins/uast-kotlin-fir/testData/legacyRenderLog/MethodReference.render.fir.txt index 39127bbd8b0..01aa37900fa 100644 --- a/plugins/uast-kotlin-fir/testData/legacyRenderLog/MethodReference.render.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyRenderLog/MethodReference.render.fir.txt @@ -1,5 +1,5 @@ public final class MethodReferenceKt { - private static final var x: kotlin.reflect.KFunction = [!] UnknownKotlinExpression (CALLABLE_REFERENCE_EXPRESSION) + private static final var x: kotlin.reflect.KFunction = Foo::bar public static final fun getX() : kotlin.reflect.KFunction = UastEmptyExpression } diff --git a/plugins/uast-kotlin-fir/testData/legacyTypes/MethodReference.types.fir.txt b/plugins/uast-kotlin-fir/testData/legacyTypes/MethodReference.types.fir.txt index b7738183593..cb916bae34e 100644 --- a/plugins/uast-kotlin-fir/testData/legacyTypes/MethodReference.types.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyTypes/MethodReference.types.fir.txt @@ -1,7 +1,7 @@ UFile (package = ) [public final class MethodReferenceKt {...] UClass (name = MethodReferenceKt) [public final class MethodReferenceKt {...}] - UField (name = x) [private static final var x: kotlin.reflect.KFunction = [!] UnknownKotlinExpression (CALLABLE_REFERENCE_EXPRESSION)] - [!] UnknownKotlinExpression (CALLABLE_REFERENCE_EXPRESSION) [[!] UnknownKotlinExpression (CALLABLE_REFERENCE_EXPRESSION)] + UField (name = x) [private static final var x: kotlin.reflect.KFunction = Foo::bar] + UCallableReferenceExpression (name = bar) [Foo::bar] : PsiType:KFunction UMethod (name = getX) [public static final fun getX() : kotlin.reflect.KFunction = UastEmptyExpression] UClass (name = Foo) [public final class Foo {...}] UMethod (name = Foo) [public fun Foo() = UastEmptyExpression] diff --git a/plugins/uast-kotlin-fir/testData/legacyValues/MethodReference.values.fir.txt b/plugins/uast-kotlin-fir/testData/legacyValues/MethodReference.values.fir.txt index aead03d0819..5f4f85343fd 100644 --- a/plugins/uast-kotlin-fir/testData/legacyValues/MethodReference.values.fir.txt +++ b/plugins/uast-kotlin-fir/testData/legacyValues/MethodReference.values.fir.txt @@ -1,7 +1,7 @@ UFile (package = ) [public final class MethodReferenceKt {...] UClass (name = MethodReferenceKt) [public final class MethodReferenceKt {...}] - UField (name = x) [private static final var x: kotlin.reflect.KFunction = [!] UnknownKotlinExpression (CALLABLE_REFERENCE_EXPRESSION)] - [!] UnknownKotlinExpression (CALLABLE_REFERENCE_EXPRESSION) [[!] UnknownKotlinExpression (CALLABLE_REFERENCE_EXPRESSION)] = Undetermined + UField (name = x) [private static final var x: kotlin.reflect.KFunction = Foo::bar] + UCallableReferenceExpression (name = bar) [Foo::bar] = external Foo::bar() UMethod (name = getX) [public static final fun getX() : kotlin.reflect.KFunction = UastEmptyExpression] UClass (name = Foo) [public final class Foo {...}] UMethod (name = Foo) [public fun Foo() = UastEmptyExpression] diff --git a/plugins/uast-kotlin-fir/testData/type/classLiteral.kt b/plugins/uast-kotlin-fir/testData/type/classLiteral.kt new file mode 100644 index 00000000000..bb8a3c2d125 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/type/classLiteral.kt @@ -0,0 +1,15 @@ +class Foo(val s: String) { + override fun equals(other: Any?): Boolean { + if (other == null) return false + if (other::class != this::class) return false + return s == (other as Foo).s + } +} + +internal val stringClass = String::class + +fun box(): String { + val x: CharSequence = "" + val xClass = x::class + return if (xClass == stringClass) "OK" else "$xClass" +} diff --git a/plugins/uast-kotlin-fir/testData/type/classLiteral.types.fe10.txt b/plugins/uast-kotlin-fir/testData/type/classLiteral.types.fe10.txt new file mode 100644 index 00000000000..a6622bfaae2 --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/type/classLiteral.types.fe10.txt @@ -0,0 +1,53 @@ +UFile (package = ) [public final class ClassLiteralKt {...] + UClass (name = ClassLiteralKt) [public final class ClassLiteralKt {...}] + UField (name = stringClass) [@org.jetbrains.annotations.NotNull private static final var stringClass: kotlin.reflect.KClass = java.lang.String] + UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] + UClassLiteralExpression [java.lang.String] : PsiType:KClass + UMethod (name = getStringClass) [public static final fun getStringClass() : kotlin.reflect.KClass = UastEmptyExpression] + UMethod (name = box) [public static final fun box() : java.lang.String {...}] + UBlockExpression [{...}] : PsiType:Void + UDeclarationsExpression [var x: java.lang.CharSequence = ""] + ULocalVariable (name = x) [var x: java.lang.CharSequence = ""] + ULiteralExpression (value = "") [""] : PsiType:String + UDeclarationsExpression [var xClass: kotlin.reflect.KClass = java.lang.CharSequence] + ULocalVariable (name = xClass) [var xClass: kotlin.reflect.KClass = java.lang.CharSequence] + UClassLiteralExpression [java.lang.CharSequence] : PsiType:KClass + UReturnExpression [return if (xClass == stringClass) "OK" else xClass] : PsiType:Void + UIfExpression [if (xClass == stringClass) "OK" else xClass] : PsiType:String + UBinaryExpression (operator = ==) [xClass == stringClass] : PsiType:boolean + USimpleNameReferenceExpression (identifier = xClass) [xClass] : PsiType:KClass + USimpleNameReferenceExpression (identifier = stringClass) [stringClass] : PsiType:KClass + ULiteralExpression (value = "OK") ["OK"] : PsiType:String + USimpleNameReferenceExpression (identifier = xClass) [xClass] : PsiType:KClass + UClass (name = Foo) [public final class Foo {...}] + UField (name = s) [@org.jetbrains.annotations.NotNull private final var s: java.lang.String] + UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] + UMethod (name = equals) [public fun equals(@org.jetbrains.annotations.Nullable other: java.lang.Object) : boolean {...}] + UParameter (name = other) [@org.jetbrains.annotations.Nullable var other: java.lang.Object] + UAnnotation (fqName = org.jetbrains.annotations.Nullable) [@org.jetbrains.annotations.Nullable] + UBlockExpression [{...}] : PsiType:Void + UIfExpression [if (other == null) return false] : PsiType:void + UBinaryExpression (operator = ==) [other == null] : PsiType:boolean + USimpleNameReferenceExpression (identifier = other) [other] : PsiType:Object + ULiteralExpression (value = null) [null] : PsiType:Void + UReturnExpression [return false] : PsiType:Void + ULiteralExpression (value = false) [false] : PsiType:boolean + UIfExpression [if (java.lang.Object != Foo) return false] : PsiType:void + UBinaryExpression (operator = !=) [java.lang.Object != Foo] : PsiType:boolean + UClassLiteralExpression [java.lang.Object] : PsiType:KClass + UClassLiteralExpression [Foo] : PsiType:KClass + UReturnExpression [return false] : PsiType:Void + ULiteralExpression (value = false) [false] : PsiType:boolean + UReturnExpression [return s == (other as Foo).s] : PsiType:Void + UBinaryExpression (operator = ==) [s == (other as Foo).s] : PsiType:boolean + USimpleNameReferenceExpression (identifier = s) [s] : PsiType:String + UQualifiedReferenceExpression [(other as Foo).s] : PsiType:String + UParenthesizedExpression [(other as Foo)] : PsiType:Foo + UBinaryExpressionWithType [other as Foo] : PsiType:Foo + USimpleNameReferenceExpression (identifier = other) [other] : PsiType:Object + UTypeReferenceExpression (name = Foo) [Foo] + USimpleNameReferenceExpression (identifier = s) [s] : PsiType:String + UMethod (name = getS) [public final fun getS() : java.lang.String = UastEmptyExpression] + UMethod (name = Foo) [public fun Foo(@org.jetbrains.annotations.NotNull s: java.lang.String) = UastEmptyExpression] + UParameter (name = s) [@org.jetbrains.annotations.NotNull var s: java.lang.String] + UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] diff --git a/plugins/uast-kotlin-fir/testData/type/classLiteral.types.fir.txt b/plugins/uast-kotlin-fir/testData/type/classLiteral.types.fir.txt new file mode 100644 index 00000000000..499d5dc9d0f --- /dev/null +++ b/plugins/uast-kotlin-fir/testData/type/classLiteral.types.fir.txt @@ -0,0 +1,32 @@ +UFile (package = ) [public final class ClassLiteralKt {...] + UClass (name = ClassLiteralKt) [public final class ClassLiteralKt {...}] + UField (name = stringClass) [private static final var stringClass: kotlin.reflect.KClass = java.lang.String] + UClassLiteralExpression [java.lang.String] : PsiType:KClass + UMethod (name = getStringClass) [public static final fun getStringClass() : kotlin.reflect.KClass = UastEmptyExpression] + UMethod (name = box) [public static final fun box() : java.lang.String {...}] + UBlockExpression [{...}] : PsiType:Void + [!] UnknownKotlinExpression (PROPERTY) [[!] UnknownKotlinExpression (PROPERTY)] + [!] UnknownKotlinExpression (PROPERTY) [[!] UnknownKotlinExpression (PROPERTY)] + UReturnExpression [return if ([!] UnknownKotlinExpression (BINARY_EXPRESSION)) "OK" else xClass] : PsiType:Void + UIfExpression [if ([!] UnknownKotlinExpression (BINARY_EXPRESSION)) "OK" else xClass] : PsiType:String + [!] UnknownKotlinExpression (BINARY_EXPRESSION) [[!] UnknownKotlinExpression (BINARY_EXPRESSION)] + ULiteralExpression (value = "OK") ["OK"] : PsiType:String + USimpleNameReferenceExpression (identifier = xClass) [xClass] : PsiType:KClass + UClass (name = Foo) [public final class Foo {...}] + UField (name = s) [private final var s: java.lang.String] + UMethod (name = Foo) [public fun Foo(s: java.lang.String) = UastEmptyExpression] + UParameter (name = s) [var s: java.lang.String] + UMethod (name = getS) [public final fun getS() : java.lang.String = UastEmptyExpression] + UMethod (name = equals) [public fun equals(other: java.lang.Object) : boolean {...}] + UParameter (name = other) [var other: java.lang.Object] + UBlockExpression [{...}] : PsiType:Void + UIfExpression [if ([!] UnknownKotlinExpression (BINARY_EXPRESSION)) return false] : PsiType:Unit + [!] UnknownKotlinExpression (BINARY_EXPRESSION) [[!] UnknownKotlinExpression (BINARY_EXPRESSION)] + UReturnExpression [return false] : PsiType:Void + ULiteralExpression (value = false) [false] : PsiType:boolean + UIfExpression [if ([!] UnknownKotlinExpression (BINARY_EXPRESSION)) return false] : PsiType:Unit + [!] UnknownKotlinExpression (BINARY_EXPRESSION) [[!] UnknownKotlinExpression (BINARY_EXPRESSION)] + UReturnExpression [return false] : PsiType:Void + ULiteralExpression (value = false) [false] : PsiType:boolean + UReturnExpression [return [!] UnknownKotlinExpression (BINARY_EXPRESSION)] : PsiType:Void + [!] UnknownKotlinExpression (BINARY_EXPRESSION) [[!] UnknownKotlinExpression (BINARY_EXPRESSION)] diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FE1UastTypesTestGenerated.java b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FE1UastTypesTestGenerated.java index ad2bb98fc00..1b71d1f4c4e 100644 --- a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FE1UastTypesTestGenerated.java +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FE1UastTypesTestGenerated.java @@ -44,6 +44,11 @@ public class FE1UastTypesTestGenerated extends AbstractFE1UastTypesTest { runTest("plugins/uast-kotlin-fir/testData/type/arrayGetAssignMultiIndex.kt"); } + @TestMetadata("classLiteral.kt") + public void testClassLiteral() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/type/classLiteral.kt"); + } + @TestMetadata("typeCast.kt") public void testTypeCast() throws Exception { runTest("plugins/uast-kotlin-fir/testData/type/typeCast.kt"); diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastResolveApiTest.kt b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastResolveApiTest.kt index 6c2232da202..d41347d65c1 100644 --- a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastResolveApiTest.kt +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastResolveApiTest.kt @@ -6,14 +6,19 @@ package org.jetbrains.uast.test.kotlin import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement import com.intellij.psi.PsiField import com.intellij.psi.PsiMethod import com.intellij.testFramework.TestDataPath import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.test.JUnit3RunnerWithInners import org.jetbrains.kotlin.test.TestMetadata +import org.jetbrains.uast.UCallableReferenceExpression +import org.jetbrains.uast.UElement import org.jetbrains.uast.UFile +import org.jetbrains.uast.test.common.kotlin.asRefNames import org.jetbrains.uast.test.env.kotlin.AbstractFirUastTest +import org.jetbrains.uast.visitor.UastVisitor import org.junit.Assert import org.junit.runner.RunWith import java.lang.IllegalStateException @@ -36,6 +41,31 @@ class FirUastResolveApiTest : AbstractFirUastTest() { // Bogus } + @TestMetadata("MethodReference.kt") + fun testMethodReference() { + doCheck("plugins/uast-kotlin/testData/MethodReference.kt") { _, uFile -> + val facade = uFile.findFacade() + ?: throw IllegalStateException("No facade found at ${uFile.asRefNames()}") + // val x = Foo::bar + val x = facade.fields.single() + var barReference: PsiElement? = null + x.accept(object : UastVisitor { + override fun visitElement(node: UElement): Boolean { + return false + } + + override fun visitCallableReferenceExpression(node: UCallableReferenceExpression): Boolean { + barReference = node.resolve() + return false + } + }) + Assert.assertNotNull("Foo::bar is not resolved", barReference) + Assert.assertTrue("Foo::bar is not a function", barReference is KtNamedFunction) + Assert.assertEquals("Foo.bar", (barReference as KtNamedFunction).fqName?.asString()) + } + } + + @TestMetadata("Imports.kt") fun testImports() { doCheck("plugins/uast-kotlin/testData/Imports.kt") { _, uFile -> diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastTypesTestGenerated.java b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastTypesTestGenerated.java index ae102d50d92..63e4f99f90e 100644 --- a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastTypesTestGenerated.java +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/FirUastTypesTestGenerated.java @@ -44,6 +44,11 @@ public class FirUastTypesTestGenerated extends AbstractFirUastTypesTest { runTest("plugins/uast-kotlin-fir/testData/type/arrayGetAssignMultiIndex.kt"); } + @TestMetadata("classLiteral.kt") + public void testClassLiteral() throws Exception { + runTest("plugins/uast-kotlin-fir/testData/type/classLiteral.kt"); + } + @TestMetadata("typeCast.kt") public void testTypeCast() throws Exception { runTest("plugins/uast-kotlin-fir/testData/type/typeCast.kt"); diff --git a/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/utils.kt b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/utils.kt new file mode 100644 index 00000000000..28091580ef3 --- /dev/null +++ b/plugins/uast-kotlin-fir/tests/org/jetbrains/uast/test/kotlin/utils.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.uast.test.kotlin + +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.uast.UClass +import org.jetbrains.uast.UFile + +internal fun UFile.findFacade(): UClass? { + return classes.find { it.sourcePsi is KtLightClassForFacade } +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastResolveProviderService.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastResolveProviderService.kt index 7cb2907bdf8..977ae6ec870 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastResolveProviderService.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastResolveProviderService.kt @@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiType import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.config.LanguageVersionSettings +import org.jetbrains.kotlin.psi.KtDoubleColonExpression import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtTypeReference @@ -38,6 +39,13 @@ interface KotlinUastResolveProviderService : BaseKotlinUastResolveProviderServic return ktTypeReference.toPsiType(source) } + override fun getDoubleColonReceiverType(ktDoubleColonExpression: KtDoubleColonExpression, source: UElement): PsiType? { + val ktType = + ktDoubleColonExpression.analyze()[BindingContext.DOUBLE_COLON_LHS, ktDoubleColonExpression.receiverExpression]?.type + ?: return null + return ktType.toPsiType(source, ktDoubleColonExpression, boxed = true) + } + override fun getExpressionType(uExpression: UExpression): PsiType? { val ktElement = uExpression.sourcePsi as? KtExpression ?: return null val ktType = ktElement.analyze()[BindingContext.EXPRESSION_TYPE_INFO, ktElement]?.type ?: return null diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUClassLiteralExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUClassLiteralExpression.kt deleted file mode 100644 index 8365e36666e..00000000000 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUClassLiteralExpression.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.uast.kotlin - -import org.jetbrains.kotlin.psi.KtClassLiteralExpression -import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS -import org.jetbrains.uast.DEFAULT_EXPRESSION_TYPES_LIST -import org.jetbrains.uast.UClassLiteralExpression -import org.jetbrains.uast.UElement -import org.jetbrains.uast.UExpression - -class KotlinUClassLiteralExpression( - override val sourcePsi: KtClassLiteralExpression, - givenParent: UElement? -) : KotlinAbstractUExpression(givenParent), UClassLiteralExpression, KotlinUElementWithType { - override val type by lz { - val ktType = sourcePsi.analyze()[DOUBLE_COLON_LHS, sourcePsi.receiverExpression]?.type ?: return@lz null - ktType.toPsiType(this, sourcePsi, boxed = true) - } - - override val expression: UExpression? - get() { - if (type != null) return null - val receiverExpression = sourcePsi.receiverExpression ?: return null - return KotlinConverter.convertExpression(receiverExpression, this, DEFAULT_EXPRESSION_TYPES_LIST) - } -} \ No newline at end of file