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
|
val psiClass = psiMethod.containingClass
|
||||||
if (psiClass == null) return Collections.emptyList()
|
if (psiClass == null) return Collections.emptyList()
|
||||||
|
|
||||||
val classToMethod = HashMap<PsiClass, PsiMethod>()
|
val classToMethod = LinkedHashMap<PsiClass, PsiMethod>()
|
||||||
val classTraverser = object : HierarchyTraverser<PsiClass> {
|
val classTraverser = object : HierarchyTraverser<PsiClass> {
|
||||||
override fun nextElements(current: PsiClass): Iterable<PsiClass> =
|
override fun nextElements(current: PsiClass): Iterable<PsiClass> =
|
||||||
DirectClassInheritorsSearch.search(
|
DirectClassInheritorsSearch.search(
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import com.intellij.find.findUsages.FindUsagesOptions
|
|||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
|
||||||
fun KtDeclaration.processAllUsages(
|
fun KtDeclaration.processAllExactUsages(
|
||||||
options: () -> FindUsagesOptions,
|
options: () -> FindUsagesOptions,
|
||||||
processor: (UsageInfo) -> Unit
|
processor: (UsageInfo) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -28,7 +28,9 @@ fun KtDeclaration.processAllUsages(
|
|||||||
findUsagesHandler.processElementUsages(
|
findUsagesHandler.processElementUsages(
|
||||||
this,
|
this,
|
||||||
{
|
{
|
||||||
processor(it)
|
if (it.reference?.isReferenceTo(this) ?: false) {
|
||||||
|
processor(it)
|
||||||
|
}
|
||||||
true
|
true
|
||||||
},
|
},
|
||||||
options()
|
options()
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.slicer
|
package org.jetbrains.kotlin.idea.slicer
|
||||||
|
|
||||||
|
import com.intellij.analysis.AnalysisScope
|
||||||
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector.Access
|
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector.Access
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.search.LocalSearchScope
|
import com.intellij.psi.search.LocalSearchScope
|
||||||
@@ -23,6 +24,7 @@ import com.intellij.psi.search.SearchScope
|
|||||||
import com.intellij.slicer.SliceUsage
|
import com.intellij.slicer.SliceUsage
|
||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import com.intellij.util.Processor
|
import com.intellij.util.Processor
|
||||||
|
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
import org.jetbrains.kotlin.cfg.pseudocode.PseudoValue
|
||||||
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
|
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.pseudocode.instructions.jumps.ReturnValueInstruction
|
||||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder
|
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder
|
||||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse
|
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
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.caches.resolve.resolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions
|
import org.jetbrains.kotlin.idea.findUsages.KotlinFunctionFindUsagesOptions
|
||||||
import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions
|
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.KotlinValVar
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar
|
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.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector
|
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReadWriteAccessDetector
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
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 org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
import java.util.*
|
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) {
|
private fun KtFunction.processCalls(scope: SearchScope, processor: (UsageInfo) -> Unit) {
|
||||||
processAllUsages(
|
processAllExactUsages(
|
||||||
{
|
{
|
||||||
KotlinFunctionFindUsagesOptions(project).apply {
|
KotlinFunctionFindUsagesOptions(project).apply {
|
||||||
isSearchForTextOccurrences = false
|
isSearchForTextOccurrences = false
|
||||||
@@ -74,7 +97,7 @@ private fun KtDeclaration.processVariableAccesses(
|
|||||||
kind: Access,
|
kind: Access,
|
||||||
processor: (UsageInfo) -> Unit
|
processor: (UsageInfo) -> Unit
|
||||||
) {
|
) {
|
||||||
processAllUsages(
|
processAllExactUsages(
|
||||||
{
|
{
|
||||||
KotlinPropertyFindUsagesOptions(project).apply {
|
KotlinPropertyFindUsagesOptions(project).apply {
|
||||||
isReadAccess = kind == Access.Read || kind == Access.ReadWrite
|
isReadAccess = kind == Access.Read || kind == Access.ReadWrite
|
||||||
@@ -126,6 +149,10 @@ class InflowSlicer(
|
|||||||
processor: Processor<SliceUsage>,
|
processor: Processor<SliceUsage>,
|
||||||
parentUsage: KotlinSliceUsage
|
parentUsage: KotlinSliceUsage
|
||||||
) : Slicer(element, processor, parentUsage) {
|
) : 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 PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true)
|
||||||
|
|
||||||
private fun KtDeclaration.processAssignments(accessSearchScope: SearchScope) {
|
private fun KtDeclaration.processAssignments(accessSearchScope: SearchScope) {
|
||||||
@@ -148,7 +175,8 @@ class InflowSlicer(
|
|||||||
|
|
||||||
private fun KtProperty.processPropertyAssignments() {
|
private fun KtProperty.processPropertyAssignments() {
|
||||||
val analysisScope = parentUsage.scope.toSearchScope()
|
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
|
val containerScope = getStrictParentOfType<KtDeclaration>()?.let { LocalSearchScope(it) } ?: return
|
||||||
analysisScope.intersectWith(containerScope)
|
analysisScope.intersectWith(containerScope)
|
||||||
}
|
}
|
||||||
@@ -238,10 +266,10 @@ class InflowSlicer(
|
|||||||
|
|
||||||
private fun KtExpression.processExpression() {
|
private fun KtExpression.processExpression() {
|
||||||
val lambda = when (this) {
|
val lambda = when (this) {
|
||||||
is KtLambdaExpression -> functionLiteral
|
is KtLambdaExpression -> functionLiteral
|
||||||
is KtNamedFunction -> if (name == null) this else null
|
is KtNamedFunction -> if (name == null) this else null
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (lambda != null) {
|
if (lambda != null) {
|
||||||
if (parentUsage.lambdaLevel > 0) {
|
if (parentUsage.lambdaLevel > 0) {
|
||||||
lambda.passToProcessor(parentUsage.lambdaLevel - 1)
|
lambda.passToProcessor(parentUsage.lambdaLevel - 1)
|
||||||
@@ -273,7 +301,7 @@ class InflowSlicer(
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
accessedDeclaration.passToProcessor()
|
accessedDeclaration.processHierarchyDownwardAndPass()
|
||||||
}
|
}
|
||||||
|
|
||||||
is MergeInstruction -> createdAt.passInputsToProcessor()
|
is MergeInstruction -> createdAt.passInputsToProcessor()
|
||||||
@@ -296,7 +324,7 @@ class InflowSlicer(
|
|||||||
(resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression?.passToProcessorAsValue(parentUsage.lambdaLevel + 1)
|
(resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression?.passToProcessorAsValue(parentUsage.lambdaLevel + 1)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resultingDescriptor.source.getPsi()?.passToProcessor()
|
(resultingDescriptor.source.getPsi() as? KtDeclaration)?.processHierarchyDownwardAndPass()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,19 +348,18 @@ class OutflowSlicer(
|
|||||||
parentUsage: KotlinSliceUsage
|
parentUsage: KotlinSliceUsage
|
||||||
) : Slicer(element, processor, parentUsage) {
|
) : Slicer(element, processor, parentUsage) {
|
||||||
private fun KtDeclaration.processVariable() {
|
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
|
val withDereferences = parentUsage.params.showInstanceDereferences
|
||||||
processVariableAccesses(
|
processVariableAccesses(parentUsage.scope.toSearchScope(), if (withDereferences) Access.ReadWrite else Access.Read) body@ {
|
||||||
parentUsage.scope.toSearchScope(),
|
val refExpression = (it.element as? KtExpression)?.let { KtPsiUtil.safeDeparenthesize(it) } ?: return@body
|
||||||
if (withDereferences) Access.ReadWrite else Access.Read
|
if (withDereferences) {
|
||||||
) body@ {
|
refExpression.processDereferences()
|
||||||
val refExpression = (it.element as? KtExpression)?.let { KtPsiUtil.safeDeparenthesize(it) } ?: return@body
|
}
|
||||||
if (withDereferences) {
|
if (!withDereferences || KotlinReadWriteAccessDetector.INSTANCE.getExpressionAccess(refExpression) == Access.Read) {
|
||||||
refExpression.processDereferences()
|
refExpression.processExpression()
|
||||||
}
|
}
|
||||||
if (!withDereferences || KotlinReadWriteAccessDetector.INSTANCE.getExpressionAccess(refExpression) == Access.Read) {
|
|
||||||
refExpression.processExpression()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -357,17 +384,20 @@ class OutflowSlicer(
|
|||||||
|
|
||||||
private fun KtFunction.processFunction() {
|
private fun KtFunction.processFunction() {
|
||||||
if (this is KtConstructor<*> || this is KtNamedFunction && name != null) {
|
if (this is KtConstructor<*> || this is KtNamedFunction && name != null) {
|
||||||
processCalls(parentUsage.scope.toSearchScope()) {
|
processHierarchyUpward(parentUsage.scope) {
|
||||||
it.element?.getCallElementForExactCallee()?.passToProcessor()
|
(this as? KtFunction)?.processCalls(parentUsage.scope.toSearchScope()) {
|
||||||
it.element?.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1)
|
it.element?.getCallElementForExactCallee()?.passToProcessor()
|
||||||
|
it.element?.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val funExpression = when (this) {
|
val funExpression = when (this) {
|
||||||
is KtFunctionLiteral -> parent as? KtLambdaExpression
|
is KtFunctionLiteral -> parent as? KtLambdaExpression
|
||||||
is KtNamedFunction -> this
|
is KtNamedFunction -> this
|
||||||
else -> null
|
else -> null
|
||||||
} ?: return
|
} ?: return
|
||||||
(funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true)
|
(funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,10 +410,10 @@ class OutflowSlicer(
|
|||||||
|
|
||||||
val receiver = instr.receiverValues[pseudoValue]
|
val receiver = instr.receiverValues[pseudoValue]
|
||||||
val resolvedCall = when (instr) {
|
val resolvedCall = when (instr) {
|
||||||
is CallInstruction -> instr.resolvedCall
|
is CallInstruction -> instr.resolvedCall
|
||||||
is ReadValueInstruction -> (instr.target as? AccessTarget.Call)?.resolvedCall
|
is ReadValueInstruction -> (instr.target as? AccessTarget.Call)?.resolvedCall
|
||||||
else -> null
|
else -> null
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
if (receiver != null && resolvedCall.dispatchReceiver == receiver) {
|
if (receiver != null && resolvedCall.dispatchReceiver == receiver) {
|
||||||
processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, parentUsage.lambdaLevel))
|
processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, parentUsage.lambdaLevel))
|
||||||
@@ -420,7 +450,7 @@ class OutflowSlicer(
|
|||||||
is ReturnValueInstruction -> instr.subroutine.passToProcessor()
|
is ReturnValueInstruction -> instr.subroutine.passToProcessor()
|
||||||
is MagicInstruction -> when (instr.kind) {
|
is MagicInstruction -> when (instr.kind) {
|
||||||
MagicKind.NOT_NULL_ASSERTION, MagicKind.CAST -> instr.outputValue.element?.passToProcessor()
|
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);
|
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")
|
@TestMetadata("inflow/doubleLambdaResult.kt")
|
||||||
public void testInflow_DoubleLambdaResult() throws Exception {
|
public void testInflow_DoubleLambdaResult() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/doubleLambdaResult.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/doubleLambdaResult.kt");
|
||||||
@@ -216,6 +234,30 @@ public class SlicerTestGenerated extends AbstractSlicerTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("inflow/primaryConstructorParameter.kt")
|
||||||
public void testInflow_PrimaryConstructorParameter() throws Exception {
|
public void testInflow_PrimaryConstructorParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/primaryConstructorParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/primaryConstructorParameter.kt");
|
||||||
@@ -300,6 +342,24 @@ public class SlicerTestGenerated extends AbstractSlicerTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("outflow/doubleLambdaResult.kt")
|
||||||
public void testOutflow_DoubleLambdaResult() throws Exception {
|
public void testOutflow_DoubleLambdaResult() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/doubleLambdaResult.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/doubleLambdaResult.kt");
|
||||||
@@ -360,6 +420,12 @@ public class SlicerTestGenerated extends AbstractSlicerTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("outflow/getterExpressionBody.kt")
|
||||||
public void testOutflow_GetterExpressionBody() throws Exception {
|
public void testOutflow_GetterExpressionBody() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/getterExpressionBody.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/getterExpressionBody.kt");
|
||||||
@@ -372,12 +438,6 @@ public class SlicerTestGenerated extends AbstractSlicerTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("outflow/ifExpression.kt")
|
||||||
public void testOutflow_IfExpression() throws Exception {
|
public void testOutflow_IfExpression() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/ifExpression.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/ifExpression.kt");
|
||||||
@@ -438,15 +498,39 @@ public class SlicerTestGenerated extends AbstractSlicerTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("outflow/operatorFunCalls.kt")
|
||||||
public void testOutflow_OperatorFunCalls() throws Exception {
|
public void testOutflow_OperatorFunCalls() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/operatorFunCalls.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/operatorFunCalls.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("outflow/operatorCallDereferences.kt")
|
@TestMetadata("outflow/overridingFunctionResult.kt")
|
||||||
public void testOutflow_OperatorCallDereferences() throws Exception {
|
public void testOutflow_OverridingFunctionResult() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/outflow/operatorCallDereferences.kt");
|
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);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user