diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt index 7889f073829..0f54d3da37c 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/psi/UastKotlinPsiVariable.kt @@ -4,12 +4,13 @@ import com.intellij.psi.* import com.intellij.psi.impl.light.LightTypeElement import org.jetbrains.kotlin.asJava.elements.LightVariableBuilder import org.jetbrains.kotlin.builtins.createFunctionType +import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns -import org.jetbrains.kotlin.utils.ifEmpty +import org.jetbrains.kotlin.types.isError import org.jetbrains.uast.UDeclaration import org.jetbrains.uast.UElement import org.jetbrains.uast.UastErrorType @@ -19,24 +20,35 @@ import org.jetbrains.uast.kotlin.lz import org.jetbrains.uast.kotlin.orAnonymous import org.jetbrains.uast.kotlin.toPsiType -class UastKotlinPsiVariable( +class UastKotlinPsiVariable private constructor( manager: PsiManager, name: String, - type: PsiType, + typeProducer: () -> PsiType, val ktInitializer: KtExpression?, val psiParent: PsiElement?, val containingElement: UElement, val ktElement: KtElement -) : LightVariableBuilder(manager, name, type, KotlinLanguage.INSTANCE), PsiLocalVariable { +) : LightVariableBuilder( + manager, + name, + UastErrorType, // Type is calculated lazily + KotlinLanguage.INSTANCE +), PsiLocalVariable { + + private val psiType: PsiType by lz(typeProducer) private val psiTypeElement: PsiTypeElement by lz { - LightTypeElement(manager, type) + LightTypeElement(manager, psiType) } private val psiInitializer: PsiExpression? by lz { ktInitializer?.let { KotlinUastPsiExpression(it, containingElement) } } + override fun getType(): PsiType = psiType + + override fun getText(): String = ktElement.text + override fun getParent() = psiParent override fun hasInitializer() = ktInitializer != null @@ -61,54 +73,55 @@ class UastKotlinPsiVariable( fun create( declaration: KtVariableDeclaration, parent: PsiElement?, - containingElement: UElement, + containingElement: UElement, initializer: KtExpression? = null ): PsiLocalVariable { val psiParent = containingElement.getParentOfType()?.psi ?: parent + val initializerExpression = initializer ?: declaration.initializer return UastKotlinPsiVariable( - declaration.manager, - declaration.name.orAnonymous("unnamed"), - declaration.typeReference.toPsiType(containingElement), - initializer ?: declaration.initializer, - psiParent, - containingElement, - declaration) + manager = declaration.manager, + name = declaration.name.orAnonymous(""), + typeProducer = { declaration.getType(containingElement) ?: UastErrorType }, + ktInitializer = initializerExpression, + psiParent = psiParent, + containingElement = containingElement, + ktElement = declaration) } fun create(declaration: KtDestructuringDeclaration, containingElement: UElement): PsiLocalVariable { val psiParent = containingElement.getParentOfType()?.psi ?: declaration.parent return UastKotlinPsiVariable( - declaration.manager, - "var" + Integer.toHexString(declaration.getHashCode()), - declaration.initializer?.getType(containingElement) ?: UastErrorType, - declaration.initializer, - psiParent, - containingElement, - declaration) + manager = declaration.manager, + name = "var" + Integer.toHexString(declaration.getHashCode()), + typeProducer = { declaration.getType(containingElement) ?: UastErrorType }, + ktInitializer = declaration.initializer, + psiParent = psiParent, + containingElement = containingElement, + ktElement = declaration) } fun create(initializer: KtExpression, containingElement: UElement, parent: PsiElement): PsiLocalVariable { val psiParent = containingElement.getParentOfType()?.psi ?: parent return UastKotlinPsiVariable( - initializer.manager, - "var" + Integer.toHexString(initializer.getHashCode()), - initializer.getType(containingElement) ?: UastErrorType, - initializer, - psiParent, - containingElement, - initializer) + manager = initializer.manager, + name = "var" + Integer.toHexString(initializer.getHashCode()), + typeProducer = { initializer.getType(containingElement) ?: UastErrorType }, + ktInitializer = initializer, + psiParent = psiParent, + containingElement = containingElement, + ktElement = initializer) } fun create(name: String, localFunction: KtFunction, containingElement: UElement): PsiLocalVariable { val psiParent = containingElement.getParentOfType()?.psi ?: localFunction.parent return UastKotlinPsiVariable( - localFunction.manager, - name, - localFunction.getFunctionType(containingElement) ?: UastErrorType, - localFunction, - psiParent, - containingElement, - localFunction) + manager = localFunction.manager, + name = name, + typeProducer = { localFunction.getFunctionType(containingElement) ?: UastErrorType }, + ktInitializer = localFunction, + psiParent = psiParent, + containingElement = containingElement, + ktElement = localFunction) } } } @@ -122,18 +135,25 @@ private fun KtFunction.getFunctionType(parent: UElement): PsiType? { val returnType = descriptor.returnType ?: return null return createFunctionType( - descriptor.builtIns, - descriptor.annotations, - descriptor.extensionReceiverParameter?.type, - descriptor.valueParameters.map { it.type }, - descriptor.valueParameters.map { it.name }, - returnType + builtIns = descriptor.builtIns, + annotations = descriptor.annotations, + receiverType = descriptor.extensionReceiverParameter?.type, + parameterTypes = descriptor.valueParameters.map { it.type }, + parameterNames = descriptor.valueParameters.map { it.name }, + returnType = returnType ).toPsiType(parent, this, boxed = false) } private fun KtExpression.getType(parent: UElement): PsiType? = analyze()[BindingContext.EXPRESSION_TYPE_INFO, this]?.type?.toPsiType(parent, this, boxed = false) +private fun KtDeclaration.getType(parent: UElement): PsiType? { + return (analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? CallableDescriptor) + ?.returnType + ?.takeIf { !it.isError } + ?.toPsiType(parent, this, false) +} + private fun PsiElement.getHashCode(): Int { var result = 42 result = 41 * result + containingFile.name.hashCode() diff --git a/plugins/uast-kotlin/testData/In.values.txt b/plugins/uast-kotlin/testData/In.values.txt index 65f9a0a752a..6e66dce6a43 100644 --- a/plugins/uast-kotlin/testData/In.values.txt +++ b/plugins/uast-kotlin/testData/In.values.txt @@ -2,11 +2,11 @@ UFile (package = ) [public final class InKt {...] UClass (name = InKt) [public final class InKt {...}] UAnnotationMethod (name = foo) [public static final fun foo() : boolean {...}] UBlockExpression [{...}] = Nothing - UDeclarationsExpression [var x: = 1] = Undetermined - ULocalVariable (name = x) [var x: = 1] + UDeclarationsExpression [var x: int = 1] = Undetermined + ULocalVariable (name = x) [var x: int = 1] ULiteralExpression (value = 1) [1] = 1 - UDeclarationsExpression [var y: = 10] = Undetermined - ULocalVariable (name = y) [var y: = 10] + UDeclarationsExpression [var y: int = 10] = Undetermined + ULocalVariable (name = y) [var y: int = 10] ULiteralExpression (value = 10) [10] = 10 UReturnExpression [return x in 0 .. 5 && y !in 4 .. 9] = Nothing UBinaryExpression (operator = &&) [x in 0 .. 5 && y !in 4 .. 9] = true (depending on: (var x = 1), (var y = 10)) diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.render.txt b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt index 2238de1dfae..8768433111f 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.render.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.render.txt @@ -6,7 +6,7 @@ public final class LocalDeclarationsKt { var bar: = fun () { () } - var baz: = fun () { + var baz: kotlin.jvm.functions.Function0 = fun () { () } var someLocalFun: kotlin.jvm.functions.Function2 = fun (var text: java.lang.String) { diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.types.txt b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt index 83d11248efa..2d879604d74 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.types.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.types.txt @@ -11,8 +11,8 @@ UFile (package = ) [public final class LocalDeclarationsKt {...] UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] : PsiType: UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] USimpleNameReferenceExpression (identifier = ) [] : PsiType: - UDeclarationsExpression [var baz: = fun () {...}] - ULocalVariable (name = baz) [var baz: = fun () {...}] + 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: diff --git a/plugins/uast-kotlin/testData/LocalDeclarations.values.txt b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt index 86e0f8f0e49..d4f166a086e 100644 --- a/plugins/uast-kotlin/testData/LocalDeclarations.values.txt +++ b/plugins/uast-kotlin/testData/LocalDeclarations.values.txt @@ -11,8 +11,8 @@ UFile (package = ) [public final class LocalDeclarationsKt {...] UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) [()] = external ()() UIdentifier (Identifier (Local)) [UIdentifier (Identifier (Local))] USimpleNameReferenceExpression (identifier = ) [] = external ()() - UDeclarationsExpression [var baz: = fun () {...}] = Undetermined - ULocalVariable (name = baz) [var baz: = fun () {...}] + 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 ()() diff --git a/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.log.txt b/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.log.txt new file mode 100644 index 00000000000..72ea91462ec --- /dev/null +++ b/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.log.txt @@ -0,0 +1,27 @@ +UFile (package = ) + UClass (name = MyAnnotation) + UClass (name = Test1) + UField (name = bar) + UAnnotation (fqName = null) + UAnnotationMethod (name = getBar) + UAnnotationMethod (name = setBar) + UParameter (name = p) + UAnnotation (fqName = null) + UAnnotationMethod (name = Test1) + UParameter (name = bar) + UAnnotation (fqName = MyAnnotation) + UAnnotation (fqName = null) + UClass (name = Test2) + UField (name = bar) + UAnnotation (fqName = MyAnnotation) + UAnnotation (fqName = null) + UAnnotationMethod (name = getBar) + UAnnotation (fqName = MyAnnotation) + UAnnotationMethod (name = setBar) + UAnnotation (fqName = MyAnnotation) + UParameter (name = p) + UAnnotation (fqName = MyAnnotation) + UAnnotation (fqName = null) + UAnnotationMethod (name = Test2) + UParameter (name = bar) + UAnnotation (fqName = null) diff --git a/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.render.txt b/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.render.txt new file mode 100644 index 00000000000..9748b245f8f --- /dev/null +++ b/plugins/uast-kotlin/testData/ParameterPropertyWithAnnotation.render.txt @@ -0,0 +1,18 @@ +public abstract annotation MyAnnotation { +} + +public final class Test1 { + private var bar: int + public final fun getBar() : int = UastEmptyExpression + public final fun setBar(p: int) : void = UastEmptyExpression + public fun Test1(bar: int) = UastEmptyExpression +} + +public final class Test2 { + private var bar: int + @MyAnnotation + public final fun getBar() : int = UastEmptyExpression + @MyAnnotation + public final fun setBar(p: int) : void = UastEmptyExpression + public fun Test2(bar: int) = UastEmptyExpression +} diff --git a/plugins/uast-kotlin/testData/ParametersWithDefaultValues.kt b/plugins/uast-kotlin/testData/ParametersWithDefaultValues.kt new file mode 100644 index 00000000000..531375e64fb --- /dev/null +++ b/plugins/uast-kotlin/testData/ParametersWithDefaultValues.kt @@ -0,0 +1,4 @@ + +fun foo(a: Int, b: String, c: Int = 0, flag: Boolean = false) { + +} \ No newline at end of file diff --git a/plugins/uast-kotlin/testData/ParametersWithDefaultValues.log.txt b/plugins/uast-kotlin/testData/ParametersWithDefaultValues.log.txt new file mode 100644 index 00000000000..325d638ff65 --- /dev/null +++ b/plugins/uast-kotlin/testData/ParametersWithDefaultValues.log.txt @@ -0,0 +1,14 @@ +UFile (package = ) + UClass (name = ParametersWithDefaultValuesKt) + UAnnotationMethod (name = foo) + UParameter (name = a) + UAnnotation (fqName = null) + UParameter (name = b) + UAnnotation (fqName = org.jetbrains.annotations.NotNull) + UParameter (name = c) + UAnnotation (fqName = null) + ULiteralExpression (value = 0) + UParameter (name = flag) + UAnnotation (fqName = null) + ULiteralExpression (value = false) + UBlockExpression diff --git a/plugins/uast-kotlin/testData/ParametersWithDefaultValues.render.txt b/plugins/uast-kotlin/testData/ParametersWithDefaultValues.render.txt new file mode 100644 index 00000000000..a47a36a47c3 --- /dev/null +++ b/plugins/uast-kotlin/testData/ParametersWithDefaultValues.render.txt @@ -0,0 +1,4 @@ +public final class ParametersWithDefaultValuesKt { + public static final fun foo(a: int, b: java.lang.String, c: int, flag: boolean) : void { + } +} diff --git a/plugins/uast-kotlin/testData/PropertyDelegate.render.txt b/plugins/uast-kotlin/testData/PropertyDelegate.render.txt index 50efc00b1a3..ce4553ea29c 100644 --- a/plugins/uast-kotlin/testData/PropertyDelegate.render.txt +++ b/plugins/uast-kotlin/testData/PropertyDelegate.render.txt @@ -2,6 +2,6 @@ public final class PropertyDelegateKt { private static final var sdCardPath$delegate: kotlin.Lazy public static final fun getSdCardPath() : java.lang.String = UastEmptyExpression public static final fun localPropertyTest() : void { - var sdCardPathLocal: + var sdCardPathLocal: java.lang.String } } diff --git a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt index a2aee061352..f61f8a538cf 100644 --- a/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt +++ b/plugins/uast-kotlin/tests/SimpleKotlinRenderLogTest.kt @@ -34,4 +34,8 @@ class SimpleKotlinRenderLogTest : AbstractKotlinRenderLogTest() { @Test fun testInnerClasses() = doTest("InnerClasses") @Test fun testSimpleScript() = doTest("SimpleScript") + + @Test fun testParameterPropertyWithAnnotation() = doTest("ParameterPropertyWithAnnotation") + + @Test fun testParametersWithDefaultValues() = doTest("ParametersWithDefaultValues") } \ No newline at end of file