Data Inflow: Support delegated assignments

#KT-19089 Fixed
This commit is contained in:
Alexey Sedunov
2017-11-09 17:43:13 +03:00
parent 9d482bbbb1
commit 56746380f7
6 changed files with 101 additions and 0 deletions
@@ -21,6 +21,7 @@ import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector.Access
import com.intellij.psi.PsiElement
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.slicer.SliceUsage
import com.intellij.usageView.UsageInfo
import com.intellij.util.Processor
@@ -48,6 +49,7 @@ import org.jetbrains.kotlin.idea.findUsages.KotlinPropertyFindUsagesOptions
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.references.KtPropertyDelegationMethodsReference
import org.jetbrains.kotlin.idea.references.ReferenceAccess
import org.jetbrains.kotlin.idea.references.readWriteAccessWithFullExpression
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
@@ -63,6 +65,7 @@ import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
private fun KtDeclaration.processHierarchyDownward(scope: SearchScope, processor: KtDeclaration.() -> Unit) {
@@ -230,6 +233,16 @@ class InflowSlicer(
return
}
if (function is KtNamedFunction
&& function.name == OperatorNameConventions.SET_VALUE.asString()
&& function.hasModifier(KtTokens.OPERATOR_KEYWORD)) {
ReferencesSearch
.search(function, parentUsage.scope.toSearchScope())
.filterIsInstance<KtPropertyDelegationMethodsReference>()
.forEach { (it.element?.parent as? KtProperty)?.processPropertyAssignments() }
}
val parameterDescriptor = analyze()[BindingContext.VALUE_PARAMETER, this] ?: return
(function as? KtFunction)?.processCalls(parentUsage.scope.toSearchScope()) body@ {
@@ -0,0 +1,26 @@
// FLOW: IN
class Delegate {
private var _value: String = ""
operator fun getValue(thisRef: Any?, property: KProperty<*>) = _value
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
_value = value
}
}
class AClass(name1: String){
var name by Delegate()
init {
name = name1
}
fun uses(){
name = "bye"
println("Now my name is '$name'")
}
}
fun main(args: Array<String>) {
val a = AClass("hello")
println("My name is '${a.<caret>name}'")
}
@@ -0,0 +1,12 @@
25 println("My name is '${a.<bold>name</bold>}'")
12 var <bold>name by Delegate()</bold>
5 operator fun <bold>getValue(thisRef: Any?, property: KProperty<*>) = _value</bold>
5 operator fun getValue(thisRef: Any?, property: KProperty<*>) = <bold>_value</bold>
4 private var <bold>_value: String = ""</bold>
4 private var _value: String = <bold>""</bold>
7 _value = <bold>value</bold>
6 operator fun setValue(thisRef: Any?, property: KProperty<*>, <bold>value: String</bold>) {
14 name = <bold>name1</bold>
11 class AClass(<bold>name1: String</bold>){
24 val a = AClass(<bold>"hello"</bold>)
18 name = <bold>"bye"</bold>
@@ -0,0 +1,26 @@
// FLOW: IN
class Delegate {
private var _value: String = ""
operator fun getValue(thisRef: Any?, property: KProperty<*>) = _value
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
_value = value
}
}
class AClass(name1: String){
var name by Delegate()
init {
name = name1
}
fun uses(){
name = "bye"
println("Now my name is '$<caret>name'")
}
}
fun main(args: Array<String>) {
val a = AClass("hello")
println("My name is '${a.name}'")
}
@@ -0,0 +1,12 @@
19 println("Now my name is '$<bold>name</bold>'")
12 var <bold>name by Delegate()</bold>
5 operator fun <bold>getValue(thisRef: Any?, property: KProperty<*>) = _value</bold>
5 operator fun getValue(thisRef: Any?, property: KProperty<*>) = <bold>_value</bold>
4 private var <bold>_value: String = ""</bold>
4 private var _value: String = <bold>""</bold>
7 _value = <bold>value</bold>
6 operator fun setValue(thisRef: Any?, property: KProperty<*>, <bold>value: String</bold>) {
14 name = <bold>name1</bold>
11 class AClass(<bold>name1: String</bold>){
24 val a = AClass(<bold>"hello"</bold>)
18 name = <bold>"bye"</bold>
@@ -306,6 +306,18 @@ public class SlicerTestGenerated extends AbstractSlicerTest {
doTest(fileName);
}
@TestMetadata("inflow/settersViaDelegateForQualifiedRef.kt")
public void testInflow_SettersViaDelegateForQualifiedRef() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/settersViaDelegateForQualifiedRef.kt");
doTest(fileName);
}
@TestMetadata("inflow/settersViaDelegateForSimpleRef.kt")
public void testInflow_SettersViaDelegateForSimpleRef() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/settersViaDelegateForSimpleRef.kt");
doTest(fileName);
}
@TestMetadata("inflow/topLevelVal.kt")
public void testInflow_TopLevelVal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/slicer/inflow/topLevelVal.kt");