From 2b83e3721adeb89d39ba2813b38559666d408aed Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 8 Apr 2020 14:08:24 +0300 Subject: [PATCH] KT-38003 "Analyze Data Flow from Here" should work on parameter of abstract method #KT-38003 Fixed --- .../declarationsSearch/overridersSearch.kt | 2 +- .../kotlin/idea/slicer/OutflowSlicer.kt | 22 +++++++++++++++++-- .../outflow/abstractMethodParameter1.kt | 11 ++++++++++ .../abstractMethodParameter1.results.txt | 3 +++ .../outflow/abstractMethodParameter2.kt | 15 +++++++++++++ .../abstractMethodParameter2.results.txt | 4 ++++ .../slicer/outflow/openMethodParameter.kt | 13 +++++++++++ .../outflow/openMethodParameter.results.txt | 4 ++++ .../idea/slicer/SlicerTreeTestGenerated.java | 15 +++++++++++++ 9 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 idea/testData/slicer/outflow/abstractMethodParameter1.kt create mode 100644 idea/testData/slicer/outflow/abstractMethodParameter1.results.txt create mode 100644 idea/testData/slicer/outflow/abstractMethodParameter2.kt create mode 100644 idea/testData/slicer/outflow/abstractMethodParameter2.results.txt create mode 100644 idea/testData/slicer/outflow/openMethodParameter.kt create mode 100644 idea/testData/slicer/outflow/openMethodParameter.results.txt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/declarationsSearch/overridersSearch.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/declarationsSearch/overridersSearch.kt index 982127576fa..6ff05997d46 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/declarationsSearch/overridersSearch.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/declarationsSearch/overridersSearch.kt @@ -153,7 +153,7 @@ private fun forEachKotlinOverride( fun KtNamedDeclaration.forEachOverridingElement( scope: SearchScope = runReadAction { useScope }, - processor: (PsiElement, PsiElement) -> Boolean + processor: (superMember: PsiElement, overridingMember: PsiElement) -> Boolean ): Boolean { val ktClass = runReadAction { containingClassOrObject as? KtClass } ?: return true diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt index ec540031c4f..0048d6de6b4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/OutflowSlicer.kt @@ -14,11 +14,13 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction import org.jetbrains.kotlin.idea.findUsages.handlers.SliceUsageProcessor +import org.jetbrains.kotlin.idea.search.declarationsSearch.forEachOverridingElement import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch import org.jetbrains.kotlin.psi.psiUtil.isAncestor +import org.jetbrains.kotlin.psi.psiUtil.parameterIndex import org.jetbrains.kotlin.resolve.source.getPsi class OutflowSlicer( @@ -40,8 +42,6 @@ class OutflowSlicer( } private fun processVariable(variable: KtCallableDeclaration) { - if (variable is KtParameter && !canProcessParameter(variable)) return - val withDereferences = parentUsage.params.showInstanceDereferences val accessKind = if (withDereferences) AccessKind.READ_OR_WRITE else AccessKind.READ_ONLY @@ -61,6 +61,24 @@ class OutflowSlicer( } } + if (variable is KtParameter) { + if (!canProcessParameter(variable)) return //TODO + + //TODO: expect/actual + + val callable = variable.ownerFunction as? KtCallableDeclaration + callable?.forEachOverridingElement(scope = analysisScope) { _, overridingMember -> + //TODO: Java overriders + if (overridingMember is KtCallableDeclaration) { + val parameters = overridingMember.valueParameters + check(parameters.size == callable.valueParameters.size) + val overridingParameter = parameters[variable.parameterIndex()] + overridingParameter.passToProcessor() + } + true + } + } + processVariableAccesses(variable, analysisScope, accessKind, ::processVariableAccess) } diff --git a/idea/testData/slicer/outflow/abstractMethodParameter1.kt b/idea/testData/slicer/outflow/abstractMethodParameter1.kt new file mode 100644 index 00000000000..d5f736ed16e --- /dev/null +++ b/idea/testData/slicer/outflow/abstractMethodParameter1.kt @@ -0,0 +1,11 @@ +// FLOW: OUT + +interface I { + fun foo(p: Any) +} + +class C : I { + override fun foo(p: Any) { + println(p) + } +} diff --git a/idea/testData/slicer/outflow/abstractMethodParameter1.results.txt b/idea/testData/slicer/outflow/abstractMethodParameter1.results.txt new file mode 100644 index 00000000000..30e7f0a4163 --- /dev/null +++ b/idea/testData/slicer/outflow/abstractMethodParameter1.results.txt @@ -0,0 +1,3 @@ +4 fun foo(p: Any) +8 override fun foo(p: Any) { +9 println(p) diff --git a/idea/testData/slicer/outflow/abstractMethodParameter2.kt b/idea/testData/slicer/outflow/abstractMethodParameter2.kt new file mode 100644 index 00000000000..3fffa563be6 --- /dev/null +++ b/idea/testData/slicer/outflow/abstractMethodParameter2.kt @@ -0,0 +1,15 @@ +// FLOW: OUT + +interface I { + fun foo(p: Any) +} + +class C : I { + override fun foo(p: Any) { + println(p) + } +} + +fun bar(i: I, s: String) { + i.foo(s) +} diff --git a/idea/testData/slicer/outflow/abstractMethodParameter2.results.txt b/idea/testData/slicer/outflow/abstractMethodParameter2.results.txt new file mode 100644 index 00000000000..49ad20f93c9 --- /dev/null +++ b/idea/testData/slicer/outflow/abstractMethodParameter2.results.txt @@ -0,0 +1,4 @@ +14 i.foo(s) +4 fun foo(p: Any) +8 override fun foo(p: Any) { +9 println(p) diff --git a/idea/testData/slicer/outflow/openMethodParameter.kt b/idea/testData/slicer/outflow/openMethodParameter.kt new file mode 100644 index 00000000000..3f1cd424bba --- /dev/null +++ b/idea/testData/slicer/outflow/openMethodParameter.kt @@ -0,0 +1,13 @@ +// FLOW: OUT + +open class C { + open fun foo(p: Any) { + println(p) + } +} + +class D : C() { + override fun foo(p: Any) { + println(p + 1) + } +} diff --git a/idea/testData/slicer/outflow/openMethodParameter.results.txt b/idea/testData/slicer/outflow/openMethodParameter.results.txt new file mode 100644 index 00000000000..39f622c244b --- /dev/null +++ b/idea/testData/slicer/outflow/openMethodParameter.results.txt @@ -0,0 +1,4 @@ +4 open fun foo(p: Any) { +5 println(p) +10 override fun foo(p: Any) { +11 println(p + 1) diff --git a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java index 2acad53c004..d3a05b0ef88 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTreeTestGenerated.java @@ -348,6 +348,16 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest { runTest("idea/testData/slicer/inflow/whenExpression.kt"); } + @TestMetadata("outflow/abstractMethodParameter1.kt") + public void testOutflow_AbstractMethodParameter1() throws Exception { + runTest("idea/testData/slicer/outflow/abstractMethodParameter1.kt"); + } + + @TestMetadata("outflow/abstractMethodParameter2.kt") + public void testOutflow_AbstractMethodParameter2() throws Exception { + runTest("idea/testData/slicer/outflow/abstractMethodParameter2.kt"); + } + @TestMetadata("outflow/anonymousFunBodyExpression.kt") public void testOutflow_AnonymousFunBodyExpression() throws Exception { runTest("idea/testData/slicer/outflow/anonymousFunBodyExpression.kt"); @@ -533,6 +543,11 @@ public class SlicerTreeTestGenerated extends AbstractSlicerTreeTest { runTest("idea/testData/slicer/outflow/notNullAssertion.kt"); } + @TestMetadata("outflow/openMethodParameter.kt") + public void testOutflow_OpenMethodParameter() throws Exception { + runTest("idea/testData/slicer/outflow/openMethodParameter.kt"); + } + @TestMetadata("outflow/operatorCallDereferences.kt") public void testOutflow_OperatorCallDereferences() throws Exception { runTest("idea/testData/slicer/outflow/operatorCallDereferences.kt");