191: Uast: making KotlinUObjectLiteralExpression provide a proper referenceNameElement (KT-30534)

This commit is contained in:
Nicolay Mitropolsky
2019-03-21 16:47:08 +03:00
parent e3a012cd19
commit ce40bfb259
9 changed files with 195 additions and 10 deletions
@@ -121,9 +121,7 @@ class KotlinUAnnotation(
override val uastAnchor by lazy {
KotlinUIdentifier(
javaPsi?.nameReferenceElement,
annotationEntry.typeReference?.typeElement?.let {
(it as? KtUserType)?.referenceExpression?.getReferencedNameElement() ?: it.navigationElement
},
annotationEntry.typeReference?.nameElement,
this
)
}
@@ -117,9 +117,7 @@ class KotlinUAnnotation(
override val uastAnchor by lazy {
KotlinUIdentifier(
javaPsi?.nameReferenceElement,
annotationEntry.typeReference?.typeElement?.let {
(it as? KtUserType)?.referenceExpression?.getReferencedNameElement() ?: it.navigationElement
},
annotationEntry.typeReference?.nameElement,
this
)
}
@@ -0,0 +1,92 @@
/*
* 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 com.intellij.psi.PsiMethod
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.psi.KtObjectLiteralExpression
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUObjectLiteralExpression(
override val psi: KtObjectLiteralExpression,
givenParent: UElement?
) : KotlinAbstractUExpression(givenParent), UObjectLiteralExpression, UCallExpressionEx, DelegatedMultiResolve, KotlinUElementWithType {
override val declaration: UClass by lz {
psi.objectDeclaration.toLightClass()
?.let { getLanguagePlugin().convert<UClass>(it, this) }
?: KotlinInvalidUClass("<invalid object code>", psi, this)
}
override fun getExpressionType() = psi.objectDeclaration.toPsiType()
private val superClassConstructorCall by lz {
psi.objectDeclaration.superTypeListEntries.firstOrNull { it is KtSuperTypeCallEntry } as? KtSuperTypeCallEntry
}
override val classReference: UReferenceExpression? by lz { superClassConstructorCall?.let { ObjectLiteralClassReference(it, this) } }
override val valueArgumentCount: Int
get() = superClassConstructorCall?.valueArguments?.size ?: 0
override val valueArguments by lz {
val psi = superClassConstructorCall ?: return@lz emptyList<UExpression>()
psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) }
}
override val typeArgumentCount: Int
get() = superClassConstructorCall?.typeArguments?.size ?: 0
override val typeArguments by lz {
val psi = superClassConstructorCall ?: return@lz emptyList<PsiType>()
psi.typeArguments.map { it.typeReference.toPsiType(this, boxed = true) }
}
override fun resolve() = superClassConstructorCall?.resolveCallToDeclaration() as? PsiMethod
override fun getArgumentForParameter(i: Int): UExpression? =
superClassConstructorCall?.let { it.getResolvedCall(it.analyze()) }?.let { getArgumentExpressionByIndex(i, it, this) }
private class ObjectLiteralClassReference(
override val psi: KtSuperTypeCallEntry,
givenParent: UElement?
) : KotlinAbstractUElement(givenParent), USimpleNameReferenceExpression {
override val javaPsi = null
override val sourcePsi = psi
override fun resolve() = (psi.resolveCallToDeclaration() as? PsiMethod)?.containingClass
override val annotations: List<UAnnotation>
get() = emptyList()
override val resolvedName: String?
get() = identifier
override val identifier: String
get() = psi.name ?: referenceNameElement.sourcePsi?.text ?: "<error>"
override val referenceNameElement: UElement
get() = KotlinUIdentifier(psi.typeReference?.nameElement, this)
}
}
@@ -326,6 +326,11 @@ internal fun KtExpression.getExpectedType(): KotlinType? = analyze()[BindingCont
internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this]
internal val KtTypeReference.nameElement: PsiElement?
get() = this.typeElement?.let {
(it as? KtUserType)?.referenceExpression?.getReferencedNameElement() ?: it.navigationElement
}
internal fun KotlinType.getFunctionalInterfaceType(source: UElement, element: KtElement): PsiType? =
takeIf { it.isInterface() && !it.isBuiltinFunctionalTypeOrSubtype }?.toPsiType(source, element, false)
@@ -19,6 +19,7 @@ runnable2 -> USimpleNameReferenceExpression (identifier = runnable2) from KtName
run -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Runnable -> USimpleNameReferenceExpression (identifier = Runnable) from KtNameReferenceExpression
Closeable -> USimpleNameReferenceExpression (identifier = Closeable) from KtNameReferenceExpression
InputStream -> USimpleNameReferenceExpression (identifier = InputStream) from KtObjectLiteralExpression
InputStream -> UObjectLiteralExpression from KtNameReferenceExpression
Runnable -> USimpleNameReferenceExpression (identifier = Runnable) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
+52
View File
@@ -0,0 +1,52 @@
A -> UClass (name = A)
str -> UParameter (name = str)
String -> USimpleNameReferenceExpression (identifier = String)
constructor -> UAnnotationMethod (name = A)
i -> UParameter (name = i)
Int -> USimpleNameReferenceExpression (identifier = Int)
this -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
i -> USimpleNameReferenceExpression (identifier = i)
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
foo -> UAnnotationMethod (name = foo)
a -> UParameter (name = a)
Long -> USimpleNameReferenceExpression (identifier = Long)
B -> UClass (name = B)
param -> UParameter (name = param)
String -> USimpleNameReferenceExpression (identifier = String)
A -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
param -> USimpleNameReferenceExpression (identifier = param)
C -> UClass (name = C)
A -> USimpleNameReferenceExpression (identifier = A)
constructor -> UAnnotationMethod (name = C)
p -> UParameter (name = p)
String -> USimpleNameReferenceExpression (identifier = String)
super -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
p -> USimpleNameReferenceExpression (identifier = p)
constructor -> UAnnotationMethod (name = C)
i -> UParameter (name = i)
Int -> USimpleNameReferenceExpression (identifier = Int)
super -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
i -> USimpleNameReferenceExpression (identifier = i)
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
foo -> UAnnotationMethod (name = foo)
a -> UParameter (name = a)
Long -> USimpleNameReferenceExpression (identifier = Long)
super -> USimpleNameReferenceExpression (identifier = super)
foo -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
a -> USimpleNameReferenceExpression (identifier = a)
O -> UClass (name = O)
A -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
anon -> UField (name = anon)
object -> UClass (name = null)
A -> UObjectLiteralExpression
bar -> UAnnotationMethod (name = bar)
cons -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1))
object -> UClass (name = null)
A -> UObjectLiteralExpression
innerObject -> UClass (name = innerObject)
A -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
InnerClass -> UClass (name = InnerClass)
A -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))
cons -> UAnnotationMethod (name = cons)
a -> UParameter (name = a)
A -> USimpleNameReferenceExpression (identifier = A)
@@ -0,0 +1,28 @@
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
i -> USimpleNameReferenceExpression (identifier = i) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Long -> USimpleNameReferenceExpression (identifier = Long) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
A -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) from KtNameReferenceExpression
param -> USimpleNameReferenceExpression (identifier = param) from KtNameReferenceExpression
A -> USimpleNameReferenceExpression (identifier = A) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
p -> USimpleNameReferenceExpression (identifier = p) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
i -> USimpleNameReferenceExpression (identifier = i) from KtNameReferenceExpression
println -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Long -> USimpleNameReferenceExpression (identifier = Long) from KtNameReferenceExpression
foo -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtDotQualifiedExpression
foo -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtNameReferenceExpression
a -> USimpleNameReferenceExpression (identifier = a) from KtNameReferenceExpression
A -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) from KtNameReferenceExpression
A -> USimpleNameReferenceExpression (identifier = A) from KtObjectLiteralExpression
A -> UObjectLiteralExpression from KtNameReferenceExpression
cons -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 1)) from KtNameReferenceExpression
A -> USimpleNameReferenceExpression (identifier = A) from KtObjectLiteralExpression
A -> UObjectLiteralExpression from KtNameReferenceExpression
A -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) from KtNameReferenceExpression
A -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1)) from KtNameReferenceExpression
A -> USimpleNameReferenceExpression (identifier = A) from KtNameReferenceExpression
@@ -1,13 +1,12 @@
package org.jetbrains.uast.test.kotlin
import com.intellij.psi.PsiElement
import org.jetbrains.uast.UFile
import org.jetbrains.uast.UReferenceExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.test.common.UElementToParentMap
import org.jetbrains.uast.test.common.kotlin.IdentifiersTestBase
import org.jetbrains.uast.test.env.assertEqualsToFile
import org.jetbrains.uast.toUElementOfType
import java.io.File
import kotlin.test.assertNotNull
abstract class AbstractKotlinIdentifiersTest : AbstractKotlinUastTest(), IdentifiersTestBase {
@@ -23,6 +22,15 @@ abstract class AbstractKotlinIdentifiersTest : AbstractKotlinUastTest(), Identif
}
}
fun UFile.asRefNames() = object : UElementToParentMap({ it.toUElementOfType<UReferenceExpression>()?.referenceNameElement }) {
private fun refNameRetriever(psiElement: PsiElement): UElement? =
when (val uElement = psiElement.toUElementOfExpectedTypes(UCallExpression::class.java, UReferenceExpression::class.java)) {
is UReferenceExpression -> uElement.referenceNameElement
is UCallExpression -> uElement.classReference?.referenceNameElement
else -> null
}?.also {
assertNotNull(it.sourcePsi, "referenceNameElement should have physical source, origin = $psiElement")
}
fun UFile.asRefNames() = object : UElementToParentMap(::refNameRetriever) {
override fun renderSource(element: PsiElement): String = element.javaClass.simpleName
}.visitUFileAndGetResult(this)
@@ -24,4 +24,7 @@ class KotlinUastIdentifiersTest : AbstractKotlinIdentifiersTest() {
@Test
fun testAnonymous() = doTest("Anonymous")
@Test
fun testSuperCalls() = doTest("SuperCalls")
}