From ff5a52b4450be2b69019823b8c819dc1f4e622be Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Wed, 31 May 2017 21:35:55 +0300 Subject: [PATCH] Analyze Data Flow: Respect member hierarchies #KT-11994 In Progress --- .../declarationsSearch/overridersSearch.kt | 2 +- .../kotlin/idea/findUsages/findUsageUtils.kt | 6 +- .../jetbrains/kotlin/idea/slicer/Slicer.kt | 98 +++++++++++------ .../inflow/diamondHierarchyMiddleClassFun.kt | 24 +++++ ...diamondHierarchyMiddleClassFun.results.txt | 6 ++ .../diamondHierarchyMiddleInterfaceFun.kt | 24 +++++ ...ondHierarchyMiddleInterfaceFun.results.txt | 6 ++ .../diamondHierarchyRootInterfaceFun.kt | 24 +++++ ...amondHierarchyRootInterfaceFun.results.txt | 10 ++ .../slicer/inflow/overridingFunctionResult.kt | 19 ++++ .../overridingFunctionResult.results.txt | 6 ++ .../slicer/inflow/overridingParameter.kt | 17 +++ .../inflow/overridingParameter.results.txt | 5 + .../inflow/overridingPropertyGetterResult.kt | 22 ++++ ...overridingPropertyGetterResult.results.txt | 6 ++ .../slicer/inflow/overridingPropertyResult.kt | 19 ++++ .../overridingPropertyResult.results.txt | 6 ++ .../outflow/diamondHierarchyLeafClassFun.kt | 24 +++++ .../diamondHierarchyLeafClassFun.results.txt | 10 ++ .../outflow/diamondHierarchyMiddleClassFun.kt | 24 +++++ ...diamondHierarchyMiddleClassFun.results.txt | 6 ++ .../diamondHierarchyMiddleInterfaceFun.kt | 24 +++++ ...ondHierarchyMiddleInterfaceFun.results.txt | 6 ++ .../outflow/overridingFunctionResult.kt | 19 ++++ .../overridingFunctionResult.results.txt | 6 ++ .../slicer/outflow/overridingParameter.kt | 17 +++ .../outflow/overridingParameter.results.txt | 5 + .../outflow/overridingPropertyGetterResult.kt | 22 ++++ ...overridingPropertyGetterResult.results.txt | 4 + .../outflow/overridingPropertyResult.kt | 19 ++++ .../overridingPropertyResult.results.txt | 4 + .../idea/slicer/SlicerTestGenerated.java | 102 ++++++++++++++++-- 32 files changed, 546 insertions(+), 46 deletions(-) create mode 100644 idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.kt create mode 100644 idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.results.txt create mode 100644 idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.kt create mode 100644 idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.results.txt create mode 100644 idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.kt create mode 100644 idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.results.txt create mode 100644 idea/testData/slicer/inflow/overridingFunctionResult.kt create mode 100644 idea/testData/slicer/inflow/overridingFunctionResult.results.txt create mode 100644 idea/testData/slicer/inflow/overridingParameter.kt create mode 100644 idea/testData/slicer/inflow/overridingParameter.results.txt create mode 100644 idea/testData/slicer/inflow/overridingPropertyGetterResult.kt create mode 100644 idea/testData/slicer/inflow/overridingPropertyGetterResult.results.txt create mode 100644 idea/testData/slicer/inflow/overridingPropertyResult.kt create mode 100644 idea/testData/slicer/inflow/overridingPropertyResult.results.txt create mode 100644 idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.kt create mode 100644 idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.results.txt create mode 100644 idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.kt create mode 100644 idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.results.txt create mode 100644 idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.kt create mode 100644 idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.results.txt create mode 100644 idea/testData/slicer/outflow/overridingFunctionResult.kt create mode 100644 idea/testData/slicer/outflow/overridingFunctionResult.results.txt create mode 100644 idea/testData/slicer/outflow/overridingParameter.kt create mode 100644 idea/testData/slicer/outflow/overridingParameter.results.txt create mode 100644 idea/testData/slicer/outflow/overridingPropertyGetterResult.kt create mode 100644 idea/testData/slicer/outflow/overridingPropertyGetterResult.results.txt create mode 100644 idea/testData/slicer/outflow/overridingPropertyResult.kt create mode 100644 idea/testData/slicer/outflow/overridingPropertyResult.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 2644e88a114..83e46845e2d 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 @@ -60,7 +60,7 @@ object KotlinPsiMethodOverridersSearch : HierarchySearch(PsiMethodOve val psiClass = psiMethod.containingClass if (psiClass == null) return Collections.emptyList() - val classToMethod = HashMap() + val classToMethod = LinkedHashMap() val classTraverser = object : HierarchyTraverser { override fun nextElements(current: PsiClass): Iterable = DirectClassInheritorsSearch.search( diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/findUsageUtils.kt b/idea/src/org/jetbrains/kotlin/idea/findUsages/findUsageUtils.kt index d7213d7c8d4..8901f492915 100644 --- a/idea/src/org/jetbrains/kotlin/idea/findUsages/findUsageUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/findUsageUtils.kt @@ -20,7 +20,7 @@ import com.intellij.find.findUsages.FindUsagesOptions import com.intellij.usageView.UsageInfo import org.jetbrains.kotlin.psi.KtDeclaration -fun KtDeclaration.processAllUsages( +fun KtDeclaration.processAllExactUsages( options: () -> FindUsagesOptions, processor: (UsageInfo) -> Unit ) { @@ -28,7 +28,9 @@ fun KtDeclaration.processAllUsages( findUsagesHandler.processElementUsages( this, { - processor(it) + if (it.reference?.isReferenceTo(this) ?: false) { + processor(it) + } true }, options() diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt index c887955cc74..da52124b6d1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/slicer/Slicer.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.idea.slicer +import com.intellij.analysis.AnalysisScope import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector.Access import com.intellij.psi.PsiElement import com.intellij.psi.search.LocalSearchScope @@ -23,6 +24,7 @@ import com.intellij.psi.search.SearchScope import com.intellij.slicer.SliceUsage import com.intellij.usageView.UsageInfo import com.intellij.util.Processor +import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode @@ -33,6 +35,7 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.* import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor @@ -41,14 +44,17 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions -import org.jetbrains.kotlin.idea.findUsages.processAllUsages +import org.jetbrains.kotlin.idea.findUsages.processAllExactUsages import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar +import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest +import org.jetbrains.kotlin.idea.search.declarationsSearch.searchOverriders import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument @@ -56,8 +62,25 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.source.getPsi import java.util.* +private fun KtDeclaration.processHierarchyDownward(scope: SearchScope, processor: KtDeclaration.() -> Unit) { + processor() + HierarchySearchRequest(this, scope).searchOverriders().forEach { + (it.namedUnwrappedElement as? KtDeclaration)?.processor() + } +} + +private fun KtDeclaration.processHierarchyUpward(scope: AnalysisScope, processor: KtDeclaration.() -> Unit) { + processor() + val descriptor = resolveToDescriptor() as? CallableMemberDescriptor ?: return + DescriptorUtils + .getAllOverriddenDescriptors(descriptor) + .mapNotNull { it.source.getPsi() as? KtDeclaration } + .filter { scope.contains(it) } + .forEach(processor) +} + private fun KtFunction.processCalls(scope: SearchScope, processor: (UsageInfo) -> Unit) { - processAllUsages( + processAllExactUsages( { KotlinFunctionFindUsagesOptions(project).apply { isSearchForTextOccurrences = false @@ -74,7 +97,7 @@ private fun KtDeclaration.processVariableAccesses( kind: Access, processor: (UsageInfo) -> Unit ) { - processAllUsages( + processAllExactUsages( { KotlinPropertyFindUsagesOptions(project).apply { isReadAccess = kind == Access.Read || kind == Access.ReadWrite @@ -126,6 +149,10 @@ class InflowSlicer( processor: Processor, parentUsage: KotlinSliceUsage ) : Slicer(element, processor, parentUsage) { + private fun KtDeclaration.processHierarchyDownwardAndPass() { + processHierarchyDownward(parentUsage.scope.toSearchScope()) { passToProcessor() } + } + private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true) private fun KtDeclaration.processAssignments(accessSearchScope: SearchScope) { @@ -148,7 +175,8 @@ class InflowSlicer( private fun KtProperty.processPropertyAssignments() { val analysisScope = parentUsage.scope.toSearchScope() - val accessSearchScope = if (isVar) analysisScope else { + val accessSearchScope = if (isVar) analysisScope + else { val containerScope = getStrictParentOfType()?.let { LocalSearchScope(it) } ?: return analysisScope.intersectWith(containerScope) } @@ -238,10 +266,10 @@ class InflowSlicer( private fun KtExpression.processExpression() { val lambda = when (this) { - is KtLambdaExpression -> functionLiteral - is KtNamedFunction -> if (name == null) this else null - else -> null - } + is KtLambdaExpression -> functionLiteral + is KtNamedFunction -> if (name == null) this else null + else -> null + } if (lambda != null) { if (parentUsage.lambdaLevel > 0) { lambda.passToProcessor(parentUsage.lambdaLevel - 1) @@ -273,7 +301,7 @@ class InflowSlicer( } return } - accessedDeclaration.passToProcessor() + accessedDeclaration.processHierarchyDownwardAndPass() } is MergeInstruction -> createdAt.passInputsToProcessor() @@ -296,7 +324,7 @@ class InflowSlicer( (resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression?.passToProcessorAsValue(parentUsage.lambdaLevel + 1) } else { - resultingDescriptor.source.getPsi()?.passToProcessor() + (resultingDescriptor.source.getPsi() as? KtDeclaration)?.processHierarchyDownwardAndPass() } } } @@ -320,19 +348,18 @@ class OutflowSlicer( parentUsage: KotlinSliceUsage ) : Slicer(element, processor, parentUsage) { private fun KtDeclaration.processVariable() { - if (this is KtParameter && !canProcess()) return + processHierarchyUpward(parentUsage.scope) { + if (this is KtParameter && !canProcess()) return@processHierarchyUpward - val withDereferences = parentUsage.params.showInstanceDereferences - processVariableAccesses( - parentUsage.scope.toSearchScope(), - if (withDereferences) Access.ReadWrite else Access.Read - ) body@ { - val refExpression = (it.element as? KtExpression)?.let { KtPsiUtil.safeDeparenthesize(it) } ?: return@body - if (withDereferences) { - refExpression.processDereferences() - } - if (!withDereferences || KotlinReadWriteAccessDetector.INSTANCE.getExpressionAccess(refExpression) == Access.Read) { - refExpression.processExpression() + val withDereferences = parentUsage.params.showInstanceDereferences + processVariableAccesses(parentUsage.scope.toSearchScope(), if (withDereferences) Access.ReadWrite else Access.Read) body@ { + val refExpression = (it.element as? KtExpression)?.let { KtPsiUtil.safeDeparenthesize(it) } ?: return@body + if (withDereferences) { + refExpression.processDereferences() + } + if (!withDereferences || KotlinReadWriteAccessDetector.INSTANCE.getExpressionAccess(refExpression) == Access.Read) { + refExpression.processExpression() + } } } } @@ -357,17 +384,20 @@ class OutflowSlicer( private fun KtFunction.processFunction() { if (this is KtConstructor<*> || this is KtNamedFunction && name != null) { - processCalls(parentUsage.scope.toSearchScope()) { - it.element?.getCallElementForExactCallee()?.passToProcessor() - it.element?.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1) + processHierarchyUpward(parentUsage.scope) { + (this as? KtFunction)?.processCalls(parentUsage.scope.toSearchScope()) { + it.element?.getCallElementForExactCallee()?.passToProcessor() + it.element?.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1) + } } return } + val funExpression = when (this) { - is KtFunctionLiteral -> parent as? KtLambdaExpression - is KtNamedFunction -> this - else -> null - } ?: return + is KtFunctionLiteral -> parent as? KtLambdaExpression + is KtNamedFunction -> this + else -> null + } ?: return (funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true) } @@ -380,10 +410,10 @@ class OutflowSlicer( val receiver = instr.receiverValues[pseudoValue] val resolvedCall = when (instr) { - is CallInstruction -> instr.resolvedCall - is ReadValueInstruction -> (instr.target as? AccessTarget.Call)?.resolvedCall - else -> null - } ?: return + is CallInstruction -> instr.resolvedCall + is ReadValueInstruction -> (instr.target as? AccessTarget.Call)?.resolvedCall + else -> null + } ?: return if (receiver != null && resolvedCall.dispatchReceiver == receiver) { processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, parentUsage.lambdaLevel)) @@ -420,7 +450,7 @@ class OutflowSlicer( is ReturnValueInstruction -> instr.subroutine.passToProcessor() is MagicInstruction -> when (instr.kind) { MagicKind.NOT_NULL_ASSERTION, MagicKind.CAST -> instr.outputValue.element?.passToProcessor() - else -> {} + else -> { } } } } diff --git a/idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.kt b/idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.kt new file mode 100644 index 00000000000..8b083285806 --- /dev/null +++ b/idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.kt @@ -0,0 +1,24 @@ +// FLOW: IN + +interface A { + fun foo() = 1 +} + +open class B : A { + override fun foo() = 2 +} + +interface C : A { + override fun foo() = 3 +} + +class D : B(), C { + override fun foo() = 4 +} + +fun test(a: A, b: B, c: C, d: D) { + val x = a.foo() + val y = b.foo() + val z = c.foo() + val u = d.foo() +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.results.txt b/idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.results.txt new file mode 100644 index 00000000000..9b70369d62f --- /dev/null +++ b/idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.results.txt @@ -0,0 +1,6 @@ +21 val y = b.foo() +21 val y = b.foo() +8 override fun foo() = 2 +8 override fun foo() = 2 +16 override fun foo() = 4 +16 override fun foo() = 4 diff --git a/idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.kt b/idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.kt new file mode 100644 index 00000000000..038176c1be6 --- /dev/null +++ b/idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.kt @@ -0,0 +1,24 @@ +// FLOW: IN + +interface A { + fun foo() = 1 +} + +open class B : A { + override fun foo() = 2 +} + +interface C : A { + override fun foo() = 3 +} + +class D : B(), C { + override fun foo() = 4 +} + +fun test(a: A, b: B, c: C, d: D) { + val x = a.foo() + val y = b.foo() + val z = c.foo() + val u = d.foo() +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.results.txt b/idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.results.txt new file mode 100644 index 00000000000..74d9098a95d --- /dev/null +++ b/idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.results.txt @@ -0,0 +1,6 @@ +22 val z = c.foo() +22 val z = c.foo() +12 override fun foo() = 3 +12 override fun foo() = 3 +16 override fun foo() = 4 +16 override fun foo() = 4 diff --git a/idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.kt b/idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.kt new file mode 100644 index 00000000000..b4e3ac8d45a --- /dev/null +++ b/idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.kt @@ -0,0 +1,24 @@ +// FLOW: IN + +interface A { + fun foo() = 1 +} + +open class B : A { + override fun foo() = 2 +} + +interface C : A { + override fun foo() = 3 +} + +class D : B(), C { + override fun foo() = 4 +} + +fun test(a: A, b: B, c: C, d: D) { + val x = a.foo() + val y = b.foo() + val z = c.foo() + val u = d.foo() +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.results.txt b/idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.results.txt new file mode 100644 index 00000000000..6611cb67f93 --- /dev/null +++ b/idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.results.txt @@ -0,0 +1,10 @@ +20 val x = a.foo() +20 val x = a.foo() +4 fun foo() = 1 +4 fun foo() = 1 +8 override fun foo() = 2 +8 override fun foo() = 2 +12 override fun foo() = 3 +12 override fun foo() = 3 +16 override fun foo() = 4 +16 override fun foo() = 4 diff --git a/idea/testData/slicer/inflow/overridingFunctionResult.kt b/idea/testData/slicer/inflow/overridingFunctionResult.kt new file mode 100644 index 00000000000..4347a6af5db --- /dev/null +++ b/idea/testData/slicer/inflow/overridingFunctionResult.kt @@ -0,0 +1,19 @@ +// FLOW: IN + +open class A { + open fun foo() = 1 +} + +open class B : A() { + override fun foo() = 2 +} + +class C : B() { + override fun foo() = 3 +} + +fun test(a: A, b: B, c: C) { + val x = a.foo() + val y = b.foo() + val z = c.foo() +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/overridingFunctionResult.results.txt b/idea/testData/slicer/inflow/overridingFunctionResult.results.txt new file mode 100644 index 00000000000..1568d394995 --- /dev/null +++ b/idea/testData/slicer/inflow/overridingFunctionResult.results.txt @@ -0,0 +1,6 @@ +17 val y = b.foo() +17 val y = b.foo() +8 override fun foo() = 2 +8 override fun foo() = 2 +12 override fun foo() = 3 +12 override fun foo() = 3 diff --git a/idea/testData/slicer/inflow/overridingParameter.kt b/idea/testData/slicer/inflow/overridingParameter.kt new file mode 100644 index 00000000000..f612dd96812 --- /dev/null +++ b/idea/testData/slicer/inflow/overridingParameter.kt @@ -0,0 +1,17 @@ +// FLOW: IN + +open class A { + open val foo = 1 +} + +open class B(override val foo: Int) : A() + +class C : B() { + override val foo = 3 +} + +fun test(a: A, b: B, c: C) { + val x = a.foo + val y = b.foo + val z = c.foo +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/overridingParameter.results.txt b/idea/testData/slicer/inflow/overridingParameter.results.txt new file mode 100644 index 00000000000..96db7c39e0b --- /dev/null +++ b/idea/testData/slicer/inflow/overridingParameter.results.txt @@ -0,0 +1,5 @@ +15 val y = b.foo +15 val y = b.foo +7 open class B(override val foo: Int) : A() +10 override val foo = 3 +10 override val foo = 3 diff --git a/idea/testData/slicer/inflow/overridingPropertyGetterResult.kt b/idea/testData/slicer/inflow/overridingPropertyGetterResult.kt new file mode 100644 index 00000000000..0a1a62154d0 --- /dev/null +++ b/idea/testData/slicer/inflow/overridingPropertyGetterResult.kt @@ -0,0 +1,22 @@ +// FLOW: IN + +open class A { + open val foo: Int + get() = 1 +} + +open class B : A() { + override val foo: Int + get() = 2 +} + +class C : B() { + override val foo: Int + get() = 3 +} + +fun test(a: A, b: B, c: C) { + val x = a.foo + val y = b.foo + val z = c.foo +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/overridingPropertyGetterResult.results.txt b/idea/testData/slicer/inflow/overridingPropertyGetterResult.results.txt new file mode 100644 index 00000000000..74f82ffb617 --- /dev/null +++ b/idea/testData/slicer/inflow/overridingPropertyGetterResult.results.txt @@ -0,0 +1,6 @@ +20 val y = b.foo +20 val y = b.foo +9 override val foo: Int +10 get() = 2 +14 override val foo: Int +15 get() = 3 diff --git a/idea/testData/slicer/inflow/overridingPropertyResult.kt b/idea/testData/slicer/inflow/overridingPropertyResult.kt new file mode 100644 index 00000000000..0022874078b --- /dev/null +++ b/idea/testData/slicer/inflow/overridingPropertyResult.kt @@ -0,0 +1,19 @@ +// FLOW: IN + +open class A { + open val foo = 1 +} + +open class B : A() { + override val foo = 2 +} + +class C : B() { + override val foo = 3 +} + +fun test(a: A, b: B, c: C) { + val x = a.foo + val y = b.foo + val z = c.foo +} \ No newline at end of file diff --git a/idea/testData/slicer/inflow/overridingPropertyResult.results.txt b/idea/testData/slicer/inflow/overridingPropertyResult.results.txt new file mode 100644 index 00000000000..fe3db8a9f5b --- /dev/null +++ b/idea/testData/slicer/inflow/overridingPropertyResult.results.txt @@ -0,0 +1,6 @@ +17 val y = b.foo +17 val y = b.foo +8 override val foo = 2 +8 override val foo = 2 +12 override val foo = 3 +12 override val foo = 3 diff --git a/idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.kt b/idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.kt new file mode 100644 index 00000000000..764e759db40 --- /dev/null +++ b/idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.kt @@ -0,0 +1,24 @@ +// FLOW: OUT + +interface A { + fun foo() = 1 +} + +open class B : A { + override fun foo() = 2 +} + +interface C : A { + override fun foo() = 3 +} + +class D : B(), C { + override fun foo() = 4 +} + +fun test(a: A, b: B, c: C, d: D) { + val x = a.foo() + val y = b.foo() + val z = c.foo() + val u = d.foo() +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.results.txt b/idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.results.txt new file mode 100644 index 00000000000..9047ae88c8a --- /dev/null +++ b/idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.results.txt @@ -0,0 +1,10 @@ +16 override fun foo() = 4 +16 override fun foo() = 4 +23 val u = d.foo() +23 val u = d.foo() +20 val x = a.foo() +20 val x = a.foo() +21 val y = b.foo() +21 val y = b.foo() +22 val z = c.foo() +22 val z = c.foo() diff --git a/idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.kt b/idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.kt new file mode 100644 index 00000000000..1052d8b4d23 --- /dev/null +++ b/idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.kt @@ -0,0 +1,24 @@ +// FLOW: OUT + +interface A { + fun foo() = 1 +} + +open class B : A { + override fun foo() = 2 +} + +interface C : A { + override fun foo() = 3 +} + +class D : B(), C { + override fun foo() = 4 +} + +fun test(a: A, b: B, c: C, d: D) { + val x = a.foo() + val y = b.foo() + val z = c.foo() + val u = d.foo() +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.results.txt b/idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.results.txt new file mode 100644 index 00000000000..45faf4b362e --- /dev/null +++ b/idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.results.txt @@ -0,0 +1,6 @@ +8 override fun foo() = 2 +8 override fun foo() = 2 +21 val y = b.foo() +21 val y = b.foo() +20 val x = a.foo() +20 val x = a.foo() diff --git a/idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.kt b/idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.kt new file mode 100644 index 00000000000..117555ddf3f --- /dev/null +++ b/idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.kt @@ -0,0 +1,24 @@ +// FLOW: OUT + +interface A { + fun foo() = 1 +} + +open class B : A { + override fun foo() = 2 +} + +interface C : A { + override fun foo() = 3 +} + +class D : B(), C { + override fun foo() = 4 +} + +fun test(a: A, b: B, c: C, d: D) { + val x = a.foo() + val y = b.foo() + val z = c.foo() + val u = d.foo() +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.results.txt b/idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.results.txt new file mode 100644 index 00000000000..da400632924 --- /dev/null +++ b/idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.results.txt @@ -0,0 +1,6 @@ +12 override fun foo() = 3 +12 override fun foo() = 3 +22 val z = c.foo() +22 val z = c.foo() +20 val x = a.foo() +20 val x = a.foo() diff --git a/idea/testData/slicer/outflow/overridingFunctionResult.kt b/idea/testData/slicer/outflow/overridingFunctionResult.kt new file mode 100644 index 00000000000..dff21397f28 --- /dev/null +++ b/idea/testData/slicer/outflow/overridingFunctionResult.kt @@ -0,0 +1,19 @@ +// FLOW: OUT + +open class A { + open fun foo() = 1 +} + +open class B : A() { + override fun foo() = 2 +} + +class C : B() { + override fun foo() = 3 +} + +fun test(a: A, b: B, c: C) { + val x = a.foo() + val y = b.foo() + val z = c.foo() +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/overridingFunctionResult.results.txt b/idea/testData/slicer/outflow/overridingFunctionResult.results.txt new file mode 100644 index 00000000000..efec88b3a9e --- /dev/null +++ b/idea/testData/slicer/outflow/overridingFunctionResult.results.txt @@ -0,0 +1,6 @@ +8 override fun foo() = 2 +8 override fun foo() = 2 +17 val y = b.foo() +17 val y = b.foo() +16 val x = a.foo() +16 val x = a.foo() diff --git a/idea/testData/slicer/outflow/overridingParameter.kt b/idea/testData/slicer/outflow/overridingParameter.kt new file mode 100644 index 00000000000..bb2325276dc --- /dev/null +++ b/idea/testData/slicer/outflow/overridingParameter.kt @@ -0,0 +1,17 @@ +// FLOW: OUT + +open class A() { + open val foo = 1 +} + +open class B(override val foo: Int) : A() + +class C : B() { + override val foo = 3 +} + +fun test(a: A, b: B, c: C) { + val x = a.foo + val y = b.foo + val z = c.foo +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/overridingParameter.results.txt b/idea/testData/slicer/outflow/overridingParameter.results.txt new file mode 100644 index 00000000000..7c8ff133c32 --- /dev/null +++ b/idea/testData/slicer/outflow/overridingParameter.results.txt @@ -0,0 +1,5 @@ +10 override val foo = 3 +10 override val foo = 3 +16 val z = c.foo +14 val x = a.foo +15 val y = b.foo diff --git a/idea/testData/slicer/outflow/overridingPropertyGetterResult.kt b/idea/testData/slicer/outflow/overridingPropertyGetterResult.kt new file mode 100644 index 00000000000..1194350c85e --- /dev/null +++ b/idea/testData/slicer/outflow/overridingPropertyGetterResult.kt @@ -0,0 +1,22 @@ +// FLOW: OUT + +open class A { + open val foo: Int + get() = 1 +} + +open class B : A() { + override val foo: Int + get() = 2 +} + +class C : B() { + override val foo: Int + get() = 3 +} + +fun test(a: A, b: B, c: C) { + val x = a.foo + val y = b.foo + val z = c.foo +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/overridingPropertyGetterResult.results.txt b/idea/testData/slicer/outflow/overridingPropertyGetterResult.results.txt new file mode 100644 index 00000000000..1c810a60b99 --- /dev/null +++ b/idea/testData/slicer/outflow/overridingPropertyGetterResult.results.txt @@ -0,0 +1,4 @@ +10 get() = 2 +10 get() = 2 +20 val y = b.foo +19 val x = a.foo diff --git a/idea/testData/slicer/outflow/overridingPropertyResult.kt b/idea/testData/slicer/outflow/overridingPropertyResult.kt new file mode 100644 index 00000000000..948b2f08ea2 --- /dev/null +++ b/idea/testData/slicer/outflow/overridingPropertyResult.kt @@ -0,0 +1,19 @@ +// FLOW: OUT + +open class A { + open val foo = 1 +} + +open class B : A() { + override val foo = 2 +} + +class C : B() { + override val foo = 3 +} + +fun test(a: A, b: B, c: C) { + val x = a.foo + val y = b.foo + val z = c.foo +} \ No newline at end of file diff --git a/idea/testData/slicer/outflow/overridingPropertyResult.results.txt b/idea/testData/slicer/outflow/overridingPropertyResult.results.txt new file mode 100644 index 00000000000..67f36298206 --- /dev/null +++ b/idea/testData/slicer/outflow/overridingPropertyResult.results.txt @@ -0,0 +1,4 @@ +8 override val foo = 2 +8 override val foo = 2 +17 val y = b.foo +16 val x = a.foo diff --git a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestGenerated.java index 2207ad83829..c795536b65a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/slicer/SlicerTestGenerated.java @@ -66,6 +66,24 @@ public class SlicerTestGenerated extends AbstractSlicerTest { doTest(fileName); } + @TestMetadata("inflow/diamondHierarchyMiddleClassFun.kt") + public void testInflow_DiamondHierarchyMiddleClassFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/diamondHierarchyMiddleClassFun.kt"); + doTest(fileName); + } + + @TestMetadata("inflow/diamondHierarchyMiddleInterfaceFun.kt") + public void testInflow_DiamondHierarchyMiddleInterfaceFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/diamondHierarchyMiddleInterfaceFun.kt"); + doTest(fileName); + } + + @TestMetadata("inflow/diamondHierarchyRootInterfaceFun.kt") + public void testInflow_DiamondHierarchyRootInterfaceFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/diamondHierarchyRootInterfaceFun.kt"); + doTest(fileName); + } + @TestMetadata("inflow/doubleLambdaResult.kt") public void testInflow_DoubleLambdaResult() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/doubleLambdaResult.kt"); @@ -216,6 +234,30 @@ public class SlicerTestGenerated extends AbstractSlicerTest { doTest(fileName); } + @TestMetadata("inflow/overridingFunctionResult.kt") + public void testInflow_OverridingFunctionResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/overridingFunctionResult.kt"); + doTest(fileName); + } + + @TestMetadata("inflow/overridingParameter.kt") + public void testInflow_OverridingParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/overridingParameter.kt"); + doTest(fileName); + } + + @TestMetadata("inflow/overridingPropertyGetterResult.kt") + public void testInflow_OverridingPropertyGetterResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/overridingPropertyGetterResult.kt"); + doTest(fileName); + } + + @TestMetadata("inflow/overridingPropertyResult.kt") + public void testInflow_OverridingPropertyResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/overridingPropertyResult.kt"); + doTest(fileName); + } + @TestMetadata("inflow/primaryConstructorParameter.kt") public void testInflow_PrimaryConstructorParameter() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/primaryConstructorParameter.kt"); @@ -300,6 +342,24 @@ public class SlicerTestGenerated extends AbstractSlicerTest { doTest(fileName); } + @TestMetadata("outflow/diamondHierarchyLeafClassFun.kt") + public void testOutflow_DiamondHierarchyLeafClassFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/diamondHierarchyLeafClassFun.kt"); + doTest(fileName); + } + + @TestMetadata("outflow/diamondHierarchyMiddleClassFun.kt") + public void testOutflow_DiamondHierarchyMiddleClassFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/diamondHierarchyMiddleClassFun.kt"); + doTest(fileName); + } + + @TestMetadata("outflow/diamondHierarchyMiddleInterfaceFun.kt") + public void testOutflow_DiamondHierarchyMiddleInterfaceFun() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/diamondHierarchyMiddleInterfaceFun.kt"); + doTest(fileName); + } + @TestMetadata("outflow/doubleLambdaResult.kt") public void testOutflow_DoubleLambdaResult() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/doubleLambdaResult.kt"); @@ -360,6 +420,12 @@ public class SlicerTestGenerated extends AbstractSlicerTest { doTest(fileName); } + @TestMetadata("outflow/getFunCalls.kt") + public void testOutflow_GetFunCalls() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/getFunCalls.kt"); + doTest(fileName); + } + @TestMetadata("outflow/getterExpressionBody.kt") public void testOutflow_GetterExpressionBody() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/getterExpressionBody.kt"); @@ -372,12 +438,6 @@ public class SlicerTestGenerated extends AbstractSlicerTest { doTest(fileName); } - @TestMetadata("outflow/getFunCalls.kt") - public void testOutflow_GetFunCalls() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/getFunCalls.kt"); - doTest(fileName); - } - @TestMetadata("outflow/ifExpression.kt") public void testOutflow_IfExpression() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/ifExpression.kt"); @@ -438,15 +498,39 @@ public class SlicerTestGenerated extends AbstractSlicerTest { doTest(fileName); } + @TestMetadata("outflow/operatorCallDereferences.kt") + public void testOutflow_OperatorCallDereferences() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/operatorCallDereferences.kt"); + doTest(fileName); + } + @TestMetadata("outflow/operatorFunCalls.kt") public void testOutflow_OperatorFunCalls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/operatorFunCalls.kt"); doTest(fileName); } - @TestMetadata("outflow/operatorCallDereferences.kt") - public void testOutflow_OperatorCallDereferences() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/operatorCallDereferences.kt"); + @TestMetadata("outflow/overridingFunctionResult.kt") + public void testOutflow_OverridingFunctionResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/overridingFunctionResult.kt"); + doTest(fileName); + } + + @TestMetadata("outflow/overridingParameter.kt") + public void testOutflow_OverridingParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/overridingParameter.kt"); + doTest(fileName); + } + + @TestMetadata("outflow/overridingPropertyGetterResult.kt") + public void testOutflow_OverridingPropertyGetterResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/overridingPropertyGetterResult.kt"); + doTest(fileName); + } + + @TestMetadata("outflow/overridingPropertyResult.kt") + public void testOutflow_OverridingPropertyResult() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/overridingPropertyResult.kt"); doTest(fileName); }