?): 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 {
+ val parent = original.parent
+ if (parent is KtLambdaExpression) {
+ KotlinULambdaExpression(parent, givenParent) // your parent is the ULambdaExpression
+ } else if (original.name.isNullOrEmpty()) {
+ 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 { KotlinUNestedAnnotation.tryCreate(original, givenParent) }
+ } 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)
+ is KtTypeElement -> unwrapElements(element.parent)
+ else -> element
+ }
+
+ private val identifiersTokens =
+ setOf(KtTokens.IDENTIFIER, KtTokens.CONSTRUCTOR_KEYWORD, KtTokens.THIS_KEYWORD, KtTokens.SUPER_KEYWORD, KtTokens.OBJECT_KEYWORD)
+
+ 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 KtLightElementBase -> {
+ val expression = element.kotlinOrigin
+ when (expression) {
+ is KtExpression -> KotlinConverter.convertExpression(expression, givenParent, requiredType)
+ else -> el { UastEmptyExpression(givenParent) }
+ }
+ }
+ 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 in identifiersTokens)
+ if (element.elementType != KtTokens.OBJECT_KEYWORD || element.getParentOfType(false)?.nameIdentifier == null)
+ el(build(::KotlinUIdentifier))
+ else null
+ else if (element.elementType in KtTokens.OPERATIONS && element.parent is KtOperationReferenceExpression)
+ el(build(::KotlinUIdentifier))
+ else if (element.elementType == KtTokens.LBRACKET && element.parent is KtCollectionLiteralExpression)
+ el {
+ UIdentifier(
+ element,
+ KotlinUCollectionLiteralExpression(
+ element.parent as KtCollectionLiteralExpression,
+ null
+ )
+ )
+ }
+ else null
+ } else null
+ }
+ }}
+ }
+
+
+ internal fun convertEntry(entry: KtStringTemplateEntry,
+ givenParent: UElement?,
+ requiredType: Class? = null): UExpression? {
+ return with(requiredType) {
+ if (entry is KtStringTemplateEntryWithExpression) {
+ expr {
+ KotlinConverter.convertOrEmpty(entry.expression, givenParent)
+ }
+ }
+ else {
+ expr {
+ if (entry is KtEscapeStringTemplateEntry)
+ KotlinStringULiteralExpression(entry, givenParent, entry.unescapedValue)
+ else
+ KotlinStringULiteralExpression(entry, givenParent)
+ }
+ }
+ }
+ }
+
+ internal fun convertExpression(expression: KtExpression,
+ givenParent: UElement?,
+ requiredType: Class? = null): UExpression? {
+ fun build(ctor: (P, UElement?) -> UExpression): () -> UExpression? {
+ return { ctor(expression as P, givenParent) }
+ }
+
+ return with (requiredType) { when (expression) {
+ is KtVariableDeclaration -> expr(build(::convertVariablesDeclaration))
+
+ is KtStringTemplateExpression -> {
+ when {
+ expression.entries.isEmpty() -> {
+ expr { KotlinStringULiteralExpression(expression, givenParent, "") }
+ }
+ expression.entries.size == 1 -> convertEntry(expression.entries[0], givenParent, requiredType)
+ else -> {
+ expr { KotlinStringTemplateUPolyadicExpression(expression, givenParent) }
+ }
+ }
+ }
+ is KtDestructuringDeclaration -> expr {
+ val declarationsExpression = KotlinUDestructuringDeclarationExpression(givenParent, expression)
+ declarationsExpression.apply {
+ val tempAssignment = KotlinULocalVariable(UastKotlinPsiVariable.create(expression, declarationsExpression), expression, declarationsExpression)
+ val destructuringAssignments = expression.entries.mapIndexed { i, entry ->
+ val psiFactory = KtPsiFactory(expression.project)
+ val initializer = psiFactory.createAnalyzableExpression("${tempAssignment.name}.component${i + 1}()",
+ expression.containingFile)
+ initializer.destructuringDeclarationInitializer = true
+ KotlinULocalVariable(UastKotlinPsiVariable.create(entry, tempAssignment.psi, declarationsExpression, initializer), entry, declarationsExpression)
+ }
+ declarations = listOf(tempAssignment) + destructuringAssignments
+ }
+ }
+ is KtLabeledExpression -> expr(build(::KotlinULabeledExpression))
+ is KtClassLiteralExpression -> expr(build(::KotlinUClassLiteralExpression))
+ is KtObjectLiteralExpression -> expr(build(::KotlinUObjectLiteralExpression))
+ is KtDotQualifiedExpression -> expr(build(::KotlinUQualifiedReferenceExpression))
+ is KtSafeQualifiedExpression -> expr(build(::KotlinUSafeQualifiedExpression))
+ is KtSimpleNameExpression -> expr(build(::KotlinUSimpleReferenceExpression))
+ is KtCallExpression -> expr(build(::KotlinUFunctionCallExpression))
+ is KtCollectionLiteralExpression -> expr(build(::KotlinUCollectionLiteralExpression))
+ is KtBinaryExpression -> {
+ if (expression.operationToken == KtTokens.ELVIS) {
+ expr(build(::createElvisExpression))
+ }
+ else expr(build(::KotlinUBinaryExpression))
+ }
+ is KtParenthesizedExpression -> expr(build(::KotlinUParenthesizedExpression))
+ is KtPrefixExpression -> expr(build(::KotlinUPrefixExpression))
+ is KtPostfixExpression -> expr(build(::KotlinUPostfixExpression))
+ is KtThisExpression -> expr(build(::KotlinUThisExpression))
+ is KtSuperExpression -> expr(build(::KotlinUSuperExpression))
+ is KtCallableReferenceExpression -> expr(build(::KotlinUCallableReferenceExpression))
+ is KtIsExpression -> expr(build(::KotlinUTypeCheckExpression))
+ is KtIfExpression -> expr(build(::KotlinUIfExpression))
+ is KtWhileExpression -> expr(build(::KotlinUWhileExpression))
+ is KtDoWhileExpression -> expr(build(::KotlinUDoWhileExpression))
+ is KtForExpression -> expr(build(::KotlinUForEachExpression))
+ is KtWhenExpression -> expr(build(::KotlinUSwitchExpression))
+ is KtBreakExpression -> expr(build(::KotlinUBreakExpression))
+ is KtContinueExpression -> expr(build(::KotlinUContinueExpression))
+ is KtReturnExpression -> expr(build(::KotlinUReturnExpression))
+ is KtThrowExpression -> expr(build(::KotlinUThrowExpression))
+ is KtBlockExpression -> expr(build(::KotlinUBlockExpression))
+ is KtConstantExpression -> expr(build(::KotlinULiteralExpression))
+ is KtTryExpression -> expr(build(::KotlinUTryExpression))
+ is KtArrayAccessExpression -> expr(build(::KotlinUArrayAccessExpression))
+ is KtLambdaExpression -> expr(build(::KotlinULambdaExpression))
+ is KtBinaryExpressionWithTypeRHS -> expr(build(::KotlinUBinaryExpressionWithType))
+ is KtClassOrObject -> expr {
+ expression.toLightClass()?.let { lightClass ->
+ KotlinUDeclarationsExpression(givenParent).apply {
+ declarations = listOf(KotlinUClass.create(lightClass, this))
+ }
+ } ?: UastEmptyExpression
+ }
+ is KtFunction -> if (expression.name.isNullOrEmpty()) {
+ expr(build(::createLocalFunctionLambdaExpression))
+ }
+ else {
+ expr(build(::createLocalFunctionDeclaration))
+ }
+
+ else -> expr(build(::UnknownKotlinExpression))
+ }}
+ }
+
+ internal fun convertWhenCondition(condition: KtWhenCondition,
+ givenParent: UElement?,
+ requiredType: Class? = null): UExpression? {
+ return with(requiredType) {
+ when (condition) {
+ is KtWhenConditionInRange -> expr {
+ KotlinCustomUBinaryExpression(condition, givenParent).apply {
+ leftOperand = KotlinStringUSimpleReferenceExpression("it", this)
+ operator = when {
+ condition.isNegated -> KotlinBinaryOperators.NOT_IN
+ else -> KotlinBinaryOperators.IN
+ }
+ rightOperand = KotlinConverter.convertOrEmpty(condition.rangeExpression, this)
+ }
+ }
+ is KtWhenConditionIsPattern -> expr {
+ KotlinCustomUBinaryExpressionWithType(condition, givenParent).apply {
+ operand = KotlinStringUSimpleReferenceExpression("it", this)
+ operationKind = when {
+ condition.isNegated -> KotlinBinaryExpressionWithTypeKinds.NEGATED_INSTANCE_CHECK
+ else -> UastBinaryExpressionWithTypeKind.INSTANCE_CHECK
+ }
+ val typeRef = condition.typeReference
+ typeReference = typeRef?.let {
+ LazyKotlinUTypeReferenceExpression(it, this) { typeRef.toPsiType(this, boxed = true) }
+ }
+ }
+ }
+
+ is KtWhenConditionWithExpression ->
+ condition.expression?.let { KotlinConverter.convertExpression(it, givenParent, requiredType) }
+
+ else -> expr { UastEmptyExpression }
+ }
+ }
+ }
+
+ internal fun convertOrEmpty(expression: KtExpression?, parent: UElement?): UExpression {
+ return expression?.let { convertExpression(it, parent, null) } ?: UastEmptyExpression
+ }
+
+ internal fun convertOrNull(expression: KtExpression?, parent: UElement?): UExpression? {
+ return if (expression != null) convertExpression(expression, parent, null) else null
+ }
+
+ internal fun KtPsiFactory.createAnalyzableExpression(text: String, context: PsiElement): KtExpression =
+ createAnalyzableProperty("val x = $text", context).initializer ?: error("Failed to create expression from text: '$text'")
+
+ internal fun KtPsiFactory.createAnalyzableProperty(text: String, context: PsiElement): KtProperty =
+ createAnalyzableDeclaration(text, context)
+
+ internal fun KtPsiFactory.createAnalyzableDeclaration(text: String, context: PsiElement): TDeclaration {
+ val file = createAnalyzableFile("dummy.kt", text, context)
+ val declarations = file.declarations
+ assert(declarations.size == 1) { "${declarations.size} declarations in $text" }
+ return declarations.first() as TDeclaration
+ }
+}
+
+private fun convertVariablesDeclaration(
+ psi: KtVariableDeclaration,
+ parent: UElement?
+): UDeclarationsExpression {
+ val declarationsExpression = parent as? KotlinUDeclarationsExpression
+ ?: psi.parent.toUElementOfType() as? KotlinUDeclarationsExpression
+ ?: 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.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt.183
new file mode 100644
index 00000000000..8beae165279
--- /dev/null
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUAnnotation.kt.183
@@ -0,0 +1,165 @@
+package org.jetbrains.uast.kotlin
+
+import com.intellij.psi.PsiAnnotation
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiElement
+import com.intellij.psi.ResolveResult
+import org.jetbrains.kotlin.asJava.toLightAnnotation
+import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.ClassKind
+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.KotlinUIdentifier
+import org.jetbrains.uast.kotlin.declarations.KotlinUMethod
+import org.jetbrains.uast.kotlin.internal.multiResolveResults
+
+abstract class KotlinUAnnotationBase(
+ final override val sourcePsi: T,
+ givenParent: UElement?
+) : KotlinAbstractUElement(givenParent), UAnnotationEx, UAnchorOwner, UMultiResolvable {
+
+ abstract override val javaPsi: PsiAnnotation?
+
+ final override val psi: PsiElement = sourcePsi
+
+ protected abstract fun annotationUseSiteTarget(): AnnotationUseSiteTarget?
+
+ private val resolvedCall: ResolvedCall<*>? get () = sourcePsi.getResolvedCall(sourcePsi.analyze())
+
+ override val qualifiedName: String? by lz {
+ computeClassDescriptor().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 fun computeClassDescriptor(): ClassDescriptor?
+
+ override fun resolve(): PsiClass? = computeClassDescriptor()?.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 = computeClassDescriptor()
+ ?.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
+ }
+
+ override fun multiResolve(): Iterable = sourcePsi.multiResolveResults().asIterable()
+}
+
+class KotlinUAnnotation(
+ annotationEntry: KtAnnotationEntry,
+ givenParent: UElement?
+) : KotlinUAnnotationBase(annotationEntry, givenParent), UAnnotation {
+
+ override val javaPsi = annotationEntry.toLightAnnotation()
+
+ override fun computeClassDescriptor(): ClassDescriptor? =
+ sourcePsi.analyze()[BindingContext.ANNOTATION, sourcePsi]?.annotationClass
+
+ override fun annotationUseSiteTarget() = sourcePsi.useSiteTarget?.getAnnotationUseSiteTarget()
+
+ override val uastAnchor by lazy {
+ KotlinUIdentifier(
+ javaPsi?.nameReferenceElement,
+ annotationEntry.typeReference?.typeElement?.let {
+ (it as? KtUserType)?.referenceExpression?.getReferencedNameElement() ?: it.navigationElement
+ },
+ this
+ )
+ }
+
+}
+
+class KotlinUNestedAnnotation private constructor(
+ original: KtCallExpression,
+ givenParent: UElement?
+) : KotlinUAnnotationBase(original, givenParent) {
+ override val javaPsi: PsiAnnotation? by lazy { original.toLightAnnotation() }
+
+ override fun computeClassDescriptor(): ClassDescriptor? = classDescriptor(sourcePsi)
+
+ override fun annotationUseSiteTarget(): AnnotationUseSiteTarget? = null
+
+ override val uastAnchor by lazy {
+ KotlinUIdentifier(
+ javaPsi?.nameReferenceElement?.referenceNameElement,
+ (original.calleeExpression as? KtNameReferenceExpression)?.getReferencedNameElement(),
+ this
+ )
+ }
+
+ companion object {
+ fun tryCreate(original: KtCallExpression, givenParent: UElement?): KotlinUNestedAnnotation? {
+ if (classDescriptor(original)?.kind == ClassKind.ANNOTATION_CLASS)
+ return KotlinUNestedAnnotation(original, givenParent)
+ else
+ return null
+ }
+
+ private fun classDescriptor(original: KtCallExpression) =
+ (original.getResolvedCall(original.analyze())?.resultingDescriptor as? ClassConstructorDescriptor)?.constructedClass
+ }
+
+}
+
+
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUImportStatement.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUImportStatement.kt
index f78e2529739..fd8b911b262 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUImportStatement.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUImportStatement.kt
@@ -25,11 +25,12 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.uast.UElement
import org.jetbrains.uast.UImportStatement
import org.jetbrains.uast.USimpleNameReferenceExpression
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUImportStatement(
override val psi: KtImportDirective,
givenParent: UElement?
-) : KotlinAbstractUElement(givenParent), UImportStatement {
+) : KotlinAbstractUElement(givenParent), UImportStatement, DelegatedMultiResolve {
override val javaPsi = null
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt
index fae24c8c8d2..0f00ced650a 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/declarations/KotlinUVariable.kt
@@ -35,6 +35,7 @@ import org.jetbrains.uast.*
import org.jetbrains.uast.internal.acceptList
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
import org.jetbrains.uast.kotlin.declarations.UastLightIdentifier
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiParameter
import org.jetbrains.uast.kotlin.psi.UastKotlinPsiVariable
import org.jetbrains.uast.visitor.UastVisitor
@@ -113,6 +114,7 @@ abstract class AbstractKotlinUVariable(givenParent: UElement?) : KotlinAbstractU
override fun equals(other: Any?) = other is AbstractKotlinUVariable && psi == other.psi
class WrappedUAnnotation(psiAnnotation: PsiAnnotation, override val uastParent: UElement) : UAnnotation, UAnchorOwner,
+ DelegatedMultiResolve,
JvmDeclarationUElementPlaceholder {
override val javaPsi: PsiAnnotation = psiAnnotation
@@ -234,7 +236,7 @@ class KotlinReceiverUParameter(
}
class KotlinNullabilityUAnnotation(val annotatedElement: PsiElement, override val uastParent: UElement) : UAnnotationEx, UAnchorOwner,
- JvmDeclarationUElementPlaceholder {
+ DelegatedMultiResolve, JvmDeclarationUElementPlaceholder {
private fun getTargetType(annotatedElement: PsiElement): KotlinType? {
if (annotatedElement is KtTypeReference) {
@@ -380,7 +382,7 @@ class KotlinUEnumConstant(
psi: PsiEnumConstant,
override val sourcePsi: KtElement?,
givenParent: UElement?
-) : AbstractKotlinUVariable(givenParent), UEnumConstant, UCallExpressionEx, PsiEnumConstant by psi {
+) : AbstractKotlinUVariable(givenParent), UEnumConstant, UCallExpressionEx, DelegatedMultiResolve, PsiEnumConstant by psi {
override val initializingClass: UClass? by lz {
(psi.initializingClass as? KtLightClass)?.let { initializingClass ->
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt.183
new file mode 100644
index 00000000000..c0c89a33c91
--- /dev/null
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCallableReferenceExpression.kt.183
@@ -0,0 +1,55 @@
+/*
+ * 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.PsiNamedElement
+import com.intellij.psi.ResolveResult
+import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
+import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
+import org.jetbrains.uast.UCallableReferenceExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.UMultiResolvable
+import org.jetbrains.uast.kotlin.internal.getResolveResultVariants
+
+class KotlinUCallableReferenceExpression(
+ override val psi: KtCallableReferenceExpression,
+ givenParent: UElement?
+) : KotlinAbstractUExpression(givenParent), UCallableReferenceExpression, UMultiResolvable, KotlinUElementWithType {
+ override val qualifierExpression: UExpression?
+ get() {
+ if (qualifierType != null) return null
+ val receiverExpression = psi.receiverExpression ?: return null
+ return KotlinConverter.convertExpression(receiverExpression, this)
+ }
+
+ override val qualifierType by lz {
+ val ktType = psi.analyze()[DOUBLE_COLON_LHS, psi.receiverExpression]?.type ?: return@lz null
+ ktType.toPsiType(this, psi, boxed = true)
+ }
+
+ override val callableName: String
+ get() = psi.callableReference.getReferencedName()
+
+ override val resolvedName: String?
+ get() = (resolve() as? PsiNamedElement)?.name
+
+ override fun resolve() = psi.callableReference.resolveCallToDeclaration(this)
+
+ override fun multiResolve(): Iterable = getResolveResultVariants(psi.callableReference)
+
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt
index f0d59284ab6..2571e0c350c 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUCollectionLiteralExpression.kt
@@ -14,11 +14,12 @@ import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.KotlinAbstractUExpression
import org.jetbrains.uast.kotlin.KotlinConverter
import org.jetbrains.uast.kotlin.KotlinUElementWithType
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUCollectionLiteralExpression(
override val sourcePsi: KtCollectionLiteralExpression,
givenParent: UElement?
-) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, KotlinUElementWithType {
+) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, DelegatedMultiResolve, KotlinUElementWithType {
override val classReference: UReferenceExpression? get() = null
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.183
new file mode 100644
index 00000000000..389285b4a81
--- /dev/null
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUFunctionCallExpression.kt.183
@@ -0,0 +1,248 @@
+/*
+ * 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.util.registry.Registry
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiNamedElement
+import com.intellij.psi.PsiType
+import com.intellij.psi.util.PsiTypesUtil
+import org.jetbrains.kotlin.asJava.toLightClass
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.jetbrains.kotlin.psi.*
+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.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
+import org.jetbrains.kotlin.utils.addToStdlib.safeAs
+import org.jetbrains.uast.*
+import org.jetbrains.uast.internal.acceptList
+import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
+import org.jetbrains.uast.kotlin.internal.TypedResolveResult
+import org.jetbrains.uast.kotlin.internal.getReferenceVariants
+import org.jetbrains.uast.kotlin.internal.multiResolveResults
+import org.jetbrains.uast.visitor.UastVisitor
+
+class KotlinUFunctionCallExpression(
+ override val psi: KtCallElement,
+ givenParent: UElement?,
+ private val _resolvedCall: ResolvedCall<*>?
+) : KotlinAbstractUExpression(givenParent), UCallExpressionEx, KotlinUElementWithType, UMultiResolvable {
+
+ constructor(psi: KtCallElement, uastParent: UElement?) : this(psi, uastParent, null)
+
+ private val resolvedCall
+ get() = _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
+ when (calleeExpression) {
+ null -> null
+ is KtNameReferenceExpression ->
+ KotlinUIdentifier(calleeExpression.getReferencedNameElement(), this)
+ is KtConstructorDelegationReferenceExpression ->
+ KotlinUIdentifier(calleeExpression.firstChild ?: calleeExpression, this)
+ is KtConstructorCalleeExpression ->
+ KotlinUIdentifier(
+ calleeExpression.constructorReferenceExpression?.getReferencedNameElement() ?: calleeExpression, this
+ )
+ else -> KotlinUIdentifier(calleeExpression, this)
+ }
+ }
+
+ override val valueArgumentCount: Int
+ get() = psi.valueArguments.size
+
+ override val valueArguments by lz { psi.valueArguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), this) } }
+
+ override fun getArgumentForParameter(i: Int): UExpression? {
+ val resolvedCall = resolvedCall
+ if (resolvedCall != null) {
+ val actualParamIndex = if (resolvedCall.extensionReceiver == null) i else i - 1
+ if (actualParamIndex == -1) return receiver
+ return getArgumentExpressionByIndex(actualParamIndex, resolvedCall, this)
+ }
+ val argument = valueArguments.getOrNull(i) ?: return null
+ val argumentType = argument.getExpressionType()
+ for (resolveResult in multiResolve()) {
+ val psiMethod = resolveResult.element as? PsiMethod ?: continue
+ val psiParameter = psiMethod.parameterList.parameters.getOrNull(i) ?: continue
+
+ if (argumentType == null || psiParameter.type.isAssignableFrom(argumentType))
+ return argument
+ }
+ return null
+ }
+
+ override fun getExpressionType(): PsiType? {
+ super.getExpressionType()?.let { return it }
+ for (resolveResult in multiResolve()) {
+ val psiMethod = resolveResult.element
+ when {
+ psiMethod.isConstructor ->
+ psiMethod.containingClass?.let { return PsiTypesUtil.getClassType(it) }
+ else ->
+ psiMethod.returnType?.let { return it }
+ }
+ }
+ return null
+ }
+
+ 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)?.let {
+ if (it.selector == this) return it.receiver
+ }
+
+ val ktNameReferenceExpression = psi.calleeExpression as? KtNameReferenceExpression ?: return null
+ val variableCallDescriptor =
+ (resolvedCall as? VariableAsFunctionResolvedCall)?.variableCall?.resultingDescriptor
+ ?: (resolvedCall?.resultingDescriptor as? FunctionDescriptor)?.takeIf { it.visibility == Visibilities.LOCAL }
+ ?: return null
+
+ // an implicit receiver for variables calls (KT-25524)
+ return object : KotlinAbstractUExpression(this), UReferenceExpression {
+
+ private val resolvedDeclaration = variableCallDescriptor.toSource()
+
+ override val psi: KtNameReferenceExpression get() = ktNameReferenceExpression
+
+ override val resolvedName: String? get() = (resolvedDeclaration as? PsiNamedElement)?.name
+
+ override fun resolve(): PsiElement? = resolvedDeclaration
+
+ }
+
+ }
+
+ private val multiResolved by lazy(fun(): Iterable> {
+ val contextElement = psi
+
+ if (!Registry.`is`("kotlin.uast.multiresolve.enabled", true)) {
+ val calleeExpression = contextElement.calleeExpression ?: return emptyList()
+ return calleeExpression.multiResolveResults()
+ .mapNotNull { it.element.safeAs()?.let { TypedResolveResult(it) } }
+ .asIterable()
+ }
+
+ val calleeExpression = contextElement.calleeExpression as? KtReferenceExpression ?: return emptyList()
+ val methodName = methodName ?: calleeExpression.text ?: return emptyList()
+ val variants = getReferenceVariants(calleeExpression, methodName)
+ return variants.flatMap {
+ when (val source = it.toSource()) {
+ is KtClass -> source.toLightClass()?.constructors?.asSequence().orEmpty()
+ else -> resolveSource(psi, it, source)?.let { sequenceOf(it) }.orEmpty()
+ }
+ }.map { TypedResolveResult(it) }.asIterable()
+ })
+
+ override fun multiResolve(): Iterable> = multiResolved
+
+
+ override fun resolve(): PsiMethod? {
+ val descriptor = resolvedCall?.resultingDescriptor ?: return null
+ val source = descriptor.toSource()
+ return resolveSource(psi, 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
+ }
+ }
+
+}
+
+internal fun getArgumentExpressionByIndex(
+ actualParamIndex: Int,
+ resolvedCall: ResolvedCall,
+ parent: UElement
+): UExpression? {
+ val (parameter, resolvedArgument) = resolvedCall.valueArguments.entries.find { it.key.index == actualParamIndex } ?: return null
+ val arguments = resolvedArgument.arguments
+ if (arguments.isEmpty()) return null
+ if (arguments.size == 1) {
+ val argument = arguments.single()
+ val expression = argument.getArgumentExpression()
+ if (parameter.varargElementType != null && argument.getSpreadElement() == null) {
+ return createVarargsHolder(arguments, parent)
+ }
+ return KotlinConverter.convertOrEmpty(expression, parent)
+ }
+ return createVarargsHolder(arguments, parent)
+}
+
+private fun createVarargsHolder(arguments: List, parent: UElement?): KotlinUExpressionList =
+ KotlinUExpressionList(null, UastSpecialExpressionKind.VARARGS, parent).apply {
+ expressions = arguments.map { KotlinConverter.convertOrEmpty(it.getArgumentExpression(), parent) }
+ }
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt
index a4fac66330a..bf958b3de0a 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUNamedExpression.kt
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.uast.*
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUNamedExpression private constructor(
override val name: String?,
@@ -60,7 +61,7 @@ class KotlinUNamedExpression private constructor(
class KotlinUVarargExpression(
private val valueArgs: List,
uastParent: UElement?
-) : KotlinAbstractUExpression(uastParent), UCallExpressionEx {
+) : KotlinAbstractUExpression(uastParent), UCallExpressionEx, DelegatedMultiResolve {
override val kind: UastCallKind = UastCallKind.NESTED_ARRAY_INITIALIZER
override val valueArguments: List by lz {
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt
index 8802269b954..69be1b1d232 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUObjectLiteralExpression.kt
@@ -23,11 +23,12 @@ import org.jetbrains.kotlin.psi.KtObjectLiteralExpression
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.uast.*
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUObjectLiteralExpression(
override val psi: KtObjectLiteralExpression,
givenParent: UElement?
-) : KotlinAbstractUExpression(givenParent), UObjectLiteralExpression, UCallExpressionEx, KotlinUElementWithType {
+) : KotlinAbstractUExpression(givenParent), UObjectLiteralExpression, UCallExpressionEx, DelegatedMultiResolve, KotlinUElementWithType {
override val declaration: UClass by lz {
psi.objectDeclaration.toLightClass()
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt
index 4d86d3b6bbf..daf5bffeb97 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUPostfixExpression.kt
@@ -21,11 +21,13 @@ import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtPostfixExpression
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUPostfixExpression(
override val psi: KtPostfixExpression,
givenParent: UElement?
-) : KotlinAbstractUExpression(givenParent), UPostfixExpression, KotlinUElementWithType, KotlinEvaluatableUElement, UResolvable {
+) : KotlinAbstractUExpression(givenParent), UPostfixExpression, KotlinUElementWithType, KotlinEvaluatableUElement,
+ UResolvable, DelegatedMultiResolve {
override val operand by lz { KotlinConverter.convertOrEmpty(psi.baseExpression, this) }
override val operator = when (psi.operationToken) {
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUQualifiedReferenceExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUQualifiedReferenceExpression.kt
index 208c99837f9..b917f9cb2b1 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUQualifiedReferenceExpression.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUQualifiedReferenceExpression.kt
@@ -25,11 +25,12 @@ import org.jetbrains.uast.UElement
import org.jetbrains.uast.UExpression
import org.jetbrains.uast.UQualifiedReferenceExpression
import org.jetbrains.uast.UastQualifiedExpressionAccessType
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUQualifiedReferenceExpression(
override val psi: KtDotQualifiedExpression,
givenParent: UElement?
-) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression,
+) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression, DelegatedMultiResolve,
KotlinUElementWithType, KotlinEvaluatableUElement {
override val receiver by lz { KotlinConverter.convertOrEmpty(psi.receiverExpression, this) }
override val selector by lz { KotlinConverter.convertOrEmpty(psi.selectorExpression, this) }
@@ -41,13 +42,14 @@ class KotlinUQualifiedReferenceExpression(
get() = (resolve() as? PsiNamedElement)?.name
}
+//TODO maybe remove it if it is unused?
class KotlinUComponentQualifiedReferenceExpression(
- override val psi: KtDestructuringDeclarationEntry,
- givenParent: UElement?
-) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression,
- KotlinUElementWithType, KotlinEvaluatableUElement {
+ override val psi: KtDestructuringDeclarationEntry,
+ givenParent: UElement?
+) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression, DelegatedMultiResolve,
+ KotlinUElementWithType, KotlinEvaluatableUElement {
override val accessType = UastQualifiedExpressionAccessType.SIMPLE
-
+
override lateinit var receiver: UExpression
internal set
@@ -56,7 +58,7 @@ class KotlinUComponentQualifiedReferenceExpression(
override val resolvedName: String?
get() = psi.analyze()[BindingContext.COMPONENT_RESOLVED_CALL, psi]?.resultingDescriptor?.name?.asString()
-
+
override fun resolve(): PsiElement? {
val bindingContext = psi.analyze()
val descriptor = bindingContext[BindingContext.COMPONENT_RESOLVED_CALL, psi]?.resultingDescriptor ?: return null
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSafeQualifiedExpression.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSafeQualifiedExpression.kt.183
new file mode 100644
index 00000000000..d9e6401b70e
--- /dev/null
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSafeQualifiedExpression.kt.183
@@ -0,0 +1,41 @@
+/*
+ * 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.PsiNamedElement
+import com.intellij.psi.ResolveResult
+import org.jetbrains.kotlin.psi.KtSafeQualifiedExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UMultiResolvable
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.kotlin.internal.getResolveResultVariants
+
+class KotlinUSafeQualifiedExpression(
+ override val psi: KtSafeQualifiedExpression,
+ givenParent: UElement?
+) : KotlinAbstractUExpression(givenParent), UQualifiedReferenceExpression, UMultiResolvable,
+ KotlinUElementWithType, KotlinEvaluatableUElement {
+ override val receiver by lz { KotlinConverter.convertOrEmpty(psi.receiverExpression, this) }
+ override val selector by lz { KotlinConverter.convertOrEmpty(psi.selectorExpression, this) }
+ override val accessType = KotlinQualifiedExpressionAccessTypes.SAFE
+
+ override val resolvedName: String?
+ get() = (resolve() as? PsiNamedElement)?.name
+
+ override fun resolve() = psi.selectorExpression?.resolveCallToDeclaration(this)
+ override fun multiResolve(): Iterable = getResolveResultVariants(psi.selectorExpression)
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt
index 90248bf9e06..fddea33e1a4 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSimpleReferenceExpression.kt
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.utils.addToStdlib.constant
import org.jetbrains.uast.*
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
import org.jetbrains.uast.visitor.UastVisitor
open class KotlinUSimpleReferenceExpression(
@@ -102,7 +103,7 @@ open class KotlinUSimpleReferenceExpression(
private val resolvedCall: ResolvedCall<*>,
private val accessorDescriptor: DeclarationDescriptor,
val setterValue: KtExpression?
- ) : UCallExpressionEx, JvmDeclarationUElementPlaceholder {
+ ) : UCallExpressionEx, DelegatedMultiResolve, JvmDeclarationUElementPlaceholder {
override val methodName: String?
get() = accessorDescriptor.name.asString()
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt
index 9ae022699d3..7a26bbc6a05 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUSuperExpression.kt
@@ -22,11 +22,12 @@ import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.USuperExpression
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUSuperExpression(
override val psi: KtSuperExpression,
givenParent: UElement?
-) : KotlinAbstractUExpression(givenParent), USuperExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
+) : KotlinAbstractUExpression(givenParent), USuperExpression, DelegatedMultiResolve, KotlinUElementWithType, KotlinEvaluatableUElement {
override val label: String?
get() = psi.getLabelName()
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt
index ce8ef9146a3..a126192989f 100644
--- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt
@@ -22,11 +22,12 @@ import org.jetbrains.uast.UElement
import org.jetbrains.uast.UIdentifier
import org.jetbrains.uast.UThisExpression
import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
class KotlinUThisExpression(
override val psi: KtThisExpression,
givenParent: UElement?
-) : KotlinAbstractUExpression(givenParent), UThisExpression, KotlinUElementWithType, KotlinEvaluatableUElement {
+) : KotlinAbstractUExpression(givenParent), UThisExpression, DelegatedMultiResolve, KotlinUElementWithType, KotlinEvaluatableUElement {
override val label: String?
get() = psi.getLabelName()
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.183
new file mode 100644
index 00000000000..a126192989f
--- /dev/null
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/expressions/KotlinUThisExpression.kt.183
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.uast.kotlin
+
+import org.jetbrains.kotlin.psi.KtThisExpression
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UIdentifier
+import org.jetbrains.uast.UThisExpression
+import org.jetbrains.uast.kotlin.declarations.KotlinUIdentifier
+import org.jetbrains.uast.kotlin.internal.DelegatedMultiResolve
+
+class KotlinUThisExpression(
+ override val psi: KtThisExpression,
+ givenParent: UElement?
+) : KotlinAbstractUExpression(givenParent), UThisExpression, DelegatedMultiResolve, KotlinUElementWithType, KotlinEvaluatableUElement {
+ override val label: String?
+ get() = psi.getLabelName()
+
+ override val labelIdentifier: UIdentifier?
+ get() = psi.getTargetLabel()?.let { KotlinUIdentifier(it, this) }
+
+ override fun resolve() = psi.analyze()[BindingContext.LABEL_TARGET, psi.getTargetLabel()]
+}
\ No newline at end of file
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/CliKotlinUastResolveProviderService.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/CliKotlinUastResolveProviderService.kt.183
new file mode 100644
index 00000000000..adb2aa866ad
--- /dev/null
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/CliKotlinUastResolveProviderService.kt.183
@@ -0,0 +1,92 @@
+package org.jetbrains.uast.kotlin.internal
+
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.analyzer.AnalysisResult
+import org.jetbrains.kotlin.codegen.ClassBuilderMode
+import org.jetbrains.kotlin.codegen.state.IncompatibleClassTracker
+import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
+import org.jetbrains.kotlin.config.JvmTarget
+import org.jetbrains.kotlin.config.LanguageVersionSettings
+import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
+import org.jetbrains.kotlin.container.ComponentProvider
+import org.jetbrains.kotlin.container.get
+import org.jetbrains.kotlin.context.ProjectContext
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.load.java.JvmAbi
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.BindingTrace
+import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
+import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
+
+class CliKotlinUastResolveProviderService : KotlinUastResolveProviderService {
+ val Project.analysisCompletedHandler: UastAnalysisHandlerExtension?
+ get() = getExtensions(AnalysisHandlerExtension.extensionPointName)
+ .filterIsInstance()
+ .firstOrNull()
+
+ override fun getBindingContext(element: KtElement): BindingContext {
+ return element.project.analysisCompletedHandler?.getBindingContext() ?: BindingContext.EMPTY
+ }
+
+ override fun getTypeMapper(element: KtElement): KotlinTypeMapper? {
+ return element.project.analysisCompletedHandler?.getTypeMapper()
+ }
+
+ override fun isJvmElement(psiElement: PsiElement) = true
+
+ override fun getLanguageVersionSettings(element: KtElement): LanguageVersionSettings {
+ return element.project.analysisCompletedHandler?.getLanguageVersionSettings() ?: LanguageVersionSettingsImpl.DEFAULT
+ }
+
+ override fun getReferenceVariants(ktElement: KtElement, nameHint: String): Sequence =
+ emptySequence() // Not supported
+}
+
+class UastAnalysisHandlerExtension : AnalysisHandlerExtension {
+ private var context: BindingContext? = null
+ private var typeMapper: KotlinTypeMapper? = null
+ private var languageVersionSettings: LanguageVersionSettings? = null
+
+ fun getBindingContext() = context
+
+ fun getLanguageVersionSettings() = languageVersionSettings
+
+ fun getTypeMapper(): KotlinTypeMapper? {
+ if (typeMapper != null) return typeMapper
+ val bindingContext = context ?: return null
+
+ val typeMapper = KotlinTypeMapper(
+ bindingContext, ClassBuilderMode.LIGHT_CLASSES,
+ IncompatibleClassTracker.DoNothing, JvmAbi.DEFAULT_MODULE_NAME, JvmTarget.DEFAULT, KotlinTypeMapper.RELEASE_COROUTINES_DEFAULT,
+ false
+ )
+ this.typeMapper = typeMapper
+ return typeMapper
+ }
+
+ override fun doAnalysis(
+ project: Project,
+ module: ModuleDescriptor,
+ projectContext: ProjectContext,
+ files: Collection,
+ bindingTrace: BindingTrace,
+ componentProvider: ComponentProvider
+ ): AnalysisResult? {
+ languageVersionSettings = componentProvider.get()
+ return super.doAnalysis(project, module, projectContext, files, bindingTrace, componentProvider)
+ }
+
+ override fun analysisCompleted(
+ project: Project,
+ module: ModuleDescriptor,
+ bindingTrace: BindingTrace,
+ files: Collection
+ ): AnalysisResult? {
+ context = bindingTrace.bindingContext
+ return null
+ }
+}
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinUastMultiresolve.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinUastMultiresolve.kt
new file mode 100644
index 00000000000..fbcbffe6359
--- /dev/null
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinUastMultiresolve.kt
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2010-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.internal
+
+import org.jetbrains.uast.UResolvable
+
+
+//Dummy holder until idea 183
+interface DelegatedMultiResolve : UResolvable
+
+
diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinUastMultiresolve.kt.183 b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinUastMultiresolve.kt.183
new file mode 100644
index 00000000000..b8c9ef57de8
--- /dev/null
+++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/internal/kotlinUastMultiresolve.kt.183
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010-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.internal
+
+import com.intellij.openapi.components.ServiceManager
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiPolyVariantReference
+import com.intellij.psi.PsiSubstitutor
+import com.intellij.psi.ResolveResult
+import com.intellij.psi.infos.CandidateInfo
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.psi.KtExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UMultiResolvable
+import org.jetbrains.uast.UResolvable
+import org.jetbrains.uast.kotlin.KotlinUastResolveProviderService
+import org.jetbrains.uast.kotlin.getMaybeLightElement
+import org.jetbrains.uast.kotlin.toSource
+
+
+internal fun getReferenceVariants(ktElement: KtElement, nameHint: String): Sequence =
+ ServiceManager.getService(ktElement.project, KotlinUastResolveProviderService::class.java).getReferenceVariants(ktElement, nameHint)
+
+internal fun UElement.getResolveResultVariants(ktExpression: KtExpression?): Iterable {
+ ktExpression ?: return emptyList()
+
+ if (!Registry.`is`("kotlin.uast.multiresolve.enabled", true)) return ktExpression.multiResolveResults().asIterable()
+
+ val referenceVariants = getReferenceVariants(ktExpression, ktExpression.name ?: ktExpression.text)
+
+ fun asCandidateInfo(descriptor: DeclarationDescriptor): CandidateInfo? =
+ descriptor.toSource()?.getMaybeLightElement(this)?.let { CandidateInfo(it, PsiSubstitutor.EMPTY) }
+
+ return referenceVariants.mapNotNull(::asCandidateInfo).asIterable()
+}
+
+
+internal fun KtElement.multiResolveResults(): Sequence =
+ references.asSequence().flatMap { ref ->
+ when (ref) {
+ is PsiPolyVariantReference -> ref.multiResolve(false).asSequence()
+ else -> (ref.resolve()?.let { sequenceOf(CandidateInfo(it, PsiSubstitutor.EMPTY)) }).orEmpty()
+ }
+ }
+
+interface DelegatedMultiResolve : UMultiResolvable, UResolvable {
+ override fun multiResolve(): Iterable = listOfNotNull(resolve()?.let { CandidateInfo(it, PsiSubstitutor.EMPTY) })
+}
+
+class TypedResolveResult(element: T) : CandidateInfo(element, PsiSubstitutor.EMPTY) {
+ @Suppress("UNCHECKED_CAST")
+ override fun getElement(): T = super.getElement() as T
+}
+
diff --git a/plugins/uast-kotlin/tests/KotlinDetachedUastTest.kt b/plugins/uast-kotlin/tests/KotlinDetachedUastTest.kt
index 65e2001a168..b8fa9b4c7c6 100644
--- a/plugins/uast-kotlin/tests/KotlinDetachedUastTest.kt
+++ b/plugins/uast-kotlin/tests/KotlinDetachedUastTest.kt
@@ -16,7 +16,6 @@
package org.jetbrains.uast.test.kotlin
-import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiLanguageInjectionHost
@@ -131,19 +130,6 @@ class KotlinDetachedUastTest : KotlinLightCodeInsightFixtureTestCase() {
}
- fun testResolveStringFromUast() {
- val file = myFixture.addFileToProject(
- "s.kt", """fun foo(){
- val s = "abc"
- s.toUpperCase()
- }
- ""${'"'}"""
- )
-
- val refs = file.findUElementByTextFromPsi("s.toUpperCase()")
- TestCase.assertNotNull((refs.receiver.getExpressionType() as PsiClassType).resolve())
- }
-
}
fun T?.orFail(msg: String): T = this ?: error(msg)
\ No newline at end of file
diff --git a/plugins/uast-kotlin/tests/KotlinUastResolveApiTest.kt b/plugins/uast-kotlin/tests/KotlinUastResolveApiTest.kt
new file mode 100644
index 00000000000..d3bb4dd3e43
--- /dev/null
+++ b/plugins/uast-kotlin/tests/KotlinUastResolveApiTest.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010-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.test.kotlin
+
+import com.intellij.psi.PsiClassType
+import com.intellij.testFramework.LightProjectDescriptor
+import junit.framework.TestCase
+import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.test.env.findUElementByTextFromPsi
+
+class KotlinUastResolveApiTest : KotlinLightCodeInsightFixtureTestCase() {
+
+ override fun getProjectDescriptor(): LightProjectDescriptor =
+ KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+ fun testResolveStringFromUast() {
+ val file = myFixture.addFileToProject(
+ "s.kt", """fun foo(){
+ val s = "abc"
+ s.toUpperCase()
+ }
+ ""${'"'}"""
+ )
+
+ val refs = file.findUElementByTextFromPsi("s.toUpperCase()")
+ TestCase.assertNotNull((refs.receiver.getExpressionType() as PsiClassType).resolve())
+ }
+
+}
diff --git a/plugins/uast-kotlin/tests/KotlinUastResolveApiTest.kt.183 b/plugins/uast-kotlin/tests/KotlinUastResolveApiTest.kt.183
new file mode 100644
index 00000000000..2841ad043a5
--- /dev/null
+++ b/plugins/uast-kotlin/tests/KotlinUastResolveApiTest.kt.183
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2010-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.test.kotlin
+
+import com.intellij.openapi.util.registry.Registry
+import com.intellij.psi.PsiClassType
+import com.intellij.psi.PsiType
+import com.intellij.testFramework.LightProjectDescriptor
+import junit.framework.TestCase
+import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.getContainingUMethod
+import org.jetbrains.uast.kotlin.KotlinUFunctionCallExpression
+import org.jetbrains.uast.test.env.findElementByText
+import org.jetbrains.uast.test.env.findElementByTextFromPsi
+import org.jetbrains.uast.test.env.findUElementByTextFromPsi
+import org.jetbrains.uast.toUElement
+
+class KotlinUastResolveApiTest : KotlinLightCodeInsightFixtureTestCase() {
+
+ override fun getProjectDescriptor(): LightProjectDescriptor =
+ KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+ override fun setUp() {
+ super.setUp()
+ Registry.get("kotlin.uast.multiresolve.enabled").setValue(true, testRootDisposable)
+ }
+
+ fun testResolveStringFromUast() {
+ val file = myFixture.addFileToProject(
+ "s.kt", """fun foo(){
+ val s = "abc"
+ s.toUpperCase()
+ }
+ ""${'"'}"""
+ )
+
+ val refs = file.findUElementByTextFromPsi("s.toUpperCase()")
+ TestCase.assertNotNull((refs.receiver.getExpressionType() as PsiClassType).resolve())
+ }
+
+ fun testMultiResolve() {
+ val file = myFixture.configureByText(
+ "s.kt", """
+ fun foo(): Int = TODO()
+ fun foo(a: Int): Int = TODO()
+ fun foo(a: Int, b: Int): Int = TODO()
+
+
+ fun main(args: Array) {
+ foo(1
+ }"""
+ )
+
+ val main = file.toUElement()!!.findElementByTextFromPsi("main").getContainingUMethod()!!
+ val functionCall =
+ main.findElementByText("foo").uastParent as KotlinUFunctionCallExpression
+
+ val resolvedDeclaration = functionCall.multiResolve()
+ val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "" }
+ assertContainsElements(
+ resolvedDeclarationsStrings,
+ "fun foo(): Int = TODO()",
+ "fun foo(a: Int): Int = TODO()",
+ "fun foo(a: Int, b: Int): Int = TODO()"
+ )
+
+ TestCase.assertEquals(PsiType.INT, functionCall.getExpressionType())
+
+ val firstArgument = main.findElementByText("1")
+ val firstParameter = functionCall.getArgumentForParameter(0)
+ TestCase.assertEquals(firstArgument, firstParameter)
+
+ }
+
+ fun testMultiResolveJava() {
+ val file = myFixture.configureByText(
+ "s.kt", """
+
+ fun main(args: Array) {
+ System.out.print(""
+ }
+ """
+ )
+
+ val main = file.toUElement()!!.findElementByTextFromPsi("main").getContainingUMethod()!!
+ val functionCall = main.findElementByText("print").uastParent as KotlinUFunctionCallExpression
+
+ val resolvedDeclaration = functionCall.multiResolve()
+ val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "" }
+ assertContainsElements(
+ resolvedDeclarationsStrings,
+ "public void print(char c) { /* compiled code */ }",
+ "public void print(int i) { /* compiled code */ }",
+ "public void print(long l) { /* compiled code */ }",
+ "public void print(float f) { /* compiled code */ }",
+ "public void print(double d) { /* compiled code */ }",
+ "public void print(char[] s) { /* compiled code */ }",
+ "public void print(java.lang.String s) { /* compiled code */ }",
+ "public void print(java.lang.Object obj) { /* compiled code */ }"
+ )
+
+ TestCase.assertEquals(PsiType.VOID, functionCall.getExpressionType())
+
+ val firstArgument = main.findElementByText("\"\"")
+ val firstParameter = functionCall.getArgumentForParameter(0)
+ TestCase.assertEquals(firstArgument, firstParameter)
+ }
+
+ fun testMultiResolveJavaAmbiguous() {
+ myFixture.addClass(
+ """
+ public class JavaClass {
+
+ public void setParameter(String name, int value){}
+ public void setParameter(String name, double value){}
+ public void setParameter(String name, String value){}
+
+ }
+ """
+ )
+ val file = myFixture.configureByText(
+ "s.kt", """
+
+ fun main(args: Array) {
+ JavaClass().setParameter(""
+ }
+ """
+ )
+
+ val main = file.toUElement()!!.findElementByTextFromPsi("main").getContainingUMethod()!!
+ val functionCall = main.findElementByText("setParameter").uastParent as KotlinUFunctionCallExpression
+
+ val resolvedDeclaration = functionCall.multiResolve()
+ val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "" }
+ assertContainsElements(
+ resolvedDeclarationsStrings,
+ "public void setParameter(String name, int value){}",
+ "public void setParameter(String name, double value){}",
+ "public void setParameter(String name, String value){}"
+
+ )
+
+ TestCase.assertEquals(PsiType.VOID, functionCall.getExpressionType())
+
+ val firstArgument = main.findElementByText("\"\"")
+ val firstParameter = functionCall.getArgumentForParameter(0)
+ TestCase.assertEquals(firstArgument, firstParameter)
+ }
+
+ fun testMultiResolveInClass() {
+ val file = myFixture.configureByText(
+ "s.kt", """
+ class MyClass {
+
+ fun foo(): Int = TODO()
+ fun foo(a: Int): Int = TODO()
+ fun foo(a: Int, b: Int): Int = TODO()
+
+ }
+
+ fun foo(string: String) = TODO()
+
+
+ fun main(args: Array) {
+ MyClass().foo(
+ }
+ """
+ )
+
+
+ val functionCall =
+ file.toUElement()!!.findElementByTextFromPsi("main").getContainingUMethod()!!
+ .findElementByText("foo").uastParent as KotlinUFunctionCallExpression
+
+ val resolvedDeclaration = functionCall.multiResolve()
+ val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "" }
+ assertContainsElements(
+ resolvedDeclarationsStrings,
+ "fun foo(): Int = TODO()",
+ "fun foo(a: Int): Int = TODO()",
+ "fun foo(a: Int, b: Int): Int = TODO()"
+ )
+ assertDoesntContain(resolvedDeclarationsStrings, "fun foo(string: String) = TODO()")
+ TestCase.assertEquals(PsiType.INT, functionCall.getExpressionType())
+ }
+
+ fun testMultiConstructorResolve() {
+ val file = myFixture.configureByText(
+ "s.kt", """
+ class MyClass(int: Int) {
+
+ constructor(int: Int, int1: Int) : this(int + int1)
+
+ fun foo(): Int = TODO()
+
+ }
+
+ fun MyClass(string: String): MyClass = MyClass(1)
+
+
+ fun main(args: Array) {
+ MyClass(
+ }
+ """
+ )
+
+
+ val functionCall =
+ file.toUElement()!!.findElementByTextFromPsi("main").getContainingUMethod()!!
+ .findElementByText("MyClass").uastParent as KotlinUFunctionCallExpression
+
+ val resolvedDeclaration = functionCall.multiResolve()
+ val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "" }
+ assertContainsElements(
+ resolvedDeclarationsStrings,
+ "(int: Int)",
+ "constructor(int: Int, int1: Int) : this(int + int1)",
+ "fun MyClass(string: String): MyClass = MyClass(1)"
+ )
+ assertDoesntContain(resolvedDeclarationsStrings, "fun foo(): Int = TODO()")
+ TestCase.assertEquals(PsiType.getTypeByName("MyClass", project, file.resolveScope), functionCall.getExpressionType())
+ }
+
+
+ fun testMultiInvokableObjectResolve() {
+ val file = myFixture.configureByText(
+ "s.kt", """
+ object Foo {
+
+ operator fun invoke(i: Int): Int = TODO()
+ operator fun invoke(i1: Int, i2: Int): Int = TODO()
+ operator fun invoke(i1: Int, i2: Int, i3: Int): Int = TODO()
+
+ }
+
+ fun main(args: Array) {
+ Foo(
+ }
+ """
+ )
+
+ val functionCall =
+ file.toUElement()!!.findElementByTextFromPsi("main").getContainingUMethod()!!
+ .findElementByText("Foo").uastParent as KotlinUFunctionCallExpression
+
+ val resolvedDeclaration = functionCall.multiResolve()
+ val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "" }
+ assertContainsElements(
+ resolvedDeclarationsStrings,
+ "operator fun invoke(i: Int): Int = TODO()",
+ "operator fun invoke(i1: Int, i2: Int): Int = TODO()",
+ "operator fun invoke(i1: Int, i2: Int, i3: Int): Int = TODO()"
+ )
+ TestCase.assertEquals(PsiType.INT, functionCall.getExpressionType())
+ }
+
+ fun testMultiResolveJvmOverloads() {
+ val file = myFixture.configureByText(
+ "s.kt", """
+
+ class MyClass {
+
+ @JvmOverloads
+ fun foo(i1: Int = 1, i2: Int = 2): Int = TODO()
+
+ }
+
+ fun main(args: Array) {
+ MyClass().foo(
+ }"""
+ )
+
+ val functionCall =
+ file.toUElement()!!.findElementByTextFromPsi("main").getContainingUMethod()!!
+ .findElementByText("foo").uastParent as KotlinUFunctionCallExpression
+
+ val resolvedDeclaration = functionCall.multiResolve()
+ val resolvedDeclarationsStrings = resolvedDeclaration.map { it.element.text ?: "" }
+ assertContainsElements(
+ resolvedDeclarationsStrings,
+ "@JvmOverloads\n fun foo(i1: Int = 1, i2: Int = 2): Int = TODO()"
+ )
+ TestCase.assertEquals(PsiType.INT, functionCall.getExpressionType())
+ }
+
+}
+