From 984c2329b491cd1c256f160af26fa4dcfee2cd70 Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Thu, 11 Jan 2018 19:50:59 +0300 Subject: [PATCH] 181: Uast: `KotlinUIdentifier` almost everywhere (KT-21688) --- .../kotlin/KotlinUastLanguagePlugin.kt.181 | 556 ++++++++++++++++++ .../kotlin/expressions/ElvisExpression.kt.181 | 121 ++++ .../KotlinUBinaryExpression.kt.181 | 107 ++++ .../KotlinUDoWhileExpression.kt.181 | 37 ++ .../KotlinUForEachExpression.kt.181 | 43 ++ .../KotlinUFunctionCallExpression.kt.181 | 142 +++++ .../KotlinULabeledExpression.kt.181 | 36 ++ .../KotlinUPostfixExpression.kt.181 | 47 ++ .../KotlinUPrefixExpression.kt.181 | 47 ++ .../KotlinUSimpleReferenceExpression.kt.181 | 221 +++++++ .../expressions/KotlinUSuperExpression.kt.181 | 37 ++ .../KotlinUSwitchExpression.kt.181 | 94 +++ .../expressions/KotlinUThisExpression.kt.181 | 37 ++ .../expressions/KotlinUTryExpression.kt.181 | 45 ++ .../expressions/KotlinUWhileExpression.kt.181 | 34 ++ 15 files changed, 1604 insertions(+) create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.181 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.181 diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.181 new file mode 100644 index 00000000000..3c612df2c93 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.181 @@ -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?): UElement? { + if (!element.isJvmElement) return null + return convertDeclarationOrElement(element, parent, requiredType) + } + + override fun convertElementWithParent(element: PsiElement, requiredType: Class?): 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?): 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?): UElement? { + fun

build(ctor: (P, UElement?) -> UElement): () -> UElement? = { ctor(element as P, givenParent) } + + fun

buildKt(ktElement: K, ctor: (P, K, UElement?) -> UElement): () -> UElement? = + { ctor(element as P, ktElement, givenParent) } + + fun

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(build(KotlinUMethod.Companion::create)) // .Companion is needed because of KT-13934 + is KtLightClass -> when (original.kotlinOrigin) { + is KtEnumEntry -> el { + convertEnumEntry(original.kotlinOrigin as KtEnumEntry, givenParent) + } + else -> el { KotlinUClass.create(original, givenParent) } + } + is KtLightFieldImpl.KtLightEnumConstant -> el(buildKtOpt(original.kotlinOrigin, ::KotlinUEnumConstant)) + is KtLightField -> el(buildKtOpt(original.kotlinOrigin, ::KotlinUField)) + is KtLightParameter -> el(buildKtOpt(original.kotlinOrigin, ::KotlinUParameter)) + is UastKotlinPsiParameter -> el(buildKt(original.ktParameter, ::KotlinUParameter)) + is UastKotlinPsiVariable -> el(buildKt(original.ktElement, ::KotlinUVariable)) + + is KtEnumEntry -> el { + convertEnumEntry(original, givenParent) + } + is KtClassOrObject -> el { + original.toLightClass()?.let { lightClass -> + KotlinUClass.create(lightClass, givenParent) + } + } + is KtFunction -> + if (original.isLocal) { + el { + 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 { + val lightMethod = LightClassUtil.getLightClassMethod(original) ?: return null + convertDeclaration(lightMethod, givenParent, requiredType) + } + } + + is KtPropertyAccessor -> el { + 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 { + 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 { KotlinUFile(original, this@KotlinUastLanguagePlugin) } + is FakeFileForLightClass -> el { KotlinUFile(original.navigationElement, this@KotlinUastLanguagePlugin) } + is KtAnnotationEntry -> el(build(::KotlinUAnnotation)) + is KtCallExpression -> + if (requiredType != null && UAnnotation::class.java.isAssignableFrom(requiredType)) { + el { + 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 Class?.el(f: () -> UElement?): UElement? { + return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null +} + +internal inline fun Class?.expr(f: () -> UExpression?): UExpression? { + return if (this == null || isAssignableFrom(ActualT::class.java)) f() else null +} + +private fun convertNonLocalProperty(property: KtProperty, + givenParent: UElement?, + requiredType: Class?): UElement? { + val methods = LightClassUtil.getLightClassPropertyMethods(property) + return methods.backingField?.let { backingField -> + with(requiredType) { + el { 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?): UElement? { + fun

build(ctor: (P, UElement?) -> UElement): () -> UElement? { + return { ctor(element as P, givenParent) } + } + + return with (requiredType) { when (element) { + is KtParameterList -> el { + val declarationsExpression = KotlinUDeclarationsExpression(givenParent) + declarationsExpression.apply { + declarations = element.parameters.mapIndexed { i, p -> + KotlinUParameter(UastKotlinPsiParameter.create(p, element, declarationsExpression, i), p, this) + } + } + } + is KtClassBody -> el(build(KotlinUExpressionList.Companion::createClassBody)) + is KtCatchClause -> el(build(::KotlinUCatchClause)) + is KtVariableDeclaration -> + if (element is KtProperty && !element.isLocal) { + el { + LightClassUtil.getLightClassBackingField(element)?.let { + KotlinUField(it, element, givenParent) + } + } + } + else { + el { + 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 { UastEmptyExpression } + } + } + is KtLiteralStringTemplateEntry, is KtEscapeStringTemplateEntry -> el(build(::KotlinStringULiteralExpression)) + is KtStringTemplateEntry -> element.expression?.let { convertExpression(it, givenParent, requiredType) } ?: expr { UastEmptyExpression } + is KtWhenEntry -> el(build(::KotlinUSwitchEntry)) + is KtWhenCondition -> convertWhenCondition(element, givenParent, requiredType) + is KtTypeReference -> el { LazyKotlinUTypeReferenceExpression(element, givenParent) } + is KtConstructorDelegationCall -> + el { KotlinUFunctionCallExpression(element, givenParent) } + is KtSuperTypeCallEntry -> + el { + (element.getParentOfType(true)?.parent as? KtObjectLiteralExpression) + ?.toUElementOfType() + ?: KotlinUFunctionCallExpression(element, givenParent) + } + is KtImportDirective -> el(build(::KotlinUImportStatement)) + else -> { + if (element is LeafPsiElement) { + if (element.elementType == KtTokens.IDENTIFIER) + el(build(::KotlinUIdentifier)) + else if (element.elementType == KtTokens.LBRACKET && element.parent is KtCollectionLiteralExpression) + el { + UIdentifier( + element, + KotlinUCollectionLiteralExpression( + element.parent as KtCollectionLiteralExpression, + null + ) + ) + } + else null + } else { + null + } + } + }} + } + + + internal fun convertEntry(entry: KtStringTemplateEntry, + givenParent: UElement?, + requiredType: Class? = null): UExpression? { + return with(requiredType) { + if (entry is KtStringTemplateEntryWithExpression) { + expr { + KotlinConverter.convertOrEmpty(entry.expression, givenParent) + } + } + else { + expr { + if (entry is KtEscapeStringTemplateEntry) + KotlinStringULiteralExpression(entry, givenParent, entry.unescapedValue) + else + KotlinStringULiteralExpression(entry, givenParent) + } + } + } + } + + internal fun convertExpression(expression: KtExpression, + givenParent: UElement?, + requiredType: Class? = null): UExpression? { + fun

build(ctor: (P, UElement?) -> UExpression): () -> UExpression? { + return { ctor(expression as P, givenParent) } + } + + return with (requiredType) { when (expression) { + is KtVariableDeclaration -> expr(build(::convertVariablesDeclaration)) + + is KtStringTemplateExpression -> { + when { + expression.entries.isEmpty() -> { + expr { KotlinStringULiteralExpression(expression, givenParent, "") } + } + expression.entries.size == 1 -> convertEntry(expression.entries[0], givenParent, requiredType) + else -> { + expr { KotlinStringTemplateUPolyadicExpression(expression, givenParent) } + } + } + } + is KtDestructuringDeclaration -> expr { + 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(build(::KotlinULabeledExpression)) + is KtClassLiteralExpression -> expr(build(::KotlinUClassLiteralExpression)) + is KtObjectLiteralExpression -> expr(build(::KotlinUObjectLiteralExpression)) + is KtDotQualifiedExpression -> expr(build(::KotlinUQualifiedReferenceExpression)) + is KtSafeQualifiedExpression -> expr(build(::KotlinUSafeQualifiedExpression)) + is KtSimpleNameExpression -> expr(build(::KotlinUSimpleReferenceExpression)) + is KtCallExpression -> expr(build(::KotlinUFunctionCallExpression)) + is KtCollectionLiteralExpression -> expr(build(::KotlinUCollectionLiteralExpression)) + is KtBinaryExpression -> { + if (expression.operationToken == KtTokens.ELVIS) { + expr(build(::createElvisExpression)) + } + else expr(build(::KotlinUBinaryExpression)) + } + is KtParenthesizedExpression -> expr(build(::KotlinUParenthesizedExpression)) + is KtPrefixExpression -> expr(build(::KotlinUPrefixExpression)) + is KtPostfixExpression -> expr(build(::KotlinUPostfixExpression)) + is KtThisExpression -> expr(build(::KotlinUThisExpression)) + is KtSuperExpression -> expr(build(::KotlinUSuperExpression)) + is KtCallableReferenceExpression -> expr(build(::KotlinUCallableReferenceExpression)) + is KtIsExpression -> expr(build(::KotlinUTypeCheckExpression)) + is KtIfExpression -> expr(build(::KotlinUIfExpression)) + is KtWhileExpression -> expr(build(::KotlinUWhileExpression)) + is KtDoWhileExpression -> expr(build(::KotlinUDoWhileExpression)) + is KtForExpression -> expr(build(::KotlinUForEachExpression)) + is KtWhenExpression -> expr(build(::KotlinUSwitchExpression)) + is KtBreakExpression -> expr(build(::KotlinUBreakExpression)) + is KtContinueExpression -> expr(build(::KotlinUContinueExpression)) + is KtReturnExpression -> expr(build(::KotlinUReturnExpression)) + is KtThrowExpression -> expr(build(::KotlinUThrowExpression)) + is KtBlockExpression -> expr(build(::KotlinUBlockExpression)) + is KtConstantExpression -> expr(build(::KotlinULiteralExpression)) + is KtTryExpression -> expr(build(::KotlinUTryExpression)) + is KtArrayAccessExpression -> expr(build(::KotlinUArrayAccessExpression)) + is KtLambdaExpression -> expr(build(::KotlinULambdaExpression)) + is KtBinaryExpressionWithTypeRHS -> expr(build(::KotlinUBinaryExpressionWithType)) + is KtClassOrObject -> expr { + expression.toLightClass()?.let { lightClass -> + KotlinUDeclarationsExpression(givenParent).apply { + declarations = listOf(KotlinUClass.create(lightClass, this)) + } + } ?: UastEmptyExpression + } + is KtFunction -> if (expression.name.isNullOrEmpty()) { + expr(build(::createLocalFunctionLambdaExpression)) + } + else { + expr(build(::createLocalFunctionDeclaration)) + } + + else -> expr(build(::UnknownKotlinExpression)) + }} + } + + internal fun convertWhenCondition(condition: KtWhenCondition, + givenParent: UElement?, + requiredType: Class? = null): UExpression? { + return with(requiredType) { + when (condition) { + is KtWhenConditionInRange -> expr { + 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 { + 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 { 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 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) } +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.181 new file mode 100644 index 00000000000..e8b4f1706cd --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.181 @@ -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 = 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 = 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 = emptyList() + override val javaPsi: PsiElement? = null + override val sourcePsi: PsiElement? = null + } + +private fun createElvisExpressions( + left: KtExpression, + right: KtExpression, + containingElement: UElement?, + psiParent: PsiElement): List { + + 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 = 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 = emptyList() + override val expressions: List 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) + } +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.181 new file mode 100644 index 00000000000..9aebf47d10d --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.181 @@ -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 +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.181 new file mode 100644 index 00000000000..b79fd597717 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.181 @@ -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) +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.181 new file mode 100644 index 00000000000..4d6c8f2c6da --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.181 @@ -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) +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.181 new file mode 100644 index 00000000000..22c2d82dfc0 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.181 @@ -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() + .firstOrNull { it.isPrimary } + ?.uastBody + ?: result + else -> result + } + } + +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.181 new file mode 100644 index 00000000000..e376f40d537 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.181 @@ -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) } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.181 new file mode 100644 index 00000000000..4d86d3b6bbf --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.181 @@ -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 + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.181 new file mode 100644 index 00000000000..63c9af6d50b --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.181 @@ -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 + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.181 new file mode 100644 index 00000000000..f767c09c2a4 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.181 @@ -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 + 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 +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.181 new file mode 100644 index 00000000000..9ae022699d3 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.181 @@ -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()] +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.181 new file mode 100644 index 00000000000..ebe356145f6 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.181 @@ -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 + get() = emptyList() + } + } + } + + override fun convertParent(): UElement? { + val result = KotlinConverter.unwrapElements(psi.parent)?.let { parentUnwrapped -> + KotlinUastLanguagePlugin().convertElementWithParent(parentUnwrapped, null) + } + return (result as? KotlinUSwitchExpression)?.body ?: result + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.181 new file mode 100644 index 00000000000..ce8ef9146a3 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.181 @@ -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()] +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.181 new file mode 100644 index 00000000000..db9c6cedd83 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.181 @@ -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 + get() = emptyList() + + override val hasResources: Boolean + get() = false + + override val tryIdentifier: UIdentifier + get() = KotlinUIdentifier(null, this) + + override val finallyIdentifier: UIdentifier? + get() = null +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.181 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.181 new file mode 100644 index 00000000000..dd4dbf194e1 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.181 @@ -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) +} \ No newline at end of file