as32: Restore uast to 181 platform state
This commit is contained in:
@@ -1,52 +0,0 @@
|
|||||||
|
|
||||||
plugins {
|
|
||||||
kotlin("jvm")
|
|
||||||
id("jps-compatible")
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compile(projectDist(":kotlin-stdlib"))
|
|
||||||
compile(project(":core:util.runtime"))
|
|
||||||
compile(project(":compiler:backend"))
|
|
||||||
compile(project(":compiler:frontend"))
|
|
||||||
compile(project(":compiler:frontend.java"))
|
|
||||||
compile(project(":compiler:light-classes"))
|
|
||||||
compile(project(":idea:idea-core"))
|
|
||||||
compileOnly(intellijDep()) { includeJars("openapi", "idea", "java-api", "java-impl", "util", "extensions", "asm-all") }
|
|
||||||
|
|
||||||
testCompile(projectDist(":kotlin-test:kotlin-test-jvm"))
|
|
||||||
testCompile(projectTests(":compiler:tests-common"))
|
|
||||||
testCompile(commonDep("junit:junit"))
|
|
||||||
testCompile(project(":compiler:util"))
|
|
||||||
testCompile(project(":compiler:cli"))
|
|
||||||
testCompile(projectTests(":idea:idea-test-framework"))
|
|
||||||
testCompileOnly(intellijDep()) { includeJars("java-api", "java-impl", "idea_rt") }
|
|
||||||
|
|
||||||
testRuntime(projectDist(":kotlin-reflect"))
|
|
||||||
testRuntime(project(":idea:idea-android"))
|
|
||||||
testRuntime(project(":idea:idea-gradle"))
|
|
||||||
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
|
|
||||||
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
|
||||||
testRuntime(project(":allopen-ide-plugin"))
|
|
||||||
testRuntime(project(":noarg-ide-plugin"))
|
|
||||||
testRuntime(project(":plugins:android-extensions-ide"))
|
|
||||||
testRuntime(project(":plugins:kapt3-idea"))
|
|
||||||
testRuntime(intellijDep())
|
|
||||||
testRuntime(intellijPluginDep("junit"))
|
|
||||||
testRuntime(intellijPluginDep("gradle"))
|
|
||||||
testRuntime(intellijPluginDep("Groovy"))
|
|
||||||
testRuntime(intellijPluginDep("properties"))
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
"main" { projectDefault() }
|
|
||||||
"test" { projectDefault() }
|
|
||||||
}
|
|
||||||
|
|
||||||
testsJar {}
|
|
||||||
|
|
||||||
projectTest {
|
|
||||||
workingDir = rootDir
|
|
||||||
}
|
|
||||||
|
|
||||||
ideaPlugin()
|
|
||||||
@@ -1,555 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.lang.Language
|
|
||||||
import com.intellij.openapi.util.Key
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.*
|
|
||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
|
||||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
|
||||||
import org.jetbrains.kotlin.idea.util.module
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
|
||||||
import org.jetbrains.uast.kotlin.expressions.*
|
|
||||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
|
|
||||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
|
||||||
|
|
||||||
interface KotlinUastBindingContextProviderService {
|
|
||||||
fun getBindingContext(element: KtElement): BindingContext
|
|
||||||
fun getTypeMapper(element: KtElement): KotlinTypeMapper?
|
|
||||||
}
|
|
||||||
|
|
||||||
var PsiElement.destructuringDeclarationInitializer: Boolean? by UserDataProperty(Key.create("kotlin.uast.destructuringDeclarationInitializer"))
|
|
||||||
|
|
||||||
class KotlinUastLanguagePlugin : UastLanguagePlugin {
|
|
||||||
override val priority = 10
|
|
||||||
|
|
||||||
override val language: Language
|
|
||||||
get() = KotlinLanguage.INSTANCE
|
|
||||||
|
|
||||||
override fun isFileSupported(fileName: String): Boolean {
|
|
||||||
return fileName.endsWith(".kt", false) || fileName.endsWith(".kts", false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val PsiElement.isJvmElement
|
|
||||||
get() = try {
|
|
||||||
// Workaround for UAST used without full-fledged IDEA when ProjectFileIndex is not available
|
|
||||||
// If we can't get the module (or don't have one), act as if the current platform is JVM
|
|
||||||
val module = module
|
|
||||||
module == null || TargetPlatformDetector.getPlatform(module) is JvmPlatform
|
|
||||||
} catch (e: Exception) {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class<out UElement>?): UElement? {
|
|
||||||
if (!element.isJvmElement) return null
|
|
||||||
return convertDeclarationOrElement(element, parent, requiredType)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun convertElementWithParent(element: PsiElement, requiredType: Class<out UElement>?): UElement? {
|
|
||||||
if (!element.isJvmElement) return null
|
|
||||||
if (element is PsiFile) return convertDeclaration(element, null, requiredType)
|
|
||||||
if (element is KtLightClassForFacade) return convertDeclaration(element, null, requiredType)
|
|
||||||
|
|
||||||
return convertDeclarationOrElement(element, null, requiredType)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertDeclarationOrElement(element: PsiElement, givenParent: UElement?, requiredType: Class<out UElement>?): UElement? {
|
|
||||||
if (element is UElement) return element
|
|
||||||
|
|
||||||
if (element.isValid) {
|
|
||||||
element.getUserData(KOTLIN_CACHED_UELEMENT_KEY)?.get()?.let { cachedUElement ->
|
|
||||||
return if (requiredType == null || requiredType.isInstance(cachedUElement)) cachedUElement else null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val uElement = convertDeclaration(element, givenParent, requiredType)
|
|
||||||
?: KotlinConverter.convertPsiElement(element, givenParent, requiredType)
|
|
||||||
/*
|
|
||||||
if (uElement != null) {
|
|
||||||
element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, WeakReference(uElement))
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return uElement
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMethodCallExpression(
|
|
||||||
element: PsiElement,
|
|
||||||
containingClassFqName: String?,
|
|
||||||
methodName: String
|
|
||||||
): UastLanguagePlugin.ResolvedMethod? {
|
|
||||||
if (element !is KtCallExpression) return null
|
|
||||||
val resolvedCall = element.getResolvedCall(element.analyze()) ?: return null
|
|
||||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
|
||||||
if (resultingDescriptor !is FunctionDescriptor || resultingDescriptor.name.asString() != methodName) return null
|
|
||||||
|
|
||||||
val parent = element.parent
|
|
||||||
val parentUElement = convertElementWithParent(parent, null) ?: return null
|
|
||||||
|
|
||||||
val uExpression = KotlinUFunctionCallExpression(element, parentUElement, resolvedCall)
|
|
||||||
val method = uExpression.resolve() ?: return null
|
|
||||||
if (method.name != methodName) return null
|
|
||||||
return UastLanguagePlugin.ResolvedMethod(uExpression, method)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getConstructorCallExpression(
|
|
||||||
element: PsiElement,
|
|
||||||
fqName: String
|
|
||||||
): UastLanguagePlugin.ResolvedConstructor? {
|
|
||||||
if (element !is KtCallExpression) return null
|
|
||||||
val resolvedCall = element.getResolvedCall(element.analyze()) ?: return null
|
|
||||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
|
||||||
if (resultingDescriptor !is ConstructorDescriptor
|
|
||||||
|| resultingDescriptor.returnType.constructor.declarationDescriptor?.name?.asString() != fqName) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val parent = KotlinConverter.unwrapElements(element.parent) ?: return null
|
|
||||||
val parentUElement = convertElementWithParent(parent, null) ?: return null
|
|
||||||
|
|
||||||
val uExpression = KotlinUFunctionCallExpression(element, parentUElement, resolvedCall)
|
|
||||||
val method = uExpression.resolve() ?: return null
|
|
||||||
val containingClass = method.containingClass ?: return null
|
|
||||||
return UastLanguagePlugin.ResolvedConstructor(uExpression, method, containingClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun convertDeclaration(element: PsiElement,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredType: Class<out UElement>?): UElement? {
|
|
||||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? = { ctor(element as P, givenParent) }
|
|
||||||
|
|
||||||
fun <P : PsiElement, K : KtElement> buildKt(ktElement: K, ctor: (P, K, UElement?) -> UElement): () -> UElement? =
|
|
||||||
{ ctor(element as P, ktElement, givenParent) }
|
|
||||||
|
|
||||||
fun <P : PsiElement, K : KtElement> buildKtOpt(ktElement: K?, ctor: (P, K?, UElement?) -> UElement): () -> UElement? =
|
|
||||||
{ ctor(element as P, ktElement, givenParent) }
|
|
||||||
|
|
||||||
val original = element.originalElement
|
|
||||||
return with(requiredType) {
|
|
||||||
when (original) {
|
|
||||||
is KtLightMethod -> el<UMethod>(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934
|
|
||||||
is KtLightClass -> when (original.kotlinOrigin) {
|
|
||||||
is KtEnumEntry -> el<UEnumConstant> {
|
|
||||||
convertEnumEntry(original.kotlinOrigin as KtEnumEntry, givenParent)
|
|
||||||
}
|
|
||||||
else -> el<UClass> { KotlinUClass.create(original, givenParent) }
|
|
||||||
}
|
|
||||||
is KtLightFieldImpl.KtLightEnumConstant -> el<UEnumConstant>(buildKtOpt(original.kotlinOrigin, ::KotlinUEnumConstant))
|
|
||||||
is KtLightField -> el<UField>(buildKtOpt(original.kotlinOrigin, ::KotlinUField))
|
|
||||||
is KtLightParameter -> el<UParameter>(buildKtOpt(original.kotlinOrigin, ::KotlinUParameter))
|
|
||||||
is UastKotlinPsiParameter -> el<UParameter>(buildKt(original.ktParameter, ::KotlinUParameter))
|
|
||||||
is UastKotlinPsiVariable -> el<UVariable>(buildKt(original.ktElement, ::KotlinUVariable))
|
|
||||||
|
|
||||||
is KtEnumEntry -> el<UEnumConstant> {
|
|
||||||
convertEnumEntry(original, givenParent)
|
|
||||||
}
|
|
||||||
is KtClassOrObject -> el<UClass> {
|
|
||||||
original.toLightClass()?.let { lightClass ->
|
|
||||||
KotlinUClass.create(lightClass, givenParent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtFunction ->
|
|
||||||
if (original.isLocal) {
|
|
||||||
el<ULambdaExpression> {
|
|
||||||
if (original.name.isNullOrEmpty() || original.parent is KtLambdaExpression) {
|
|
||||||
createLocalFunctionLambdaExpression(original, givenParent)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val uDeclarationsExpression = createLocalFunctionDeclaration(original, givenParent)
|
|
||||||
val localFunctionVar = uDeclarationsExpression.declarations.single() as KotlinLocalFunctionUVariable
|
|
||||||
localFunctionVar.uastInitializer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
el<UMethod> {
|
|
||||||
val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null
|
|
||||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtPropertyAccessor -> el<UMethod> {
|
|
||||||
val lightMethod = LightClassUtil.getLightClassAccessorMethod(original) ?: return null
|
|
||||||
convertDeclaration(lightMethod, givenParent, requiredType)
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtProperty ->
|
|
||||||
if (original.isLocal) {
|
|
||||||
KotlinConverter.convertPsiElement(element, givenParent, requiredType)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
convertNonLocalProperty(original, givenParent, requiredType)
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtParameter -> el<UParameter> {
|
|
||||||
val ownerFunction = original.ownerFunction as? KtFunction ?: return null
|
|
||||||
val lightMethod = LightClassUtil.getLightClassMethod(ownerFunction) ?: return null
|
|
||||||
val lightParameter = lightMethod.parameterList.parameters.find { it.name == original.name } ?: return null
|
|
||||||
KotlinUParameter(lightParameter, original, givenParent)
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtFile -> el<UFile> { KotlinUFile(original, this@KotlinUastLanguagePlugin) }
|
|
||||||
is FakeFileForLightClass -> el<UFile> { KotlinUFile(original.navigationElement, this@KotlinUastLanguagePlugin) }
|
|
||||||
is KtAnnotationEntry -> el<UAnnotation>(build(::KotlinUAnnotation))
|
|
||||||
is KtCallExpression ->
|
|
||||||
if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) {
|
|
||||||
el<UAnnotation> {
|
|
||||||
val classDescriptor =
|
|
||||||
(original.getResolvedCall(original.analyze())?.resultingDescriptor as? ClassConstructorDescriptor)?.constructedClass
|
|
||||||
if (classDescriptor?.kind == ClassKind.ANNOTATION_CLASS)
|
|
||||||
KotlinUNestedAnnotation(original, givenParent, classDescriptor)
|
|
||||||
else
|
|
||||||
null
|
|
||||||
}
|
|
||||||
} else null
|
|
||||||
is KtLightAnnotationForSourceEntry -> convertElement(original.kotlinOrigin, givenParent, requiredType)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertEnumEntry(original: KtEnumEntry, givenParent: UElement?): UElement? {
|
|
||||||
return LightClassUtil.getLightClassBackingField(original)?.let { psiField ->
|
|
||||||
if (psiField is KtLightFieldImpl.KtLightEnumConstant) {
|
|
||||||
KotlinUEnumConstant(psiField, psiField.kotlinOrigin, givenParent)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isExpressionValueUsed(element: UExpression): Boolean {
|
|
||||||
return when (element) {
|
|
||||||
is KotlinUSimpleReferenceExpression.KotlinAccessorCallExpression -> element.setterValue != null
|
|
||||||
is KotlinAbstractUExpression -> {
|
|
||||||
val ktElement = element.psi as? KtElement ?: return false
|
|
||||||
ktElement.analyze()[BindingContext.USED_AS_EXPRESSION, ktElement] ?: false
|
|
||||||
}
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal inline fun <reified ActualT : UElement> Class<out UElement>?.el(f: () -> UElement?): UElement? {
|
|
||||||
return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null
|
|
||||||
}
|
|
||||||
|
|
||||||
internal inline fun <reified ActualT : UElement> Class<out UElement>?.expr(f: () -> UExpression?): UExpression? {
|
|
||||||
return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertNonLocalProperty(property: KtProperty,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredType: Class<out UElement>?): UElement? {
|
|
||||||
val methods = LightClassUtil.getLightClassPropertyMethods(property)
|
|
||||||
return methods.backingField?.let { backingField ->
|
|
||||||
with(requiredType) {
|
|
||||||
el<UField> { KotlinUField(backingField, (backingField as? KtLightElement<*,*>)?.kotlinOrigin, givenParent) }
|
|
||||||
}
|
|
||||||
} ?: methods.getter?.let { getter ->
|
|
||||||
KotlinUastLanguagePlugin().convertDeclaration(getter, givenParent, requiredType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal object KotlinConverter {
|
|
||||||
internal tailrec fun unwrapElements(element: PsiElement?): PsiElement? = when (element) {
|
|
||||||
is KtValueArgumentList -> unwrapElements(element.parent)
|
|
||||||
is KtValueArgument -> unwrapElements(element.parent)
|
|
||||||
is KtDeclarationModifierList -> unwrapElements(element.parent)
|
|
||||||
is KtContainerNode -> unwrapElements(element.parent)
|
|
||||||
is KtSimpleNameStringTemplateEntry -> unwrapElements(element.parent)
|
|
||||||
is KtLightParameterList -> unwrapElements(element.parent)
|
|
||||||
else -> element
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun convertPsiElement(element: PsiElement?,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredType: Class<out UElement>?): UElement? {
|
|
||||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UElement): () -> UElement? {
|
|
||||||
return { ctor(element as P, givenParent) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return with (requiredType) { when (element) {
|
|
||||||
is KtParameterList -> el<UDeclarationsExpression> {
|
|
||||||
val declarationsExpression = KotlinUDeclarationsExpression(givenParent)
|
|
||||||
declarationsExpression.apply {
|
|
||||||
declarations = element.parameters.mapIndexed { i, p ->
|
|
||||||
KotlinUParameter(UastKotlinPsiParameter.create(p, element, declarationsExpression, i), p, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtClassBody -> el<UExpressionList>(build(KotlinUExpressionList.Companion::createClassBody))
|
|
||||||
is KtCatchClause -> el<UCatchClause>(build(::KotlinUCatchClause))
|
|
||||||
is KtVariableDeclaration ->
|
|
||||||
if (element is KtProperty && !element.isLocal) {
|
|
||||||
el<UField> {
|
|
||||||
LightClassUtil.getLightClassBackingField(element)?.let {
|
|
||||||
KotlinUField(it, element, givenParent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
el<UVariable> {
|
|
||||||
convertVariablesDeclaration(element, givenParent).declarations.singleOrNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtExpression -> KotlinConverter.convertExpression(element, givenParent, requiredType)
|
|
||||||
is KtLambdaArgument -> element.getLambdaExpression()?.let { KotlinConverter.convertExpression(it, givenParent, requiredType) }
|
|
||||||
is KtLightAnnotationForSourceEntry.LightExpressionValue<*> -> {
|
|
||||||
val expression = element.originalExpression
|
|
||||||
when (expression) {
|
|
||||||
is KtExpression -> KotlinConverter.convertExpression(expression, givenParent, requiredType)
|
|
||||||
else -> el<UExpression> { UastEmptyExpression }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtLiteralStringTemplateEntry, is KtEscapeStringTemplateEntry -> el<ULiteralExpression>(build(::KotlinStringULiteralExpression))
|
|
||||||
is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, requiredType) } ?: expr<UExpression> { UastEmptyExpression }
|
|
||||||
is KtWhenEntry -> el<USwitchClauseExpressionWithBody>(build(::KotlinUSwitchEntry))
|
|
||||||
is KtWhenCondition -> convertWhenCondition(element, givenParent, requiredType)
|
|
||||||
is KtTypeReference -> el<UTypeReferenceExpression> { LazyKotlinUTypeReferenceExpression(element, givenParent) }
|
|
||||||
is KtConstructorDelegationCall ->
|
|
||||||
el<UCallExpression> { KotlinUFunctionCallExpression(element, givenParent) }
|
|
||||||
is KtSuperTypeCallEntry ->
|
|
||||||
el<UExpression> {
|
|
||||||
(element.getParentOfType<KtClassOrObject>(true)?.parent as? KtObjectLiteralExpression)
|
|
||||||
?.toUElementOfType<UExpression>()
|
|
||||||
?: KotlinUFunctionCallExpression(element, givenParent)
|
|
||||||
}
|
|
||||||
is KtImportDirective -> el<UImportStatement>(build(::KotlinUImportStatement))
|
|
||||||
else -> {
|
|
||||||
if (element is LeafPsiElement) {
|
|
||||||
if (element.elementType == KtTokens.IDENTIFIER)
|
|
||||||
el<UIdentifier>(build(::UIdentifier))
|
|
||||||
else if (element.elementType == KtTokens.LBRACKET && element.parent is KtCollectionLiteralExpression)
|
|
||||||
el<UIdentifier> {
|
|
||||||
UIdentifier(
|
|
||||||
element,
|
|
||||||
KotlinUCollectionLiteralExpression(
|
|
||||||
element.parent as KtCollectionLiteralExpression,
|
|
||||||
null
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else null
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal fun convertEntry(entry: KtStringTemplateEntry,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredType: Class<out UElement>? = null): UExpression? {
|
|
||||||
return with(requiredType) {
|
|
||||||
if (entry is KtStringTemplateEntryWithExpression) {
|
|
||||||
expr<UExpression> {
|
|
||||||
KotlinConverter.convertOrEmpty(entry.expression, givenParent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
expr<ULiteralExpression> {
|
|
||||||
if (entry is KtEscapeStringTemplateEntry)
|
|
||||||
KotlinStringULiteralExpression(entry, givenParent, entry.unescapedValue)
|
|
||||||
else
|
|
||||||
KotlinStringULiteralExpression(entry, givenParent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun convertExpression(expression: KtExpression,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredType: Class<out UElement>? = null): UExpression? {
|
|
||||||
fun <P : PsiElement> build(ctor: (P, UElement?) -> UExpression): () -> UExpression? {
|
|
||||||
return { ctor(expression as P, givenParent) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return with (requiredType) { when (expression) {
|
|
||||||
is KtVariableDeclaration -> expr<UDeclarationsExpression>(build(::convertVariablesDeclaration))
|
|
||||||
|
|
||||||
is KtStringTemplateExpression -> {
|
|
||||||
when {
|
|
||||||
expression.entries.isEmpty() -> {
|
|
||||||
expr<ULiteralExpression> { KotlinStringULiteralExpression(expression, givenParent, "") }
|
|
||||||
}
|
|
||||||
expression.entries.size == 1 -> convertEntry(expression.entries[0], givenParent, requiredType)
|
|
||||||
else -> {
|
|
||||||
expr<UExpression> { KotlinStringTemplateUPolyadicExpression(expression, givenParent) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtDestructuringDeclaration -> expr<UDeclarationsExpression> {
|
|
||||||
val declarationsExpression = KotlinUDestructuringDeclarationExpression(givenParent, expression)
|
|
||||||
declarationsExpression.apply {
|
|
||||||
val tempAssignment = KotlinULocalVariable(UastKotlinPsiVariable.create(expression, declarationsExpression), expression, declarationsExpression)
|
|
||||||
val destructuringAssignments = expression.entries.mapIndexed { i, entry ->
|
|
||||||
val psiFactory = KtPsiFactory(expression.project)
|
|
||||||
val initializer = psiFactory.createAnalyzableExpression("${tempAssignment.name}.component${i + 1}()",
|
|
||||||
expression.containingFile)
|
|
||||||
initializer.destructuringDeclarationInitializer = true
|
|
||||||
KotlinULocalVariable(UastKotlinPsiVariable.create(entry, tempAssignment.psi, declarationsExpression, initializer), entry, declarationsExpression)
|
|
||||||
}
|
|
||||||
declarations = listOf(tempAssignment) + destructuringAssignments
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtLabeledExpression -> expr<ULabeledExpression>(build(::KotlinULabeledExpression))
|
|
||||||
is KtClassLiteralExpression -> expr<UClassLiteralExpression>(build(::KotlinUClassLiteralExpression))
|
|
||||||
is KtObjectLiteralExpression -> expr<UObjectLiteralExpression>(build(::KotlinUObjectLiteralExpression))
|
|
||||||
is KtDotQualifiedExpression -> expr<UQualifiedReferenceExpression>(build(::KotlinUQualifiedReferenceExpression))
|
|
||||||
is KtSafeQualifiedExpression -> expr<UQualifiedReferenceExpression>(build(::KotlinUSafeQualifiedExpression))
|
|
||||||
is KtSimpleNameExpression -> expr<USimpleNameReferenceExpression>(build(::KotlinUSimpleReferenceExpression))
|
|
||||||
is KtCallExpression -> expr<UCallExpression>(build(::KotlinUFunctionCallExpression))
|
|
||||||
is KtCollectionLiteralExpression -> expr<UCallExpression>(build(::KotlinUCollectionLiteralExpression))
|
|
||||||
is KtBinaryExpression -> {
|
|
||||||
if (expression.operationToken == KtTokens.ELVIS) {
|
|
||||||
expr<UExpressionList>(build(::createElvisExpression))
|
|
||||||
}
|
|
||||||
else expr<UBinaryExpression>(build(::KotlinUBinaryExpression))
|
|
||||||
}
|
|
||||||
is KtParenthesizedExpression -> expr<UParenthesizedExpression>(build(::KotlinUParenthesizedExpression))
|
|
||||||
is KtPrefixExpression -> expr<UPrefixExpression>(build(::KotlinUPrefixExpression))
|
|
||||||
is KtPostfixExpression -> expr<UPostfixExpression>(build(::KotlinUPostfixExpression))
|
|
||||||
is KtThisExpression -> expr<UThisExpression>(build(::KotlinUThisExpression))
|
|
||||||
is KtSuperExpression -> expr<USuperExpression>(build(::KotlinUSuperExpression))
|
|
||||||
is KtCallableReferenceExpression -> expr<UCallableReferenceExpression>(build(::KotlinUCallableReferenceExpression))
|
|
||||||
is KtIsExpression -> expr<UBinaryExpressionWithType>(build(::KotlinUTypeCheckExpression))
|
|
||||||
is KtIfExpression -> expr<UIfExpression>(build(::KotlinUIfExpression))
|
|
||||||
is KtWhileExpression -> expr<UWhileExpression>(build(::KotlinUWhileExpression))
|
|
||||||
is KtDoWhileExpression -> expr<UDoWhileExpression>(build(::KotlinUDoWhileExpression))
|
|
||||||
is KtForExpression -> expr<UForEachExpression>(build(::KotlinUForEachExpression))
|
|
||||||
is KtWhenExpression -> expr<USwitchExpression>(build(::KotlinUSwitchExpression))
|
|
||||||
is KtBreakExpression -> expr<UBreakExpression>(build(::KotlinUBreakExpression))
|
|
||||||
is KtContinueExpression -> expr<UContinueExpression>(build(::KotlinUContinueExpression))
|
|
||||||
is KtReturnExpression -> expr<UReturnExpression>(build(::KotlinUReturnExpression))
|
|
||||||
is KtThrowExpression -> expr<UThrowExpression>(build(::KotlinUThrowExpression))
|
|
||||||
is KtBlockExpression -> expr<UBlockExpression>(build(::KotlinUBlockExpression))
|
|
||||||
is KtConstantExpression -> expr<ULiteralExpression>(build(::KotlinULiteralExpression))
|
|
||||||
is KtTryExpression -> expr<UTryExpression>(build(::KotlinUTryExpression))
|
|
||||||
is KtArrayAccessExpression -> expr<UArrayAccessExpression>(build(::KotlinUArrayAccessExpression))
|
|
||||||
is KtLambdaExpression -> expr<ULambdaExpression>(build(::KotlinULambdaExpression))
|
|
||||||
is KtBinaryExpressionWithTypeRHS -> expr<UBinaryExpressionWithType>(build(::KotlinUBinaryExpressionWithType))
|
|
||||||
is KtClassOrObject -> expr<UDeclarationsExpression> {
|
|
||||||
expression.toLightClass()?.let { lightClass ->
|
|
||||||
KotlinUDeclarationsExpression(givenParent).apply {
|
|
||||||
declarations = listOf(KotlinUClass.create(lightClass, this))
|
|
||||||
}
|
|
||||||
} ?: UastEmptyExpression
|
|
||||||
}
|
|
||||||
is KtFunction -> if (expression.name.isNullOrEmpty()) {
|
|
||||||
expr<ULambdaExpression>(build(::createLocalFunctionLambdaExpression))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
expr<UDeclarationsExpression>(build(::createLocalFunctionDeclaration))
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> expr<UExpression>(build(::UnknownKotlinExpression))
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun convertWhenCondition(condition: KtWhenCondition,
|
|
||||||
givenParent: UElement?,
|
|
||||||
requiredType: Class<out UElement>? = null): UExpression? {
|
|
||||||
return with(requiredType) {
|
|
||||||
when (condition) {
|
|
||||||
is KtWhenConditionInRange -> expr<UBinaryExpression> {
|
|
||||||
KotlinCustomUBinaryExpression(condition, givenParent).apply {
|
|
||||||
leftOperand = KotlinStringUSimpleReferenceExpression("it", this)
|
|
||||||
operator = when {
|
|
||||||
condition.isNegated -> KotlinBinaryOperators.NOT_IN
|
|
||||||
else -> KotlinBinaryOperators.IN
|
|
||||||
}
|
|
||||||
rightOperand = KotlinConverter.convertOrEmpty(condition.rangeExpression, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtWhenConditionIsPattern -> expr<UBinaryExpression> {
|
|
||||||
KotlinCustomUBinaryExpressionWithType(condition, givenParent).apply {
|
|
||||||
operand = KotlinStringUSimpleReferenceExpression("it", this)
|
|
||||||
operationKind = when {
|
|
||||||
condition.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
|
|
||||||
else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
|
|
||||||
}
|
|
||||||
val typeRef = condition.typeReference
|
|
||||||
typeReference = typeRef?.let {
|
|
||||||
LazyKotlinUTypeReferenceExpression(it, this) { typeRef.toPsiType(this, boxed = true) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is KtWhenConditionWithExpression ->
|
|
||||||
condition.expression?.let { KotlinConverter.convertExpression(it, givenParent, requiredType) }
|
|
||||||
|
|
||||||
else -> expr<UExpression> { UastEmptyExpression }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
|
|
||||||
return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun convertOrNull(expression: KtExpression?, parent: UElement?): UExpression? {
|
|
||||||
return if (expression != null) convertExpression(expression, parent, null) else null
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun KtPsiFactory.createAnalyzableExpression(text: String, context: PsiElement): KtExpression =
|
|
||||||
createAnalyzableProperty("val x = $text", context).initializer ?: error("Failed to create expression from text: '$text'")
|
|
||||||
|
|
||||||
internal fun KtPsiFactory.createAnalyzableProperty(text: String, context: PsiElement): KtProperty =
|
|
||||||
createAnalyzableDeclaration(text, context)
|
|
||||||
|
|
||||||
internal fun <TDeclaration : KtDeclaration> KtPsiFactory.createAnalyzableDeclaration(text: String, context: PsiElement): TDeclaration {
|
|
||||||
val file = createAnalyzableFile("dummy.kt", text, context)
|
|
||||||
val declarations = file.declarations
|
|
||||||
assert(declarations.size == 1) { "${declarations.size} declarations in $text" }
|
|
||||||
return declarations.first() as TDeclaration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertVariablesDeclaration(
|
|
||||||
psi: KtVariableDeclaration,
|
|
||||||
parent: UElement?
|
|
||||||
): UDeclarationsExpression {
|
|
||||||
val declarationsExpression = KotlinUDeclarationsExpression(null, parent, psi)
|
|
||||||
val parentPsiElement = parent?.psi
|
|
||||||
val variable = KotlinUAnnotatedLocalVariable(
|
|
||||||
UastKotlinPsiVariable.create(psi, parentPsiElement, declarationsExpression), psi, declarationsExpression) { annotationParent ->
|
|
||||||
psi.annotationEntries.map { KotlinUAnnotation(it, annotationParent) }
|
|
||||||
}
|
|
||||||
return declarationsExpression.apply { declarations = listOf(variable) }
|
|
||||||
}
|
|
||||||
-133
@@ -1,133 +0,0 @@
|
|||||||
package org.jetbrains.uast.kotlin
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiAnnotation
|
|
||||||
import com.intellij.psi.PsiClass
|
|
||||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
|
||||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
|
||||||
|
|
||||||
abstract class KotlinUAnnotationBase(
|
|
||||||
final override val psi: KtElement,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUElement(givenParent), UAnnotation {
|
|
||||||
|
|
||||||
abstract override val javaPsi: PsiAnnotation?
|
|
||||||
|
|
||||||
final override val sourcePsi = psi
|
|
||||||
|
|
||||||
protected abstract fun annotationUseSiteTarget(): AnnotationUseSiteTarget?
|
|
||||||
|
|
||||||
private val resolvedCall: ResolvedCall<*>? by lz { psi.getResolvedCall(psi.analyze()) }
|
|
||||||
|
|
||||||
override val qualifiedName: String?
|
|
||||||
get() = annotationClassDescriptor.takeUnless(ErrorUtils::isError)
|
|
||||||
?.fqNameUnsafe
|
|
||||||
?.takeIf(FqNameUnsafe::isSafe)
|
|
||||||
?.toSafe()
|
|
||||||
?.toString()
|
|
||||||
|
|
||||||
override val attributeValues: List<UNamedExpression> by lz {
|
|
||||||
resolvedCall?.valueArguments?.entries?.mapNotNull {
|
|
||||||
val arguments = it.value.arguments
|
|
||||||
val name = it.key.name.asString()
|
|
||||||
when {
|
|
||||||
arguments.size == 1 ->
|
|
||||||
KotlinUNamedExpression.create(name, arguments.first(), this)
|
|
||||||
arguments.size > 1 ->
|
|
||||||
KotlinUNamedExpression.create(name, arguments, this)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
} ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract val annotationClassDescriptor: ClassDescriptor?
|
|
||||||
|
|
||||||
override fun resolve(): PsiClass? {
|
|
||||||
val descriptor = annotationClassDescriptor ?: return null
|
|
||||||
return descriptor.toSource()?.getMaybeLightElement(this) as? PsiClass
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun findAttributeValue(name: String?): UExpression? =
|
|
||||||
findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value")
|
|
||||||
|
|
||||||
fun findAttributeValueExpression(arg: ValueArgument): UExpression? {
|
|
||||||
val mapping = resolvedCall?.getArgumentMapping(arg)
|
|
||||||
return (mapping as? ArgumentMatch)?.let { match ->
|
|
||||||
val namedExpression = attributeValues.find { it.name == match.valueParameter.name.asString() }
|
|
||||||
namedExpression?.expression as? KotlinUVarargExpression ?: namedExpression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun findDeclaredAttributeValue(name: String?): UExpression? {
|
|
||||||
return attributeValues.find {
|
|
||||||
it.name == name ||
|
|
||||||
(name == null && it.name == "value") ||
|
|
||||||
(name == "value" && it.name == null)
|
|
||||||
}?.expression
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findAttributeDefaultValue(name: String): UExpression? {
|
|
||||||
val parameter = annotationClassDescriptor
|
|
||||||
?.unsubstitutedPrimaryConstructor
|
|
||||||
?.valueParameters
|
|
||||||
?.find { it.name.asString() == name } ?: return null
|
|
||||||
|
|
||||||
val defaultValue = (parameter.source.getPsi() as? KtParameter)?.defaultValue ?: return null
|
|
||||||
return getLanguagePlugin().convertWithParent(defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun convertParent(): UElement? {
|
|
||||||
val superParent = super.convertParent() ?: return null
|
|
||||||
if (annotationUseSiteTarget() == AnnotationUseSiteTarget.RECEIVER) {
|
|
||||||
(superParent.uastParent as? KotlinUMethod)?.uastParameters?.firstIsInstance<KotlinReceiverUParameter>()?.let {
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return superParent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinUAnnotation(
|
|
||||||
val annotationEntry: KtAnnotationEntry,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinUAnnotationBase(annotationEntry, givenParent), UAnnotation {
|
|
||||||
|
|
||||||
override val javaPsi = annotationEntry.toLightAnnotation()
|
|
||||||
|
|
||||||
private val resolvedAnnotation: AnnotationDescriptor? by lz { annotationEntry.analyze()[BindingContext.ANNOTATION, annotationEntry] }
|
|
||||||
|
|
||||||
override val annotationClassDescriptor: ClassDescriptor?
|
|
||||||
get() = resolvedAnnotation?.annotationClass
|
|
||||||
|
|
||||||
override fun annotationUseSiteTarget() = annotationEntry.useSiteTarget?.getAnnotationUseSiteTarget()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinUNestedAnnotation(
|
|
||||||
original: KtCallExpression,
|
|
||||||
givenParent: UElement?,
|
|
||||||
private val classDescriptor: ClassDescriptor?
|
|
||||||
) : KotlinUAnnotationBase(original, givenParent) {
|
|
||||||
override val javaPsi: PsiAnnotation? by lazy { original.toLightAnnotation() }
|
|
||||||
override val annotationClassDescriptor: ClassDescriptor?
|
|
||||||
get() = classDescriptor
|
|
||||||
|
|
||||||
override fun annotationUseSiteTarget(): AnnotationUseSiteTarget? = null
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,292 +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 com.intellij.psi.*
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
|
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
|
|
||||||
import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier
|
|
||||||
|
|
||||||
abstract class AbstractKotlinUClass(givenParent: UElement?) : KotlinAbstractUElement(givenParent), UClass, JvmDeclarationUElementPlaceholder {
|
|
||||||
|
|
||||||
override val uastDeclarations by lz {
|
|
||||||
mutableListOf<UDeclaration>().apply {
|
|
||||||
addAll(fields)
|
|
||||||
addAll(initializers)
|
|
||||||
addAll(methods)
|
|
||||||
addAll(innerClasses)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val uastSuperTypes: List<UTypeReferenceExpression>
|
|
||||||
get() {
|
|
||||||
val ktClass = (psi as? KtLightClass)?.kotlinOrigin ?: return emptyList()
|
|
||||||
return ktClass.superTypeListEntries.mapNotNull { it.typeReference }.map {
|
|
||||||
LazyKotlinUTypeReferenceExpression(it, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val uastAnchor: UElement?
|
|
||||||
get() = UIdentifier(psi.nameIdentifier, this)
|
|
||||||
|
|
||||||
override val annotations: List<UAnnotation> by lz {
|
|
||||||
(sourcePsi as? KtModifierListOwner)?.annotationEntries.orEmpty().map { KotlinUAnnotation(it, this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?) = other is AbstractKotlinUClass && psi == other.psi
|
|
||||||
override fun hashCode() = psi.hashCode()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
open class KotlinUClass private constructor(
|
|
||||||
psi: KtLightClass,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
|
||||||
|
|
||||||
val ktClass = psi.kotlinOrigin
|
|
||||||
|
|
||||||
override val javaPsi: KtLightClass = psi
|
|
||||||
|
|
||||||
override val sourcePsi: KtClassOrObject? = ktClass
|
|
||||||
|
|
||||||
override val psi = unwrap<UClass, PsiClass>(psi)
|
|
||||||
|
|
||||||
override fun getSourceElement() = sourcePsi ?: this
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? = super.getOriginalElement()
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, ktClass)
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile)
|
|
||||||
|
|
||||||
override val uastAnchor: UElement
|
|
||||||
get() = UIdentifier(nameIdentifier, this)
|
|
||||||
|
|
||||||
override fun getInnerClasses(): Array<UClass> {
|
|
||||||
// filter DefaultImpls to avoid processing same methods from original interface multiple times
|
|
||||||
// filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class
|
|
||||||
return psi.innerClasses.filter {
|
|
||||||
it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass()
|
|
||||||
}.mapNotNull {
|
|
||||||
getLanguagePlugin().convertOpt<UClass>(it, this)
|
|
||||||
}.toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSuperClass(): UClass? = super.getSuperClass()
|
|
||||||
override fun getFields(): Array<UField> = super.getFields()
|
|
||||||
override fun getInitializers(): Array<UClassInitializer> = super.getInitializers()
|
|
||||||
|
|
||||||
override fun getMethods(): Array<UMethod> {
|
|
||||||
val hasPrimaryConstructor = ktClass?.hasPrimaryConstructor() ?: false
|
|
||||||
var secondaryConstructorsCount = 0
|
|
||||||
|
|
||||||
fun createUMethod(psiMethod: PsiMethod): UMethod {
|
|
||||||
return if (psiMethod is KtLightMethod &&
|
|
||||||
psiMethod.isConstructor) {
|
|
||||||
if (!hasPrimaryConstructor && secondaryConstructorsCount++ == 0)
|
|
||||||
KotlinSecondaryConstructorWithInitializersUMethod(ktClass, psiMethod, this)
|
|
||||||
else
|
|
||||||
KotlinConstructorUMethod(ktClass, psiMethod, this)
|
|
||||||
} else {
|
|
||||||
getLanguagePlugin().convertOpt(psiMethod, this) ?: reportConvertFailure(psiMethod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated
|
|
||||||
|
|
||||||
return psi.methods.asSequence()
|
|
||||||
.filterNot(::isDelegatedMethod)
|
|
||||||
.map(::createUMethod)
|
|
||||||
.toList()
|
|
||||||
.toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiClass.isEnumEntryLightClass() = (this as? KtLightClass)?.kotlinOrigin is KtEnumEntry
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun create(psi: KtLightClass, containingElement: UElement?): UClass = when (psi) {
|
|
||||||
is PsiAnonymousClass -> KotlinUAnonymousClass(psi, containingElement)
|
|
||||||
is KtLightClassForScript -> KotlinScriptUClass(psi, containingElement)
|
|
||||||
else -> KotlinUClass(psi, containingElement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
open class KotlinConstructorUMethod(
|
|
||||||
private val ktClass: KtClassOrObject?,
|
|
||||||
override val psi: KtLightMethod,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinUMethod(psi, givenParent) {
|
|
||||||
|
|
||||||
val isPrimary: Boolean
|
|
||||||
get() = psi.kotlinOrigin.let { it is KtPrimaryConstructor || it is KtClassOrObject }
|
|
||||||
|
|
||||||
override val uastBody: UExpression? by lz {
|
|
||||||
val delegationCall: KtCallElement? = psi.kotlinOrigin.let {
|
|
||||||
when {
|
|
||||||
isPrimary -> ktClass?.superTypeListEntries?.firstIsInstanceOrNull<KtSuperTypeCallEntry>()
|
|
||||||
it is KtSecondaryConstructor -> it.getDelegationCall()
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val bodyExpressions = getBodyExpressions()
|
|
||||||
if (delegationCall == null && bodyExpressions.isEmpty()) return@lz null
|
|
||||||
KotlinUBlockExpression.KotlinLazyUBlockExpression(this) { uastParent ->
|
|
||||||
SmartList<UExpression>().apply {
|
|
||||||
delegationCall?.let {
|
|
||||||
add(KotlinUFunctionCallExpression(it, uastParent))
|
|
||||||
}
|
|
||||||
bodyExpressions.forEach {
|
|
||||||
add(KotlinConverter.convertOrEmpty(it, uastParent))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val javaPsi = psi
|
|
||||||
|
|
||||||
override val sourcePsi = psi.kotlinOrigin
|
|
||||||
|
|
||||||
open protected fun getBodyExpressions(): List<KtExpression> {
|
|
||||||
if (isPrimary) return getInitializers()
|
|
||||||
val bodyExpression = (psi.kotlinOrigin as? KtFunction)?.bodyExpression ?: return emptyList()
|
|
||||||
if (bodyExpression is KtBlockExpression) return bodyExpression.statements
|
|
||||||
return listOf(bodyExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun getInitializers() = ktClass?.getAnonymousInitializers()?.mapNotNull { it.body } ?: emptyList()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// This class was created as a workaround for KT-21617 to be the only constructor which includes `init` block
|
|
||||||
// when there is no primary constructors in the class.
|
|
||||||
// It is expected to have only one constructor of this type in a UClass.
|
|
||||||
class KotlinSecondaryConstructorWithInitializersUMethod(
|
|
||||||
ktClass: KtClassOrObject?,
|
|
||||||
psi: KtLightMethod,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinConstructorUMethod(ktClass, psi, givenParent) {
|
|
||||||
override fun getBodyExpressions(): List<KtExpression> = getInitializers() + super.getBodyExpressions()
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinUAnonymousClass(
|
|
||||||
psi: PsiAnonymousClass,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : AbstractKotlinUClass(givenParent), UAnonymousClass, PsiAnonymousClass by psi {
|
|
||||||
|
|
||||||
override val psi: PsiAnonymousClass = unwrap<UAnonymousClass, PsiAnonymousClass>(psi)
|
|
||||||
|
|
||||||
override val javaPsi: PsiAnonymousClass = psi
|
|
||||||
|
|
||||||
override val sourcePsi: KtClassOrObject? = (psi as? KtLightClass)?.kotlinOrigin
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? = super<AbstractKotlinUClass>.getOriginalElement()
|
|
||||||
|
|
||||||
override fun getSuperClass(): UClass? = super<AbstractKotlinUClass>.getSuperClass()
|
|
||||||
override fun getFields(): Array<UField> = super<AbstractKotlinUClass>.getFields()
|
|
||||||
override fun getMethods(): Array<UMethod> = super<AbstractKotlinUClass>.getMethods()
|
|
||||||
override fun getInitializers(): Array<UClassInitializer> = super<AbstractKotlinUClass>.getInitializers()
|
|
||||||
override fun getInnerClasses(): Array<UClass> = super<AbstractKotlinUClass>.getInnerClasses()
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
|
|
||||||
|
|
||||||
override val uastAnchor: UElement?
|
|
||||||
get() {
|
|
||||||
val ktClassOrObject = (psi.originalElement as? KtLightClass)?.kotlinOrigin as? KtObjectDeclaration ?: return null
|
|
||||||
return UIdentifier(ktClassOrObject.getObjectKeyword(), this)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinScriptUClass(
|
|
||||||
psi: KtLightClassForScript,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : AbstractKotlinUClass(givenParent), PsiClass by psi {
|
|
||||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, psi.kotlinOrigin)
|
|
||||||
|
|
||||||
override val uastAnchor: UElement
|
|
||||||
get() = UIdentifier(nameIdentifier, this)
|
|
||||||
|
|
||||||
override val javaPsi: PsiClass = psi
|
|
||||||
|
|
||||||
override val sourcePsi: KtClassOrObject? = psi.kotlinOrigin
|
|
||||||
|
|
||||||
override val psi = unwrap<UClass, KtLightClassForScript>(psi)
|
|
||||||
|
|
||||||
override fun getSuperClass(): UClass? = super.getSuperClass()
|
|
||||||
|
|
||||||
override fun getFields(): Array<UField> = super.getFields()
|
|
||||||
|
|
||||||
override fun getInitializers(): Array<UClassInitializer> = super.getInitializers()
|
|
||||||
|
|
||||||
override fun getInnerClasses(): Array<UClass> =
|
|
||||||
psi.innerClasses.mapNotNull { getLanguagePlugin().convertOpt<UClass>(it, this) }.toTypedArray()
|
|
||||||
|
|
||||||
override fun getMethods(): Array<UMethod> = psi.methods.map(this::createUMethod).toTypedArray()
|
|
||||||
|
|
||||||
private fun createUMethod(method: PsiMethod): UMethod {
|
|
||||||
return if (method.isConstructor) {
|
|
||||||
KotlinScriptConstructorUMethod(psi.script, method as KtLightMethod, this)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
getLanguagePlugin().convertOpt(method, this) ?: reportConvertFailure(method)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? = psi.originalElement
|
|
||||||
|
|
||||||
class KotlinScriptConstructorUMethod(
|
|
||||||
script: KtScript,
|
|
||||||
override val psi: KtLightMethod,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinUMethod(psi, givenParent) {
|
|
||||||
override val uastBody: UExpression? by lz {
|
|
||||||
val initializers = script.declarations.filterIsInstance<KtScriptInitializer>()
|
|
||||||
KotlinUBlockExpression.create(initializers, this)
|
|
||||||
}
|
|
||||||
override val javaPsi = psi
|
|
||||||
override val sourcePsi = psi.kotlinOrigin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reportConvertFailure(psiMethod: PsiMethod): Nothing {
|
|
||||||
val isValid = psiMethod.isValid
|
|
||||||
val report = KotlinExceptionWithAttachments(
|
|
||||||
"cant convert $psiMethod of ${psiMethod.javaClass} to UMethod"
|
|
||||||
+ if (!isValid) " (method is not valid)" else ""
|
|
||||||
)
|
|
||||||
|
|
||||||
if (isValid) {
|
|
||||||
report.withAttachment("method", psiMethod.text)
|
|
||||||
psiMethod.containingFile?.let {
|
|
||||||
report.withAttachment("file", it.text)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw report
|
|
||||||
}
|
|
||||||
@@ -1,130 +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.declarations
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiCodeBlock
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.isGetter
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.isSetter
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.java.internal.JavaUElementWithComments
|
|
||||||
import org.jetbrains.uast.kotlin.*
|
|
||||||
|
|
||||||
open class KotlinUMethod(
|
|
||||||
psi: KtLightMethod,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUElement(givenParent), UAnnotationMethod, JavaUElementWithComments, PsiMethod by psi {
|
|
||||||
override val comments: List<UComment>
|
|
||||||
get() = super<KotlinAbstractUElement>.comments
|
|
||||||
|
|
||||||
override val psi: KtLightMethod = unwrap<UMethod, KtLightMethod>(psi)
|
|
||||||
|
|
||||||
override val javaPsi = psi
|
|
||||||
|
|
||||||
override val sourcePsi = psi.kotlinOrigin
|
|
||||||
|
|
||||||
override fun getSourceElement() = sourcePsi ?: this
|
|
||||||
|
|
||||||
override val uastDefaultValue by lz {
|
|
||||||
val annotationParameter = psi.kotlinOrigin as? KtParameter ?: return@lz null
|
|
||||||
val defaultValue = annotationParameter.defaultValue ?: return@lz null
|
|
||||||
getLanguagePlugin().convertElement(defaultValue, this) as? UExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
private val kotlinOrigin = (psi.originalElement as KtLightElement<*, *>).kotlinOrigin
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile)
|
|
||||||
|
|
||||||
override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
|
|
||||||
|
|
||||||
override val annotations by lz {
|
|
||||||
psi.annotations
|
|
||||||
.mapNotNull { (it as? KtLightElement<*, *>)?.kotlinOrigin as? KtAnnotationEntry }
|
|
||||||
.map { KotlinUAnnotation(it, this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private val receiver by lz { (sourcePsi as? KtCallableDeclaration)?.receiverTypeReference }
|
|
||||||
|
|
||||||
override val uastParameters by lz {
|
|
||||||
val lightParams = psi.parameterList.parameters
|
|
||||||
val receiver = receiver ?: return@lz lightParams.map {
|
|
||||||
KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this)
|
|
||||||
}
|
|
||||||
val receiverLight = lightParams.firstOrNull() ?: return@lz emptyList<UParameter>()
|
|
||||||
val uParameters = SmartList<UParameter>(KotlinReceiverUParameter(receiverLight, receiver, this))
|
|
||||||
lightParams.drop(1).mapTo(uParameters) { KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this) }
|
|
||||||
uParameters
|
|
||||||
}
|
|
||||||
|
|
||||||
override val uastAnchor: UElement
|
|
||||||
get() = UIdentifier(nameIdentifier, this)
|
|
||||||
|
|
||||||
|
|
||||||
override val uastBody by lz {
|
|
||||||
val bodyExpression = when (kotlinOrigin) {
|
|
||||||
is KtFunction -> kotlinOrigin.bodyExpression
|
|
||||||
is KtProperty -> when {
|
|
||||||
psi.isGetter -> kotlinOrigin.getter?.bodyExpression
|
|
||||||
psi.isSetter -> kotlinOrigin.setter?.bodyExpression
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
} ?: return@lz null
|
|
||||||
|
|
||||||
when (bodyExpression) {
|
|
||||||
!is KtBlockExpression -> {
|
|
||||||
KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block ->
|
|
||||||
val implicitReturn = KotlinUImplicitReturnExpression(block)
|
|
||||||
val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression
|
|
||||||
?: return@KotlinLazyUBlockExpression emptyList()
|
|
||||||
listOf(implicitReturn.apply { returnExpression = uBody })
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val isOverride: Boolean
|
|
||||||
get() = (kotlinOrigin as? KtCallableDeclaration)?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false
|
|
||||||
|
|
||||||
override fun getBody(): PsiCodeBlock? = super.getBody()
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? = super.getOriginalElement()
|
|
||||||
|
|
||||||
override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun create(psi: KtLightMethod, containingElement: UElement?) =
|
|
||||||
if (psi.kotlinOrigin is KtConstructor<*>) {
|
|
||||||
KotlinConstructorUMethod(
|
|
||||||
psi.kotlinOrigin?.containingClassOrObject,
|
|
||||||
psi, containingElement
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
KotlinUMethod(psi, containingElement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-441
@@ -1,441 +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 com.intellij.psi.*
|
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
|
||||||
import org.jetbrains.annotations.NotNull
|
|
||||||
import org.jetbrains.annotations.Nullable
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.nullability
|
|
||||||
import org.jetbrains.kotlin.utils.SmartList
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.internal.acceptList
|
|
||||||
import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier
|
|
||||||
import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments
|
|
||||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
|
|
||||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
|
||||||
import org.jetbrains.uast.visitor.UastVisitor
|
|
||||||
|
|
||||||
abstract class AbstractKotlinUVariable(givenParent: UElement?)
|
|
||||||
: KotlinAbstractUElement(givenParent), PsiVariable, UVariable {
|
|
||||||
|
|
||||||
override val uastInitializer: UExpression?
|
|
||||||
get() {
|
|
||||||
val psi = psi
|
|
||||||
val initializerExpression = when (psi) {
|
|
||||||
is UastKotlinPsiVariable -> psi.ktInitializer
|
|
||||||
is UastKotlinPsiParameter -> psi.ktDefaultValue
|
|
||||||
is KtLightElement<*, *> -> {
|
|
||||||
val origin = psi.kotlinOrigin
|
|
||||||
when (origin) {
|
|
||||||
is KtVariableDeclaration -> origin.initializer
|
|
||||||
is KtParameter -> origin.defaultValue
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
} ?: return null
|
|
||||||
return getLanguagePlugin().convertElement(initializerExpression, this) as? UExpression ?: UastEmptyExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
val delegateExpression: UExpression? by lz {
|
|
||||||
val psi = psi
|
|
||||||
val expression = when (psi) {
|
|
||||||
is KtLightElement<*, *> -> (psi.kotlinOrigin as? KtProperty)?.delegateExpression
|
|
||||||
is UastKotlinPsiVariable -> (psi.ktElement as? KtProperty)?.delegateExpression
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
expression?.let { getLanguagePlugin().convertElement(it, this) as? UExpression }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier {
|
|
||||||
val kotlinOrigin = (psi as? KtLightElement<*, *>)?.kotlinOrigin
|
|
||||||
return UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile)
|
|
||||||
|
|
||||||
override val annotations by lz {
|
|
||||||
val sourcePsi = sourcePsi ?: return@lz psi.annotations.map { WrappedUAnnotation(it, this) }
|
|
||||||
val annotations = SmartList<UAnnotation>(KotlinNullabilityUAnnotation(sourcePsi, this))
|
|
||||||
if (sourcePsi is KtModifierListOwner) {
|
|
||||||
sourcePsi.annotationEntries.
|
|
||||||
filter { acceptsAnnotationTarget(it.useSiteTarget?.getAnnotationUseSiteTarget()) }.
|
|
||||||
mapTo(annotations) { KotlinUAnnotation(it, this) }
|
|
||||||
}
|
|
||||||
annotations
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
abstract protected fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean
|
|
||||||
|
|
||||||
override val typeReference by lz { getLanguagePlugin().convertOpt<UTypeReferenceExpression>(psi.typeElement, this) }
|
|
||||||
|
|
||||||
override val uastAnchor: UElement?
|
|
||||||
get() = UIdentifier(nameIdentifier, this)
|
|
||||||
|
|
||||||
override fun equals(other: Any?) = other is AbstractKotlinUVariable && psi == other.psi
|
|
||||||
|
|
||||||
class WrappedUAnnotation(psiAnnotation: PsiAnnotation, override val uastParent: UElement) : UAnnotation, JvmDeclarationUElementPlaceholder {
|
|
||||||
|
|
||||||
override val javaPsi: PsiAnnotation = psiAnnotation
|
|
||||||
override val psi: PsiAnnotation = javaPsi
|
|
||||||
override val sourcePsi: PsiElement? = null
|
|
||||||
|
|
||||||
override val attributeValues: List<UNamedExpression> by lz {
|
|
||||||
psi.parameterList.attributes.map { WrappedUNamedExpression(it, this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class WrappedUNamedExpression(pair: PsiNameValuePair, override val uastParent: UElement?) : UNamedExpression, JvmDeclarationUElementPlaceholder {
|
|
||||||
override val name: String? = pair.name
|
|
||||||
override val psi = pair
|
|
||||||
override val javaPsi: PsiElement? = psi
|
|
||||||
override val sourcePsi: PsiElement? = null
|
|
||||||
override val annotations: List<UAnnotation> = emptyList()
|
|
||||||
override val expression: UExpression by lz { toUExpression(psi.value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override val qualifiedName: String? = psi.qualifiedName
|
|
||||||
override fun findAttributeValue(name: String?): UExpression? = psi.findAttributeValue(name)?.let { toUExpression(it) }
|
|
||||||
override fun findDeclaredAttributeValue(name: String?): UExpression? = psi.findDeclaredAttributeValue(name)?.let { toUExpression(it) }
|
|
||||||
override fun resolve(): PsiClass? = psi.nameReferenceElement?.resolve() as? PsiClass
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toUExpression(psi: PsiElement?): UExpression = psi.toUElementOfType<UExpression>() ?: UastEmptyExpression
|
|
||||||
|
|
||||||
class KotlinUVariable(
|
|
||||||
psi: PsiVariable,
|
|
||||||
override val sourcePsi: KtElement,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : AbstractKotlinUVariable(givenParent), UVariable, PsiVariable by psi {
|
|
||||||
|
|
||||||
override val javaPsi = unwrap<UVariable, PsiVariable>(psi)
|
|
||||||
|
|
||||||
override val psi = javaPsi
|
|
||||||
|
|
||||||
override val typeReference by lz { getLanguagePlugin().convertOpt<UTypeReferenceExpression>(psi.typeElement, this) }
|
|
||||||
|
|
||||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true
|
|
||||||
|
|
||||||
override fun getInitializer(): PsiExpression? {
|
|
||||||
return super<AbstractKotlinUVariable>.getInitializer()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? {
|
|
||||||
return super<AbstractKotlinUVariable>.getOriginalElement()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier {
|
|
||||||
return super.getNameIdentifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile {
|
|
||||||
return super.getContainingFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
open class KotlinUParameter(
|
|
||||||
psi: PsiParameter,
|
|
||||||
final override val sourcePsi: KtElement?,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : AbstractKotlinUVariable(givenParent), UParameter, PsiParameter by psi {
|
|
||||||
|
|
||||||
final override val javaPsi = unwrap<UParameter, PsiParameter>(psi)
|
|
||||||
|
|
||||||
override val psi = javaPsi
|
|
||||||
|
|
||||||
private val isLightConstructorParam by lz { psi.getParentOfType<PsiMethod>(true)?.isConstructor }
|
|
||||||
|
|
||||||
private val isKtConstructorParam by lz { sourcePsi?.getParentOfType<KtCallableDeclaration>(true)?.let { it is KtConstructor<*> } }
|
|
||||||
|
|
||||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean {
|
|
||||||
if (sourcePsi !is KtParameter) return false
|
|
||||||
if (isKtConstructorParam == isLightConstructorParam && target == null) return true
|
|
||||||
when (target) {
|
|
||||||
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> return isLightConstructorParam == true
|
|
||||||
AnnotationUseSiteTarget.SETTER_PARAMETER -> return isLightConstructorParam != true
|
|
||||||
else -> return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getInitializer(): PsiExpression? {
|
|
||||||
return super<AbstractKotlinUVariable>.getInitializer()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? {
|
|
||||||
return super<AbstractKotlinUVariable>.getOriginalElement()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier {
|
|
||||||
return super.getNameIdentifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile {
|
|
||||||
return super.getContainingFile()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinReceiverUParameter(
|
|
||||||
psi: PsiParameter,
|
|
||||||
private val receiver: KtTypeReference,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinUParameter(psi, receiver, givenParent) {
|
|
||||||
|
|
||||||
override val annotations: List<UAnnotation> by lz {
|
|
||||||
receiver.annotationEntries
|
|
||||||
.filter { it.useSiteTarget?.getAnnotationUseSiteTarget() == AnnotationUseSiteTarget.RECEIVER }
|
|
||||||
.map { KotlinUAnnotation(it, this) } +
|
|
||||||
super.annotations
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinNullabilityUAnnotation(val annotatedElement: PsiElement, override val uastParent: UElement) : UAnnotation, JvmDeclarationUElementPlaceholder {
|
|
||||||
|
|
||||||
private fun getTargetType(annotatedElement: PsiElement): KotlinType? {
|
|
||||||
if (annotatedElement is KtTypeReference) {
|
|
||||||
annotatedElement.getType()?.let { return it }
|
|
||||||
}
|
|
||||||
if (annotatedElement is KtCallableDeclaration) {
|
|
||||||
annotatedElement.typeReference?.getType()?.let { return it }
|
|
||||||
}
|
|
||||||
if (annotatedElement is KtProperty) {
|
|
||||||
annotatedElement.initializer?.let { it.getType(it.analyze()) }?.let { return it }
|
|
||||||
annotatedElement.delegateExpression?.let { it.getType(it.analyze())?.arguments?.firstOrNull()?.type }?.let { return it }
|
|
||||||
}
|
|
||||||
annotatedElement.getParentOfType<KtProperty>(false)?.let {
|
|
||||||
it.typeReference?.getType() ?: it.initializer?.let { it.getType(it.analyze()) }
|
|
||||||
}?.let { return it }
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val nullability by lz { getTargetType(annotatedElement)?.nullability() }
|
|
||||||
|
|
||||||
override val attributeValues: List<UNamedExpression>
|
|
||||||
get() = emptyList()
|
|
||||||
override val psi: PsiElement?
|
|
||||||
get() = null
|
|
||||||
override val javaPsi: PsiAnnotation?
|
|
||||||
get() = null
|
|
||||||
override val sourcePsi: PsiElement?
|
|
||||||
get() = null
|
|
||||||
override val qualifiedName: String?
|
|
||||||
get() = when (nullability) {
|
|
||||||
TypeNullability.NOT_NULL -> NotNull::class.qualifiedName
|
|
||||||
TypeNullability.NULLABLE -> Nullable::class.qualifiedName
|
|
||||||
TypeNullability.FLEXIBLE -> null
|
|
||||||
null -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun findAttributeValue(name: String?): UExpression? = null
|
|
||||||
|
|
||||||
override fun findDeclaredAttributeValue(name: String?): UExpression? = null
|
|
||||||
|
|
||||||
override fun resolve(): PsiClass? = qualifiedName?.let {
|
|
||||||
val project = annotatedElement.project
|
|
||||||
JavaPsiFacade.getInstance(project).findClass(it, GlobalSearchScope.allScope(project))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
open class KotlinUField(
|
|
||||||
psi: PsiField,
|
|
||||||
override val sourcePsi: KtElement?,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : AbstractKotlinUVariable(givenParent), UField, PsiField by psi {
|
|
||||||
override fun getSourceElement() = sourcePsi ?: this
|
|
||||||
|
|
||||||
override val javaPsi = unwrap<UField, PsiField>(psi)
|
|
||||||
|
|
||||||
override val psi = javaPsi
|
|
||||||
|
|
||||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean =
|
|
||||||
target == AnnotationUseSiteTarget.FIELD ||
|
|
||||||
target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD ||
|
|
||||||
(sourcePsi is KtProperty) && (target == null || target == AnnotationUseSiteTarget.PROPERTY)
|
|
||||||
|
|
||||||
override fun getInitializer(): PsiExpression? {
|
|
||||||
return super<AbstractKotlinUVariable>.getInitializer()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? {
|
|
||||||
return super<AbstractKotlinUVariable>.getOriginalElement()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier {
|
|
||||||
return super.getNameIdentifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile {
|
|
||||||
return super.getContainingFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isPhysical(): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun accept(visitor: UastVisitor) {
|
|
||||||
if (visitor.visitField(this)) return
|
|
||||||
annotations.acceptList(visitor)
|
|
||||||
uastInitializer?.accept(visitor)
|
|
||||||
delegateExpression?.accept(visitor)
|
|
||||||
visitor.afterVisitField(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class KotlinULocalVariable(
|
|
||||||
psi: PsiLocalVariable,
|
|
||||||
override val sourcePsi: KtElement,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : AbstractKotlinUVariable(givenParent), ULocalVariable, PsiLocalVariable by psi {
|
|
||||||
|
|
||||||
override val javaPsi = unwrap<ULocalVariable, PsiLocalVariable>(psi)
|
|
||||||
|
|
||||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true
|
|
||||||
|
|
||||||
override val psi = javaPsi
|
|
||||||
|
|
||||||
override fun getInitializer(): PsiExpression? {
|
|
||||||
return super<AbstractKotlinUVariable>.getInitializer()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? {
|
|
||||||
return super<AbstractKotlinUVariable>.getOriginalElement()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier {
|
|
||||||
return super.getNameIdentifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile {
|
|
||||||
return super.getContainingFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun accept(visitor: UastVisitor) {
|
|
||||||
if (visitor.visitLocalVariable(this)) return
|
|
||||||
annotations.acceptList(visitor)
|
|
||||||
uastInitializer?.accept(visitor)
|
|
||||||
delegateExpression?.accept(visitor)
|
|
||||||
visitor.afterVisitLocalVariable(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class KotlinUAnnotatedLocalVariable(
|
|
||||||
psi: PsiLocalVariable,
|
|
||||||
sourcePsi: KtElement,
|
|
||||||
uastParent: UElement?,
|
|
||||||
computeAnnotations: (parent: UElement) -> List<UAnnotation>
|
|
||||||
) : KotlinULocalVariable(psi, sourcePsi, uastParent) {
|
|
||||||
|
|
||||||
override val annotations: List<UAnnotation> by lz { computeAnnotations(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinUEnumConstant(
|
|
||||||
psi: PsiEnumConstant,
|
|
||||||
override val sourcePsi: KtElement?,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : AbstractKotlinUVariable(givenParent), UEnumConstant, PsiEnumConstant by psi {
|
|
||||||
|
|
||||||
override val initializingClass: UClass? by lz {
|
|
||||||
(psi.initializingClass as? KtLightClass)?.let { initializingClass ->
|
|
||||||
KotlinUClass.create(initializingClass, this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getInitializer(): PsiExpression? = super<AbstractKotlinUVariable>.getInitializer()
|
|
||||||
|
|
||||||
override fun getOriginalElement(): PsiElement? = super<AbstractKotlinUVariable>.getOriginalElement()
|
|
||||||
|
|
||||||
override val javaPsi = unwrap<UEnumConstant, PsiEnumConstant>(psi)
|
|
||||||
|
|
||||||
override val psi = javaPsi
|
|
||||||
|
|
||||||
override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true
|
|
||||||
|
|
||||||
override fun getContainingFile(): PsiFile {
|
|
||||||
return super.getContainingFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier {
|
|
||||||
return super.getNameIdentifier()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val kind: UastCallKind
|
|
||||||
get() = UastCallKind.CONSTRUCTOR_CALL
|
|
||||||
|
|
||||||
override val receiver: UExpression?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val receiverType: PsiType?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val methodIdentifier: UIdentifier?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val classReference: UReferenceExpression?
|
|
||||||
get() = KotlinEnumConstantClassReference(psi, sourcePsi, this)
|
|
||||||
|
|
||||||
override val typeArgumentCount: Int
|
|
||||||
get() = 0
|
|
||||||
|
|
||||||
override val typeArguments: List<PsiType>
|
|
||||||
get() = emptyList()
|
|
||||||
|
|
||||||
override val valueArgumentCount: Int
|
|
||||||
get() = psi.argumentList?.expressions?.size ?: 0
|
|
||||||
|
|
||||||
override val valueArguments by lz {
|
|
||||||
psi.argumentList?.expressions?.map {
|
|
||||||
getLanguagePlugin().convertElement(it, this) as? UExpression ?: UastEmptyExpression
|
|
||||||
} ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val returnType: PsiType?
|
|
||||||
get() = psi.type
|
|
||||||
|
|
||||||
override fun resolve() = psi.resolveMethod()
|
|
||||||
|
|
||||||
override val methodName: String?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
private class KotlinEnumConstantClassReference(
|
|
||||||
override val psi: PsiEnumConstant,
|
|
||||||
override val sourcePsi: KtElement?,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression {
|
|
||||||
override val javaPsi: PsiElement?
|
|
||||||
get() = psi
|
|
||||||
|
|
||||||
override fun resolve() = psi.containingClass
|
|
||||||
override val resolvedName: String?
|
|
||||||
get() = psi.containingClass?.name
|
|
||||||
override val identifier: String
|
|
||||||
get() = psi.containingClass?.name ?: "<error>"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-28
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 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.declarations
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import com.intellij.psi.PsiNameIdentifierOwner
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
|
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
|
||||||
import org.jetbrains.uast.kotlin.unwrapFakeFileForLightClass
|
|
||||||
|
|
||||||
class UastLightIdentifier(lightOwner: PsiNameIdentifierOwner, ktDeclaration: KtNamedDeclaration?)
|
|
||||||
: KtLightIdentifier(lightOwner, ktDeclaration) {
|
|
||||||
override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(super.getContainingFile())
|
|
||||||
}
|
|
||||||
-120
@@ -1,120 +0,0 @@
|
|||||||
package org.jetbrains.uast.kotlin.expressions
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import com.intellij.psi.PsiType
|
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.types.CommonSupertypes
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.kotlin.*
|
|
||||||
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
|
|
||||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
|
||||||
|
|
||||||
|
|
||||||
private fun createVariableReferenceExpression(variable: UVariable, containingElement: UElement?) =
|
|
||||||
object : USimpleNameReferenceExpression, JvmDeclarationUElementPlaceholder {
|
|
||||||
override val psi: PsiElement? = null
|
|
||||||
override fun resolve(): PsiElement? = variable
|
|
||||||
override val uastParent: UElement? = containingElement
|
|
||||||
override val resolvedName: String? = variable.name
|
|
||||||
override val annotations: List<UAnnotation> = emptyList()
|
|
||||||
override val identifier: String = variable.name.orAnonymous()
|
|
||||||
override val javaPsi: PsiElement? = null
|
|
||||||
override val sourcePsi: PsiElement? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createNullLiteralExpression(containingElement: UElement?) =
|
|
||||||
object : ULiteralExpression, JvmDeclarationUElementPlaceholder {
|
|
||||||
override val psi: PsiElement? = null
|
|
||||||
override val uastParent: UElement? = containingElement
|
|
||||||
override val value: Any? = null
|
|
||||||
override val annotations: List<UAnnotation> = emptyList()
|
|
||||||
override val javaPsi: PsiElement? = null
|
|
||||||
override val sourcePsi: PsiElement? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createNotEqWithNullExpression(variable: UVariable, containingElement: UElement?) =
|
|
||||||
object : UBinaryExpression, JvmDeclarationUElementPlaceholder {
|
|
||||||
override val psi: PsiElement? = null
|
|
||||||
override val uastParent: UElement? = containingElement
|
|
||||||
override val leftOperand: UExpression by lz { createVariableReferenceExpression(variable, this) }
|
|
||||||
override val rightOperand: UExpression by lz { createNullLiteralExpression(this) }
|
|
||||||
override val operator: UastBinaryOperator = UastBinaryOperator.NOT_EQUALS
|
|
||||||
override val operatorIdentifier: UIdentifier? = UIdentifier(null, this)
|
|
||||||
override fun resolveOperator(): PsiMethod? = null
|
|
||||||
override val annotations: List<UAnnotation> = emptyList()
|
|
||||||
override val javaPsi: PsiElement? = null
|
|
||||||
override val sourcePsi: PsiElement? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createElvisExpressions(
|
|
||||||
left: KtExpression,
|
|
||||||
right: KtExpression,
|
|
||||||
containingElement: UElement?,
|
|
||||||
psiParent: PsiElement): List<UExpression> {
|
|
||||||
|
|
||||||
val declaration = KotlinUDeclarationsExpression(containingElement)
|
|
||||||
val tempVariable = KotlinULocalVariable(UastKotlinPsiVariable.create(left, declaration, psiParent), left, declaration)
|
|
||||||
declaration.declarations = listOf(tempVariable)
|
|
||||||
|
|
||||||
val ifExpression = object : UIfExpression, JvmDeclarationUElementPlaceholder {
|
|
||||||
override val psi: PsiElement? = null
|
|
||||||
override val uastParent: UElement? = containingElement
|
|
||||||
override val javaPsi: PsiElement? = null
|
|
||||||
override val sourcePsi: PsiElement? = null
|
|
||||||
override val condition: UExpression by lz { createNotEqWithNullExpression(tempVariable, this) }
|
|
||||||
override val thenExpression: UExpression? by lz { createVariableReferenceExpression(tempVariable, this) }
|
|
||||||
override val elseExpression: UExpression? by lz { KotlinConverter.convertExpression(right, this ) }
|
|
||||||
override val isTernary: Boolean = false
|
|
||||||
override val annotations: List<UAnnotation> = emptyList()
|
|
||||||
override val ifIdentifier: UIdentifier = UIdentifier(null, this)
|
|
||||||
override val elseIdentifier: UIdentifier? = UIdentifier(null, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
return listOf(declaration, ifExpression)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createElvisExpression(elvisExpression: KtBinaryExpression, givenParent: UElement?): UExpression {
|
|
||||||
val left = elvisExpression.left ?: return UastEmptyExpression
|
|
||||||
val right = elvisExpression.right ?: return UastEmptyExpression
|
|
||||||
|
|
||||||
return KotlinUElvisExpression(elvisExpression, left, right, givenParent)
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinUElvisExpression(
|
|
||||||
private val elvisExpression: KtBinaryExpression,
|
|
||||||
private val left: KtExpression,
|
|
||||||
private val right: KtExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUElement(givenParent), UExpressionList, KotlinEvaluatableUElement {
|
|
||||||
|
|
||||||
override val javaPsi: PsiElement? = null
|
|
||||||
override val sourcePsi: PsiElement? = elvisExpression
|
|
||||||
override val psi: PsiElement? = sourcePsi
|
|
||||||
override val kind = KotlinSpecialExpressionKinds.ELVIS
|
|
||||||
override val annotations: List<UAnnotation> = emptyList()
|
|
||||||
override val expressions: List<UExpression> by lz {
|
|
||||||
createElvisExpressions(left, right, this, elvisExpression.parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
val lhsDeclaration get() = (expressions[0] as UDeclarationsExpression).declarations.single()
|
|
||||||
val rhsIfExpression get() = expressions[1] as UIfExpression
|
|
||||||
|
|
||||||
override fun asRenderString(): String {
|
|
||||||
return kind.name + " " +
|
|
||||||
expressions.joinToString(separator = "\n", prefix = "{\n", postfix = "\n}") {
|
|
||||||
it.asRenderString().withMargin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getExpressionType(): PsiType? {
|
|
||||||
val leftType = left.analyze()[BindingContext.EXPRESSION_TYPE_INFO, left]?.type ?: return null
|
|
||||||
val rightType = right.analyze()[BindingContext.EXPRESSION_TYPE_INFO, right]?.type ?: return null
|
|
||||||
|
|
||||||
return CommonSupertypes
|
|
||||||
.commonSupertype(listOf(leftType, rightType))
|
|
||||||
.toPsiType(this, elvisExpression, boxed = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-106
@@ -1,106 +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 com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
|
|
||||||
class KotlinUBinaryExpression(
|
|
||||||
override val psi: KtBinaryExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UBinaryExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
|
|
||||||
private companion object {
|
|
||||||
val BITWISE_OPERATORS = mapOf(
|
|
||||||
"or" to UastBinaryOperator.BITWISE_OR,
|
|
||||||
"and" to UastBinaryOperator.BITWISE_AND,
|
|
||||||
"xor" to UastBinaryOperator.BITWISE_XOR
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val leftOperand by lz { KotlinConverter.convertOrEmpty(psi.left, this) }
|
|
||||||
override val rightOperand by lz { KotlinConverter.convertOrEmpty(psi.right, this) }
|
|
||||||
|
|
||||||
override val operatorIdentifier: UIdentifier?
|
|
||||||
get() = UIdentifier(psi.operationReference, this)
|
|
||||||
|
|
||||||
override fun resolveOperator() = psi.operationReference.resolveCallToDeclaration(context = this) as? PsiMethod
|
|
||||||
|
|
||||||
override val operator = when (psi.operationToken) {
|
|
||||||
KtTokens.EQ -> UastBinaryOperator.ASSIGN
|
|
||||||
KtTokens.PLUS -> UastBinaryOperator.PLUS
|
|
||||||
KtTokens.MINUS -> UastBinaryOperator.MINUS
|
|
||||||
KtTokens.MUL -> UastBinaryOperator.MULTIPLY
|
|
||||||
KtTokens.DIV -> UastBinaryOperator.DIV
|
|
||||||
KtTokens.PERC -> UastBinaryOperator.MOD
|
|
||||||
KtTokens.OROR -> UastBinaryOperator.LOGICAL_OR
|
|
||||||
KtTokens.ANDAND -> UastBinaryOperator.LOGICAL_AND
|
|
||||||
KtTokens.EQEQ -> UastBinaryOperator.EQUALS
|
|
||||||
KtTokens.EXCLEQ -> UastBinaryOperator.NOT_EQUALS
|
|
||||||
KtTokens.EQEQEQ -> UastBinaryOperator.IDENTITY_EQUALS
|
|
||||||
KtTokens.EXCLEQEQEQ -> UastBinaryOperator.IDENTITY_NOT_EQUALS
|
|
||||||
KtTokens.GT -> UastBinaryOperator.GREATER
|
|
||||||
KtTokens.GTEQ -> UastBinaryOperator.GREATER_OR_EQUALS
|
|
||||||
KtTokens.LT -> UastBinaryOperator.LESS
|
|
||||||
KtTokens.LTEQ -> UastBinaryOperator.LESS_OR_EQUALS
|
|
||||||
KtTokens.PLUSEQ -> UastBinaryOperator.PLUS_ASSIGN
|
|
||||||
KtTokens.MINUSEQ -> UastBinaryOperator.MINUS_ASSIGN
|
|
||||||
KtTokens.MULTEQ -> UastBinaryOperator.MULTIPLY_ASSIGN
|
|
||||||
KtTokens.DIVEQ -> UastBinaryOperator.DIVIDE_ASSIGN
|
|
||||||
KtTokens.PERCEQ -> UastBinaryOperator.REMAINDER_ASSIGN
|
|
||||||
KtTokens.IN_KEYWORD -> KotlinBinaryOperators.IN
|
|
||||||
KtTokens.NOT_IN -> KotlinBinaryOperators.NOT_IN
|
|
||||||
KtTokens.RANGE -> KotlinBinaryOperators.RANGE_TO
|
|
||||||
else -> run { // Handle bitwise operators
|
|
||||||
val other = UastBinaryOperator.OTHER
|
|
||||||
val ref = psi.operationReference
|
|
||||||
val resolvedCall = psi.operationReference.getResolvedCall(ref.analyze()) ?: return@run other
|
|
||||||
val resultingDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return@run other
|
|
||||||
val applicableOperator = BITWISE_OPERATORS[resultingDescriptor.name.asString()] ?: return@run other
|
|
||||||
|
|
||||||
val containingClass = resultingDescriptor.containingDeclaration as? ClassDescriptor ?: return@run other
|
|
||||||
if (containingClass.typeConstructor.supertypes.any {
|
|
||||||
it.constructor.declarationDescriptor?.fqNameSafe?.asString() == "kotlin.Number"
|
|
||||||
}) applicableOperator else other
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinCustomUBinaryExpression(
|
|
||||||
override val psi: PsiElement,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UBinaryExpression {
|
|
||||||
lateinit override var leftOperand: UExpression
|
|
||||||
internal set
|
|
||||||
|
|
||||||
lateinit override var operator: UastBinaryOperator
|
|
||||||
internal set
|
|
||||||
|
|
||||||
lateinit override var rightOperand: UExpression
|
|
||||||
internal set
|
|
||||||
|
|
||||||
override val operatorIdentifier: UIdentifier?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override fun resolveOperator() = null
|
|
||||||
}
|
|
||||||
-54
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 JetBrains s.r.o. 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.expressions
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiArrayType
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import com.intellij.psi.PsiType
|
|
||||||
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.kotlin.KotlinAbstractUExpression
|
|
||||||
import org.jetbrains.uast.kotlin.KotlinConverter
|
|
||||||
import org.jetbrains.uast.kotlin.KotlinUElementWithType
|
|
||||||
|
|
||||||
class KotlinUCollectionLiteralExpression(
|
|
||||||
override val sourcePsi: KtCollectionLiteralExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UCallExpression, KotlinUElementWithType {
|
|
||||||
|
|
||||||
override val classReference: UReferenceExpression? get() = null
|
|
||||||
|
|
||||||
override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER
|
|
||||||
|
|
||||||
override val methodIdentifier: UIdentifier? by lazy { UIdentifier(sourcePsi.leftBracket, this) }
|
|
||||||
|
|
||||||
override val methodName: String? get() = null
|
|
||||||
|
|
||||||
override val receiver: UExpression? get() = null
|
|
||||||
|
|
||||||
override val receiverType: PsiType? get() = null
|
|
||||||
|
|
||||||
override val returnType: PsiType? get() = getExpressionType()
|
|
||||||
|
|
||||||
override val typeArgumentCount: Int get() = typeArguments.size
|
|
||||||
|
|
||||||
override val typeArguments: List<PsiType> get() = listOfNotNull((returnType as? PsiArrayType)?.componentType)
|
|
||||||
|
|
||||||
override val valueArgumentCount: Int
|
|
||||||
get() = sourcePsi.getInnerExpressions().size
|
|
||||||
|
|
||||||
override val valueArguments by lazy {
|
|
||||||
sourcePsi.getInnerExpressions().map { KotlinConverter.convertOrEmpty(it, this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun asRenderString(): String = "collectionLiteral[" + valueArguments.joinToString { it.asRenderString() } + "]"
|
|
||||||
|
|
||||||
override fun resolve(): PsiMethod? = null
|
|
||||||
|
|
||||||
override val psi: PsiElement get() = sourcePsi
|
|
||||||
|
|
||||||
}
|
|
||||||
-36
@@ -1,36 +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.KtDoWhileExpression
|
|
||||||
import org.jetbrains.uast.UDoWhileExpression
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UIdentifier
|
|
||||||
|
|
||||||
class KotlinUDoWhileExpression(
|
|
||||||
override val psi: KtDoWhileExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UDoWhileExpression {
|
|
||||||
override val condition by lz { KotlinConverter.convertOrEmpty(psi.condition, this) }
|
|
||||||
override val body by lz { KotlinConverter.convertOrEmpty(psi.body, this) }
|
|
||||||
|
|
||||||
override val doIdentifier: UIdentifier
|
|
||||||
get() = UIdentifier(null, this)
|
|
||||||
|
|
||||||
override val whileIdentifier: UIdentifier
|
|
||||||
get() = UIdentifier(null, this)
|
|
||||||
}
|
|
||||||
-42
@@ -1,42 +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.idea.KotlinLanguage
|
|
||||||
import org.jetbrains.kotlin.psi.KtForExpression
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UForEachExpression
|
|
||||||
import org.jetbrains.uast.UIdentifier
|
|
||||||
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
|
|
||||||
import org.jetbrains.uast.psi.UastPsiParameterNotResolved
|
|
||||||
|
|
||||||
class KotlinUForEachExpression(
|
|
||||||
override val psi: KtForExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UForEachExpression {
|
|
||||||
override val iteratedValue by lz { KotlinConverter.convertOrEmpty(psi.loopRange, this) }
|
|
||||||
override val body by lz { KotlinConverter.convertOrEmpty(psi.body, this) }
|
|
||||||
|
|
||||||
override val variable by lz {
|
|
||||||
val parameter = psi.loopParameter?.let { UastKotlinPsiParameter.create(it, psi, this, 0) }
|
|
||||||
?: UastPsiParameterNotResolved(psi, KotlinLanguage.INSTANCE)
|
|
||||||
KotlinUParameter(parameter, psi, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val forIdentifier: UIdentifier
|
|
||||||
get() = UIdentifier(null, this)
|
|
||||||
}
|
|
||||||
-141
@@ -1,141 +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 com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import com.intellij.psi.PsiType
|
|
||||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
|
||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
|
||||||
import org.jetbrains.kotlin.psi.KtCallElement
|
|
||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
|
||||||
import org.jetbrains.kotlin.psi.KtFunction
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
|
||||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.internal.acceptList
|
|
||||||
import org.jetbrains.uast.visitor.UastVisitor
|
|
||||||
|
|
||||||
class KotlinUFunctionCallExpression(
|
|
||||||
override val psi: KtCallElement,
|
|
||||||
givenParent: UElement?,
|
|
||||||
private val _resolvedCall: ResolvedCall<*>?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UCallExpression, KotlinUElementWithType {
|
|
||||||
companion object {
|
|
||||||
fun resolveSource(descriptor: DeclarationDescriptor, source: PsiElement?): PsiMethod? {
|
|
||||||
if (descriptor is ConstructorDescriptor && descriptor.isPrimary
|
|
||||||
&& source is KtClassOrObject && source.primaryConstructor == null
|
|
||||||
&& source.secondaryConstructors.isEmpty()) {
|
|
||||||
return source.toLightClass()?.constructors?.firstOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
return when (source) {
|
|
||||||
is KtFunction -> LightClassUtil.getLightClassMethod(source)
|
|
||||||
is PsiMethod -> source
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null)
|
|
||||||
|
|
||||||
private val resolvedCall by lz {
|
|
||||||
_resolvedCall ?: psi.getResolvedCall(psi.analyze())
|
|
||||||
}
|
|
||||||
|
|
||||||
override val receiverType by lz {
|
|
||||||
val resolvedCall = this.resolvedCall ?: return@lz null
|
|
||||||
val receiver = resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver ?: return@lz null
|
|
||||||
receiver.type.toPsiType(this, psi, boxed = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val methodName by lz { resolvedCall?.resultingDescriptor?.name?.asString() }
|
|
||||||
|
|
||||||
override val classReference by lz {
|
|
||||||
KotlinClassViaConstructorUSimpleReferenceExpression(psi, methodName.orAnonymous("class"), this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val methodIdentifier by lz {
|
|
||||||
val calleeExpression = psi.calleeExpression ?: return@lz null
|
|
||||||
UIdentifier(calleeExpression, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val valueArgumentCount: Int
|
|
||||||
get() = psi.valueArguments.size
|
|
||||||
|
|
||||||
override val valueArguments by lz { psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) } }
|
|
||||||
|
|
||||||
override val typeArgumentCount: Int
|
|
||||||
get() = psi.typeArguments.size
|
|
||||||
|
|
||||||
override val typeArguments by lz { psi.typeArguments.map { it.typeReference.toPsiType(this, boxed = true) } }
|
|
||||||
|
|
||||||
override val returnType: PsiType?
|
|
||||||
get() = getExpressionType()
|
|
||||||
|
|
||||||
override val kind: UastCallKind by lz {
|
|
||||||
val resolvedCall = resolvedCall ?: return@lz UastCallKind.METHOD_CALL
|
|
||||||
when {
|
|
||||||
resolvedCall.resultingDescriptor is ConstructorDescriptor -> UastCallKind.CONSTRUCTOR_CALL
|
|
||||||
this.isAnnotationArgumentArrayInitializer() -> UastCallKind.NESTED_ARRAY_INITIALIZER
|
|
||||||
else -> UastCallKind.METHOD_CALL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val receiver: UExpression?
|
|
||||||
get() = (uastParent as? UQualifiedReferenceExpression)?.takeIf { it.selector == this }?.receiver
|
|
||||||
|
|
||||||
override fun resolve(): PsiMethod? {
|
|
||||||
val descriptor = resolvedCall?.resultingDescriptor ?: return null
|
|
||||||
val source = descriptor.toSource() ?: return null
|
|
||||||
return resolveSource(descriptor, source)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun accept(visitor: UastVisitor) {
|
|
||||||
if (visitor.visitCallExpression(this)) return
|
|
||||||
methodIdentifier?.accept(visitor)
|
|
||||||
classReference.accept(visitor)
|
|
||||||
valueArguments.acceptList(visitor)
|
|
||||||
|
|
||||||
visitor.afterVisitCallExpression(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isAnnotationArgumentArrayInitializer(): Boolean {
|
|
||||||
val resolvedCall = resolvedCall ?: return false
|
|
||||||
// KtAnnotationEntry -> KtValueArgumentList -> KtValueArgument -> arrayOf call
|
|
||||||
return psi.parents.elementAtOrNull(2) is KtAnnotationEntry && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun convertParent(): UElement? = super.convertParent().let { result ->
|
|
||||||
when (result) {
|
|
||||||
is UMethod -> result.uastBody ?: result
|
|
||||||
is UClass ->
|
|
||||||
result.methods
|
|
||||||
.filterIsInstance<KotlinConstructorUMethod>()
|
|
||||||
.firstOrNull { it.isPrimary }
|
|
||||||
?.uastBody
|
|
||||||
?: result
|
|
||||||
else -> result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-35
@@ -1,35 +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.KtLabeledExpression
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UIdentifier
|
|
||||||
import org.jetbrains.uast.ULabeledExpression
|
|
||||||
|
|
||||||
class KotlinULabeledExpression(
|
|
||||||
override val psi: KtLabeledExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), ULabeledExpression {
|
|
||||||
override val label: String
|
|
||||||
get() = psi.getLabelName().orAnonymous("label")
|
|
||||||
|
|
||||||
override val labelIdentifier: UIdentifier?
|
|
||||||
get() = psi.getTargetLabel()?.let { UIdentifier(it, this) }
|
|
||||||
|
|
||||||
override val expression by lz { KotlinConverter.convertOrEmpty(psi.baseExpression, this) }
|
|
||||||
}
|
|
||||||
-100
@@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 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.PsiElement
|
|
||||||
import com.intellij.psi.PsiType
|
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
|
|
||||||
class KotlinUNamedExpression private constructor(
|
|
||||||
override val name: String?,
|
|
||||||
override val sourcePsi: PsiElement?,
|
|
||||||
givenParent: UElement?,
|
|
||||||
expressionProducer: (UElement) -> UExpression
|
|
||||||
) : KotlinAbstractUElement(givenParent), UNamedExpression {
|
|
||||||
|
|
||||||
override val expression: UExpression by lz { expressionProducer(this) }
|
|
||||||
|
|
||||||
override val annotations: List<UAnnotation> = emptyList()
|
|
||||||
|
|
||||||
override val psi: PsiElement? = null
|
|
||||||
|
|
||||||
override val javaPsi: PsiElement? = null
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
internal fun create(name: String?, valueArgument: ValueArgument, uastParent: UElement?): UNamedExpression {
|
|
||||||
val expression = valueArgument.getArgumentExpression()
|
|
||||||
return KotlinUNamedExpression(name, valueArgument.asElement(), uastParent) { expressionParent ->
|
|
||||||
expression?.let { expressionParent.getLanguagePlugin().convert<UExpression>(it, expressionParent) } ?: UastEmptyExpression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun create(
|
|
||||||
name: String?,
|
|
||||||
valueArguments: List<ValueArgument>,
|
|
||||||
uastParent: UElement?): UNamedExpression {
|
|
||||||
return KotlinUNamedExpression(name, null, uastParent) { expressionParent ->
|
|
||||||
KotlinUVarargExpression(valueArguments, expressionParent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class KotlinUVarargExpression(private val valueArgs: List<ValueArgument>,
|
|
||||||
uastParent: UElement?) : KotlinAbstractUExpression(uastParent), UCallExpression {
|
|
||||||
override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER
|
|
||||||
|
|
||||||
override val valueArguments: List<UExpression> by lz {
|
|
||||||
valueArgs.map {
|
|
||||||
it.getArgumentExpression()?.let { argumentExpression ->
|
|
||||||
getLanguagePlugin().convert<UExpression>(argumentExpression, this)
|
|
||||||
} ?: UastEmptyExpression
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override val valueArgumentCount: Int
|
|
||||||
get() = valueArgs.size
|
|
||||||
|
|
||||||
override val psi: PsiElement?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val methodIdentifier: UIdentifier?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val classReference: UReferenceExpression?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val methodName: String?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val typeArgumentCount: Int
|
|
||||||
get() = 0
|
|
||||||
|
|
||||||
override val typeArguments: List<PsiType>
|
|
||||||
get() = emptyList()
|
|
||||||
|
|
||||||
override val returnType: PsiType?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override fun resolve() = null
|
|
||||||
|
|
||||||
override val receiver: UExpression?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val receiverType: PsiType?
|
|
||||||
get() = null
|
|
||||||
}
|
|
||||||
-97
@@ -1,97 +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 com.intellij.openapi.diagnostic.Attachment
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import com.intellij.psi.PsiType
|
|
||||||
import com.intellij.psi.impl.light.LightPsiClassBuilder
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
|
||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
|
||||||
import org.jetbrains.kotlin.psi.KtObjectLiteralExpression
|
|
||||||
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
|
|
||||||
class KotlinUObjectLiteralExpression(
|
|
||||||
override val psi: KtObjectLiteralExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UObjectLiteralExpression, KotlinUElementWithType {
|
|
||||||
override val declaration: UClass by lz {
|
|
||||||
val lightClass: KtLightClass? = psi.objectDeclaration.toLightClass()
|
|
||||||
if (lightClass != null) {
|
|
||||||
getLanguagePlugin().convert<UClass>(lightClass, this)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logger.error(
|
|
||||||
"Failed to create light class for object declaration",
|
|
||||||
Attachment(psi.containingFile.virtualFile?.path ?: "<no path>", psi.containingFile.text))
|
|
||||||
|
|
||||||
getLanguagePlugin().convert(LightPsiClassBuilder(psi, "<unnamed>"), 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(this) as? PsiMethod
|
|
||||||
|
|
||||||
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(this) as? PsiMethod)?.containingClass
|
|
||||||
|
|
||||||
override val annotations: List<UAnnotation>
|
|
||||||
get() = emptyList()
|
|
||||||
|
|
||||||
override val resolvedName: String?
|
|
||||||
get() = identifier
|
|
||||||
|
|
||||||
override val identifier: String
|
|
||||||
get() = psi.name ?: "<error>"
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val logger by lz { Logger.getInstance(KotlinUObjectLiteralExpression::class.java) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-46
@@ -1,46 +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 com.intellij.psi.PsiMethod
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.psi.KtPostfixExpression
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
|
|
||||||
class KotlinUPostfixExpression(
|
|
||||||
override val psi: KtPostfixExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UPostfixExpression, KotlinUElementWithType, KotlinEvaluatableUElement, UResolvable {
|
|
||||||
override val operand by lz { KotlinConverter.convertOrEmpty(psi.baseExpression, this) }
|
|
||||||
|
|
||||||
override val operator = when (psi.operationToken) {
|
|
||||||
KtTokens.PLUSPLUS -> UastPostfixOperator.INC
|
|
||||||
KtTokens.MINUSMINUS -> UastPostfixOperator.DEC
|
|
||||||
KtTokens.EXCLEXCL -> KotlinPostfixOperators.EXCLEXCL
|
|
||||||
else -> UastPostfixOperator.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override val operatorIdentifier: UIdentifier?
|
|
||||||
get() = UIdentifier(psi.operationReference, this)
|
|
||||||
|
|
||||||
override fun resolveOperator() = psi.operationReference.resolveCallToDeclaration(context = this) as? PsiMethod
|
|
||||||
|
|
||||||
override fun resolve(): PsiMethod? = when (psi.operationToken) {
|
|
||||||
KtTokens.EXCLEXCL -> operand.tryResolve() as? PsiMethod
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-46
@@ -1,46 +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 com.intellij.psi.PsiMethod
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.psi.KtPrefixExpression
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UIdentifier
|
|
||||||
import org.jetbrains.uast.UPrefixExpression
|
|
||||||
import org.jetbrains.uast.UastPrefixOperator
|
|
||||||
|
|
||||||
class KotlinUPrefixExpression(
|
|
||||||
override val psi: KtPrefixExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UPrefixExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
|
|
||||||
override val operand by lz { KotlinConverter.convertOrEmpty(psi.baseExpression, this) }
|
|
||||||
|
|
||||||
override val operatorIdentifier: UIdentifier?
|
|
||||||
get() = UIdentifier(psi.operationReference, this)
|
|
||||||
|
|
||||||
override fun resolveOperator() = psi.operationReference.resolveCallToDeclaration(context = this) as? PsiMethod
|
|
||||||
|
|
||||||
override val operator = when (psi.operationToken) {
|
|
||||||
KtTokens.EXCL -> UastPrefixOperator.LOGICAL_NOT
|
|
||||||
KtTokens.PLUS -> UastPrefixOperator.UNARY_PLUS
|
|
||||||
KtTokens.MINUS -> UastPrefixOperator.UNARY_MINUS
|
|
||||||
KtTokens.PLUSPLUS -> UastPrefixOperator.INC
|
|
||||||
KtTokens.MINUSMINUS -> UastPrefixOperator.DEC
|
|
||||||
else -> UastPrefixOperator.UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-220
@@ -1,220 +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 com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import com.intellij.psi.PsiNamedElement
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
|
||||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.constant
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.visitor.UastVisitor
|
|
||||||
|
|
||||||
open class KotlinUSimpleReferenceExpression(
|
|
||||||
override val psi: KtSimpleNameExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
|
|
||||||
private val resolvedDeclaration by lz { psi.resolveCallToDeclaration(this) }
|
|
||||||
|
|
||||||
override val identifier get() = psi.getReferencedName()
|
|
||||||
|
|
||||||
override fun resolve() = resolvedDeclaration
|
|
||||||
|
|
||||||
override val resolvedName: String?
|
|
||||||
get() = (resolvedDeclaration as? PsiNamedElement)?.name
|
|
||||||
|
|
||||||
override fun accept(visitor: UastVisitor) {
|
|
||||||
visitor.visitSimpleNameReferenceExpression(this)
|
|
||||||
|
|
||||||
if (psi.parent.destructuringDeclarationInitializer != true) {
|
|
||||||
visitAccessorCalls(visitor)
|
|
||||||
}
|
|
||||||
|
|
||||||
visitor.afterVisitSimpleNameReferenceExpression(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitAccessorCalls(visitor: UastVisitor) {
|
|
||||||
// Visit Kotlin get-set synthetic Java property calls as function calls
|
|
||||||
val bindingContext = psi.analyze()
|
|
||||||
val access = psi.readWriteAccess()
|
|
||||||
val resolvedCall = psi.getResolvedCall(bindingContext)
|
|
||||||
val resultingDescriptor = resolvedCall?.resultingDescriptor as? SyntheticJavaPropertyDescriptor
|
|
||||||
if (resultingDescriptor != null) {
|
|
||||||
val setterValue = if (access.isWrite) {
|
|
||||||
findAssignment(psi, psi.parent)?.right ?: run {
|
|
||||||
visitor.afterVisitSimpleNameReferenceExpression(this)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resolvedCall != null) {
|
|
||||||
if (access.isRead) {
|
|
||||||
val getDescriptor = resultingDescriptor.getMethod
|
|
||||||
KotlinAccessorCallExpression(psi, this, resolvedCall, getDescriptor, null).accept(visitor)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (access.isWrite && setterValue != null) {
|
|
||||||
val setDescriptor = resultingDescriptor.setMethod
|
|
||||||
if (setDescriptor != null) {
|
|
||||||
KotlinAccessorCallExpression(psi, this, resolvedCall, setDescriptor, setterValue).accept(visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private tailrec fun findAssignment(prev: PsiElement?, element: PsiElement?): KtBinaryExpression? = when (element) {
|
|
||||||
is KtBinaryExpression -> if (element.left == prev && element.operationToken == KtTokens.EQ) element else null
|
|
||||||
is KtQualifiedExpression -> findAssignment(element, element.parent)
|
|
||||||
is KtSimpleNameExpression -> findAssignment(element, element.parent)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinAccessorCallExpression(
|
|
||||||
override val psi: KtElement,
|
|
||||||
override val uastParent: KotlinUSimpleReferenceExpression,
|
|
||||||
private val resolvedCall: ResolvedCall<*>,
|
|
||||||
private val accessorDescriptor: DeclarationDescriptor,
|
|
||||||
val setterValue: KtExpression?
|
|
||||||
) : UCallExpression, JvmDeclarationUElementPlaceholder {
|
|
||||||
override val methodName: String?
|
|
||||||
get() = accessorDescriptor.name.asString()
|
|
||||||
|
|
||||||
override val receiver: UExpression?
|
|
||||||
get() {
|
|
||||||
val containingElement = uastParent.uastParent
|
|
||||||
return if (containingElement is UQualifiedReferenceExpression && containingElement.selector == this)
|
|
||||||
containingElement.receiver
|
|
||||||
else
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
override val javaPsi: PsiElement? = null
|
|
||||||
override val sourcePsi: PsiElement? = psi
|
|
||||||
|
|
||||||
override val annotations: List<UAnnotation>
|
|
||||||
get() = emptyList()
|
|
||||||
|
|
||||||
override val receiverType by lz {
|
|
||||||
val type = (resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver)?.type ?: return@lz null
|
|
||||||
type.toPsiType(this, psi, boxed = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val methodIdentifier: UIdentifier?
|
|
||||||
get() = UIdentifier(uastParent.psi, this)
|
|
||||||
|
|
||||||
override val classReference: UReferenceExpression?
|
|
||||||
get() = null
|
|
||||||
|
|
||||||
override val valueArgumentCount: Int
|
|
||||||
get() = if (setterValue != null) 1 else 0
|
|
||||||
|
|
||||||
override val valueArguments by lz {
|
|
||||||
if (setterValue != null)
|
|
||||||
listOf(KotlinConverter.convertOrEmpty(setterValue, this))
|
|
||||||
else
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val typeArgumentCount: Int
|
|
||||||
get() = resolvedCall.typeArguments.size
|
|
||||||
|
|
||||||
override val typeArguments by lz {
|
|
||||||
resolvedCall.typeArguments.values.map { it.toPsiType(this, psi, true) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override val returnType by lz {
|
|
||||||
(accessorDescriptor as? CallableDescriptor)?.returnType?.toPsiType(this, psi, boxed = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val kind: UastCallKind
|
|
||||||
get() = UastCallKind.METHOD_CALL
|
|
||||||
|
|
||||||
override fun resolve(): PsiMethod? {
|
|
||||||
val source = accessorDescriptor.toSource()
|
|
||||||
return KotlinUFunctionCallExpression.resolveSource(accessorDescriptor, source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class ReferenceAccess(val isRead: Boolean, val isWrite: Boolean) {
|
|
||||||
READ(true, false), WRITE(false, true), READ_WRITE(true, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KtExpression.readWriteAccess(): ReferenceAccess {
|
|
||||||
var expression = getQualifiedExpressionForSelectorOrThis()
|
|
||||||
loop@ while (true) {
|
|
||||||
val parent = expression.parent
|
|
||||||
when (parent) {
|
|
||||||
is KtParenthesizedExpression, is KtAnnotatedExpression, is KtLabeledExpression -> expression = parent as KtExpression
|
|
||||||
else -> break@loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val assignment = expression.getAssignmentByLHS()
|
|
||||||
if (assignment != null) {
|
|
||||||
return when (assignment.operationToken) {
|
|
||||||
KtTokens.EQ -> ReferenceAccess.WRITE
|
|
||||||
else -> ReferenceAccess.READ_WRITE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return if ((expression.parent as? KtUnaryExpression)?.operationToken
|
|
||||||
in constant { setOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) })
|
|
||||||
ReferenceAccess.READ_WRITE
|
|
||||||
else
|
|
||||||
ReferenceAccess.READ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinClassViaConstructorUSimpleReferenceExpression(
|
|
||||||
override val psi: KtCallElement,
|
|
||||||
override val identifier: String,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType {
|
|
||||||
override val resolvedName: String?
|
|
||||||
get() = (psi.getResolvedCall(psi.analyze())?.resultingDescriptor as? ConstructorDescriptor)
|
|
||||||
?.containingDeclaration?.name?.asString()
|
|
||||||
|
|
||||||
override fun resolve(): PsiElement? {
|
|
||||||
val resolvedCall = psi.getResolvedCall(psi.analyze())
|
|
||||||
val resultingDescriptor = resolvedCall?.resultingDescriptor as? ConstructorDescriptor ?: return null
|
|
||||||
val clazz = resultingDescriptor.containingDeclaration
|
|
||||||
return clazz.toSource()?.getMaybeLightElement(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinStringUSimpleReferenceExpression(
|
|
||||||
override val identifier: String,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression {
|
|
||||||
override val psi: PsiElement?
|
|
||||||
get() = null
|
|
||||||
override fun resolve() = null
|
|
||||||
override val resolvedName: String?
|
|
||||||
get() = identifier
|
|
||||||
}
|
|
||||||
-36
@@ -1,36 +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.KtSuperExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UIdentifier
|
|
||||||
import org.jetbrains.uast.USuperExpression
|
|
||||||
|
|
||||||
class KotlinUSuperExpression(
|
|
||||||
override val psi: KtSuperExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), USuperExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
|
|
||||||
override val label: String?
|
|
||||||
get() = psi.getLabelName()
|
|
||||||
|
|
||||||
override val labelIdentifier: UIdentifier?
|
|
||||||
get() = psi.getTargetLabel()?.let { UIdentifier(it, this) }
|
|
||||||
|
|
||||||
override fun resolve() = psi.analyze()[BindingContext.LABEL_TARGET, psi.getTargetLabel()]
|
|
||||||
}
|
|
||||||
-93
@@ -1,93 +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 com.intellij.psi.PsiElement
|
|
||||||
import org.jetbrains.kotlin.psi.KtBlockExpression
|
|
||||||
import org.jetbrains.kotlin.psi.KtWhenEntry
|
|
||||||
import org.jetbrains.kotlin.psi.KtWhenExpression
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
|
|
||||||
|
|
||||||
class KotlinUSwitchExpression(
|
|
||||||
override val psi: KtWhenExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), USwitchExpression, KotlinUElementWithType {
|
|
||||||
override val expression by lz { KotlinConverter.convertOrNull(psi.subjectExpression, this) }
|
|
||||||
|
|
||||||
override val body: UExpressionList by lz {
|
|
||||||
object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN, this@KotlinUSwitchExpression) {
|
|
||||||
override fun asRenderString() = expressions.joinToString("\n") { it.asRenderString().withMargin }
|
|
||||||
}.apply {
|
|
||||||
expressions = this@KotlinUSwitchExpression.psi.entries.map { KotlinUSwitchEntry(it, this) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun asRenderString() = buildString {
|
|
||||||
val expr = expression?.let { "(" + it.asRenderString() + ") " } ?: ""
|
|
||||||
appendln("switch $expr {")
|
|
||||||
appendln(body.asRenderString())
|
|
||||||
appendln("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override val switchIdentifier: UIdentifier
|
|
||||||
get() = UIdentifier(null, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinUSwitchEntry(
|
|
||||||
override val psi: KtWhenEntry,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), USwitchClauseExpressionWithBody {
|
|
||||||
override val caseValues by lz {
|
|
||||||
psi.conditions.map { KotlinConverter.convertWhenCondition(it, this) ?: UastEmptyExpression }
|
|
||||||
}
|
|
||||||
|
|
||||||
override val body: UExpressionList by lz {
|
|
||||||
object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN_ENTRY, this@KotlinUSwitchEntry) {
|
|
||||||
override fun asRenderString() = buildString {
|
|
||||||
appendln("{")
|
|
||||||
expressions.forEach { appendln(it.asRenderString().withMargin) }
|
|
||||||
appendln("}")
|
|
||||||
}
|
|
||||||
}.apply {
|
|
||||||
val exprPsi = this@KotlinUSwitchEntry.psi.expression
|
|
||||||
val userExpressions = when (exprPsi) {
|
|
||||||
is KtBlockExpression -> exprPsi.statements.map { KotlinConverter.convertOrEmpty(it, this) }
|
|
||||||
else -> listOf(KotlinConverter.convertOrEmpty(exprPsi, this))
|
|
||||||
}
|
|
||||||
expressions = userExpressions + object : UBreakExpression, JvmDeclarationUElementPlaceholder {
|
|
||||||
override val javaPsi: PsiElement? = null
|
|
||||||
override val sourcePsi: PsiElement? = null
|
|
||||||
override val psi: PsiElement?
|
|
||||||
get() = null
|
|
||||||
override val label: String?
|
|
||||||
get() = null
|
|
||||||
override val uastParent: UElement?
|
|
||||||
get() = this@KotlinUSwitchEntry
|
|
||||||
override val annotations: List<UAnnotation>
|
|
||||||
get() = emptyList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun convertParent(): UElement? {
|
|
||||||
val result = KotlinConverter.unwrapElements(psi.parent)?.let { parentUnwrapped ->
|
|
||||||
KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null)
|
|
||||||
}
|
|
||||||
return (result as? KotlinUSwitchExpression)?.body ?: result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-36
@@ -1,36 +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.KtThisExpression
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UIdentifier
|
|
||||||
import org.jetbrains.uast.UThisExpression
|
|
||||||
|
|
||||||
class KotlinUThisExpression(
|
|
||||||
override val psi: KtThisExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UThisExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
|
|
||||||
override val label: String?
|
|
||||||
get() = psi.getLabelName()
|
|
||||||
|
|
||||||
override val labelIdentifier: UIdentifier?
|
|
||||||
get() = psi.getTargetLabel()?.let { UIdentifier(it, this) }
|
|
||||||
|
|
||||||
override fun resolve() = psi.analyze()[BindingContext.LABEL_TARGET, psi.getTargetLabel()]
|
|
||||||
}
|
|
||||||
-44
@@ -1,44 +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.KtTryExpression
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UIdentifier
|
|
||||||
import org.jetbrains.uast.UTryExpression
|
|
||||||
import org.jetbrains.uast.UVariable
|
|
||||||
|
|
||||||
class KotlinUTryExpression(
|
|
||||||
override val psi: KtTryExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UTryExpression, KotlinUElementWithType {
|
|
||||||
override val tryClause by lz { KotlinConverter.convertOrEmpty(psi.tryBlock, this) }
|
|
||||||
override val catchClauses by lz { psi.catchClauses.map { KotlinUCatchClause(it, this) } }
|
|
||||||
override val finallyClause by lz { psi.finallyBlock?.finalExpression?.let { KotlinConverter.convertExpression(it, this) } }
|
|
||||||
|
|
||||||
override val resourceVariables: List<UVariable>
|
|
||||||
get() = emptyList()
|
|
||||||
|
|
||||||
override val hasResources: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override val tryIdentifier: UIdentifier
|
|
||||||
get() = UIdentifier(null, this)
|
|
||||||
|
|
||||||
override val finallyIdentifier: UIdentifier?
|
|
||||||
get() = null
|
|
||||||
}
|
|
||||||
-33
@@ -1,33 +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.KtWhileExpression
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UIdentifier
|
|
||||||
import org.jetbrains.uast.UWhileExpression
|
|
||||||
|
|
||||||
class KotlinUWhileExpression(
|
|
||||||
override val psi: KtWhileExpression,
|
|
||||||
givenParent: UElement?
|
|
||||||
) : KotlinAbstractUExpression(givenParent), UWhileExpression {
|
|
||||||
override val condition by lz { KotlinConverter.convertOrEmpty(psi.condition, this) }
|
|
||||||
override val body by lz { KotlinConverter.convertOrEmpty(psi.body, this) }
|
|
||||||
|
|
||||||
override val whileIdentifier: UIdentifier
|
|
||||||
get() = UIdentifier(null, this)
|
|
||||||
}
|
|
||||||
-218
@@ -1,218 +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 com.intellij.openapi.components.ServiceManager
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
|
||||||
import com.intellij.openapi.util.Key
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import com.intellij.psi.PsiPrimitiveType
|
|
||||||
import com.intellij.psi.PsiType
|
|
||||||
import com.intellij.psi.impl.cache.TypeInfo
|
|
||||||
import com.intellij.psi.impl.compiled.ClsTypeElementImpl
|
|
||||||
import com.intellij.psi.impl.compiled.SignatureParsing
|
|
||||||
import com.intellij.psi.impl.compiled.StubBuildingVisitor
|
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
|
||||||
import com.intellij.psi.util.PsiTypesUtil
|
|
||||||
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
|
|
||||||
import org.jetbrains.kotlin.asJava.toLightClass
|
|
||||||
import org.jetbrains.kotlin.asJava.toLightElements
|
|
||||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
|
|
||||||
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
|
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
|
||||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
|
||||||
import org.jetbrains.kotlin.types.TypeApproximator
|
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
|
||||||
import org.jetbrains.kotlin.types.isError
|
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isInterface
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
import java.text.StringCharacterIterator
|
|
||||||
|
|
||||||
internal val KOTLIN_CACHED_UELEMENT_KEY = Key.create<WeakReference<UElement>>("cached-kotlin-uelement")
|
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
internal inline fun String?.orAnonymous(kind: String = ""): String = this ?: "<anonymous" + (if (kind.isNotBlank()) " $kind" else "") + ">"
|
|
||||||
|
|
||||||
internal fun DeclarationDescriptor.toSource(): PsiElement? {
|
|
||||||
return try {
|
|
||||||
DescriptorToSourceUtils.getEffectiveReferencedDescriptors(this)
|
|
||||||
.asSequence()
|
|
||||||
.mapNotNull { DescriptorToSourceUtils.getSourceFromDescriptor(it) }
|
|
||||||
.firstOrNull()
|
|
||||||
}
|
|
||||||
catch (e: Exception) {
|
|
||||||
Logger.getInstance("DeclarationDescriptor.toSource").error(e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun <T> lz(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE, initializer)
|
|
||||||
|
|
||||||
internal fun KotlinType.toPsiType(source: UElement, element: KtElement, boxed: Boolean): PsiType {
|
|
||||||
if (this.isError) return UastErrorType
|
|
||||||
|
|
||||||
(constructor.declarationDescriptor as? TypeAliasDescriptor)?.let { typeAlias ->
|
|
||||||
return typeAlias.expandedType.toPsiType(source, element, boxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arguments.isEmpty()) {
|
|
||||||
val typeFqName = this.constructor.declarationDescriptor?.fqNameSafe?.asString()
|
|
||||||
fun PsiPrimitiveType.orBoxed() = if (boxed) getBoxedType(element) else this
|
|
||||||
val psiType = when (typeFqName) {
|
|
||||||
"kotlin.Int" -> PsiType.INT.orBoxed()
|
|
||||||
"kotlin.Long" -> PsiType.LONG.orBoxed()
|
|
||||||
"kotlin.Short" -> PsiType.SHORT.orBoxed()
|
|
||||||
"kotlin.Boolean" -> PsiType.BOOLEAN.orBoxed()
|
|
||||||
"kotlin.Byte" -> PsiType.BYTE.orBoxed()
|
|
||||||
"kotlin.Char" -> PsiType.CHAR.orBoxed()
|
|
||||||
"kotlin.Double" -> PsiType.DOUBLE.orBoxed()
|
|
||||||
"kotlin.Float" -> PsiType.FLOAT.orBoxed()
|
|
||||||
"kotlin.String" -> PsiType.getJavaLangString(element.manager, GlobalSearchScope.projectScope(element.project))
|
|
||||||
else -> {
|
|
||||||
val typeConstructor = this.constructor
|
|
||||||
if (typeConstructor is IntegerValueTypeConstructor) {
|
|
||||||
TypeUtils.getDefaultPrimitiveNumberType(typeConstructor).toPsiType(source, element, boxed)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (psiType != null) return psiType
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.containsLocalTypes()) return UastErrorType
|
|
||||||
|
|
||||||
val project = element.project
|
|
||||||
val typeMapper = ServiceManager.getService(project, KotlinUastBindingContextProviderService::class.java)
|
|
||||||
.getTypeMapper(element) ?: return UastErrorType
|
|
||||||
|
|
||||||
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
|
|
||||||
val typeMappingMode = if (boxed) TypeMappingMode.GENERIC_ARGUMENT else TypeMappingMode.DEFAULT
|
|
||||||
val approximatedType = TypeApproximator().approximateDeclarationType(this, true, element.languageVersionSettings)
|
|
||||||
typeMapper.mapType(approximatedType, signatureWriter, typeMappingMode)
|
|
||||||
|
|
||||||
val signature = StringCharacterIterator(signatureWriter.toString())
|
|
||||||
|
|
||||||
val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER)
|
|
||||||
val typeInfo = TypeInfo.fromString(javaType, false)
|
|
||||||
val typeText = TypeInfo.createTypeText(typeInfo) ?: return UastErrorType
|
|
||||||
|
|
||||||
return ClsTypeElementImpl(source.getParentOfType<UDeclaration>(false)?.psi ?: element, typeText, '\u0000').type
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun KotlinType.containsLocalTypes(): Boolean {
|
|
||||||
val typeDeclarationDescriptor = this.constructor.declarationDescriptor
|
|
||||||
if (typeDeclarationDescriptor is ClassDescriptor && DescriptorUtils.isLocal(typeDeclarationDescriptor)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return arguments.any { !it.isStarProjection && it.type.containsLocalTypes() }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun KtTypeReference?.toPsiType(source: UElement, boxed: Boolean = false): PsiType {
|
|
||||||
if (this == null) return UastErrorType
|
|
||||||
return (analyze()[BindingContext.TYPE, this] ?: return UastErrorType).toPsiType(source, this, boxed)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun KtClassOrObject.toPsiType(): PsiType {
|
|
||||||
val lightClass = toLightClass() ?: return UastErrorType
|
|
||||||
return PsiTypesUtil.getClassType(lightClass)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun PsiElement.getMaybeLightElement(context: UElement): PsiElement? {
|
|
||||||
return when (this) {
|
|
||||||
is KtVariableDeclaration -> {
|
|
||||||
val lightElement = toLightElements().firstOrNull()
|
|
||||||
if (lightElement != null) return lightElement
|
|
||||||
|
|
||||||
val languagePlugin = context.getLanguagePlugin()
|
|
||||||
val uElement = languagePlugin.convertElementWithParent(this, null)
|
|
||||||
when (uElement) {
|
|
||||||
is UDeclaration -> uElement.psi
|
|
||||||
is UDeclarationsExpression -> uElement.declarations.firstOrNull()?.psi
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is KtDeclaration -> toLightElements().firstOrNull()
|
|
||||||
is KtElement -> null
|
|
||||||
else -> this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun KtElement.resolveCallToDeclaration(
|
|
||||||
context: KotlinAbstractUElement,
|
|
||||||
resultingDescriptor: DeclarationDescriptor? = null
|
|
||||||
): PsiElement? {
|
|
||||||
val descriptor = resultingDescriptor ?: run {
|
|
||||||
val resolvedCall = getResolvedCall(analyze()) ?: return null
|
|
||||||
resolvedCall.resultingDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
return descriptor.toSource()?.getMaybeLightElement(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
|
|
||||||
val innerExpression = KtPsiUtil.safeDeparenthesize(this)
|
|
||||||
if (innerExpression is KtBlockExpression) {
|
|
||||||
val statement = innerExpression.statements.singleOrNull() ?: return this
|
|
||||||
return KtPsiUtil.safeDeparenthesize(statement)
|
|
||||||
}
|
|
||||||
return innerExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun KtElement.analyze(): BindingContext {
|
|
||||||
if(containingFile !is KtFile) return BindingContext.EMPTY // EA-114080, EA-113475
|
|
||||||
return ServiceManager.getService(project, KotlinUastBindingContextProviderService::class.java)
|
|
||||||
?.getBindingContext(this) ?: BindingContext.EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
internal inline fun <reified T : UDeclaration, reified P : PsiElement> unwrap(element: P): P {
|
|
||||||
val unwrapped = if (element is T) element.psi else element
|
|
||||||
assert(unwrapped !is UElement)
|
|
||||||
return unwrapped as P
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun KtExpression.getExpectedType(): KotlinType? = analyze()[BindingContext.EXPECTED_EXPRESSION_TYPE, this]
|
|
||||||
|
|
||||||
internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this]
|
|
||||||
|
|
||||||
internal fun KotlinType.getFunctionalInterfaceType(source: UElement, element: KtElement): PsiType? =
|
|
||||||
takeIf { it.isInterface() && !it.isBuiltinFunctionalTypeOrSubtype }?.toPsiType(source, element, false)
|
|
||||||
|
|
||||||
internal fun KotlinULambdaExpression.getFunctionalInterfaceType(): PsiType? {
|
|
||||||
val parent = psi.parent
|
|
||||||
return when(parent) {
|
|
||||||
is KtBinaryExpressionWithTypeRHS -> parent.right?.getType()?.getFunctionalInterfaceType(this, psi)
|
|
||||||
else -> psi.getExpectedType()?.getFunctionalInterfaceType(this, psi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun unwrapFakeFileForLightClass(file: PsiFile): PsiFile = (file as? FakeFileForLightClass)?.ktFile ?: file
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
fun foo(): Boolean {
|
|
||||||
class Local
|
|
||||||
fun bar() = Local()
|
|
||||||
|
|
||||||
val baz = fun() {
|
|
||||||
Local()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Int.someLocalFun(text: String) = 42
|
|
||||||
|
|
||||||
return bar() == Local()
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
UFile (package = )
|
|
||||||
UClass (name = LocalDeclarationsKt)
|
|
||||||
UAnnotationMethod (name = foo)
|
|
||||||
UBlockExpression
|
|
||||||
UDeclarationsExpression
|
|
||||||
UClass (name = Local)
|
|
||||||
UAnnotationMethod (name = LocalDeclarationsKt$foo$Local)
|
|
||||||
UDeclarationsExpression
|
|
||||||
UVariable (name = bar)
|
|
||||||
ULambdaExpression
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))
|
|
||||||
UIdentifier (Identifier (Local))
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>)
|
|
||||||
UDeclarationsExpression
|
|
||||||
ULocalVariable (name = baz)
|
|
||||||
ULambdaExpression
|
|
||||||
UBlockExpression
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))
|
|
||||||
UIdentifier (Identifier (Local))
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>)
|
|
||||||
UDeclarationsExpression
|
|
||||||
UVariable (name = someLocalFun)
|
|
||||||
ULambdaExpression
|
|
||||||
UParameter (name = text)
|
|
||||||
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
|
|
||||||
ULiteralExpression (value = 42)
|
|
||||||
UReturnExpression
|
|
||||||
UBinaryExpression (operator = ==)
|
|
||||||
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
|
|
||||||
UIdentifier (Identifier (bar))
|
|
||||||
USimpleNameReferenceExpression (identifier = bar)
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0))
|
|
||||||
UIdentifier (Identifier (Local))
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>)
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
public final class LocalDeclarationsKt {
|
|
||||||
public static final fun foo() : boolean {
|
|
||||||
public static final class Local {
|
|
||||||
public fun LocalDeclarationsKt$foo$Local() = UastEmptyExpression
|
|
||||||
}
|
|
||||||
var bar: <ErrorType> = fun () {
|
|
||||||
<init>()
|
|
||||||
}
|
|
||||||
var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {
|
|
||||||
<init>()
|
|
||||||
}
|
|
||||||
var someLocalFun: kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.String,? extends java.lang.Integer> = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {
|
|
||||||
42
|
|
||||||
}
|
|
||||||
return bar() == <init>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
UFile (package = ) [public final class LocalDeclarationsKt {...]
|
|
||||||
UClass (name = LocalDeclarationsKt) [public final class LocalDeclarationsKt {...}]
|
|
||||||
UAnnotationMethod (name = foo) [public static final fun foo() : boolean {...}]
|
|
||||||
UBlockExpression [{...}] : PsiType:Void
|
|
||||||
UDeclarationsExpression [public static final class Local {...}]
|
|
||||||
UClass (name = Local) [public static final class Local {...}]
|
|
||||||
UAnnotationMethod (name = LocalDeclarationsKt$foo$Local) [public fun LocalDeclarationsKt$foo$Local() = UastEmptyExpression]
|
|
||||||
UDeclarationsExpression [var bar: <ErrorType> = fun () {...}]
|
|
||||||
UVariable (name = bar) [var bar: <ErrorType> = fun () {...}]
|
|
||||||
ULambdaExpression [fun () {...}]
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : PsiType:<ErrorType>
|
|
||||||
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>) [<init>] : PsiType:<ErrorType>
|
|
||||||
UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
|
|
||||||
ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
|
|
||||||
ULambdaExpression [fun () {...}]
|
|
||||||
UBlockExpression [{...}] : PsiType:<ErrorType>
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : PsiType:<ErrorType>
|
|
||||||
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>) [<init>] : PsiType:<ErrorType>
|
|
||||||
UDeclarationsExpression [var someLocalFun: kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.String,? extends java.lang.Integer> = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}]
|
|
||||||
UVariable (name = someLocalFun) [var someLocalFun: kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.String,? extends java.lang.Integer> = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}]
|
|
||||||
ULambdaExpression [fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}]
|
|
||||||
UParameter (name = text) [@org.jetbrains.annotations.NotNull var text: java.lang.String]
|
|
||||||
UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull]
|
|
||||||
ULiteralExpression (value = 42) [42] : PsiType:int
|
|
||||||
UReturnExpression [return bar() == <init>()] : PsiType:Void
|
|
||||||
UBinaryExpression (operator = ==) [bar() == <init>()] : PsiType:boolean
|
|
||||||
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) [bar()] : PsiType:<ErrorType>
|
|
||||||
UIdentifier (Identifier (bar)) [UIdentifier (Identifier (bar))]
|
|
||||||
USimpleNameReferenceExpression (identifier = bar) [bar] : PsiType:<ErrorType>
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] : PsiType:<ErrorType>
|
|
||||||
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>) [<init>] : PsiType:<ErrorType>
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
UFile (package = ) [public final class LocalDeclarationsKt {...]
|
|
||||||
UClass (name = LocalDeclarationsKt) [public final class LocalDeclarationsKt {...}]
|
|
||||||
UAnnotationMethod (name = foo) [public static final fun foo() : boolean {...}]
|
|
||||||
UBlockExpression [{...}] = Nothing
|
|
||||||
UDeclarationsExpression [public static final class Local {...}] = Undetermined
|
|
||||||
UClass (name = Local) [public static final class Local {...}]
|
|
||||||
UAnnotationMethod (name = LocalDeclarationsKt$foo$Local) [public fun LocalDeclarationsKt$foo$Local() = UastEmptyExpression]
|
|
||||||
UDeclarationsExpression [var bar: <ErrorType> = fun () {...}] = Undetermined
|
|
||||||
UVariable (name = bar) [var bar: <ErrorType> = fun () {...}]
|
|
||||||
ULambdaExpression [fun () {...}] = Undetermined
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] = external <init>()()
|
|
||||||
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>) [<init>] = external <init>()()
|
|
||||||
UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}] = Undetermined
|
|
||||||
ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0<? extends kotlin.Unit> = fun () {...}]
|
|
||||||
ULambdaExpression [fun () {...}] = Undetermined
|
|
||||||
UBlockExpression [{...}] = external <init>()()
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] = external <init>()()
|
|
||||||
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>) [<init>] = external <init>()()
|
|
||||||
UDeclarationsExpression [var someLocalFun: kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.String,? extends java.lang.Integer> = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] = Undetermined
|
|
||||||
UVariable (name = someLocalFun) [var someLocalFun: kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.String,? extends java.lang.Integer> = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}]
|
|
||||||
ULambdaExpression [fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] = Undetermined
|
|
||||||
UParameter (name = text) [@org.jetbrains.annotations.NotNull var text: java.lang.String]
|
|
||||||
UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull]
|
|
||||||
ULiteralExpression (value = 42) [42] = 42
|
|
||||||
UReturnExpression [return bar() == <init>()] = Nothing
|
|
||||||
UBinaryExpression (operator = ==) [bar() == <init>()] = Undetermined
|
|
||||||
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) [bar()] = external bar()()
|
|
||||||
UIdentifier (Identifier (bar)) [UIdentifier (Identifier (bar))]
|
|
||||||
USimpleNameReferenceExpression (identifier = bar) [bar] = external bar()()
|
|
||||||
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [<init>()] = external <init>()()
|
|
||||||
UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))]
|
|
||||||
USimpleNameReferenceExpression (identifier = <init>) [<init>] = external <init>()()
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
class SimpleAnnotated {
|
|
||||||
@Suppress("abc")
|
|
||||||
fun method() {
|
|
||||||
println("Hello, world!")
|
|
||||||
}
|
|
||||||
|
|
||||||
@SinceKotlin("1.0")
|
|
||||||
val property: String = "Mary"
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
package org.jetbrains.uast.test.kotlin
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiFile
|
|
||||||
import com.intellij.psi.PsiRecursiveElementVisitor
|
|
||||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
|
||||||
import org.jetbrains.uast.UDeclaration
|
|
||||||
import org.jetbrains.uast.UElement
|
|
||||||
import org.jetbrains.uast.UFile
|
|
||||||
import org.jetbrains.uast.kotlin.JvmDeclarationUElementPlaceholder
|
|
||||||
import org.jetbrains.uast.kotlin.KOTLIN_CACHED_UELEMENT_KEY
|
|
||||||
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
|
|
||||||
import org.jetbrains.uast.test.common.RenderLogTestBase
|
|
||||||
import org.jetbrains.uast.visitor.UastVisitor
|
|
||||||
import org.junit.Assert
|
|
||||||
import java.io.File
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLogTestBase {
|
|
||||||
override fun getTestFile(testName: String, ext: String) =
|
|
||||||
File(File(TEST_KOTLIN_MODEL_DIR, testName).canonicalPath + '.' + ext)
|
|
||||||
|
|
||||||
override fun check(testName: String, file: UFile) {
|
|
||||||
check(testName, file, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun check(testName: String, file: UFile, checkParentConsistency: Boolean) {
|
|
||||||
super.check(testName, file)
|
|
||||||
|
|
||||||
if (checkParentConsistency) {
|
|
||||||
checkParentConsistency(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
file.checkContainingFileForAllElements()
|
|
||||||
file.checkJvmDeclarationsImplementations()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkParentConsistency(file: UFile) {
|
|
||||||
val parentMap = mutableMapOf<PsiElement, String>()
|
|
||||||
|
|
||||||
file.accept(object : UastVisitor {
|
|
||||||
private val parentStack = Stack<UElement>()
|
|
||||||
|
|
||||||
override fun visitElement(node: UElement): Boolean {
|
|
||||||
val parent = node.uastParent
|
|
||||||
if (parent == null) {
|
|
||||||
Assert.assertTrue("Wrong parent of $node", parentStack.empty())
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Assert.assertEquals("Wrong parent of $node", parentStack.peek(), parent)
|
|
||||||
}
|
|
||||||
node.psi?.let {
|
|
||||||
if (it !in parentMap) {
|
|
||||||
parentMap[it] = parentStack.reversed().joinToString { it.asLogString() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parentStack.push(node)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun afterVisitElement(node: UElement) {
|
|
||||||
super.afterVisitElement(node)
|
|
||||||
parentStack.pop()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
file.psi.clearUastCaches()
|
|
||||||
|
|
||||||
file.psi.accept(object : PsiRecursiveElementVisitor() {
|
|
||||||
override fun visitElement(element: PsiElement) {
|
|
||||||
val uElement = KotlinUastLanguagePlugin().convertElementWithParent(element, null)
|
|
||||||
val expectedParents = parentMap[element]
|
|
||||||
if (expectedParents != null) {
|
|
||||||
assertNotNull("Expected to be able to convert PSI element $element", uElement)
|
|
||||||
val parents = generateSequence(uElement!!.uastParent) { it.uastParent }.joinToString { it.asLogString() }
|
|
||||||
assertEquals("Inconsistent parents for ${uElement.asRenderString()}(${uElement.asLogString()})(${uElement.javaClass}) (converted from $element[${element.text}])", expectedParents, parents)
|
|
||||||
}
|
|
||||||
super.visitElement(element)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun UFile.checkContainingFileForAllElements() {
|
|
||||||
accept(object : UastVisitor {
|
|
||||||
override fun visitElement(node: UElement): Boolean {
|
|
||||||
if (node is PsiElement) {
|
|
||||||
node.containingFile.assertedCast<KtFile> { "containingFile should be KtFile for ${node.asLogString()}" }
|
|
||||||
}
|
|
||||||
|
|
||||||
val anchorPsi = (node as? UDeclaration)?.uastAnchor?.psi
|
|
||||||
if (anchorPsi != null) {
|
|
||||||
anchorPsi.containingFile.assertedCast<KtFile> { "uastAnchor.containingFile should be KtFile for ${node.asLogString()}" }
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun UFile.checkJvmDeclarationsImplementations() {
|
|
||||||
accept(object : UastVisitor {
|
|
||||||
override fun visitElement(node: UElement): Boolean {
|
|
||||||
|
|
||||||
val jvmDeclaration = node as? JvmDeclarationUElementPlaceholder
|
|
||||||
?: throw AssertionError("${node.javaClass} should implement 'JvmDeclarationUElement'")
|
|
||||||
|
|
||||||
jvmDeclaration.sourcePsi?.let {
|
|
||||||
assertTrue("sourcePsi should be physical but ${it.javaClass} found for [${it.text}] " +
|
|
||||||
"for ${jvmDeclaration.javaClass}->${jvmDeclaration.uastParent?.javaClass}",
|
|
||||||
it is KtElement || it is LeafPsiElement
|
|
||||||
)
|
|
||||||
}
|
|
||||||
jvmDeclaration.javaPsi?.let {
|
|
||||||
assertTrue("javaPsi should be light but ${it.javaClass} found for [${it.text}] " +
|
|
||||||
"for ${jvmDeclaration.javaClass}->${jvmDeclaration.uastParent?.javaClass}", it !is KtElement)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PsiFile.clearUastCaches() {
|
|
||||||
accept(object : PsiRecursiveElementVisitor() {
|
|
||||||
override fun visitElement(element: PsiElement) {
|
|
||||||
super.visitElement(element)
|
|
||||||
element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, null)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
package org.jetbrains.uast.test.kotlin
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiAnnotation
|
|
||||||
import com.intellij.psi.PsiModifier
|
|
||||||
import com.intellij.testFramework.UsefulTestCase
|
|
||||||
import org.jetbrains.kotlin.asJava.toLightAnnotation
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList
|
|
||||||
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
|
||||||
import org.jetbrains.uast.*
|
|
||||||
import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin
|
|
||||||
import org.jetbrains.uast.test.env.findElementByText
|
|
||||||
import org.jetbrains.uast.test.env.findElementByTextFromPsi
|
|
||||||
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
|
|
||||||
class KotlinUastApiTest : AbstractKotlinUastTest() {
|
|
||||||
override fun check(testName: String, file: UFile) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testAnnotationParameters() {
|
|
||||||
doTest("AnnotationParameters") { _, file ->
|
|
||||||
val annotation = file.findElementByText<UAnnotation>("@IntRange(from = 10, to = 0)")
|
|
||||||
assertEquals(annotation.findAttributeValue("from")?.evaluate(), 10)
|
|
||||||
val toAttribute = annotation.findAttributeValue("to")!!
|
|
||||||
assertEquals(toAttribute.evaluate(), 0)
|
|
||||||
KtUsefulTestCase.assertInstanceOf(annotation.psi.toUElement(), UAnnotation::class.java)
|
|
||||||
KtUsefulTestCase.assertInstanceOf(
|
|
||||||
annotation.psi.cast<KtAnnotationEntry>().toLightAnnotation().toUElement(),
|
|
||||||
UAnnotation::class.java
|
|
||||||
)
|
|
||||||
KtUsefulTestCase.assertInstanceOf(toAttribute.uastParent, UNamedExpression::class.java)
|
|
||||||
KtUsefulTestCase.assertInstanceOf(toAttribute.psi.toUElement()?.uastParent, UNamedExpression::class.java)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testConvertStringTemplate() {
|
|
||||||
doTest("StringTemplateInClass") { _, file ->
|
|
||||||
val literalExpression = file.findElementByText<ULiteralExpression>("lorem")
|
|
||||||
val psi = literalExpression.psi!!
|
|
||||||
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
|
|
||||||
val literalExpressionAgain = psi.toUElement()
|
|
||||||
Assert.assertTrue(literalExpressionAgain is ULiteralExpression)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testConvertStringTemplateWithExpectedType() {
|
|
||||||
doTest("StringTemplateWithVar") { _, file ->
|
|
||||||
val index = file.psi.text.indexOf("foo")
|
|
||||||
val stringTemplate = file.psi.findElementAt(index)!!.getParentOfType<KtStringTemplateExpression>(false)
|
|
||||||
val uLiteral = stringTemplate.toUElementOfType<ULiteralExpression>()
|
|
||||||
assertNull(uLiteral)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testNameContainingFile() {
|
|
||||||
doTest("NameContainingFile") { _, file ->
|
|
||||||
val foo = file.findElementByText<UClass>("class Foo")
|
|
||||||
assertEquals(file.psi, foo.nameIdentifier!!.containingFile)
|
|
||||||
|
|
||||||
val bar = file.findElementByText<UMethod>("fun bar() {}")
|
|
||||||
assertEquals(file.psi, bar.nameIdentifier!!.containingFile)
|
|
||||||
|
|
||||||
val xyzzy = file.findElementByText<UVariable>("val xyzzy: Int = 0")
|
|
||||||
assertEquals(file.psi, xyzzy.nameIdentifier!!.containingFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testInterfaceMethodWithBody() {
|
|
||||||
doTest("DefaultImpls") { _, file ->
|
|
||||||
val bar = file.findElementByText<UMethod>("fun bar() = \"Hello!\"")
|
|
||||||
assertFalse(bar.containingFile.text!!, bar.psi.modifierList.hasExplicitModifier(PsiModifier.DEFAULT))
|
|
||||||
assertTrue(bar.containingFile.text!!, bar.psi.modifierList.hasModifierProperty(PsiModifier.DEFAULT))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testSAM() {
|
|
||||||
doTest("SAM") { _, file ->
|
|
||||||
assertNull(file.findElementByText<ULambdaExpression>("{ /* Not SAM */ }").functionalInterfaceType)
|
|
||||||
|
|
||||||
assertEquals("java.lang.Runnable",
|
|
||||||
file.findElementByText<ULambdaExpression>("{/* Variable */}").functionalInterfaceType?.canonicalText)
|
|
||||||
|
|
||||||
assertEquals("java.lang.Runnable",
|
|
||||||
file.findElementByText<ULambdaExpression>("{/* Assignment */}").functionalInterfaceType?.canonicalText)
|
|
||||||
|
|
||||||
assertEquals("java.lang.Runnable",
|
|
||||||
file.findElementByText<ULambdaExpression>("{/* Type Cast */}").functionalInterfaceType?.canonicalText)
|
|
||||||
|
|
||||||
assertEquals("java.lang.Runnable",
|
|
||||||
file.findElementByText<ULambdaExpression>("{/* Argument */}").functionalInterfaceType?.canonicalText)
|
|
||||||
|
|
||||||
assertEquals("java.lang.Runnable",
|
|
||||||
file.findElementByText<ULambdaExpression>("{/* Return */}").functionalInterfaceType?.canonicalText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testParameterPropertyWithAnnotation() {
|
|
||||||
doTest("ParameterPropertyWithAnnotation") { _, file ->
|
|
||||||
val test1 = file.classes.find { it.name == "Test1" }!!
|
|
||||||
|
|
||||||
val constructor1 = test1.methods.find { it.name == "Test1" }!!
|
|
||||||
assertTrue(constructor1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" })
|
|
||||||
|
|
||||||
val getter1 = test1.methods.find { it.name == "getBar" }!!
|
|
||||||
assertFalse(getter1.annotations.any { it.qualifiedName == "MyAnnotation" })
|
|
||||||
|
|
||||||
val setter1 = test1.methods.find { it.name == "setBar" }!!
|
|
||||||
assertFalse(setter1.annotations.any { it.qualifiedName == "MyAnnotation" })
|
|
||||||
assertFalse(setter1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" })
|
|
||||||
|
|
||||||
|
|
||||||
val test2 = file.classes.find { it.name == "Test2" }!!
|
|
||||||
val constructor2 = test2.methods.find { it.name == "Test2" }!!
|
|
||||||
assertFalse(constructor2.uastParameters.first().annotations.any { it.qualifiedName?.startsWith("MyAnnotation") ?: false })
|
|
||||||
|
|
||||||
val getter2 = test2.methods.find { it.name == "getBar" }!!
|
|
||||||
getter2.annotations.single { it.qualifiedName == "MyAnnotation" }
|
|
||||||
|
|
||||||
val setter2 = test2.methods.find { it.name == "setBar" }!!
|
|
||||||
setter2.annotations.single { it.qualifiedName == "MyAnnotation2" }
|
|
||||||
setter2.uastParameters.first().annotations.single { it.qualifiedName == "MyAnnotation3" }
|
|
||||||
|
|
||||||
test2.fields.find { it.name == "bar" }!!.annotations.single { it.qualifiedName == "MyAnnotation5" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testConvertTypeInAnnotation() {
|
|
||||||
doTest("TypeInAnnotation") { _, file ->
|
|
||||||
val index = file.psi.text.indexOf("Test")
|
|
||||||
val element = file.psi.findElementAt(index)!!.getParentOfType<KtUserType>(false)!!
|
|
||||||
assertNotNull(element.getUastParentOfType(UAnnotation::class.java))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testElvisType() {
|
|
||||||
doTest("ElvisType") { _, file ->
|
|
||||||
val elvisExpression = file.findElementByText<UExpression>("text ?: return")
|
|
||||||
assertEquals("String", elvisExpression.getExpressionType()!!.presentableText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testFindAttributeDefaultValue() {
|
|
||||||
doTest("AnnotationParameters") { _, file ->
|
|
||||||
val witDefaultValue = file.findElementByText<UAnnotation>("@WithDefaultValue")
|
|
||||||
assertEquals(42, witDefaultValue.findAttributeValue("value")!!.evaluate())
|
|
||||||
assertEquals(42, witDefaultValue.findAttributeValue(null)!!.evaluate())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test fun testIfCondition() {
|
|
||||||
doTest("IfStatement") { _, file ->
|
|
||||||
val psiFile = file.psi
|
|
||||||
val element = psiFile.findElementAt(psiFile.text.indexOf("\"abc\""))!!
|
|
||||||
val binaryExpression = element.getParentOfType<KtBinaryExpression>(false)!!
|
|
||||||
val uBinaryExpression = KotlinUastLanguagePlugin().convertElementWithParent(binaryExpression, null)!!
|
|
||||||
UsefulTestCase.assertInstanceOf(uBinaryExpression.uastParent, UIfExpression::class.java)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testWhenStringLiteral() {
|
|
||||||
doTest("WhenStringLiteral") { _, file ->
|
|
||||||
|
|
||||||
file.findElementByTextFromPsi<ULiteralExpression>("abc").let { literalExpression ->
|
|
||||||
val psi = literalExpression.psi!!
|
|
||||||
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
|
|
||||||
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, USwitchClauseExpressionWithBody::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
file.findElementByTextFromPsi<ULiteralExpression>("def").let { literalExpression ->
|
|
||||||
val psi = literalExpression.psi!!
|
|
||||||
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
|
|
||||||
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, USwitchClauseExpressionWithBody::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
file.findElementByTextFromPsi<ULiteralExpression>("def1").let { literalExpression ->
|
|
||||||
val psi = literalExpression.psi!!
|
|
||||||
Assert.assertTrue(psi is KtLiteralStringTemplateEntry)
|
|
||||||
UsefulTestCase.assertInstanceOf(literalExpression.uastParent, UBlockExpression::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testWhenAndDestructing() {
|
|
||||||
doTest("WhenAndDestructing") { _, file ->
|
|
||||||
|
|
||||||
file.findElementByTextFromPsi<UExpression>("val (bindingContext, statementFilter) = arr").let { e ->
|
|
||||||
val uBlockExpression = e.getParentOfType<UBlockExpression>()
|
|
||||||
Assert.assertNotNull(uBlockExpression)
|
|
||||||
val uMethod = uBlockExpression!!.getParentOfType<UMethod>()
|
|
||||||
Assert.assertNotNull(uMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testBrokenMethodTypeResolve() {
|
|
||||||
doTest("BrokenMethod") { _, file ->
|
|
||||||
|
|
||||||
file.accept(object : AbstractUastVisitor() {
|
|
||||||
override fun visitCallExpression(node: UCallExpression): Boolean {
|
|
||||||
node.returnType
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testSimpleAnnotated() {
|
|
||||||
doTest("SimpleAnnotated") { _, file ->
|
|
||||||
file.findElementByTextFromPsi<UField>("@SinceKotlin(\"1.0\")\n val property: String = \"Mary\"").let { field ->
|
|
||||||
val annotation = field.annotations.assertedFind("kotlin.SinceKotlin") { it.qualifiedName }
|
|
||||||
Assert.assertEquals(annotation.findDeclaredAttributeValue("version")?.evaluateString(), "1.0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun UFile.checkUastSuperTypes(refText: String, superTypes: List<String>) {
|
|
||||||
findElementByTextFromPsi<UClass>(refText, false).let {
|
|
||||||
assertEquals("base classes", superTypes, it.uastSuperTypes.map { it.getQualifiedName() })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testSuperTypes() {
|
|
||||||
doTest("SuperCalls") { _, file ->
|
|
||||||
file.checkUastSuperTypes("B", listOf("A"))
|
|
||||||
file.checkUastSuperTypes("O", listOf("A"))
|
|
||||||
file.checkUastSuperTypes("innerObject ", listOf("A"))
|
|
||||||
file.checkUastSuperTypes("InnerClass", listOf("A"))
|
|
||||||
file.checkUastSuperTypes("object : A(\"textForAnon\")", listOf("A"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testAnonymousSuperTypes() {
|
|
||||||
doTest("Anonymous") { _, file ->
|
|
||||||
file.checkUastSuperTypes("object : Runnable { override fun run() {} }", listOf("java.lang.Runnable"))
|
|
||||||
file.checkUastSuperTypes(
|
|
||||||
"object : Runnable, Closeable { override fun close() {} override fun run() {} }",
|
|
||||||
listOf("java.lang.Runnable", "java.io.Closeable")
|
|
||||||
)
|
|
||||||
file.checkUastSuperTypes(
|
|
||||||
"object : InputStream(), Runnable { override fun read(): Int = 0; override fun run() {} }",
|
|
||||||
listOf("java.io.InputStream", "java.lang.Runnable")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testLiteralArraysTypes() {
|
|
||||||
doTest("AnnotationParameters") { _, file ->
|
|
||||||
file.findElementByTextFromPsi<UCallExpression>("intArrayOf(1, 2, 3)").let { field ->
|
|
||||||
Assert.assertEquals("PsiType:int[]", field.returnType.toString())
|
|
||||||
}
|
|
||||||
file.findElementByTextFromPsi<UCallExpression>("[1, 2, 3]").let { field ->
|
|
||||||
Assert.assertEquals("PsiType:int[]", field.returnType.toString())
|
|
||||||
Assert.assertEquals("PsiType:int", field.typeArguments.single().toString())
|
|
||||||
}
|
|
||||||
file.findElementByTextFromPsi<UCallExpression>("[\"a\", \"b\", \"c\"]").let { field ->
|
|
||||||
Assert.assertEquals("PsiType:String[]", field.returnType.toString())
|
|
||||||
Assert.assertEquals("PsiType:String", field.typeArguments.single().toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testTypeAliases() {
|
|
||||||
doTest("TypeAliases") { _, file ->
|
|
||||||
val g = (file.psi as KtFile).declarations.single { it.name == "G" } as KtTypeAlias
|
|
||||||
val originalType = g.getTypeReference()!!.typeElement as KtFunctionType
|
|
||||||
val originalTypeParameters = originalType.parameterList.toUElement() as UDeclarationsExpression
|
|
||||||
Assert.assertTrue((originalTypeParameters.declarations.single() as UParameter).type.isValid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testNestedAnnotation() = doTest("AnnotationComplex") { _, file ->
|
|
||||||
file.findElementByTextFromPsi<UElement>("@AnnotationArray(value = Annotation())")
|
|
||||||
.findElementByTextFromPsi<UElement>("Annotation()")
|
|
||||||
.sourcePsiElement
|
|
||||||
.let { referenceExpression ->
|
|
||||||
val convertedUAnnotation = referenceExpression
|
|
||||||
.cast<KtReferenceExpression>()
|
|
||||||
.toUElementOfType<UAnnotation>()
|
|
||||||
?: throw AssertionError("haven't got annotation from $referenceExpression(${referenceExpression?.javaClass})")
|
|
||||||
|
|
||||||
assertEquals("Annotation", convertedUAnnotation.qualifiedName)
|
|
||||||
val lightAnnotation = convertedUAnnotation.getAsJavaPsiElement(PsiAnnotation::class.java)
|
|
||||||
?: throw AssertionError("can't get lightAnnotation from $convertedUAnnotation")
|
|
||||||
assertEquals("Annotation", lightAnnotation.qualifiedName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T, R> Iterable<T>.assertedFind(value: R, transform: (T) -> R): T = find { transform(it) == value } ?: throw AssertionError("'$value' not found, only ${this.joinToString { transform(it).toString() }}")
|
|
||||||
Reference in New Issue
Block a user