From 8efee7bd9c88a7001d16e916d840eb39e5df3768 Mon Sep 17 00:00:00 2001 From: Vyacheslav Gerasimov Date: Thu, 12 Apr 2018 21:49:06 +0300 Subject: [PATCH] as32: Revert uast to the state of idea 173, AS 3.2 C10 has uast from idea 173 --- plugins/uast-kotlin/build.gradle.kts.173.as32 | 0 .../KotlinUastLanguagePlugin.kt.173.as32 | 0 .../kotlin/KotlinUastLanguagePlugin.kt.as32 | 555 ++++++++++++++++++ .../KotlinUAnnotation.kt.173.as32 | 0 .../declarations/KotlinUAnnotation.kt.as32 | 133 +++++ .../declarations/KotlinUClass.kt.173.as32 | 0 .../kotlin/declarations/KotlinUClass.kt.as32 | 292 +++++++++ .../declarations/KotlinUMethod.kt.173.as32 | 0 .../kotlin/declarations/KotlinUMethod.kt.as32 | 127 ++++ .../declarations/KotlinUVariable.kt.173.as32 | 0 .../declarations/KotlinUVariable.kt.as32 | 441 ++++++++++++++ .../UastLightIdentifier.kt.173.as32 | 0 .../declarations/UastLightIdentifier.kt.as32 | 28 + .../expressions/ElvisExpression.kt.173.as32 | 0 .../expressions/ElvisExpression.kt.as32 | 120 ++++ .../KotlinUBinaryExpression.kt.173.as32 | 0 .../KotlinUBinaryExpression.kt.as32 | 106 ++++ ...inUCollectionLiteralExpression.kt.173.as32 | 0 ...KotlinUCollectionLiteralExpression.kt.as32 | 54 ++ .../KotlinUDoWhileExpression.kt.173.as32 | 0 .../KotlinUDoWhileExpression.kt.as32 | 36 ++ .../KotlinUForEachExpression.kt.173.as32 | 0 .../KotlinUForEachExpression.kt.as32 | 42 ++ .../KotlinUFunctionCallExpression.kt.173.as32 | 0 .../KotlinUFunctionCallExpression.kt.as32 | 141 +++++ .../KotlinULabeledExpression.kt.173.as32 | 0 .../KotlinULabeledExpression.kt.as32 | 35 ++ .../KotlinUNamedExpression.kt.173.as32 | 0 .../KotlinUNamedExpression.kt.as32 | 100 ++++ ...KotlinUObjectLiteralExpression.kt.173.as32 | 0 .../KotlinUObjectLiteralExpression.kt.as32 | 97 +++ .../KotlinUPostfixExpression.kt.173.as32 | 0 .../KotlinUPostfixExpression.kt.as32 | 46 ++ .../KotlinUPrefixExpression.kt.173.as32 | 0 .../KotlinUPrefixExpression.kt.as32 | 46 ++ ...tlinUSimpleReferenceExpression.kt.173.as32 | 0 .../KotlinUSimpleReferenceExpression.kt.as32 | 220 +++++++ .../KotlinUSuperExpression.kt.173.as32 | 0 .../KotlinUSuperExpression.kt.as32 | 36 ++ .../KotlinUSwitchExpression.kt.173.as32 | 0 .../KotlinUSwitchExpression.kt.as32 | 93 +++ .../KotlinUThisExpression.kt.173.as32 | 0 .../expressions/KotlinUThisExpression.kt.as32 | 36 ++ .../KotlinUTryExpression.kt.173.as32 | 0 .../expressions/KotlinUTryExpression.kt.as32 | 44 ++ .../KotlinUWhileExpression.kt.173.as32 | 0 .../KotlinUWhileExpression.kt.as32 | 33 ++ .../kotlinInternalUastUtils.kt.173.as32 | 0 .../internal/kotlinInternalUastUtils.kt.as32 | 213 +++++++ .../testData/Anonymous.identifiers.txt.as32 | 0 .../ClassAnnotation.identifiers.txt.as32 | 0 .../Constructors.identifiers.txt.as32 | 0 .../LocalDeclarations.identifiers.txt.as32 | 0 .../testData/LocalDeclarations.kt.173.as32 | 0 .../testData/LocalDeclarations.kt.as32 | 12 + .../LocalDeclarations.log.txt.173.as32 | 0 .../testData/LocalDeclarations.log.txt.as32 | 34 ++ .../LocalDeclarations.render.txt.173.as32 | 0 .../LocalDeclarations.render.txt.as32 | 17 + .../LocalDeclarations.types.txt.173.as32 | 0 .../testData/LocalDeclarations.types.txt.as32 | 34 ++ .../LocalDeclarations.values.txt.173.as32 | 0 .../LocalDeclarations.values.txt.as32 | 34 ++ .../testData/ParametersDisorder.kt.as32 | 0 .../testData/ParametersDisorder.log.txt.as32 | 0 .../ParametersDisorder.render.txt.as32 | 0 .../SimpleAnnotated.identifiers.txt.as32 | 0 .../testData/SimpleAnnotated.kt.173.as32 | 0 .../testData/SimpleAnnotated.kt.as32 | 9 + .../AbstractKotlinIdentifiersTest.kt.as32 | 0 .../AbstractKotlinRenderLogTest.kt.173.as32 | 0 .../tests/AbstractKotlinRenderLogTest.kt.as32 | 134 +++++ .../tests/KotlinUastApiTest.kt.173.as32 | 0 .../tests/KotlinUastApiTest.kt.as32 | 312 ++++++++++ .../tests/KotlinUastIdentifiersTest.kt.as32 | 0 .../SimpleKotlinRenderLogTest.kt.173.as32 | 0 .../tests/SimpleKotlinRenderLogTest.kt.as32 | 78 +++ .../test/common/IdentifiersTestBase.kt.as32 | 0 .../test/env/AbstractUastTest.kt.173.as32 | 0 .../uast/test/env/AbstractUastTest.kt.as32 | 82 +++ 80 files changed, 3820 insertions(+) create mode 100644 plugins/uast-kotlin/build.gradle.kts.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/UastLightIdentifier.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/UastLightIdentifier.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt.173.as32 create mode 100644 plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt.as32 create mode 100644 plugins/uast-kotlin/testData/Anonymous.identifiers.txt.as32 create mode 100644 plugins/uast-kotlin/testData/ClassAnnotation.identifiers.txt.as32 create mode 100644 plugins/uast-kotlin/testData/Constructors.identifiers.txt.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.identifiers.txt.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.kt.173.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.kt.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.log.txt.173.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.log.txt.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.render.txt.173.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.render.txt.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.types.txt.173.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.types.txt.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.values.txt.173.as32 create mode 100644 plugins/uast-kotlin/testData/LocalDeclarations.values.txt.as32 create mode 100644 plugins/uast-kotlin/testData/ParametersDisorder.kt.as32 create mode 100644 plugins/uast-kotlin/testData/ParametersDisorder.log.txt.as32 create mode 100644 plugins/uast-kotlin/testData/ParametersDisorder.render.txt.as32 create mode 100644 plugins/uast-kotlin/testData/SimpleAnnotated.identifiers.txt.as32 create mode 100644 plugins/uast-kotlin/testData/SimpleAnnotated.kt.173.as32 create mode 100644 plugins/uast-kotlin/testData/SimpleAnnotated.kt.as32 create mode 100644 plugins/uast-kotlin/tests/AbstractKotlinIdentifiersTest.kt.as32 create mode 100644 plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt.173.as32 create mode 100644 plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt.as32 create mode 100644 plugins/uast-kotlin/tests/KotlinUastApiTest.kt.173.as32 create mode 100644 plugins/uast-kotlin/tests/KotlinUastApiTest.kt.as32 create mode 100644 plugins/uast-kotlin/tests/KotlinUastIdentifiersTest.kt.as32 create mode 100644 plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.173.as32 create mode 100644 plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.as32 create mode 100644 plugins/uast-kotlin/tests/org/jetbrains/uast/test/common/IdentifiersTestBase.kt.as32 create mode 100644 plugins/uast-kotlin/tests/org/jetbrains/uast/test/env/AbstractUastTest.kt.173.as32 create mode 100644 plugins/uast-kotlin/tests/org/jetbrains/uast/test/env/AbstractUastTest.kt.as32 diff --git a/plugins/uast-kotlin/build.gradle.kts.173.as32 b/plugins/uast-kotlin/build.gradle.kts.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.as32 new file mode 100644 index 00000000000..6d49284e33f --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt.as32 @@ -0,0 +1,555 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.lang.Language +import com.intellij.openapi.util.Key +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.impl.source.tree.LeafPsiElement +import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.kotlin.asJava.elements.* +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.idea.project.TargetPlatformDetector +import org.jetbrains.kotlin.idea.util.module +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform +import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.declarations.KotlinUMethod +import org.jetbrains.uast.kotlin.expressions.* +import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter +import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable + +interface KotlinUastBindingContextProviderService { + fun getBindingContext(element: KtElement): BindingContext + fun getTypeMapper(element: KtElement): KotlinTypeMapper? +} + +var PsiElement.destructuringDeclarationInitializer: Boolean? by UserDataProperty(Key.create("kotlin.uast.destructuringDeclarationInitializer")) + +class KotlinUastLanguagePlugin : UastLanguagePlugin { + override val priority = 10 + + override val language: Language + get() = KotlinLanguage.INSTANCE + + override fun isFileSupported(fileName: String): Boolean { + return fileName.endsWith(".kt", false) || fileName.endsWith(".kts", false) + } + + private val PsiElement.isJvmElement + get() = try { + // Workaround for UAST used without full-fledged IDEA when ProjectFileIndex is not available + // If we can't get the module (or don't have one), act as if the current platform is JVM + val module = module + module == null || TargetPlatformDetector.getPlatform(module) is JvmPlatform + } catch (e: Exception) { + true + } + + override fun convertElement(element: PsiElement, parent: UElement?, requiredType: Class?): 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(::UIdentifier)) + 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/declarations/KotlinUAnnotation.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt.as32 new file mode 100644 index 00000000000..486c8ecaa91 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt.as32 @@ -0,0 +1,133 @@ +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiClass +import org.jetbrains.kotlin.asJava.toLightAnnotation +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe +import org.jetbrains.kotlin.resolve.source.getPsi +import org.jetbrains.kotlin.types.ErrorUtils +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance +import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.declarations.KotlinUMethod + +abstract class KotlinUAnnotationBase( + final override val psi: KtElement, + givenParent: UElement? +) : KotlinAbstractUElement(givenParent), UAnnotation { + + abstract override val javaPsi: PsiAnnotation? + + final override val sourcePsi = psi + + protected abstract fun annotationUseSiteTarget(): AnnotationUseSiteTarget? + + private val resolvedCall: ResolvedCall<*>? by lz { psi.getResolvedCall(psi.analyze()) } + + override val qualifiedName: String? + get() = annotationClassDescriptor.takeUnless(ErrorUtils::isError) + ?.fqNameUnsafe + ?.takeIf(FqNameUnsafe::isSafe) + ?.toSafe() + ?.toString() + + override val attributeValues: List by lz { + resolvedCall?.valueArguments?.entries?.mapNotNull { + val arguments = it.value.arguments + val name = it.key.name.asString() + when { + arguments.size == 1 -> + KotlinUNamedExpression.create(name, arguments.first(), this) + arguments.size > 1 -> + KotlinUNamedExpression.create(name, arguments, this) + else -> null + } + } ?: emptyList() + } + + protected abstract val annotationClassDescriptor: ClassDescriptor? + + override fun resolve(): PsiClass? { + val descriptor = annotationClassDescriptor ?: return null + return descriptor.toSource()?.getMaybeLightElement(this) as? PsiClass + } + + override fun findAttributeValue(name: String?): UExpression? = + findDeclaredAttributeValue(name) ?: findAttributeDefaultValue(name ?: "value") + + fun findAttributeValueExpression(arg: ValueArgument): UExpression? { + val mapping = resolvedCall?.getArgumentMapping(arg) + return (mapping as? ArgumentMatch)?.let { match -> + val namedExpression = attributeValues.find { it.name == match.valueParameter.name.asString() } + namedExpression?.expression as? KotlinUVarargExpression ?: namedExpression + } + } + + override fun findDeclaredAttributeValue(name: String?): UExpression? { + return attributeValues.find { + it.name == name || + (name == null && it.name == "value") || + (name == "value" && it.name == null) + }?.expression + } + + private fun findAttributeDefaultValue(name: String): UExpression? { + val parameter = annotationClassDescriptor + ?.unsubstitutedPrimaryConstructor + ?.valueParameters + ?.find { it.name.asString() == name } ?: return null + + val defaultValue = (parameter.source.getPsi() as? KtParameter)?.defaultValue ?: return null + return getLanguagePlugin().convertWithParent(defaultValue) + } + + override fun convertParent(): UElement? { + val superParent = super.convertParent() ?: return null + if (annotationUseSiteTarget() == AnnotationUseSiteTarget.RECEIVER) { + (superParent.uastParent as? KotlinUMethod)?.uastParameters?.firstIsInstance()?.let { + return it + } + } + return superParent + } +} + +class KotlinUAnnotation( + val annotationEntry: KtAnnotationEntry, + givenParent: UElement? +) : KotlinUAnnotationBase(annotationEntry, givenParent), UAnnotation { + + override val javaPsi = annotationEntry.toLightAnnotation() + + private val resolvedAnnotation: AnnotationDescriptor? by lz { annotationEntry.analyze()[BindingContext.ANNOTATION, annotationEntry] } + + override val annotationClassDescriptor: ClassDescriptor? + get() = resolvedAnnotation?.annotationClass + + override fun annotationUseSiteTarget() = annotationEntry.useSiteTarget?.getAnnotationUseSiteTarget() + +} + +class KotlinUNestedAnnotation( + original: KtCallExpression, + givenParent: UElement?, + private val classDescriptor: ClassDescriptor? +) : KotlinUAnnotationBase(original, givenParent) { + override val javaPsi: PsiAnnotation? by lazy { original.toLightAnnotation() } + override val annotationClassDescriptor: ClassDescriptor? + get() = classDescriptor + + override fun annotationUseSiteTarget(): AnnotationUseSiteTarget? = null + +} + + diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt.as32 new file mode 100644 index 00000000000..23634caebf8 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUClass.kt.as32 @@ -0,0 +1,292 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.* +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.KtLightClassForScript +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.declarations.KotlinUMethod +import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier + +abstract class AbstractKotlinUClass(givenParent: UElement?) : KotlinAbstractUElement(givenParent), UClass, JvmDeclarationUElement { + + override val uastDeclarations by lz { + mutableListOf().apply { + addAll(fields) + addAll(initializers) + addAll(methods) + addAll(innerClasses) + } + } + + override val uastSuperTypes: List + get() { + val ktClass = (psi as? KtLightClass)?.kotlinOrigin ?: return emptyList() + return ktClass.superTypeListEntries.mapNotNull { it.typeReference }.map { + LazyKotlinUTypeReferenceExpression(it, this) + } + } + + override val uastAnchor: UElement? + get() = UIdentifier(psi.nameIdentifier, this) + + override val annotations: List by lz { + (sourcePsi as? KtModifierListOwner)?.annotationEntries.orEmpty().map { KotlinUAnnotation(it, this) } + } + + override fun equals(other: Any?) = other is AbstractKotlinUClass && psi == other.psi + override fun hashCode() = psi.hashCode() + +} + +open class KotlinUClass private constructor( + psi: KtLightClass, + givenParent: UElement? +) : AbstractKotlinUClass(givenParent), PsiClass by psi { + + val ktClass = psi.kotlinOrigin + + override val javaPsi: KtLightClass = psi + + override val sourcePsi: KtClassOrObject? = ktClass + + override val psi = unwrap(psi) + + override fun getSourceElement() = sourcePsi ?: this + + override fun getOriginalElement(): PsiElement? = super.getOriginalElement() + + override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, ktClass) + + override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile) + + override val uastAnchor: UElement + get() = UIdentifier(nameIdentifier, this) + + override fun getInnerClasses(): Array { + // filter DefaultImpls to avoid processing same methods from original interface multiple times + // filter Enum entry classes to avoid duplication with PsiEnumConstant initializer class + return psi.innerClasses.filter { + it.name != JvmAbi.DEFAULT_IMPLS_CLASS_NAME && !it.isEnumEntryLightClass() + }.mapNotNull { + getLanguagePlugin().convertOpt(it, this) + }.toTypedArray() + } + + override fun getSuperClass(): UClass? = super.getSuperClass() + override fun getFields(): Array = super.getFields() + override fun getInitializers(): Array = super.getInitializers() + + override fun getMethods(): Array { + val hasPrimaryConstructor = ktClass?.hasPrimaryConstructor() ?: false + var secondaryConstructorsCount = 0 + + fun createUMethod(psiMethod: PsiMethod): UMethod { + return if (psiMethod is KtLightMethod && + psiMethod.isConstructor) { + if (!hasPrimaryConstructor && secondaryConstructorsCount++ == 0) + KotlinSecondaryConstructorWithInitializersUMethod(ktClass, psiMethod, this) + else + KotlinConstructorUMethod(ktClass, psiMethod, this) + } else { + getLanguagePlugin().convertOpt(psiMethod, this) ?: reportConvertFailure(psiMethod) + } + } + + fun isDelegatedMethod(psiMethod: PsiMethod) = psiMethod is KtLightMethod && psiMethod.isDelegated + + return psi.methods.asSequence() + .filterNot(::isDelegatedMethod) + .map(::createUMethod) + .toList() + .toTypedArray() + } + + private fun PsiClass.isEnumEntryLightClass() = (this as? KtLightClass)?.kotlinOrigin is KtEnumEntry + + companion object { + fun create(psi: KtLightClass, containingElement: UElement?): UClass = when (psi) { + is PsiAnonymousClass -> KotlinUAnonymousClass(psi, containingElement) + is KtLightClassForScript -> KotlinScriptUClass(psi, containingElement) + else -> KotlinUClass(psi, containingElement) + } + } + +} + +open class KotlinConstructorUMethod( + private val ktClass: KtClassOrObject?, + override val psi: KtLightMethod, + givenParent: UElement? +) : KotlinUMethod(psi, givenParent) { + + val isPrimary: Boolean + get() = psi.kotlinOrigin.let { it is KtPrimaryConstructor || it is KtClassOrObject } + + override val uastBody: UExpression? by lz { + val delegationCall: KtCallElement? = psi.kotlinOrigin.let { + when { + isPrimary -> ktClass?.superTypeListEntries?.firstIsInstanceOrNull() + it is KtSecondaryConstructor -> it.getDelegationCall() + else -> null + } + } + val bodyExpressions = getBodyExpressions() + if (delegationCall == null && bodyExpressions.isEmpty()) return@lz null + KotlinUBlockExpression.KotlinLazyUBlockExpression(this) { uastParent -> + SmartList().apply { + delegationCall?.let { + add(KotlinUFunctionCallExpression(it, uastParent)) + } + bodyExpressions.forEach { + add(KotlinConverter.convertOrEmpty(it, uastParent)) + } + } + } + } + + override val javaPsi = psi + + override val sourcePsi = psi.kotlinOrigin + + open protected fun getBodyExpressions(): List { + if (isPrimary) return getInitializers() + val bodyExpression = (psi.kotlinOrigin as? KtFunction)?.bodyExpression ?: return emptyList() + if (bodyExpression is KtBlockExpression) return bodyExpression.statements + return listOf(bodyExpression) + } + + protected fun getInitializers() = ktClass?.getAnonymousInitializers()?.mapNotNull { it.body } ?: emptyList() + +} + +// This class was created as a workaround for KT-21617 to be the only constructor which includes `init` block +// when there is no primary constructors in the class. +// It is expected to have only one constructor of this type in a UClass. +class KotlinSecondaryConstructorWithInitializersUMethod( + ktClass: KtClassOrObject?, + psi: KtLightMethod, + givenParent: UElement? +) : KotlinConstructorUMethod(ktClass, psi, givenParent) { + override fun getBodyExpressions(): List = getInitializers() + super.getBodyExpressions() +} + +class KotlinUAnonymousClass( + psi: PsiAnonymousClass, + givenParent: UElement? +) : AbstractKotlinUClass(givenParent), UAnonymousClass, PsiAnonymousClass by psi { + + override val psi: PsiAnonymousClass = unwrap(psi) + + override val javaPsi: PsiAnonymousClass = psi + + override val sourcePsi: KtClassOrObject? = (psi as? KtLightClass)?.kotlinOrigin + + override fun getOriginalElement(): PsiElement? = super.getOriginalElement() + + override fun getSuperClass(): UClass? = super.getSuperClass() + override fun getFields(): Array = super.getFields() + override fun getMethods(): Array = super.getMethods() + override fun getInitializers(): Array = super.getInitializers() + override fun getInnerClasses(): Array = super.getInnerClasses() + + override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile) + + override val uastAnchor: UElement? + get() { + val ktClassOrObject = (psi.originalElement as? KtLightClass)?.kotlinOrigin as? KtObjectDeclaration ?: return null + return UIdentifier(ktClassOrObject.getObjectKeyword(), this) + } + +} + +class KotlinScriptUClass( + psi: KtLightClassForScript, + givenParent: UElement? +) : AbstractKotlinUClass(givenParent), PsiClass by psi { + override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile) + + override fun getNameIdentifier(): PsiIdentifier? = UastLightIdentifier(psi, psi.kotlinOrigin) + + override val uastAnchor: UElement + get() = UIdentifier(nameIdentifier, this) + + override val javaPsi: PsiClass = psi + + override val sourcePsi: KtClassOrObject? = psi.kotlinOrigin + + override val psi = unwrap(psi) + + override fun getSuperClass(): UClass? = super.getSuperClass() + + override fun getFields(): Array = super.getFields() + + override fun getInitializers(): Array = super.getInitializers() + + override fun getInnerClasses(): Array = + psi.innerClasses.mapNotNull { getLanguagePlugin().convertOpt(it, this) }.toTypedArray() + + override fun getMethods(): Array = psi.methods.map(this::createUMethod).toTypedArray() + + private fun createUMethod(method: PsiMethod): UMethod { + return if (method.isConstructor) { + KotlinScriptConstructorUMethod(psi.script, method as KtLightMethod, this) + } + else { + getLanguagePlugin().convertOpt(method, this) ?: reportConvertFailure(method) + } + } + + override fun getOriginalElement(): PsiElement? = psi.originalElement + + class KotlinScriptConstructorUMethod( + script: KtScript, + override val psi: KtLightMethod, + givenParent: UElement? + ) : KotlinUMethod(psi, givenParent) { + override val uastBody: UExpression? by lz { + val initializers = script.declarations.filterIsInstance() + KotlinUBlockExpression.create(initializers, this) + } + override val javaPsi = psi + override val sourcePsi = psi.kotlinOrigin + } +} + +private fun reportConvertFailure(psiMethod: PsiMethod): Nothing { + val isValid = psiMethod.isValid + val report = KotlinExceptionWithAttachments( + "cant convert $psiMethod of ${psiMethod.javaClass} to UMethod" + + if (!isValid) " (method is not valid)" else "" + ) + + if (isValid) { + report.withAttachment("method", psiMethod.text) + psiMethod.containingFile?.let { + report.withAttachment("file", it.text) + } + } + + throw report +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.as32 new file mode 100644 index 00000000000..5a2d576619e --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUMethod.kt.as32 @@ -0,0 +1,127 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin.declarations + +import com.intellij.psi.PsiCodeBlock +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiMethod +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.asJava.elements.isGetter +import org.jetbrains.kotlin.asJava.elements.isSetter +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.uast.* +import org.jetbrains.uast.java.internal.JavaUElementWithComments +import org.jetbrains.uast.kotlin.* + +open class KotlinUMethod( + psi: KtLightMethod, + givenParent: UElement? +) : KotlinAbstractUElement(givenParent), UAnnotationMethod, JavaUElementWithComments, PsiMethod by psi { + override val psi: KtLightMethod = unwrap(psi) + + override val javaPsi = psi + + override val sourcePsi = psi.kotlinOrigin + + override fun getSourceElement() = sourcePsi ?: this + + override val uastDefaultValue by lz { + val annotationParameter = psi.kotlinOrigin as? KtParameter ?: return@lz null + val defaultValue = annotationParameter.defaultValue ?: return@lz null + getLanguagePlugin().convertElement(defaultValue, this) as? UExpression + } + + private val kotlinOrigin = (psi.originalElement as KtLightElement<*, *>).kotlinOrigin + + override fun getContainingFile(): PsiFile? = unwrapFakeFileForLightClass(psi.containingFile) + + override fun getNameIdentifier() = UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?) + + override val annotations by lz { + psi.annotations + .mapNotNull { (it as? KtLightElement<*, *>)?.kotlinOrigin as? KtAnnotationEntry } + .map { KotlinUAnnotation(it, this) } + } + + private val receiver by lz { (sourcePsi as? KtCallableDeclaration)?.receiverTypeReference } + + override val uastParameters by lz { + val lightParams = psi.parameterList.parameters + val receiver = receiver ?: return@lz lightParams.map { + KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this) + } + val receiverLight = lightParams.firstOrNull() ?: return@lz emptyList() + val uParameters = SmartList(KotlinReceiverUParameter(receiverLight, receiver, this)) + lightParams.drop(1).mapTo(uParameters) { KotlinUParameter(it, (it as? KtLightElement<*, *>)?.kotlinOrigin, this) } + uParameters + } + + override val uastAnchor: UElement + get() = UIdentifier(nameIdentifier, this) + + + override val uastBody by lz { + val bodyExpression = when (kotlinOrigin) { + is KtFunction -> kotlinOrigin.bodyExpression + is KtProperty -> when { + psi.isGetter -> kotlinOrigin.getter?.bodyExpression + psi.isSetter -> kotlinOrigin.setter?.bodyExpression + else -> null + } + else -> null + } ?: return@lz null + + when (bodyExpression) { + !is KtBlockExpression -> { + KotlinUBlockExpression.KotlinLazyUBlockExpression(this, { block -> + val implicitReturn = KotlinUImplicitReturnExpression(block) + val uBody = getLanguagePlugin().convertElement(bodyExpression, implicitReturn) as? UExpression + ?: return@KotlinLazyUBlockExpression emptyList() + listOf(implicitReturn.apply { returnExpression = uBody }) + }) + + } + else -> getLanguagePlugin().convertElement(bodyExpression, this) as? UExpression + } + } + + override val isOverride: Boolean + get() = (kotlinOrigin as? KtCallableDeclaration)?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false + + override fun getBody(): PsiCodeBlock? = super.getBody() + + override fun getOriginalElement(): PsiElement? = super.getOriginalElement() + + override fun equals(other: Any?) = other is KotlinUMethod && psi == other.psi + + companion object { + fun create(psi: KtLightMethod, containingElement: UElement?) = + if (psi.kotlinOrigin is KtConstructor<*>) { + KotlinConstructorUMethod( + psi.kotlinOrigin?.containingClassOrObject, + psi, containingElement + ) + } + else + KotlinUMethod(psi, containingElement) + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.as32 new file mode 100644 index 00000000000..78a1665e80c --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt.as32 @@ -0,0 +1,441 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.* +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.resolve.calls.callUtil.getType +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.TypeNullability +import org.jetbrains.kotlin.types.typeUtil.nullability +import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.uast.* +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier +import org.jetbrains.uast.kotlin.internal.KotlinUElementWithComments +import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter +import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable +import org.jetbrains.uast.visitor.UastVisitor + +abstract class AbstractKotlinUVariable(givenParent: UElement?) + : KotlinAbstractUElement(givenParent), PsiVariable, UVariable, KotlinUElementWithComments { + + override val uastInitializer: UExpression? + get() { + val psi = psi + val initializerExpression = when (psi) { + is UastKotlinPsiVariable -> psi.ktInitializer + is UastKotlinPsiParameter -> psi.ktDefaultValue + is KtLightElement<*, *> -> { + val origin = psi.kotlinOrigin + when (origin) { + is KtVariableDeclaration -> origin.initializer + is KtParameter -> origin.defaultValue + else -> null + } + } + else -> null + } ?: return null + return getLanguagePlugin().convertElement(initializerExpression, this) as? UExpression ?: UastEmptyExpression + } + + val delegateExpression: UExpression? by lz { + val psi = psi + val expression = when (psi) { + is KtLightElement<*, *> -> (psi.kotlinOrigin as? KtProperty)?.delegateExpression + is UastKotlinPsiVariable -> (psi.ktElement as? KtProperty)?.delegateExpression + else -> null + } + + expression?.let { getLanguagePlugin().convertElement(it, this) as? UExpression } + } + + override fun getNameIdentifier(): PsiIdentifier { + val kotlinOrigin = (psi as? KtLightElement<*, *>)?.kotlinOrigin + return UastLightIdentifier(psi, kotlinOrigin as KtNamedDeclaration?) + } + + override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(psi.containingFile) + + override val annotations by lz { + val sourcePsi = sourcePsi ?: return@lz psi.annotations.map { WrappedUAnnotation(it, this) } + val annotations = SmartList(KotlinNullabilityUAnnotation(sourcePsi, this)) + if (sourcePsi is KtModifierListOwner) { + sourcePsi.annotationEntries. + filter { acceptsAnnotationTarget(it.useSiteTarget?.getAnnotationUseSiteTarget()) }. + mapTo(annotations) { KotlinUAnnotation(it, this) } + } + annotations + } + + + abstract protected fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean + + override val typeReference by lz { getLanguagePlugin().convertOpt(psi.typeElement, this) } + + override val uastAnchor: UElement? + get() = UIdentifier(nameIdentifier, this) + + override fun equals(other: Any?) = other is AbstractKotlinUVariable && psi == other.psi + + class WrappedUAnnotation(psiAnnotation: PsiAnnotation, override val uastParent: UElement) : UAnnotation, JvmDeclarationUElement { + + override val javaPsi: PsiAnnotation = psiAnnotation + override val psi: PsiAnnotation = javaPsi + override val sourcePsi: PsiElement? = null + + override val attributeValues: List by lz { + psi.parameterList.attributes.map { WrappedUNamedExpression(it, this) } + } + + class WrappedUNamedExpression(pair: PsiNameValuePair, override val uastParent: UElement?) : UNamedExpression, JvmDeclarationUElement { + override val name: String? = pair.name + override val psi = pair + override val javaPsi: PsiElement? = psi + override val sourcePsi: PsiElement? = null + override val annotations: List = emptyList() + override val expression: UExpression by lz { toUExpression(psi.value) } + } + + override val qualifiedName: String? = psi.qualifiedName + override fun findAttributeValue(name: String?): UExpression? = psi.findAttributeValue(name)?.let { toUExpression(it) } + override fun findDeclaredAttributeValue(name: String?): UExpression? = psi.findDeclaredAttributeValue(name)?.let { toUExpression(it) } + override fun resolve(): PsiClass? = psi.nameReferenceElement?.resolve() as? PsiClass + } + +} + +private fun toUExpression(psi: PsiElement?): UExpression = psi.toUElementOfType() ?: UastEmptyExpression + +class KotlinUVariable( + psi: PsiVariable, + override val sourcePsi: KtElement, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), UVariable, PsiVariable by psi { + + override val javaPsi = unwrap(psi) + + override val psi = javaPsi + + override val typeReference by lz { getLanguagePlugin().convertOpt(psi.typeElement, this) } + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + +} + +open class KotlinUParameter( + psi: PsiParameter, + final override val sourcePsi: KtElement?, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), UParameter, PsiParameter by psi { + + final override val javaPsi = unwrap(psi) + + override val psi = javaPsi + + private val isLightConstructorParam by lz { psi.getParentOfType(true)?.isConstructor } + + private val isKtConstructorParam by lz { sourcePsi?.getParentOfType(true)?.let { it is KtConstructor<*> } } + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean { + if (sourcePsi !is KtParameter) return false + if (isKtConstructorParam == isLightConstructorParam && target == null) return true + when (target) { + AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> return isLightConstructorParam == true + AnnotationUseSiteTarget.SETTER_PARAMETER -> return isLightConstructorParam != true + else -> return false + } + } + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } +} + +class KotlinReceiverUParameter( + psi: PsiParameter, + private val receiver: KtTypeReference, + givenParent: UElement? +) : KotlinUParameter(psi, receiver, givenParent) { + + override val annotations: List by lz { + receiver.annotationEntries + .filter { it.useSiteTarget?.getAnnotationUseSiteTarget() == AnnotationUseSiteTarget.RECEIVER } + .map { KotlinUAnnotation(it, this) } + + super.annotations + } + +} + +class KotlinNullabilityUAnnotation(val annotatedElement: PsiElement, override val uastParent: UElement) : UAnnotation, JvmDeclarationUElement { + + private fun getTargetType(annotatedElement: PsiElement): KotlinType? { + if (annotatedElement is KtTypeReference) { + annotatedElement.getType()?.let { return it } + } + if (annotatedElement is KtCallableDeclaration) { + annotatedElement.typeReference?.getType()?.let { return it } + } + if (annotatedElement is KtProperty) { + annotatedElement.initializer?.let { it.getType(it.analyze()) }?.let { return it } + annotatedElement.delegateExpression?.let { it.getType(it.analyze())?.arguments?.firstOrNull()?.type }?.let { return it } + } + annotatedElement.getParentOfType(false)?.let { + it.typeReference?.getType() ?: it.initializer?.let { it.getType(it.analyze()) } + }?.let { return it } + return null + } + + val nullability by lz { getTargetType(annotatedElement)?.nullability() } + + override val attributeValues: List + get() = emptyList() + override val psi: PsiElement? + get() = null + override val javaPsi: PsiAnnotation? + get() = null + override val sourcePsi: PsiElement? + get() = null + override val qualifiedName: String? + get() = when (nullability) { + TypeNullability.NOT_NULL -> NotNull::class.qualifiedName + TypeNullability.NULLABLE -> Nullable::class.qualifiedName + TypeNullability.FLEXIBLE -> null + null -> null + } + + override fun findAttributeValue(name: String?): UExpression? = null + + override fun findDeclaredAttributeValue(name: String?): UExpression? = null + + override fun resolve(): PsiClass? = qualifiedName?.let { + val project = annotatedElement.project + JavaPsiFacade.getInstance(project).findClass(it, GlobalSearchScope.allScope(project)) + } + +} + +open class KotlinUField( + psi: PsiField, + override val sourcePsi: KtElement?, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), UField, PsiField by psi { + override fun getSourceElement() = sourcePsi ?: this + + override val javaPsi = unwrap(psi) + + override val psi = javaPsi + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = + target == AnnotationUseSiteTarget.FIELD || + target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD || + (sourcePsi is KtProperty) && (target == null || target == AnnotationUseSiteTarget.PROPERTY) + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + + override fun isPhysical(): Boolean { + return true + } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitField(this)) return + annotations.acceptList(visitor) + uastInitializer?.accept(visitor) + delegateExpression?.accept(visitor) + visitor.afterVisitField(this) + } +} + +open class KotlinULocalVariable( + psi: PsiLocalVariable, + override val sourcePsi: KtElement, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), ULocalVariable, PsiLocalVariable by psi { + + override val javaPsi = unwrap(psi) + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true + + override val psi = javaPsi + + override fun getInitializer(): PsiExpression? { + return super.getInitializer() + } + + override fun getOriginalElement(): PsiElement? { + return super.getOriginalElement() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitLocalVariable(this)) return + annotations.acceptList(visitor) + uastInitializer?.accept(visitor) + delegateExpression?.accept(visitor) + visitor.afterVisitLocalVariable(this) + } +} + +open class KotlinUAnnotatedLocalVariable( + psi: PsiLocalVariable, + sourcePsi: KtElement, + uastParent: UElement?, + computeAnnotations: (parent: UElement) -> List +) : KotlinULocalVariable(psi, sourcePsi, uastParent) { + + override val annotations: List by lz { computeAnnotations(this) } +} + +class KotlinUEnumConstant( + psi: PsiEnumConstant, + override val sourcePsi: KtElement?, + givenParent: UElement? +) : AbstractKotlinUVariable(givenParent), UEnumConstant, PsiEnumConstant by psi { + + override val initializingClass: UClass? by lz { + (psi.initializingClass as? KtLightClass)?.let { initializingClass -> + KotlinUClass.create(initializingClass, this) + } + } + + override fun getInitializer(): PsiExpression? = super.getInitializer() + + override fun getOriginalElement(): PsiElement? = super.getOriginalElement() + + override val javaPsi = unwrap(psi) + + override val psi = javaPsi + + override fun acceptsAnnotationTarget(target: AnnotationUseSiteTarget?): Boolean = true + + override fun getContainingFile(): PsiFile { + return super.getContainingFile() + } + + override fun getNameIdentifier(): PsiIdentifier { + return super.getNameIdentifier() + } + + override val kind: UastCallKind + get() = UastCallKind.CONSTRUCTOR_CALL + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null + + override val methodIdentifier: UIdentifier? + get() = null + + override val classReference: UReferenceExpression? + get() = KotlinEnumConstantClassReference(psi, sourcePsi, this) + + override val typeArgumentCount: Int + get() = 0 + + override val typeArguments: List + get() = emptyList() + + override val valueArgumentCount: Int + get() = psi.argumentList?.expressions?.size ?: 0 + + override val valueArguments by lz { + psi.argumentList?.expressions?.map { + getLanguagePlugin().convertElement(it, this) as? UExpression ?: UastEmptyExpression + } ?: emptyList() + } + + override val returnType: PsiType? + get() = psi.type + + override fun resolve() = psi.resolveMethod() + + override val methodName: String? + get() = null + + private class KotlinEnumConstantClassReference( + override val psi: PsiEnumConstant, + override val sourcePsi: KtElement?, + givenParent: UElement? + ) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression { + override val javaPsi: PsiElement? + get() = psi + + override fun resolve() = psi.containingClass + override val resolvedName: String? + get() = psi.containingClass?.name + override val identifier: String + get() = psi.containingClass?.name ?: "" + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/UastLightIdentifier.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/UastLightIdentifier.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/UastLightIdentifier.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/UastLightIdentifier.kt.as32 new file mode 100644 index 00000000000..53f313d6cdf --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/UastLightIdentifier.kt.as32 @@ -0,0 +1,28 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin.declarations + +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiNameIdentifierOwner +import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier +import org.jetbrains.kotlin.psi.KtNamedDeclaration +import org.jetbrains.uast.kotlin.unwrapFakeFileForLightClass + +class UastLightIdentifier(lightOwner: PsiNameIdentifierOwner, ktDeclaration: KtNamedDeclaration?) + : KtLightIdentifier(lightOwner, ktDeclaration) { + override fun getContainingFile(): PsiFile = unwrapFakeFileForLightClass(super.getContainingFile()) +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.as32 new file mode 100644 index 00000000000..49ee7c994ca --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/ElvisExpression.kt.as32 @@ -0,0 +1,120 @@ +package org.jetbrains.uast.kotlin.expressions + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.psi.KtBinaryExpression +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.types.CommonSupertypes +import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.* +import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds +import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable + + +private fun createVariableReferenceExpression(variable: UVariable, containingElement: UElement?) = + object : USimpleNameReferenceExpression, 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? = UIdentifier(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 = UIdentifier(null, this) + override val elseIdentifier: UIdentifier? = UIdentifier(null, this) + } + + return listOf(declaration, ifExpression) +} + +fun createElvisExpression(elvisExpression: KtBinaryExpression, givenParent: UElement?): UExpression { + val left = elvisExpression.left ?: return UastEmptyExpression + val right = elvisExpression.right ?: return UastEmptyExpression + + return KotlinUElvisExpression(elvisExpression, left, right, givenParent) +} + +class KotlinUElvisExpression( + private val elvisExpression: KtBinaryExpression, + private val left: KtExpression, + private val right: KtExpression, + givenParent: UElement? +) : KotlinAbstractUElement(givenParent), UExpressionList, KotlinEvaluatableUElement { + + override val javaPsi: PsiElement? = null + override val sourcePsi: PsiElement? = elvisExpression + override val psi: PsiElement? = sourcePsi + override val kind = KotlinSpecialExpressionKinds.ELVIS + override val annotations: List = 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.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.as32 new file mode 100644 index 00000000000..06c62b035ea --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUBinaryExpression.kt.as32 @@ -0,0 +1,106 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtBinaryExpression +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.uast.* + +class KotlinUBinaryExpression( + override val psi: KtBinaryExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UBinaryExpression, KotlinUElementWithType, KotlinEvaluatableUElement { + private companion object { + val BITWISE_OPERATORS = mapOf( + "or" to UastBinaryOperator.BITWISE_OR, + "and" to UastBinaryOperator.BITWISE_AND, + "xor" to UastBinaryOperator.BITWISE_XOR + ) + } + + override val leftOperand by lz { KotlinConverter.convertOrEmpty(psi.left, this) } + override val rightOperand by lz { KotlinConverter.convertOrEmpty(psi.right, this) } + + override val operatorIdentifier: UIdentifier? + get() = UIdentifier(psi.operationReference, this) + + override fun resolveOperator() = psi.operationReference.resolveCallToDeclaration(context = this) as? PsiMethod + + override val operator = when (psi.operationToken) { + KtTokens.EQ -> UastBinaryOperator.ASSIGN + KtTokens.PLUS -> UastBinaryOperator.PLUS + KtTokens.MINUS -> UastBinaryOperator.MINUS + KtTokens.MUL -> UastBinaryOperator.MULTIPLY + KtTokens.DIV -> UastBinaryOperator.DIV + KtTokens.PERC -> UastBinaryOperator.MOD + KtTokens.OROR -> UastBinaryOperator.LOGICAL_OR + KtTokens.ANDAND -> UastBinaryOperator.LOGICAL_AND + KtTokens.EQEQ -> UastBinaryOperator.EQUALS + KtTokens.EXCLEQ -> UastBinaryOperator.NOT_EQUALS + KtTokens.EQEQEQ -> UastBinaryOperator.IDENTITY_EQUALS + KtTokens.EXCLEQEQEQ -> UastBinaryOperator.IDENTITY_NOT_EQUALS + KtTokens.GT -> UastBinaryOperator.GREATER + KtTokens.GTEQ -> UastBinaryOperator.GREATER_OR_EQUALS + KtTokens.LT -> UastBinaryOperator.LESS + KtTokens.LTEQ -> UastBinaryOperator.LESS_OR_EQUALS + KtTokens.PLUSEQ -> UastBinaryOperator.PLUS_ASSIGN + KtTokens.MINUSEQ -> UastBinaryOperator.MINUS_ASSIGN + KtTokens.MULTEQ -> UastBinaryOperator.MULTIPLY_ASSIGN + KtTokens.DIVEQ -> UastBinaryOperator.DIVIDE_ASSIGN + KtTokens.PERCEQ -> UastBinaryOperator.REMAINDER_ASSIGN + KtTokens.IN_KEYWORD -> KotlinBinaryOperators.IN + KtTokens.NOT_IN -> KotlinBinaryOperators.NOT_IN + KtTokens.RANGE -> KotlinBinaryOperators.RANGE_TO + else -> run { // Handle bitwise operators + val other = UastBinaryOperator.OTHER + val ref = psi.operationReference + val resolvedCall = psi.operationReference.getResolvedCall(ref.analyze()) ?: return@run other + val resultingDescriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return@run other + val applicableOperator = BITWISE_OPERATORS[resultingDescriptor.name.asString()] ?: return@run other + + val containingClass = resultingDescriptor.containingDeclaration as? ClassDescriptor ?: return@run other + if (containingClass.typeConstructor.supertypes.any { + it.constructor.declarationDescriptor?.fqNameSafe?.asString() == "kotlin.Number" + }) applicableOperator else other + } + } +} + +class KotlinCustomUBinaryExpression( + override val psi: PsiElement, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UBinaryExpression { + lateinit override var leftOperand: UExpression + internal set + + lateinit override var operator: UastBinaryOperator + internal set + + lateinit override var rightOperand: UExpression + internal set + + override val operatorIdentifier: UIdentifier? + get() = null + + override fun resolveOperator() = null +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt.as32 new file mode 100644 index 00000000000..69ec94ebbdb --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt.as32 @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.uast.kotlin.expressions + +import com.intellij.psi.PsiArrayType +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression +import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.KotlinAbstractUExpression +import org.jetbrains.uast.kotlin.KotlinConverter +import org.jetbrains.uast.kotlin.KotlinUElementWithType + +class KotlinUCollectionLiteralExpression( + override val sourcePsi: KtCollectionLiteralExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UCallExpression, KotlinUElementWithType { + + override val classReference: UReferenceExpression? get() = null + + override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER + + override val methodIdentifier: UIdentifier? by lazy { UIdentifier(sourcePsi.leftBracket, this) } + + override val methodName: String? get() = null + + override val receiver: UExpression? get() = null + + override val receiverType: PsiType? get() = null + + override val returnType: PsiType? get() = getExpressionType() + + override val typeArgumentCount: Int get() = typeArguments.size + + override val typeArguments: List get() = listOfNotNull((returnType as? PsiArrayType)?.componentType) + + override val valueArgumentCount: Int + get() = sourcePsi.getInnerExpressions().size + + override val valueArguments by lazy { + sourcePsi.getInnerExpressions().map { KotlinConverter.convertOrEmpty(it, this) } + } + + override fun asRenderString(): String = "collectionLiteral[" + valueArguments.joinToString { it.asRenderString() } + "]" + + override fun resolve(): PsiMethod? = null + + override val psi: PsiElement get() = sourcePsi + +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.as32 new file mode 100644 index 00000000000..8461fad28e8 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUDoWhileExpression.kt.as32 @@ -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.KtDoWhileExpression +import org.jetbrains.uast.UDoWhileExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier + +class KotlinUDoWhileExpression( + override val psi: KtDoWhileExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UDoWhileExpression { + override val condition by lz { KotlinConverter.convertOrEmpty(psi.condition, this) } + override val body by lz { KotlinConverter.convertOrEmpty(psi.body, this) } + + override val doIdentifier: UIdentifier + get() = UIdentifier(null, this) + + override val whileIdentifier: UIdentifier + get() = UIdentifier(null, this) +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.as32 new file mode 100644 index 00000000000..7345cbe99d7 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUForEachExpression.kt.as32 @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.psi.KtForExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UForEachExpression +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter +import org.jetbrains.uast.psi.UastPsiParameterNotResolved + +class KotlinUForEachExpression( + override val psi: KtForExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UForEachExpression { + override val iteratedValue by lz { KotlinConverter.convertOrEmpty(psi.loopRange, this) } + override val body by lz { KotlinConverter.convertOrEmpty(psi.body, this) } + + override val variable by lz { + val parameter = psi.loopParameter?.let { UastKotlinPsiParameter.create(it, psi, this, 0) } + ?: UastPsiParameterNotResolved(psi, KotlinLanguage.INSTANCE) + KotlinUParameter(parameter, psi, this) + } + + override val forIdentifier: UIdentifier + get() = UIdentifier(null, this) +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.as32 new file mode 100644 index 00000000000..b2dfc81fcab --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.as32 @@ -0,0 +1,141 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.asJava.LightClassUtil +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.psi.KtAnnotationEntry +import org.jetbrains.kotlin.psi.KtCallElement +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.psi.psiUtil.parents +import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.uast.* +import org.jetbrains.uast.internal.acceptList +import org.jetbrains.uast.visitor.UastVisitor + +class KotlinUFunctionCallExpression( + override val psi: KtCallElement, + givenParent: UElement?, + private val _resolvedCall: ResolvedCall<*>? +) : KotlinAbstractUExpression(givenParent), UCallExpression, KotlinUElementWithType { + companion object { + fun resolveSource(descriptor: DeclarationDescriptor, source: PsiElement?): PsiMethod? { + if (descriptor is ConstructorDescriptor && descriptor.isPrimary + && source is KtClassOrObject && source.primaryConstructor == null + && source.secondaryConstructors.isEmpty()) { + return source.toLightClass()?.constructors?.firstOrNull() + } + + return when (source) { + is KtFunction -> LightClassUtil.getLightClassMethod(source) + is PsiMethod -> source + else -> null + } + } + } + + constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null) + + private val resolvedCall by lz { + _resolvedCall ?: psi.getResolvedCall(psi.analyze()) + } + + override val receiverType by lz { + val resolvedCall = this.resolvedCall ?: return@lz null + val receiver = resolvedCall.dispatchReceiver ?: resolvedCall.extensionReceiver ?: return@lz null + receiver.type.toPsiType(this, psi, boxed = true) + } + + override val methodName by lz { resolvedCall?.resultingDescriptor?.name?.asString() } + + override val classReference by lz { + KotlinClassViaConstructorUSimpleReferenceExpression(psi, methodName.orAnonymous("class"), this) + } + + override val methodIdentifier by lz { + val calleeExpression = psi.calleeExpression ?: return@lz null + UIdentifier(calleeExpression, this) + } + + override val valueArgumentCount: Int + get() = psi.valueArguments.size + + override val valueArguments by lz { psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) } } + + override val typeArgumentCount: Int + get() = psi.typeArguments.size + + override val typeArguments by lz { psi.typeArguments.map { it.typeReference.toPsiType(this, boxed = true) } } + + override val returnType: PsiType? + get() = getExpressionType() + + override val kind: UastCallKind by lz { + val resolvedCall = resolvedCall ?: return@lz UastCallKind.METHOD_CALL + when { + resolvedCall.resultingDescriptor is ConstructorDescriptor -> UastCallKind.CONSTRUCTOR_CALL + this.isAnnotationArgumentArrayInitializer() -> UastCallKind.NESTED_ARRAY_INITIALIZER + else -> UastCallKind.METHOD_CALL + } + } + + override val receiver: UExpression? + get() = (uastParent as? UQualifiedReferenceExpression)?.takeIf { it.selector == this }?.receiver + + override fun resolve(): PsiMethod? { + val descriptor = resolvedCall?.resultingDescriptor ?: return null + val source = descriptor.toSource() ?: return null + return resolveSource(descriptor, source) + } + + override fun accept(visitor: UastVisitor) { + if (visitor.visitCallExpression(this)) return + methodIdentifier?.accept(visitor) + classReference.accept(visitor) + valueArguments.acceptList(visitor) + + visitor.afterVisitCallExpression(this) + } + + private fun isAnnotationArgumentArrayInitializer(): Boolean { + val resolvedCall = resolvedCall ?: return false + // KtAnnotationEntry -> KtValueArgumentList -> KtValueArgument -> arrayOf call + return psi.parents.elementAtOrNull(2) is KtAnnotationEntry && CompileTimeConstantUtils.isArrayFunctionCall(resolvedCall) + } + + override fun convertParent(): UElement? = super.convertParent().let { result -> + when (result) { + is UMethod -> result.uastBody ?: result + is UClass -> + result.methods + .filterIsInstance() + .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.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.as32 new file mode 100644 index 00000000000..2130def4799 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinULabeledExpression.kt.as32 @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import org.jetbrains.kotlin.psi.KtLabeledExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.ULabeledExpression + +class KotlinULabeledExpression( + override val psi: KtLabeledExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), ULabeledExpression { + override val label: String + get() = psi.getLabelName().orAnonymous("label") + + override val labelIdentifier: UIdentifier? + get() = psi.getTargetLabel()?.let { UIdentifier(it, this) } + + override val expression by lz { KotlinConverter.convertOrEmpty(psi.baseExpression, this) } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt.as32 new file mode 100644 index 00000000000..21c1459699f --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt.as32 @@ -0,0 +1,100 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiType +import org.jetbrains.kotlin.psi.ValueArgument +import org.jetbrains.uast.* + +class KotlinUNamedExpression private constructor( + override val name: String?, + override val sourcePsi: PsiElement?, + givenParent: UElement?, + expressionProducer: (UElement) -> UExpression +) : KotlinAbstractUElement(givenParent), UNamedExpression { + + override val expression: UExpression by lz { expressionProducer(this) } + + override val annotations: List = emptyList() + + override val psi: PsiElement? = null + + override val javaPsi: PsiElement? = null + + companion object { + internal fun create(name: String?, valueArgument: ValueArgument, uastParent: UElement?): UNamedExpression { + val expression = valueArgument.getArgumentExpression() + return KotlinUNamedExpression(name, valueArgument.asElement(), uastParent) { expressionParent -> + expression?.let { expressionParent.getLanguagePlugin().convert(it, expressionParent) } ?: UastEmptyExpression + } + } + + internal fun create( + name: String?, + valueArguments: List, + uastParent: UElement?): UNamedExpression { + return KotlinUNamedExpression(name, null, uastParent) { expressionParent -> + KotlinUVarargExpression(valueArguments, expressionParent) + } + } + } +} +class KotlinUVarargExpression(private val valueArgs: List, + uastParent: UElement?) : KotlinAbstractUExpression(uastParent), UCallExpression { + override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER + + override val valueArguments: List by lz { + valueArgs.map { + it.getArgumentExpression()?.let { argumentExpression -> + getLanguagePlugin().convert(argumentExpression, this) + } ?: UastEmptyExpression + } + } + + override val valueArgumentCount: Int + get() = valueArgs.size + + override val psi: PsiElement? + get() = null + + override val methodIdentifier: UIdentifier? + get() = null + + override val classReference: UReferenceExpression? + get() = null + + override val methodName: String? + get() = null + + override val typeArgumentCount: Int + get() = 0 + + override val typeArguments: List + get() = emptyList() + + override val returnType: PsiType? + get() = null + + override fun resolve() = null + + override val receiver: UExpression? + get() = null + + override val receiverType: PsiType? + get() = null +} diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt.as32 new file mode 100644 index 00000000000..b65009c9809 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt.as32 @@ -0,0 +1,97 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.openapi.diagnostic.Attachment +import com.intellij.openapi.diagnostic.Logger +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiType +import com.intellij.psi.impl.light.LightPsiClassBuilder +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.psi.KtObjectLiteralExpression +import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry +import org.jetbrains.uast.* + +class KotlinUObjectLiteralExpression( + override val psi: KtObjectLiteralExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UObjectLiteralExpression, KotlinUElementWithType { + override val declaration: UClass by lz { + val lightClass: KtLightClass? = psi.objectDeclaration.toLightClass() + if (lightClass != null) { + getLanguagePlugin().convert(lightClass, this) + } + else { + logger.error( + "Failed to create light class for object declaration", + Attachment(psi.containingFile.virtualFile?.path ?: "", psi.containingFile.text)) + + getLanguagePlugin().convert(LightPsiClassBuilder(psi, ""), this) + } + } + + override fun getExpressionType() = psi.objectDeclaration.toPsiType() + + private val superClassConstructorCall by lz { + psi.objectDeclaration.superTypeListEntries.firstOrNull { it is KtSuperTypeCallEntry } as? KtSuperTypeCallEntry + } + + override val classReference: UReferenceExpression? by lz { superClassConstructorCall?.let { ObjectLiteralClassReference(it, this) } } + + override val valueArgumentCount: Int + get() = superClassConstructorCall?.valueArguments?.size ?: 0 + + override val valueArguments by lz { + val psi = superClassConstructorCall ?: return@lz emptyList() + psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) } + } + + override val typeArgumentCount: Int + get() = superClassConstructorCall?.typeArguments?.size ?: 0 + + override val typeArguments by lz { + val psi = superClassConstructorCall ?: return@lz emptyList() + psi.typeArguments.map { it.typeReference.toPsiType(this, boxed = true) } + } + + override fun resolve() = superClassConstructorCall?.resolveCallToDeclaration(this) as? PsiMethod + + private class ObjectLiteralClassReference( + override val psi: KtSuperTypeCallEntry, + givenParent: UElement? + ) : KotlinAbstractUElement(givenParent), USimpleNameReferenceExpression { + + override val javaPsi = null + override val sourcePsi = psi + + override fun resolve() = (psi.resolveCallToDeclaration(this) as? PsiMethod)?.containingClass + + override val annotations: List + get() = emptyList() + + override val resolvedName: String? + get() = identifier + + override val identifier: String + get() = psi.name ?: "" + } + + companion object { + val logger by lz { Logger.getInstance(KotlinUObjectLiteralExpression::class.java) } + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.as32 new file mode 100644 index 00000000000..5e6963bb4fc --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt.as32 @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiMethod +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtPostfixExpression +import org.jetbrains.uast.* + +class KotlinUPostfixExpression( + override val psi: KtPostfixExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UPostfixExpression, KotlinUElementWithType, KotlinEvaluatableUElement, UResolvable { + override val operand by lz { KotlinConverter.convertOrEmpty(psi.baseExpression, this) } + + override val operator = when (psi.operationToken) { + KtTokens.PLUSPLUS -> UastPostfixOperator.INC + KtTokens.MINUSMINUS -> UastPostfixOperator.DEC + KtTokens.EXCLEXCL -> KotlinPostfixOperators.EXCLEXCL + else -> UastPostfixOperator.UNKNOWN + } + + override val operatorIdentifier: UIdentifier? + get() = UIdentifier(psi.operationReference, this) + + override fun resolveOperator() = psi.operationReference.resolveCallToDeclaration(context = this) as? PsiMethod + + override fun resolve(): PsiMethod? = when (psi.operationToken) { + KtTokens.EXCLEXCL -> operand.tryResolve() as? PsiMethod + else -> null + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.as32 new file mode 100644 index 00000000000..af7d2f999d3 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPrefixExpression.kt.as32 @@ -0,0 +1,46 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiMethod +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtPrefixExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UPrefixExpression +import org.jetbrains.uast.UastPrefixOperator + +class KotlinUPrefixExpression( + override val psi: KtPrefixExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UPrefixExpression, KotlinUElementWithType, KotlinEvaluatableUElement { + override val operand by lz { KotlinConverter.convertOrEmpty(psi.baseExpression, this) } + + override val operatorIdentifier: UIdentifier? + get() = UIdentifier(psi.operationReference, this) + + override fun resolveOperator() = psi.operationReference.resolveCallToDeclaration(context = this) as? PsiMethod + + override val operator = when (psi.operationToken) { + KtTokens.EXCL -> UastPrefixOperator.LOGICAL_NOT + KtTokens.PLUS -> UastPrefixOperator.UNARY_PLUS + KtTokens.MINUS -> UastPrefixOperator.UNARY_MINUS + KtTokens.PLUSPLUS -> UastPrefixOperator.INC + KtTokens.MINUSMINUS -> UastPrefixOperator.DEC + else -> UastPrefixOperator.UNKNOWN + } +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.as32 new file mode 100644 index 00000000000..e3f258a99e6 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt.as32 @@ -0,0 +1,220 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiNamedElement +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor +import org.jetbrains.kotlin.utils.addToStdlib.constant +import org.jetbrains.uast.* +import org.jetbrains.uast.visitor.UastVisitor + +open class KotlinUSimpleReferenceExpression( + override val psi: KtSimpleNameExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType, KotlinEvaluatableUElement { + private val resolvedDeclaration by lz { psi.resolveCallToDeclaration(this) } + + override val identifier get() = psi.getReferencedName() + + override fun resolve() = resolvedDeclaration + + override val resolvedName: String? + get() = (resolvedDeclaration as? PsiNamedElement)?.name + + override fun accept(visitor: UastVisitor) { + visitor.visitSimpleNameReferenceExpression(this) + + if (psi.parent.destructuringDeclarationInitializer != true) { + visitAccessorCalls(visitor) + } + + visitor.afterVisitSimpleNameReferenceExpression(this) + } + + private fun visitAccessorCalls(visitor: UastVisitor) { + // Visit Kotlin get-set synthetic Java property calls as function calls + val bindingContext = psi.analyze() + val access = psi.readWriteAccess() + val resolvedCall = psi.getResolvedCall(bindingContext) + val resultingDescriptor = resolvedCall?.resultingDescriptor as? SyntheticJavaPropertyDescriptor + if (resultingDescriptor != null) { + val setterValue = if (access.isWrite) { + findAssignment(psi, psi.parent)?.right ?: run { + visitor.afterVisitSimpleNameReferenceExpression(this) + return + } + } else { + null + } + + if (resolvedCall != null) { + if (access.isRead) { + val getDescriptor = resultingDescriptor.getMethod + KotlinAccessorCallExpression(psi, this, resolvedCall, getDescriptor, null).accept(visitor) + } + + if (access.isWrite && setterValue != null) { + val setDescriptor = resultingDescriptor.setMethod + if (setDescriptor != null) { + KotlinAccessorCallExpression(psi, this, resolvedCall, setDescriptor, setterValue).accept(visitor) + } + } + } + } + } + + private tailrec fun findAssignment(prev: PsiElement?, element: PsiElement?): KtBinaryExpression? = when (element) { + is KtBinaryExpression -> if (element.left == prev && element.operationToken == KtTokens.EQ) element else null + is KtQualifiedExpression -> findAssignment(element, element.parent) + is KtSimpleNameExpression -> findAssignment(element, element.parent) + else -> null + } + + class KotlinAccessorCallExpression( + override val psi: KtElement, + override val uastParent: KotlinUSimpleReferenceExpression, + private val resolvedCall: ResolvedCall<*>, + private val accessorDescriptor: DeclarationDescriptor, + val setterValue: KtExpression? + ) : UCallExpression, 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() = UIdentifier(uastParent.psi, this) + + override val classReference: UReferenceExpression? + get() = null + + override val valueArgumentCount: Int + get() = if (setterValue != null) 1 else 0 + + override val valueArguments by lz { + if (setterValue != null) + listOf(KotlinConverter.convertOrEmpty(setterValue, this)) + else + emptyList() + } + + override val typeArgumentCount: Int + get() = resolvedCall.typeArguments.size + + override val typeArguments by lz { + resolvedCall.typeArguments.values.map { it.toPsiType(this, psi, true) } + } + + override val returnType by lz { + (accessorDescriptor as? CallableDescriptor)?.returnType?.toPsiType(this, psi, boxed = false) + } + + override val kind: UastCallKind + get() = UastCallKind.METHOD_CALL + + override fun resolve(): PsiMethod? { + val source = accessorDescriptor.toSource() + return KotlinUFunctionCallExpression.resolveSource(accessorDescriptor, source) + } + } + + enum class ReferenceAccess(val isRead: Boolean, val isWrite: Boolean) { + READ(true, false), WRITE(false, true), READ_WRITE(true, true) + } + + private fun KtExpression.readWriteAccess(): ReferenceAccess { + var expression = getQualifiedExpressionForSelectorOrThis() + loop@ while (true) { + val parent = expression.parent + when (parent) { + is KtParenthesizedExpression, is KtAnnotatedExpression, is KtLabeledExpression -> expression = parent as KtExpression + else -> break@loop + } + } + + val assignment = expression.getAssignmentByLHS() + if (assignment != null) { + return when (assignment.operationToken) { + KtTokens.EQ -> ReferenceAccess.WRITE + else -> ReferenceAccess.READ_WRITE + } + } + + return if ((expression.parent as? KtUnaryExpression)?.operationToken + in constant { setOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) }) + ReferenceAccess.READ_WRITE + else + ReferenceAccess.READ + } +} + +class KotlinClassViaConstructorUSimpleReferenceExpression( + override val psi: KtCallElement, + override val identifier: String, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression, KotlinUElementWithType { + override val resolvedName: String? + get() = (psi.getResolvedCall(psi.analyze())?.resultingDescriptor as? ConstructorDescriptor) + ?.containingDeclaration?.name?.asString() + + override fun resolve(): PsiElement? { + val resolvedCall = psi.getResolvedCall(psi.analyze()) + val resultingDescriptor = resolvedCall?.resultingDescriptor as? ConstructorDescriptor ?: return null + val clazz = resultingDescriptor.containingDeclaration + return clazz.toSource()?.getMaybeLightElement(this) + } +} + +class KotlinStringUSimpleReferenceExpression( + override val identifier: String, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USimpleNameReferenceExpression { + override val psi: PsiElement? + get() = null + override fun resolve() = null + override val resolvedName: String? + get() = identifier +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.as32 new file mode 100644 index 00000000000..b87476a1f9b --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt.as32 @@ -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.KtSuperExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.USuperExpression + +class KotlinUSuperExpression( + override val psi: KtSuperExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USuperExpression, KotlinUElementWithType, KotlinEvaluatableUElement { + override val label: String? + get() = psi.getLabelName() + + override val labelIdentifier: UIdentifier? + get() = psi.getTargetLabel()?.let { UIdentifier(it, this) } + + override fun resolve() = psi.analyze()[BindingContext.LABEL_TARGET, psi.getTargetLabel()] +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.as32 new file mode 100644 index 00000000000..4fecbaeb828 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSwitchExpression.kt.as32 @@ -0,0 +1,93 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.KtWhenEntry +import org.jetbrains.kotlin.psi.KtWhenExpression +import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.kinds.KotlinSpecialExpressionKinds + +class KotlinUSwitchExpression( + override val psi: KtWhenExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USwitchExpression, KotlinUElementWithType { + override val expression by lz { KotlinConverter.convertOrNull(psi.subjectExpression, this) } + + override val body: UExpressionList by lz { + object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN, this@KotlinUSwitchExpression) { + override fun asRenderString() = expressions.joinToString("\n") { it.asRenderString().withMargin } + }.apply { + expressions = this@KotlinUSwitchExpression.psi.entries.map { KotlinUSwitchEntry(it, this) } + } + } + + override fun asRenderString() = buildString { + val expr = expression?.let { "(" + it.asRenderString() + ") " } ?: "" + appendln("switch $expr {") + appendln(body.asRenderString()) + appendln("}") + } + + override val switchIdentifier: UIdentifier + get() = UIdentifier(null, this) +} + +class KotlinUSwitchEntry( + override val psi: KtWhenEntry, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), USwitchClauseExpressionWithBody { + override val caseValues by lz { + psi.conditions.map { KotlinConverter.convertWhenCondition(it, this) ?: UastEmptyExpression } + } + + override val body: UExpressionList by lz { + object : KotlinUExpressionList(psi, KotlinSpecialExpressionKinds.WHEN_ENTRY, this@KotlinUSwitchEntry) { + override fun asRenderString() = buildString { + appendln("{") + expressions.forEach { appendln(it.asRenderString().withMargin) } + appendln("}") + } + }.apply { + val exprPsi = this@KotlinUSwitchEntry.psi.expression + val userExpressions = when (exprPsi) { + is KtBlockExpression -> exprPsi.statements.map { KotlinConverter.convertOrEmpty(it, this) } + else -> listOf(KotlinConverter.convertOrEmpty(exprPsi, this)) + } + expressions = userExpressions + object : UBreakExpression, 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.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.as32 new file mode 100644 index 00000000000..ca81276a4db --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.as32 @@ -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.KtThisExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UThisExpression + +class KotlinUThisExpression( + override val psi: KtThisExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UThisExpression, KotlinUElementWithType, KotlinEvaluatableUElement { + override val label: String? + get() = psi.getLabelName() + + override val labelIdentifier: UIdentifier? + get() = psi.getTargetLabel()?.let { UIdentifier(it, this) } + + override fun resolve() = psi.analyze()[BindingContext.LABEL_TARGET, psi.getTargetLabel()] +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.as32 new file mode 100644 index 00000000000..544ea9db537 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUTryExpression.kt.as32 @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import org.jetbrains.kotlin.psi.KtTryExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UTryExpression +import org.jetbrains.uast.UVariable + +class KotlinUTryExpression( + override val psi: KtTryExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UTryExpression, KotlinUElementWithType { + override val tryClause by lz { KotlinConverter.convertOrEmpty(psi.tryBlock, this) } + override val catchClauses by lz { psi.catchClauses.map { KotlinUCatchClause(it, this) } } + override val finallyClause by lz { psi.finallyBlock?.finalExpression?.let { KotlinConverter.convertExpression(it, this) } } + + override val resourceVariables: List + get() = emptyList() + + override val hasResources: Boolean + get() = false + + override val tryIdentifier: UIdentifier + get() = UIdentifier(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.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.as32 new file mode 100644 index 00000000000..2032dfa4210 --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUWhileExpression.kt.as32 @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import org.jetbrains.kotlin.psi.KtWhileExpression +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UIdentifier +import org.jetbrains.uast.UWhileExpression + +class KotlinUWhileExpression( + override val psi: KtWhileExpression, + givenParent: UElement? +) : KotlinAbstractUExpression(givenParent), UWhileExpression { + override val condition by lz { KotlinConverter.convertOrEmpty(psi.condition, this) } + override val body by lz { KotlinConverter.convertOrEmpty(psi.body, this) } + + override val whileIdentifier: UIdentifier + get() = UIdentifier(null, this) +} \ No newline at end of file diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt.173.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt.as32 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt.as32 new file mode 100644 index 00000000000..93aa080ecdc --- /dev/null +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinInternalUastUtils.kt.as32 @@ -0,0 +1,213 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.kotlin + +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.util.Key +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiPrimitiveType +import com.intellij.psi.PsiType +import com.intellij.psi.impl.cache.TypeInfo +import com.intellij.psi.impl.compiled.ClsTypeElementImpl +import com.intellij.psi.impl.compiled.SignatureParsing +import com.intellij.psi.impl.compiled.StubBuildingVisitor +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.PsiTypesUtil +import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass +import org.jetbrains.kotlin.asJava.toLightClass +import org.jetbrains.kotlin.asJava.toLightElements +import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype +import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.isError +import org.jetbrains.kotlin.types.typeUtil.isInterface +import org.jetbrains.uast.* +import java.lang.ref.WeakReference +import java.text.StringCharacterIterator + +internal val KOTLIN_CACHED_UELEMENT_KEY = Key.create>("cached-kotlin-uelement") + +@Suppress("NOTHING_TO_INLINE") +internal inline fun String?.orAnonymous(kind: String = ""): String = this ?: "" + +internal fun DeclarationDescriptor.toSource(): PsiElement? { + return try { + DescriptorToSourceUtils.getEffectiveReferencedDescriptors(this) + .asSequence() + .mapNotNull { DescriptorToSourceUtils.getSourceFromDescriptor(it) } + .firstOrNull() + } + catch (e: Exception) { + Logger.getInstance("DeclarationDescriptor.toSource").error(e) + null + } +} + +internal fun lz(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE, initializer) + +internal fun KotlinType.toPsiType(source: UElement, element: KtElement, boxed: Boolean): PsiType { + if (this.isError) return UastErrorType + + (constructor.declarationDescriptor as? TypeAliasDescriptor)?.let { typeAlias -> + return typeAlias.expandedType.toPsiType(source, element, boxed) + } + + if (arguments.isEmpty()) { + val typeFqName = this.constructor.declarationDescriptor?.fqNameSafe?.asString() + fun PsiPrimitiveType.orBoxed() = if (boxed) getBoxedType(element) else this + val psiType = when (typeFqName) { + "kotlin.Int" -> PsiType.INT.orBoxed() + "kotlin.Long" -> PsiType.LONG.orBoxed() + "kotlin.Short" -> PsiType.SHORT.orBoxed() + "kotlin.Boolean" -> PsiType.BOOLEAN.orBoxed() + "kotlin.Byte" -> PsiType.BYTE.orBoxed() + "kotlin.Char" -> PsiType.CHAR.orBoxed() + "kotlin.Double" -> PsiType.DOUBLE.orBoxed() + "kotlin.Float" -> PsiType.FLOAT.orBoxed() + "kotlin.String" -> PsiType.getJavaLangString(element.manager, GlobalSearchScope.projectScope(element.project)) + else -> { + val typeConstructor = this.constructor + if (typeConstructor is IntegerValueTypeConstructor) { + typeConstructor.supertypes.first().toPsiType(source, element, boxed) + } else { + null + } + } + } + if (psiType != null) return psiType + } + + if (this.containsLocalTypes()) return UastErrorType + + val project = element.project + val typeMapper = ServiceManager.getService(project, KotlinUastBindingContextProviderService::class.java) + .getTypeMapper(element) ?: return UastErrorType + + val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE) + val typeMappingMode = if (boxed) TypeMappingMode.GENERIC_ARGUMENT else TypeMappingMode.DEFAULT + typeMapper.mapType(this, signatureWriter, typeMappingMode) + + val signature = StringCharacterIterator(signatureWriter.toString()) + + val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER) + val typeInfo = TypeInfo.fromString(javaType, false) + val typeText = TypeInfo.createTypeText(typeInfo) ?: return UastErrorType + + return ClsTypeElementImpl(source.getParentOfType(false)?.psi ?: element, typeText, '\u0000').type +} + +private fun KotlinType.containsLocalTypes(): Boolean { + val typeDeclarationDescriptor = this.constructor.declarationDescriptor + if (typeDeclarationDescriptor is ClassDescriptor && DescriptorUtils.isLocal(typeDeclarationDescriptor)) { + return true + } + + return arguments.any { !it.isStarProjection && it.type.containsLocalTypes() } +} + +internal fun KtTypeReference?.toPsiType(source: UElement, boxed: Boolean = false): PsiType { + if (this == null) return UastErrorType + return (analyze()[BindingContext.TYPE, this] ?: return UastErrorType).toPsiType(source, this, boxed) +} + +internal fun KtClassOrObject.toPsiType(): PsiType { + val lightClass = toLightClass() ?: return UastErrorType + return PsiTypesUtil.getClassType(lightClass) +} + +internal fun PsiElement.getMaybeLightElement(context: UElement): PsiElement? { + return when (this) { + is KtVariableDeclaration -> { + val lightElement = toLightElements().firstOrNull() + if (lightElement != null) return lightElement + + val languagePlugin = context.getLanguagePlugin() + val uElement = languagePlugin.convertElementWithParent(this, null) + when (uElement) { + is UDeclaration -> uElement.psi + is UDeclarationsExpression -> uElement.declarations.firstOrNull()?.psi + else -> null + } + } + is KtDeclaration -> toLightElements().firstOrNull() + is KtElement -> null + else -> this + } +} + +internal fun KtElement.resolveCallToDeclaration( + context: KotlinAbstractUElement, + resultingDescriptor: DeclarationDescriptor? = null +): PsiElement? { + val descriptor = resultingDescriptor ?: run { + val resolvedCall = getResolvedCall(analyze()) ?: return null + resolvedCall.resultingDescriptor + } + + return descriptor.toSource()?.getMaybeLightElement(context) +} + +internal fun KtExpression.unwrapBlockOrParenthesis(): KtExpression { + val innerExpression = KtPsiUtil.safeDeparenthesize(this) + if (innerExpression is KtBlockExpression) { + val statement = innerExpression.statements.singleOrNull() ?: return this + return KtPsiUtil.safeDeparenthesize(statement) + } + return innerExpression +} + +internal fun KtElement.analyze(): BindingContext { + if(containingFile !is KtFile) return BindingContext.EMPTY // EA-114080, EA-113475 + return ServiceManager.getService(project, KotlinUastBindingContextProviderService::class.java) + ?.getBindingContext(this) ?: BindingContext.EMPTY +} + +internal inline fun unwrap(element: P): P { + val unwrapped = if (element is T) element.psi else element + assert(unwrapped !is UElement) + return unwrapped as P +} + +internal fun KtExpression.getExpectedType(): KotlinType? = analyze()[BindingContext.EXPECTED_EXPRESSION_TYPE, this] + +internal fun KtTypeReference.getType(): KotlinType? = analyze()[BindingContext.TYPE, this] + +internal fun KotlinType.getFunctionalInterfaceType(source: UElement, element: KtElement): PsiType? = + takeIf { it.isInterface() && !it.isBuiltinFunctionalTypeOrSubtype }?.toPsiType(source, element, false) + +internal fun KotlinULambdaExpression.getFunctionalInterfaceType(): PsiType? { + val parent = psi.parent + return when(parent) { + is KtBinaryExpressionWithTypeRHS -> parent.right?.getType()?.getFunctionalInterfaceType(this, psi) + else -> psi.getExpectedType()?.getFunctionalInterfaceType(this, psi) + } +} + +internal fun unwrapFakeFileForLightClass(file: PsiFile): PsiFile = (file as? FakeFileForLightClass)?.ktFile ?: file diff --git a/plugins/uast-kotlin/testData/Anonymous.identifiers.txt.as32 b/plugins/uast-kotlin/testData/Anonymous.identifiers.txt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/ClassAnnotation.identifiers.txt.as32 b/plugins/uast-kotlin/testData/ClassAnnotation.identifiers.txt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/Constructors.identifiers.txt.as32 b/plugins/uast-kotlin/testData/Constructors.identifiers.txt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.identifiers.txt.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.identifiers.txt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.kt.173.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.kt.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.kt.as32 new file mode 100644 index 00000000000..ff45265e296 --- /dev/null +++ b/plugins/uast-kotlin/testData/LocalDeclarations.kt.as32 @@ -0,0 +1,12 @@ +fun foo(): Boolean { + class Local + fun bar() = Local() + + val baz = fun() { + Local() + } + + fun Int.someLocalFun(text: String) = 42 + + return bar() == Local() +} \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.log.txt.173.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.log.txt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.log.txt.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.log.txt.as32 new file mode 100644 index 00000000000..26480d28ca7 --- /dev/null +++ b/plugins/uast-kotlin/testData/LocalDeclarations.log.txt.as32 @@ -0,0 +1,34 @@ +UFile (package = ) + UClass (name = LocalDeclarationsKt) + UAnnotationMethod (name = foo) + UBlockExpression + UDeclarationsExpression + UClass (name = Local) + UAnnotationMethod (name = LocalDeclarationsKt$foo$Local) + UDeclarationsExpression + UVariable (name = bar) + ULambdaExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier (Local)) + USimpleNameReferenceExpression (identifier = ) + UDeclarationsExpression + ULocalVariable (name = baz) + ULambdaExpression + UBlockExpression + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier (Local)) + USimpleNameReferenceExpression (identifier = ) + UDeclarationsExpression + UVariable (name = someLocalFun) + ULambdaExpression + UParameter (name = text) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + ULiteralExpression (value = 42) + UReturnExpression + UBinaryExpression (operator = ==) + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) + UIdentifier (Identifier (bar)) + USimpleNameReferenceExpression (identifier = bar) + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) + UIdentifier (Identifier (Local)) + USimpleNameReferenceExpression (identifier = ) diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.render.txt.173.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.render.txt.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt.as32 new file mode 100644 index 00000000000..b287c0bb920 --- /dev/null +++ b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt.as32 @@ -0,0 +1,17 @@ +public final class LocalDeclarationsKt { + public static final fun foo() : boolean { + public static final class Local { + public fun LocalDeclarationsKt$foo$Local() = UastEmptyExpression + } + var bar: = fun () { + () + } + var baz: kotlin.jvm.functions.Function0 = fun () { + () + } + var someLocalFun: kotlin.jvm.functions.Function2 = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) { + 42 + } + return bar() == () + } +} diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.types.txt.173.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.types.txt.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt.as32 new file mode 100644 index 00000000000..8310b9965b3 --- /dev/null +++ b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt.as32 @@ -0,0 +1,34 @@ +UFile (package = ) [public final class LocalDeclarationsKt {...] + UClass (name = LocalDeclarationsKt) [public final class LocalDeclarationsKt {...}] + UAnnotationMethod (name = foo) [public static final fun foo() : boolean {...}] + UBlockExpression [{...}] : PsiType:Void + UDeclarationsExpression [public static final class Local {...}] + UClass (name = Local) [public static final class Local {...}] + UAnnotationMethod (name = LocalDeclarationsKt$foo$Local) [public fun LocalDeclarationsKt$foo$Local() = UastEmptyExpression] + UDeclarationsExpression [var bar: = fun () {...}] + UVariable (name = bar) [var bar: = fun () {...}] + ULambdaExpression [fun () {...}] + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] : PsiType: + UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] + USimpleNameReferenceExpression (identifier = ) [] : PsiType: + UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0 = fun () {...}] + ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0 = fun () {...}] + ULambdaExpression [fun () {...}] + UBlockExpression [{...}] : PsiType: + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] : PsiType: + UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] + USimpleNameReferenceExpression (identifier = ) [] : PsiType: + UDeclarationsExpression [var someLocalFun: kotlin.jvm.functions.Function2 = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] + UVariable (name = someLocalFun) [var someLocalFun: kotlin.jvm.functions.Function2 = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] + ULambdaExpression [fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] + UParameter (name = text) [@org.jetbrains.annotations.NotNull var text: java.lang.String] + UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] + ULiteralExpression (value = 42) [42] : PsiType:int + UReturnExpression [return bar() == ()] : PsiType:Void + UBinaryExpression (operator = ==) [bar() == ()] : PsiType:boolean + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) [bar()] : PsiType: + UIdentifier (Identifier (bar)) [UIdentifier (Identifier (bar))] + USimpleNameReferenceExpression (identifier = bar) [bar] : PsiType: + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] : PsiType: + UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] + USimpleNameReferenceExpression (identifier = ) [] : PsiType: diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.values.txt.173.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.values.txt.as32 b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt.as32 new file mode 100644 index 00000000000..69f4beabfb2 --- /dev/null +++ b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt.as32 @@ -0,0 +1,34 @@ +UFile (package = ) [public final class LocalDeclarationsKt {...] + UClass (name = LocalDeclarationsKt) [public final class LocalDeclarationsKt {...}] + UAnnotationMethod (name = foo) [public static final fun foo() : boolean {...}] + UBlockExpression [{...}] = Nothing + UDeclarationsExpression [public static final class Local {...}] = Undetermined + UClass (name = Local) [public static final class Local {...}] + UAnnotationMethod (name = LocalDeclarationsKt$foo$Local) [public fun LocalDeclarationsKt$foo$Local() = UastEmptyExpression] + UDeclarationsExpression [var bar: = fun () {...}] = Undetermined + UVariable (name = bar) [var bar: = fun () {...}] + ULambdaExpression [fun () {...}] = Undetermined + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] = external ()() + UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] + USimpleNameReferenceExpression (identifier = ) [] = external ()() + UDeclarationsExpression [var baz: kotlin.jvm.functions.Function0 = fun () {...}] = Undetermined + ULocalVariable (name = baz) [var baz: kotlin.jvm.functions.Function0 = fun () {...}] + ULambdaExpression [fun () {...}] = Undetermined + UBlockExpression [{...}] = external ()() + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] = external ()() + UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] + USimpleNameReferenceExpression (identifier = ) [] = external ()() + UDeclarationsExpression [var someLocalFun: kotlin.jvm.functions.Function2 = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] = Undetermined + UVariable (name = someLocalFun) [var someLocalFun: kotlin.jvm.functions.Function2 = fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] + ULambdaExpression [fun (@org.jetbrains.annotations.NotNull var text: java.lang.String) {...}] = Undetermined + UParameter (name = text) [@org.jetbrains.annotations.NotNull var text: java.lang.String] + UAnnotation (fqName = org.jetbrains.annotations.NotNull) [@org.jetbrains.annotations.NotNull] + ULiteralExpression (value = 42) [42] = 42 + UReturnExpression [return bar() == ()] = Nothing + UBinaryExpression (operator = ==) [bar() == ()] = Undetermined + UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) [bar()] = external bar()() + UIdentifier (Identifier (bar)) [UIdentifier (Identifier (bar))] + USimpleNameReferenceExpression (identifier = bar) [bar] = external bar()() + UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] = external ()() + UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] + USimpleNameReferenceExpression (identifier = ) [] = external ()() diff --git a/plugins/uast-kotlin/testData/ParametersDisorder.kt.as32 b/plugins/uast-kotlin/testData/ParametersDisorder.kt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/ParametersDisorder.log.txt.as32 b/plugins/uast-kotlin/testData/ParametersDisorder.log.txt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/ParametersDisorder.render.txt.as32 b/plugins/uast-kotlin/testData/ParametersDisorder.render.txt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/SimpleAnnotated.identifiers.txt.as32 b/plugins/uast-kotlin/testData/SimpleAnnotated.identifiers.txt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/SimpleAnnotated.kt.173.as32 b/plugins/uast-kotlin/testData/SimpleAnnotated.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/testData/SimpleAnnotated.kt.as32 b/plugins/uast-kotlin/testData/SimpleAnnotated.kt.as32 new file mode 100644 index 00000000000..b0742abd2f4 --- /dev/null +++ b/plugins/uast-kotlin/testData/SimpleAnnotated.kt.as32 @@ -0,0 +1,9 @@ +class SimpleAnnotated { + @Suppress("abc") + fun method() { + println("Hello, world!") + } + + @SinceKotlin("1.0") + val property: String = "Mary" +} \ No newline at end of file diff --git a/plugins/uast-kotlin/tests/AbstractKotlinIdentifiersTest.kt.as32 b/plugins/uast-kotlin/tests/AbstractKotlinIdentifiersTest.kt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt.173.as32 b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt.as32 b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt.as32 new file mode 100644 index 00000000000..f0fd8111308 --- /dev/null +++ b/plugins/uast-kotlin/tests/AbstractKotlinRenderLogTest.kt.as32 @@ -0,0 +1,134 @@ +package org.jetbrains.uast.test.kotlin + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiRecursiveElementVisitor +import com.intellij.psi.impl.source.tree.LeafPsiElement +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.utils.addToStdlib.assertedCast +import org.jetbrains.uast.JvmDeclarationUElement +import org.jetbrains.uast.UDeclaration +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UFile +import org.jetbrains.uast.kotlin.KOTLIN_CACHED_UELEMENT_KEY +import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin +import org.jetbrains.uast.test.common.RenderLogTestBase +import org.jetbrains.uast.visitor.UastVisitor +import org.junit.Assert +import java.io.File +import java.util.* + +abstract class AbstractKotlinRenderLogTest : AbstractKotlinUastTest(), RenderLogTestBase { + override fun getTestFile(testName: String, ext: String) = + File(File(TEST_KOTLIN_MODEL_DIR, testName).canonicalPath + '.' + ext) + + override fun check(testName: String, file: UFile) { + check(testName, file, true) + } + + fun check(testName: String, file: UFile, checkParentConsistency: Boolean) { + super.check(testName, file) + + if (checkParentConsistency) { + checkParentConsistency(file) + } + + file.checkContainingFileForAllElements() + file.checkJvmDeclarationsImplementations() + } + + private fun checkParentConsistency(file: UFile) { + val parentMap = mutableMapOf() + + file.accept(object : UastVisitor { + private val parentStack = Stack() + + override fun visitElement(node: UElement): Boolean { + val parent = node.uastParent + if (parent == null) { + Assert.assertTrue("Wrong parent of $node", parentStack.empty()) + } + else { + Assert.assertEquals("Wrong parent of $node", parentStack.peek(), parent) + } + node.psi?.let { + if (it !in parentMap) { + parentMap[it] = parentStack.reversed().joinToString { it.asLogString() } + } + } + parentStack.push(node) + return false + } + + override fun afterVisitElement(node: UElement) { + super.afterVisitElement(node) + parentStack.pop() + } + }) + + file.psi.clearUastCaches() + + file.psi.accept(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + val uElement = KotlinUastLanguagePlugin().convertElementWithParent(element, null) + val expectedParents = parentMap[element] + if (expectedParents != null) { + assertNotNull("Expected to be able to convert PSI element $element", uElement) + val parents = generateSequence(uElement!!.uastParent) { it.uastParent }.joinToString { it.asLogString() } + assertEquals("Inconsistent parents for ${uElement.asRenderString()}(${uElement.asLogString()})(${uElement.javaClass}) (converted from $element[${element.text}])", expectedParents, parents) + } + super.visitElement(element) + } + }) + } + + private fun UFile.checkContainingFileForAllElements() { + accept(object : UastVisitor { + override fun visitElement(node: UElement): Boolean { + if (node is PsiElement) { + node.containingFile.assertedCast { "containingFile should be KtFile for ${node.asLogString()}" } + } + + val anchorPsi = (node as? UDeclaration)?.uastAnchor?.psi + if (anchorPsi != null) { + anchorPsi.containingFile.assertedCast { "uastAnchor.containingFile should be KtFile for ${node.asLogString()}" } + } + + return false + } + }) + } + + private fun UFile.checkJvmDeclarationsImplementations() { + accept(object : UastVisitor { + override fun visitElement(node: UElement): Boolean { + + val jvmDeclaration = node as? JvmDeclarationUElement + ?: throw AssertionError("${node.javaClass} should implement 'JvmDeclarationUElement'") + + jvmDeclaration.sourcePsi?.let { + assertTrue("sourcePsi should be physical but ${it.javaClass} found for [${it.text}] " + + "for ${jvmDeclaration.javaClass}->${jvmDeclaration.uastParent?.javaClass}", + it is KtElement || it is LeafPsiElement + ) + } + jvmDeclaration.javaPsi?.let { + assertTrue("javaPsi should be light but ${it.javaClass} found for [${it.text}] " + + "for ${jvmDeclaration.javaClass}->${jvmDeclaration.uastParent?.javaClass}", it !is KtElement) + } + + return false + } + }) + } +} + +private fun PsiFile.clearUastCaches() { + accept(object : PsiRecursiveElementVisitor() { + override fun visitElement(element: PsiElement) { + super.visitElement(element) + element.putUserData(KOTLIN_CACHED_UELEMENT_KEY, null) + } + }) +} diff --git a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.173.as32 b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.as32 b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.as32 new file mode 100644 index 00000000000..4e673d38b1a --- /dev/null +++ b/plugins/uast-kotlin/tests/KotlinUastApiTest.kt.as32 @@ -0,0 +1,312 @@ +package org.jetbrains.uast.test.kotlin + +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiModifier +import com.intellij.testFramework.UsefulTestCase +import org.jetbrains.kotlin.asJava.toLightAnnotation +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType +import org.jetbrains.kotlin.psi.psiUtil.getValueParameterList +import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase +import org.jetbrains.kotlin.utils.addToStdlib.cast +import org.jetbrains.uast.* +import org.jetbrains.uast.kotlin.KotlinUastLanguagePlugin +import org.jetbrains.uast.test.env.findElementByText +import org.jetbrains.uast.test.env.findElementByTextFromPsi +import org.jetbrains.uast.visitor.AbstractUastVisitor +import org.junit.Assert +import org.junit.Test + + +class KotlinUastApiTest : AbstractKotlinUastTest() { + override fun check(testName: String, file: UFile) { + } + + @Test fun testAnnotationParameters() { + doTest("AnnotationParameters") { _, file -> + val annotation = file.findElementByText("@IntRange(from = 10, to = 0)") + assertEquals(annotation.findAttributeValue("from")?.evaluate(), 10) + val toAttribute = annotation.findAttributeValue("to")!! + assertEquals(toAttribute.evaluate(), 0) + KtUsefulTestCase.assertInstanceOf(annotation.psi.toUElement(), UAnnotation::class.java) + KtUsefulTestCase.assertInstanceOf( + annotation.psi.cast().toLightAnnotation().toUElement(), + UAnnotation::class.java + ) + KtUsefulTestCase.assertInstanceOf(toAttribute.uastParent, UNamedExpression::class.java) + KtUsefulTestCase.assertInstanceOf(toAttribute.psi.toUElement()?.uastParent, UNamedExpression::class.java) + } + } + + @Test fun testConvertStringTemplate() { + doTest("StringTemplateInClass") { _, file -> + val literalExpression = file.findElementByText("lorem") + val psi = literalExpression.psi!! + Assert.assertTrue(psi is KtLiteralStringTemplateEntry) + val literalExpressionAgain = psi.toUElement() + Assert.assertTrue(literalExpressionAgain is ULiteralExpression) + + } + } + + @Test fun testConvertStringTemplateWithExpectedType() { + doTest("StringTemplateWithVar") { _, file -> + val index = file.psi.text.indexOf("foo") + val stringTemplate = file.psi.findElementAt(index)!!.getParentOfType(false) + val uLiteral = stringTemplate.toUElementOfType() + assertNull(uLiteral) + } + } + + @Test fun testNameContainingFile() { + doTest("NameContainingFile") { _, file -> + val foo = file.findElementByText("class Foo") + assertEquals(file.psi, foo.nameIdentifier!!.containingFile) + + val bar = file.findElementByText("fun bar() {}") + assertEquals(file.psi, bar.nameIdentifier!!.containingFile) + + val xyzzy = file.findElementByText("val xyzzy: Int = 0") + assertEquals(file.psi, xyzzy.nameIdentifier!!.containingFile) + } + } + + @Test fun testInterfaceMethodWithBody() { + doTest("DefaultImpls") { _, file -> + val bar = file.findElementByText("fun bar() = \"Hello!\"") + assertFalse(bar.containingFile.text!!, bar.psi.modifierList.hasExplicitModifier(PsiModifier.DEFAULT)) + assertTrue(bar.containingFile.text!!, bar.psi.modifierList.hasModifierProperty(PsiModifier.DEFAULT)) + } + } + + @Test fun testSAM() { + doTest("SAM") { _, file -> + assertNull(file.findElementByText("{ /* Not SAM */ }").functionalInterfaceType) + + assertEquals("java.lang.Runnable", + file.findElementByText("{/* Variable */}").functionalInterfaceType?.canonicalText) + + assertEquals("java.lang.Runnable", + file.findElementByText("{/* Assignment */}").functionalInterfaceType?.canonicalText) + + assertEquals("java.lang.Runnable", + file.findElementByText("{/* Type Cast */}").functionalInterfaceType?.canonicalText) + + assertEquals("java.lang.Runnable", + file.findElementByText("{/* Argument */}").functionalInterfaceType?.canonicalText) + + assertEquals("java.lang.Runnable", + file.findElementByText("{/* Return */}").functionalInterfaceType?.canonicalText) + } + } + + @Test fun testParameterPropertyWithAnnotation() { + doTest("ParameterPropertyWithAnnotation") { _, file -> + val test1 = file.classes.find { it.name == "Test1" }!! + + val constructor1 = test1.methods.find { it.name == "Test1" }!! + assertTrue(constructor1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" }) + + val getter1 = test1.methods.find { it.name == "getBar" }!! + assertFalse(getter1.annotations.any { it.qualifiedName == "MyAnnotation" }) + + val setter1 = test1.methods.find { it.name == "setBar" }!! + assertFalse(setter1.annotations.any { it.qualifiedName == "MyAnnotation" }) + assertFalse(setter1.uastParameters.first().annotations.any { it.qualifiedName == "MyAnnotation" }) + + + val test2 = file.classes.find { it.name == "Test2" }!! + val constructor2 = test2.methods.find { it.name == "Test2" }!! + assertFalse(constructor2.uastParameters.first().annotations.any { it.qualifiedName?.startsWith("MyAnnotation") ?: false }) + + val getter2 = test2.methods.find { it.name == "getBar" }!! + getter2.annotations.single { it.qualifiedName == "MyAnnotation" } + + val setter2 = test2.methods.find { it.name == "setBar" }!! + setter2.annotations.single { it.qualifiedName == "MyAnnotation2" } + setter2.uastParameters.first().annotations.single { it.qualifiedName == "MyAnnotation3" } + + test2.fields.find { it.name == "bar" }!!.annotations.single { it.qualifiedName == "MyAnnotation5" } + } + } + + @Test fun testConvertTypeInAnnotation() { + doTest("TypeInAnnotation") { _, file -> + val index = file.psi.text.indexOf("Test") + val element = file.psi.findElementAt(index)!!.getParentOfType(false)!! + assertNotNull(element.getUastParentOfType(UAnnotation::class.java)) + } + } + + @Test fun testElvisType() { + doTest("ElvisType") { _, file -> + val elvisExpression = file.findElementByText("text ?: return") + assertEquals("String", elvisExpression.getExpressionType()!!.presentableText) + } + } + + @Test fun testFindAttributeDefaultValue() { + doTest("AnnotationParameters") { _, file -> + val witDefaultValue = file.findElementByText("@WithDefaultValue") + assertEquals(42, witDefaultValue.findAttributeValue("value")!!.evaluate()) + assertEquals(42, witDefaultValue.findAttributeValue(null)!!.evaluate()) + } + } + + @Test fun testIfCondition() { + doTest("IfStatement") { _, file -> + val psiFile = file.psi + val element = psiFile.findElementAt(psiFile.text.indexOf("\"abc\""))!! + val binaryExpression = element.getParentOfType(false)!! + val uBinaryExpression = KotlinUastLanguagePlugin().convertElementWithParent(binaryExpression, null)!! + UsefulTestCase.assertInstanceOf(uBinaryExpression.uastParent, UIfExpression::class.java) + } + } + + @Test + fun testWhenStringLiteral() { + doTest("WhenStringLiteral") { _, file -> + + file.findElementByTextFromPsi("abc").let { literalExpression -> + val psi = literalExpression.psi!! + Assert.assertTrue(psi is KtLiteralStringTemplateEntry) + UsefulTestCase.assertInstanceOf(literalExpression.uastParent, USwitchClauseExpressionWithBody::class.java) + } + + file.findElementByTextFromPsi("def").let { literalExpression -> + val psi = literalExpression.psi!! + Assert.assertTrue(psi is KtLiteralStringTemplateEntry) + UsefulTestCase.assertInstanceOf(literalExpression.uastParent, USwitchClauseExpressionWithBody::class.java) + } + + file.findElementByTextFromPsi("def1").let { literalExpression -> + val psi = literalExpression.psi!! + Assert.assertTrue(psi is KtLiteralStringTemplateEntry) + UsefulTestCase.assertInstanceOf(literalExpression.uastParent, UBlockExpression::class.java) + } + + + } + } + + @Test + fun testWhenAndDestructing() { + doTest("WhenAndDestructing") { _, file -> + + file.findElementByTextFromPsi("val (bindingContext, statementFilter) = arr").let { e -> + val uBlockExpression = e.getParentOfType() + Assert.assertNotNull(uBlockExpression) + val uMethod = uBlockExpression!!.getParentOfType() + Assert.assertNotNull(uMethod) + } + + } + } + + @Test + fun testBrokenMethodTypeResolve() { + doTest("BrokenMethod") { _, file -> + + file.accept(object : AbstractUastVisitor() { + override fun visitCallExpression(node: UCallExpression): Boolean { + node.returnType + return false + } + }) + } + } + + @Test + fun testSimpleAnnotated() { + doTest("SimpleAnnotated") { _, file -> + file.findElementByTextFromPsi("@SinceKotlin(\"1.0\")\n val property: String = \"Mary\"").let { field -> + val annotation = field.annotations.assertedFind("kotlin.SinceKotlin") { it.qualifiedName } + Assert.assertEquals(annotation.findDeclaredAttributeValue("version")?.evaluateString(), "1.0") + } + } + } + + + fun UFile.checkUastSuperTypes(refText: String, superTypes: List) { + findElementByTextFromPsi(refText, false).let { + assertEquals("base classes", superTypes, it.uastSuperTypes.map { it.getQualifiedName() }) + } + } + + + @Test + fun testSuperTypes() { + doTest("SuperCalls") { _, file -> + file.checkUastSuperTypes("B", listOf("A")) + file.checkUastSuperTypes("O", listOf("A")) + file.checkUastSuperTypes("innerObject ", listOf("A")) + file.checkUastSuperTypes("InnerClass", listOf("A")) + file.checkUastSuperTypes("object : A(\"textForAnon\")", listOf("A")) + } + } + + @Test + fun testAnonymousSuperTypes() { + doTest("Anonymous") { _, file -> + file.checkUastSuperTypes("object : Runnable { override fun run() {} }", listOf("java.lang.Runnable")) + file.checkUastSuperTypes( + "object : Runnable, Closeable { override fun close() {} override fun run() {} }", + listOf("java.lang.Runnable", "java.io.Closeable") + ) + file.checkUastSuperTypes( + "object : InputStream(), Runnable { override fun read(): Int = 0; override fun run() {} }", + listOf("java.io.InputStream", "java.lang.Runnable") + ) + } + } + + @Test + fun testLiteralArraysTypes() { + doTest("AnnotationParameters") { _, file -> + file.findElementByTextFromPsi("intArrayOf(1, 2, 3)").let { field -> + Assert.assertEquals("PsiType:int[]", field.returnType.toString()) + } + file.findElementByTextFromPsi("[1, 2, 3]").let { field -> + Assert.assertEquals("PsiType:int[]", field.returnType.toString()) + Assert.assertEquals("PsiType:int", field.typeArguments.single().toString()) + } + file.findElementByTextFromPsi("[\"a\", \"b\", \"c\"]").let { field -> + Assert.assertEquals("PsiType:String[]", field.returnType.toString()) + Assert.assertEquals("PsiType:String", field.typeArguments.single().toString()) + } + + } + } + + @Test + fun testTypeAliases() { + doTest("TypeAliases") { _, file -> + val g = (file.psi as KtFile).declarations.single { it.name == "G" } as KtTypeAlias + val originalType = g.getTypeReference()!!.typeElement as KtFunctionType + val originalTypeParameters = originalType.parameterList.toUElement() as UDeclarationsExpression + Assert.assertTrue((originalTypeParameters.declarations.single() as UParameter).type.isValid) + } + } + + @Test + fun testNestedAnnotation() = doTest("AnnotationComplex") { _, file -> + file.findElementByTextFromPsi("@AnnotationArray(value = Annotation())") + .findElementByTextFromPsi("Annotation()") + .sourcePsiElement + .let { referenceExpression -> + val convertedUAnnotation = referenceExpression + .cast() + .toUElementOfType() + ?: throw AssertionError("haven't got annotation from $referenceExpression(${referenceExpression?.javaClass})") + + assertEquals("Annotation", convertedUAnnotation.qualifiedName) + val lightAnnotation = convertedUAnnotation.getAsJavaPsiElement(PsiAnnotation::class.java) + ?: throw AssertionError("can't get lightAnnotation from $convertedUAnnotation") + assertEquals("Annotation", lightAnnotation.qualifiedName) + } + } + + +} + +fun Iterable.assertedFind(value: R, transform: (T) -> R): T = find { transform(it) == value } ?: throw AssertionError("'$value' not found, only ${this.joinToString { transform(it).toString() }}") diff --git a/plugins/uast-kotlin/tests/KotlinUastIdentifiersTest.kt.as32 b/plugins/uast-kotlin/tests/KotlinUastIdentifiersTest.kt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.173.as32 b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.as32 b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.as32 new file mode 100644 index 00000000000..217297a5a3a --- /dev/null +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt.as32 @@ -0,0 +1,78 @@ +package org.jetbrains.uast.test.kotlin + +import org.junit.Test + +class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { + @Test fun testLocalDeclarations() = doTest("LocalDeclarations") + + @Test fun testSimple() = doTest("Simple") + + @Test fun testWhenIs() = doTest("WhenIs") + + @Test fun testDefaultImpls() = doTest("DefaultImpls") + + @Test fun testElvis() = doTest("Elvis") + + @Test fun testPropertyAccessors() = doTest("PropertyAccessors") + + @Test fun testPropertyInitializer() = doTest("PropertyInitializer") + + @Test fun testPropertyInitializerWithoutSetter() = doTest("PropertyInitializerWithoutSetter") + + @Test fun testAnnotationParameters() = doTest("AnnotationParameters") + + @Test fun testEnumValueMembers() = doTest("EnumValueMembers") + + @Test fun testStringTemplate() = doTest("StringTemplate") + + @Test fun testStringTemplateComplex() = doTest("StringTemplateComplex") + + @Test fun testQualifiedConstructorCall() = doTest("QualifiedConstructorCall") + + @Test fun testPropertyDelegate() = doTest("PropertyDelegate") { testName, file -> check(testName, file, false) } + + @Test fun testLocalVariableWithAnnotation() = doTest("LocalVariableWithAnnotation") + + @Test fun testPropertyWithAnnotation() = doTest("PropertyWithAnnotation") + + @Test fun testIfStatement() = doTest("IfStatement") + + @Test fun testInnerClasses() = doTest("InnerClasses") + + @Test fun testSimpleScript() = doTest("SimpleScript") { testName, file -> check(testName, file, false) } + + @Test fun testDestructuringDeclaration() = doTest("DestructuringDeclaration") + + @Test fun testDefaultParameterValues() = doTest("DefaultParameterValues") + + @Test fun testParameterPropertyWithAnnotation() = doTest("ParameterPropertyWithAnnotation") + + @Test fun testParametersWithDefaultValues() = doTest("ParametersWithDefaultValues") + + @Test + fun testUnexpectedContainer() = doTest("UnexpectedContainerException") + + @Test + fun testWhenStringLiteral() = doTest("WhenStringLiteral") + + @Test + fun testWhenAndDestructing() = doTest("WhenAndDestructing") { testName, file -> check(testName, file, false) } + + @Test + fun testSuperCalls() = doTest("SuperCalls") + + @Test + fun testConstructors() = doTest("Constructors") + + @Test + fun testClassAnnotation() = doTest("ClassAnnotation") + + @Test + fun testReceiverFun() = doTest("ReceiverFun") + + @Test + fun testAnonymous() = doTest("Anonymous") + + @Test + fun testAnnotationComplex() = doTest("AnnotationComplex") +} diff --git a/plugins/uast-kotlin/tests/org/jetbrains/uast/test/common/IdentifiersTestBase.kt.as32 b/plugins/uast-kotlin/tests/org/jetbrains/uast/test/common/IdentifiersTestBase.kt.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/tests/org/jetbrains/uast/test/env/AbstractUastTest.kt.173.as32 b/plugins/uast-kotlin/tests/org/jetbrains/uast/test/env/AbstractUastTest.kt.173.as32 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/plugins/uast-kotlin/tests/org/jetbrains/uast/test/env/AbstractUastTest.kt.as32 b/plugins/uast-kotlin/tests/org/jetbrains/uast/test/env/AbstractUastTest.kt.as32 new file mode 100644 index 00000000000..1d9a80c77fb --- /dev/null +++ b/plugins/uast-kotlin/tests/org/jetbrains/uast/test/env/AbstractUastTest.kt.as32 @@ -0,0 +1,82 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.uast.test.env + +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf +import org.jetbrains.uast.UElement +import org.jetbrains.uast.UFile +import org.jetbrains.uast.toUElementOfType +import org.jetbrains.uast.visitor.UastVisitor +import java.io.File +import kotlin.test.fail + +abstract class AbstractUastTest : AbstractTestWithCoreEnvironment() { + protected companion object { + val TEST_DATA_DIR = File("testData") + } + + abstract fun getVirtualFile(testName: String): VirtualFile + abstract fun check(testName: String, file: UFile) + + fun doTest(testName: String, checkCallback: (String, UFile) -> Unit = { testName, file -> check(testName, file) }) { + val virtualFile = getVirtualFile(testName) + + val psiFile = psiManager.findFile(virtualFile) ?: error("Can't get psi file for $testName") + val uFile = uastContext.convertElementWithParent(psiFile, null) ?: error("Can't get UFile for $testName") + checkCallback(testName, uFile as UFile) + } +} + +fun UElement.findElementByText(refText: String, cls: Class): T { + val matchingElements = mutableListOf() + accept(object : UastVisitor { + override fun visitElement(node: UElement): Boolean { + if (cls.isInstance(node) && node.psi?.text == refText) { + matchingElements.add(node as T) + } + return false + } + }) + + if (matchingElements.isEmpty()) { + throw IllegalArgumentException("Reference '$refText' not found") + } + if (matchingElements.size != 1) { + throw IllegalArgumentException("Reference '$refText' is ambiguous") + } + return matchingElements.single() +} + +inline fun UElement.findElementByText(refText: String): T = findElementByText(refText, T::class.java) + +inline fun UElement.findElementByTextFromPsi(refText: String, strict: Boolean = true): T = + (this.psi ?: fail("no psi for $this")).findUElementByTextFromPsi(refText, strict) + +inline fun PsiElement.findUElementByTextFromPsi(refText: String, strict: Boolean = true): T { + val elementAtStart = this.findElementAt(this.text.indexOf(refText)) + ?: throw AssertionError("requested text '$refText' was not found in $this") + val uElementContainingText = elementAtStart.parentsWithSelf.let { + if (strict) it.dropWhile { !it.text.contains(refText) } else it + }.mapNotNull { it.toUElementOfType() }.firstOrNull() + ?: throw AssertionError("requested text '$refText' not found as '${T::class.java.canonicalName}' in $this") + if (strict && uElementContainingText.psi != null && uElementContainingText.psi?.text != refText) { + throw AssertionError("requested text '$refText' found as '${uElementContainingText.psi?.text}' in $uElementContainingText") + } + return uElementContainingText; +}