From 31776d9a3bd124b2453ee9ef69cdc1539e77a7fe Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 12 Mar 2020 18:53:45 +0300 Subject: [PATCH] [CFA] Mark arguments of all annotation calls as `USED_AS_EXPRESSION` Also revert hacky fix of KT-37294 introduced in 80caa063b #KT-37447 Fixed --- .../cfg/ControlFlowInformationProvider.kt | 11 +- .../testData/cfg/bugs/kt37447.instructions | 104 ++++++++++++++++++ compiler/testData/cfg/bugs/kt37447.kt | 23 ++++ compiler/testData/cfg/bugs/kt37447.values | 48 ++++++++ .../kotlin/cfg/ControlFlowTestGenerated.java | 5 + .../kotlin/cfg/PseudoValueTestGenerated.java | 5 + .../UnusedUnaryOperatorInspection.kt | 8 -- 7 files changed, 193 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/cfg/bugs/kt37447.instructions create mode 100644 compiler/testData/cfg/bugs/kt37447.kt create mode 100644 compiler/testData/cfg/bugs/kt37447.values diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index e3af2785581..6767dd4846c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -804,9 +804,14 @@ class ControlFlowInformationProvider private constructor( } private fun markAnnotationArguments() { - when (subroutine) { - is KtAnnotationEntry -> markAnnotationArguments(subroutine) - is KtAnnotated -> subroutine.annotationEntries.forEach { markAnnotationArguments(it) } + if (subroutine is KtAnnotationEntry) { + markAnnotationArguments(subroutine) + } else { + subroutine.children.forEach { child -> + child.forEachDescendantOfType( + canGoInside = { it !is KtDeclaration || it is KtParameter } + ) { markAnnotationArguments(it) } + } } } diff --git a/compiler/testData/cfg/bugs/kt37447.instructions b/compiler/testData/cfg/bugs/kt37447.instructions new file mode 100644 index 00000000000..56999e7b729 --- /dev/null +++ b/compiler/testData/cfg/bugs/kt37447.instructions @@ -0,0 +1,104 @@ +== Test_1 == +class Test_1 { + @Target(AnnotationTarget.VALUE_PARAMETER) + annotation class Range(val min: Long = 0) + + fun foo(@Range(min = -90L) x: Int) = Unit // KtPrefixExpression isn't marked as BindingContext.USED_AS_EXPRESSION +} +--------------------- +L0: + 1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== foo == +fun foo(@Range(min = -90L) x: Int) = Unit // KtPrefixExpression isn't marked as BindingContext.USED_AS_EXPRESSION +--------------------- +L0: + 1 + v(@Range(min = -90L) x: Int) + magic[FAKE_INITIALIZER](@Range(min = -90L) x: Int) -> + w(x|) + r(Unit) -> + ret(*|) L1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== Test_2 == +class Test_2 { + @Target(AnnotationTarget.FUNCTION) + annotation class Range(val min: Long = 0) + + @Range(min = -90L) // KtPrefixExpression is marked as BindingContext.USED_AS_EXPRESSION + fun foo(x: Int) = Unit +} +--------------------- +L0: + 1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== foo == +@Range(min = -90L) // KtPrefixExpression is marked as BindingContext.USED_AS_EXPRESSION + fun foo(x: Int) = Unit +--------------------- +L0: + 1 + v(x: Int) + magic[FAKE_INITIALIZER](x: Int) -> + w(x|) + r(Unit) -> + ret(*|) L1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== Test_3 == +class Test_3 { + @Target(AnnotationTarget.EXPRESSION) + annotation class Range(val min: Long = 0) + + fun foo(x: Int) = @Range(min = -90L) Unit +} +--------------------- +L0: + 1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== +== foo == +fun foo(x: Int) = @Range(min = -90L) Unit +--------------------- +L0: + 1 + v(x: Int) + magic[FAKE_INITIALIZER](x: Int) -> + w(x|) + r(Unit) -> + ret(*|) L1 +L1: + NEXT:[] +error: + PREV:[] +sink: + PREV:[, ] +===================== diff --git a/compiler/testData/cfg/bugs/kt37447.kt b/compiler/testData/cfg/bugs/kt37447.kt new file mode 100644 index 00000000000..aa8007ec87f --- /dev/null +++ b/compiler/testData/cfg/bugs/kt37447.kt @@ -0,0 +1,23 @@ +// ISSUE: KT-37447 + +class Test_1 { + @Target(AnnotationTarget.VALUE_PARAMETER) + annotation class Range(val min: Long = 0) + + fun foo(@Range(min = -90L) x: Int) = Unit // KtPrefixExpression isn't marked as BindingContext.USED_AS_EXPRESSION +} + +class Test_2 { + @Target(AnnotationTarget.FUNCTION) + annotation class Range(val min: Long = 0) + + @Range(min = -90L) // KtPrefixExpression is marked as BindingContext.USED_AS_EXPRESSION + fun foo(x: Int) = Unit +} + +class Test_3 { + @Target(AnnotationTarget.EXPRESSION) + annotation class Range(val min: Long = 0) + + fun foo(x: Int) = @Range(min = -90L) Unit +} \ No newline at end of file diff --git a/compiler/testData/cfg/bugs/kt37447.values b/compiler/testData/cfg/bugs/kt37447.values new file mode 100644 index 00000000000..7a5ec298d65 --- /dev/null +++ b/compiler/testData/cfg/bugs/kt37447.values @@ -0,0 +1,48 @@ +== Test_1 == +class Test_1 { + @Target(AnnotationTarget.VALUE_PARAMETER) + annotation class Range(val min: Long = 0) + + fun foo(@Range(min = -90L) x: Int) = Unit // KtPrefixExpression isn't marked as BindingContext.USED_AS_EXPRESSION +} +--------------------- +===================== +== foo == +fun foo(@Range(min = -90L) x: Int) = Unit // KtPrefixExpression isn't marked as BindingContext.USED_AS_EXPRESSION +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](@Range(min = -90L) x: Int) -> +Unit : Unit NEW: r(Unit) -> +===================== +== Test_2 == +class Test_2 { + @Target(AnnotationTarget.FUNCTION) + annotation class Range(val min: Long = 0) + + @Range(min = -90L) // KtPrefixExpression is marked as BindingContext.USED_AS_EXPRESSION + fun foo(x: Int) = Unit +} +--------------------- +===================== +== foo == +@Range(min = -90L) // KtPrefixExpression is marked as BindingContext.USED_AS_EXPRESSION + fun foo(x: Int) = Unit +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](x: Int) -> +Unit : Unit NEW: r(Unit) -> +===================== +== Test_3 == +class Test_3 { + @Target(AnnotationTarget.EXPRESSION) + annotation class Range(val min: Long = 0) + + fun foo(x: Int) = @Range(min = -90L) Unit +} +--------------------- +===================== +== foo == +fun foo(x: Int) = @Range(min = -90L) Unit +--------------------- + : Int NEW: magic[FAKE_INITIALIZER](x: Int) -> +Unit : Unit NEW: r(Unit) -> +@Range(min = -90L) Unit : Unit COPY +===================== diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java index 945a0989a58..5150fe84efd 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/ControlFlowTestGenerated.java @@ -148,6 +148,11 @@ public class ControlFlowTestGenerated extends AbstractControlFlowTest { runTest("compiler/testData/cfg/bugs/kt10105.kt"); } + @TestMetadata("kt37447.kt") + public void testKt37447() throws Exception { + runTest("compiler/testData/cfg/bugs/kt37447.kt"); + } + @TestMetadata("kt7761.kt") public void testKt7761() throws Exception { runTest("compiler/testData/cfg/bugs/kt7761.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java index fa418b5e8ee..da92e9ce193 100644 --- a/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/cfg/PseudoValueTestGenerated.java @@ -148,6 +148,11 @@ public class PseudoValueTestGenerated extends AbstractPseudoValueTest { runTest("compiler/testData/cfg/bugs/kt10105.kt"); } + @TestMetadata("kt37447.kt") + public void testKt37447() throws Exception { + runTest("compiler/testData/cfg/bugs/kt37447.kt"); + } + @TestMetadata("kt7761.kt") public void testKt7761() throws Exception { runTest("compiler/testData/cfg/bugs/kt7761.kt"); diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedUnaryOperatorInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedUnaryOperatorInspection.kt index 27f4ff3cf49..6a96488478f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedUnaryOperatorInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedUnaryOperatorInspection.kt @@ -15,11 +15,8 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.util.textRangeIn import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.KtAnnotationEntry -import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPrefixExpression import org.jetbrains.kotlin.psi.prefixExpressionVisitor -import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -30,8 +27,6 @@ class UnusedUnaryOperatorInspection : AbstractKotlinInspection() { val operationToken = prefix.operationToken if (operationToken != KtTokens.PLUS && operationToken != KtTokens.MINUS) return - // ISSUE: KT-37447 - if (prefix.isInAnnotationEntry) return val context = prefix.analyze(BodyResolveMode.PARTIAL_WITH_CFA) if (prefix.isUsedAsExpression(context)) return val operatorDescriptor = prefix.operationReference.getResolvedCall(context)?.resultingDescriptor as? DeclarationDescriptor ?: return @@ -58,6 +53,3 @@ class UnusedUnaryOperatorInspection : AbstractKotlinInspection() { } } } - -private val KtPrefixExpression.isInAnnotationEntry: Boolean - get() = parentsWithSelf.takeWhile { it is KtExpression }.last().parent?.parent?.parent is KtAnnotationEntry \ No newline at end of file