Analyze Data Flow: Respect member hierarchies
#KT-11994 In Progress
This commit is contained in:
+1
-1
@@ -60,7 +60,7 @@ object KotlinPsiMethodOverridersSearch : HierarchySearch<PsiMethod>(PsiMethodOve
|
||||
val psiClass = psiMethod.containingClass
|
||||
if (psiClass == null) return Collections.emptyList()
|
||||
|
||||
val classToMethod = HashMap<PsiClass, PsiMethod>()
|
||||
val classToMethod = LinkedHashMap<PsiClass, PsiMethod>()
|
||||
val classTraverser = object : HierarchyTraverser<PsiClass> {
|
||||
override fun nextElements(current: PsiClass): Iterable<PsiClass> =
|
||||
DirectClassInheritorsSearch.search(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<SliceUsage>,
|
||||
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<KtDeclaration>()?.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 -> { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <caret>y = b.foo()
|
||||
val z = c.foo()
|
||||
val u = d.foo()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
21 val <bold>y = b.foo()</bold>
|
||||
21 val y = <bold>b.foo()</bold>
|
||||
8 override fun <bold>foo() = 2</bold>
|
||||
8 override fun foo() = <bold>2</bold>
|
||||
16 override fun <bold>foo() = 4</bold>
|
||||
16 override fun foo() = <bold>4</bold>
|
||||
@@ -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 <caret>z = c.foo()
|
||||
val u = d.foo()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
22 val <bold>z = c.foo()</bold>
|
||||
22 val z = <bold>c.foo()</bold>
|
||||
12 override fun <bold>foo() = 3</bold>
|
||||
12 override fun foo() = <bold>3</bold>
|
||||
16 override fun <bold>foo() = 4</bold>
|
||||
16 override fun foo() = <bold>4</bold>
|
||||
@@ -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 <caret>x = a.foo()
|
||||
val y = b.foo()
|
||||
val z = c.foo()
|
||||
val u = d.foo()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
20 val <bold>x = a.foo()</bold>
|
||||
20 val x = <bold>a.foo()</bold>
|
||||
4 fun <bold>foo() = 1</bold>
|
||||
4 fun foo() = <bold>1</bold>
|
||||
8 override fun <bold>foo() = 2</bold>
|
||||
8 override fun foo() = <bold>2</bold>
|
||||
12 override fun <bold>foo() = 3</bold>
|
||||
12 override fun foo() = <bold>3</bold>
|
||||
16 override fun <bold>foo() = 4</bold>
|
||||
16 override fun foo() = <bold>4</bold>
|
||||
@@ -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 <caret>y = b.foo()
|
||||
val z = c.foo()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
17 val <bold>y = b.foo()</bold>
|
||||
17 val y = <bold>b.foo()</bold>
|
||||
8 override fun <bold>foo() = 2</bold>
|
||||
8 override fun foo() = <bold>2</bold>
|
||||
12 override fun <bold>foo() = 3</bold>
|
||||
12 override fun foo() = <bold>3</bold>
|
||||
@@ -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 <caret>y = b.foo
|
||||
val z = c.foo
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
15 val <bold>y = b.foo</bold>
|
||||
15 val y = <bold>b.foo</bold>
|
||||
7 open class B(override val <bold>foo: Int</bold>) : A()
|
||||
10 override val <bold>foo = 3</bold>
|
||||
10 override val foo = <bold>3</bold>
|
||||
@@ -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 <caret>y = b.foo
|
||||
val z = c.foo
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
20 val <bold>y = b.foo</bold>
|
||||
20 val y = <bold>b.foo</bold>
|
||||
9 override val <bold>foo: Int</bold>
|
||||
10 get() = <bold>2</bold>
|
||||
14 override val <bold>foo: Int</bold>
|
||||
15 get() = <bold>3</bold>
|
||||
@@ -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 <caret>y = b.foo
|
||||
val z = c.foo
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
17 val <bold>y = b.foo</bold>
|
||||
17 val y = <bold>b.foo</bold>
|
||||
8 override val <bold>foo = 2</bold>
|
||||
8 override val foo = <bold>2</bold>
|
||||
12 override val <bold>foo = 3</bold>
|
||||
12 override val foo = <bold>3</bold>
|
||||
@@ -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() = <caret>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()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
16 override fun foo() = <bold>4</bold>
|
||||
16 override fun <bold>foo() = 4</bold>
|
||||
23 val u = d.<bold>foo()</bold>
|
||||
23 val <bold>u = d.foo()</bold>
|
||||
20 val x = a.<bold>foo()</bold>
|
||||
20 val <bold>x = a.foo()</bold>
|
||||
21 val y = b.<bold>foo()</bold>
|
||||
21 val <bold>y = b.foo()</bold>
|
||||
22 val z = c.<bold>foo()</bold>
|
||||
22 val <bold>z = c.foo()</bold>
|
||||
@@ -0,0 +1,24 @@
|
||||
// FLOW: OUT
|
||||
|
||||
interface A {
|
||||
fun foo() = 1
|
||||
}
|
||||
|
||||
open class B : A {
|
||||
override fun foo() = <caret>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()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
8 override fun foo() = <bold>2</bold>
|
||||
8 override fun <bold>foo() = 2</bold>
|
||||
21 val y = b.<bold>foo()</bold>
|
||||
21 val <bold>y = b.foo()</bold>
|
||||
20 val x = a.<bold>foo()</bold>
|
||||
20 val <bold>x = a.foo()</bold>
|
||||
@@ -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() = <caret>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()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
12 override fun foo() = <bold>3</bold>
|
||||
12 override fun <bold>foo() = 3</bold>
|
||||
22 val z = c.<bold>foo()</bold>
|
||||
22 val <bold>z = c.foo()</bold>
|
||||
20 val x = a.<bold>foo()</bold>
|
||||
20 val <bold>x = a.foo()</bold>
|
||||
@@ -0,0 +1,19 @@
|
||||
// FLOW: OUT
|
||||
|
||||
open class A {
|
||||
open fun foo() = 1
|
||||
}
|
||||
|
||||
open class B : A() {
|
||||
override fun foo() = <caret>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()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
8 override fun foo() = <bold>2</bold>
|
||||
8 override fun <bold>foo() = 2</bold>
|
||||
17 val y = b.<bold>foo()</bold>
|
||||
17 val <bold>y = b.foo()</bold>
|
||||
16 val x = a.<bold>foo()</bold>
|
||||
16 val <bold>x = a.foo()</bold>
|
||||
@@ -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 = <caret>3
|
||||
}
|
||||
|
||||
fun test(a: A, b: B, c: C) {
|
||||
val x = a.foo
|
||||
val y = b.foo
|
||||
val z = c.foo
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
10 override val foo = <bold>3</bold>
|
||||
10 override val <bold>foo = 3</bold>
|
||||
16 val <bold>z = c.foo</bold>
|
||||
14 val <bold>x = a.foo</bold>
|
||||
15 val <bold>y = b.foo</bold>
|
||||
@@ -0,0 +1,22 @@
|
||||
// FLOW: OUT
|
||||
|
||||
open class A {
|
||||
open val foo: Int
|
||||
get() = 1
|
||||
}
|
||||
|
||||
open class B : A() {
|
||||
override val foo: Int
|
||||
get() = <caret>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
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
10 get() = <bold>2</bold>
|
||||
10 <bold>get() = 2</bold>
|
||||
20 val <bold>y = b.foo</bold>
|
||||
19 val <bold>x = a.foo</bold>
|
||||
@@ -0,0 +1,19 @@
|
||||
// FLOW: OUT
|
||||
|
||||
open class A {
|
||||
open val foo = 1
|
||||
}
|
||||
|
||||
open class B : A() {
|
||||
override val foo = <caret>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
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
8 override val foo = <bold>2</bold>
|
||||
8 override val <bold>foo = 2</bold>
|
||||
17 val <bold>y = b.foo</bold>
|
||||
16 val <bold>x = a.foo</bold>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user