181: Uast: KotlinUIdentifier almost everywhere (KT-21688)
This commit is contained in:
committed by
Nikolay Krasko
parent
9efa79f352
commit
984c2329b4
@@ -0,0 +1,556 @@
|
|||||||
|
/*
|
||||||
|
* 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.KotlinUIdentifier
|
||||||
|
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(::KotlinUIdentifier))
|
||||||
|
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) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
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.declarations.KotlinUIdentifier
|
||||||
|
import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds
|
||||||
|
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
|
||||||
|
|
||||||
|
|
||||||
|
private fun createVariableReferenceExpression(variable: UVariable, containingElement: UElement?) =
|
||||||
|
object : USimpleNameReferenceExpression, JvmDeclarationUElement {
|
||||||
|
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, JvmDeclarationUElement {
|
||||||
|
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, JvmDeclarationUElement {
|
||||||
|
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? = KotlinUIdentifier(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, JvmDeclarationUElement {
|
||||||
|
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 = KotlinUIdentifier(null, this)
|
||||||
|
override val elseIdentifier: UIdentifier? = KotlinUIdentifier(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+107
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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.*
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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() = KotlinUIdentifier(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
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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() = KotlinUIdentifier(null, this)
|
||||||
|
|
||||||
|
override val whileIdentifier: UIdentifier
|
||||||
|
get() = KotlinUIdentifier(null, this)
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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.declarations.KotlinUIdentifier
|
||||||
|
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() = KotlinUIdentifier(null, this)
|
||||||
|
}
|
||||||
+142
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* 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.kotlin.declarations.KotlinUIdentifier
|
||||||
|
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
|
||||||
|
KotlinUIdentifier(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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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 { KotlinUIdentifier(it, this) }
|
||||||
|
|
||||||
|
override val expression by lz { KotlinConverter.convertOrEmpty(psi.baseExpression, this) }
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.*
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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() = KotlinUIdentifier(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
|
||||||
|
}
|
||||||
|
}
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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() = KotlinUIdentifier(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
|
||||||
|
}
|
||||||
|
}
|
||||||
+221
@@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* 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.kotlin.declarations.KotlinUIdentifier
|
||||||
|
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, JvmDeclarationUElement {
|
||||||
|
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() = KotlinUIdentifier(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
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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 { KotlinUIdentifier(it, this) }
|
||||||
|
|
||||||
|
override fun resolve() = psi.analyze()[BindingContext.LABEL_TARGET, psi.getTargetLabel()]
|
||||||
|
}
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* 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.declarations.KotlinUIdentifier
|
||||||
|
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() = KotlinUIdentifier(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, JvmDeclarationUElement {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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 { KotlinUIdentifier(it, this) }
|
||||||
|
|
||||||
|
override fun resolve() = psi.analyze()[BindingContext.LABEL_TARGET, psi.getTargetLabel()]
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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() = KotlinUIdentifier(null, this)
|
||||||
|
|
||||||
|
override val finallyIdentifier: UIdentifier?
|
||||||
|
get() = null
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
|
||||||
|
|
||||||
|
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() = KotlinUIdentifier(null, this)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user