Correct read/write access detection in case of plusAssign etc
This commit is contained in:
@@ -308,29 +308,6 @@ public inline fun <reified T : JetElement, R> flatMapDescendantsOfTypeVisitor(ac
|
|||||||
return forEachDescendantOfTypeVisitor<T> { accumulator.addAll(map(it)) }
|
return forEachDescendantOfTypeVisitor<T> { accumulator.addAll(map(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------- Read/write access -----------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public enum class ReferenceAccess {
|
|
||||||
READ, WRITE, READ_WRITE
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun JetExpression.readWriteAccess(): ReferenceAccess {
|
|
||||||
var expression = getQualifiedExpressionForSelectorOrThis()
|
|
||||||
while (expression.parent is JetParenthesizedExpression || expression.parent is JetAnnotatedExpression) {
|
|
||||||
expression = expression.parent as JetExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
val assignment = expression.getAssignmentByLHS()
|
|
||||||
if (assignment != null) {
|
|
||||||
return if (assignment.operationToken == JetTokens.EQ) ReferenceAccess.WRITE else ReferenceAccess.READ_WRITE
|
|
||||||
}
|
|
||||||
|
|
||||||
return if ((expression.parent as? JetUnaryExpression)?.operationToken in constant { setOf(JetTokens.PLUSPLUS, JetTokens.MINUSMINUS) })
|
|
||||||
ReferenceAccess.READ_WRITE
|
|
||||||
else
|
|
||||||
ReferenceAccess.READ
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------- Other -----------------------------------------------------------------------------------------------------------------------
|
// ----------- Other -----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
public fun JetClassOrObject.effectiveDeclarations(): List<JetDeclaration> {
|
public fun JetClassOrObject.effectiveDeclarations(): List<JetDeclaration> {
|
||||||
|
|||||||
@@ -30,10 +30,7 @@ import com.intellij.psi.PsiReferenceExpression
|
|||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.idea.findUsages.UsageTypeEnum.*
|
import org.jetbrains.kotlin.idea.findUsages.UsageTypeEnum.*
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.references.JetArrayAccessReference
|
import org.jetbrains.kotlin.idea.references.*
|
||||||
import org.jetbrains.kotlin.idea.references.JetInvokeFunctionReference
|
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
|
||||||
import org.jetbrains.kotlin.idea.references.unwrappedTargets
|
|
||||||
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.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
@@ -146,7 +143,7 @@ public object UsageTypeUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (refExpr.readWriteAccess()) {
|
return when (refExpr.readWriteAccess(useResolveForReadWrite = true)) {
|
||||||
ReferenceAccess.READ -> READ
|
ReferenceAccess.READ -> READ
|
||||||
ReferenceAccess.WRITE, ReferenceAccess.READ_WRITE -> WRITE
|
ReferenceAccess.WRITE, ReferenceAccess.READ_WRITE -> WRITE
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -23,8 +23,6 @@ import org.jetbrains.kotlin.idea.kdoc.KDocReference
|
|||||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.ReferenceAccess
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.readWriteAccess
|
|
||||||
|
|
||||||
public class JetReferenceContributor() : PsiReferenceContributor() {
|
public class JetReferenceContributor() : PsiReferenceContributor() {
|
||||||
public override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
public override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||||
@@ -36,7 +34,7 @@ public class JetReferenceContributor() : PsiReferenceContributor() {
|
|||||||
registerMultiProvider(javaClass<JetNameReferenceExpression>()) {
|
registerMultiProvider(javaClass<JetNameReferenceExpression>()) {
|
||||||
if (it.getReferencedNameElementType() != JetTokens.IDENTIFIER) return@registerMultiProvider emptyArray()
|
if (it.getReferencedNameElementType() != JetTokens.IDENTIFIER) return@registerMultiProvider emptyArray()
|
||||||
|
|
||||||
when (it.readWriteAccess()) {
|
when (it.readWriteAccess(useResolveForReadWrite = false)) {
|
||||||
ReferenceAccess.READ -> arrayOf(SyntheticPropertyAccessorReference.Getter(it))
|
ReferenceAccess.READ -> arrayOf(SyntheticPropertyAccessorReference.Getter(it))
|
||||||
ReferenceAccess.WRITE -> arrayOf(SyntheticPropertyAccessorReference.Setter(it))
|
ReferenceAccess.WRITE -> arrayOf(SyntheticPropertyAccessorReference.Setter(it))
|
||||||
ReferenceAccess.READ_WRITE -> arrayOf(SyntheticPropertyAccessorReference.Getter(it), SyntheticPropertyAccessorReference.Setter(it))
|
ReferenceAccess.READ_WRITE -> arrayOf(SyntheticPropertyAccessorReference.Getter(it), SyntheticPropertyAccessorReference.Setter(it))
|
||||||
|
|||||||
@@ -18,12 +18,20 @@ package org.jetbrains.kotlin.idea.references
|
|||||||
|
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import org.jetbrains.kotlin.asJava.unwrapped
|
import org.jetbrains.kotlin.asJava.unwrapped
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
||||||
import org.jetbrains.kotlin.idea.kdoc.KDocReference
|
import org.jetbrains.kotlin.idea.kdoc.KDocReference
|
||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||||
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.constant
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
import org.jetbrains.kotlin.utils.emptyOrSingletonList
|
import org.jetbrains.kotlin.utils.emptyOrSingletonList
|
||||||
@@ -132,3 +140,40 @@ val JetElement.mainReference: JetReference?
|
|||||||
else -> getReferences().firstIsInstanceOrNull<JetReference>()
|
else -> getReferences().firstIsInstanceOrNull<JetReference>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------- Read/write access -----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public enum class ReferenceAccess {
|
||||||
|
READ, WRITE, READ_WRITE
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun JetExpression.readWriteAccess(useResolveForReadWrite: Boolean): ReferenceAccess {
|
||||||
|
var expression = getQualifiedExpressionForSelectorOrThis()
|
||||||
|
while (expression.parent is JetParenthesizedExpression || expression.parent is JetAnnotatedExpression) {
|
||||||
|
expression = expression.parent as JetExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
val assignment = expression.getAssignmentByLHS()
|
||||||
|
if (assignment != null) {
|
||||||
|
when (assignment.operationToken) {
|
||||||
|
JetTokens.EQ -> return ReferenceAccess.WRITE
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
if (!useResolveForReadWrite) return ReferenceAccess.READ_WRITE
|
||||||
|
|
||||||
|
val bindingContext = assignment.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
val resolvedCall = assignment.getResolvedCall(bindingContext) ?: return ReferenceAccess.READ_WRITE
|
||||||
|
if (!resolvedCall.status.isSuccess) return ReferenceAccess.READ_WRITE
|
||||||
|
return if (resolvedCall.resultingDescriptor.name.asString().endsWith("Assign"))
|
||||||
|
ReferenceAccess.READ
|
||||||
|
else
|
||||||
|
ReferenceAccess.READ_WRITE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if ((expression.parent as? JetUnaryExpression)?.operationToken in constant { setOf(JetTokens.PLUSPLUS, JetTokens.MINUSMINUS) })
|
||||||
|
ReferenceAccess.READ_WRITE
|
||||||
|
else
|
||||||
|
ReferenceAccess.READ
|
||||||
|
}
|
||||||
|
|||||||
+3
-3
@@ -20,11 +20,11 @@ import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.PsiReference
|
import com.intellij.psi.PsiReference
|
||||||
import org.jetbrains.kotlin.asJava.KotlinLightMethod
|
import org.jetbrains.kotlin.asJava.KotlinLightMethod
|
||||||
|
import org.jetbrains.kotlin.idea.references.ReferenceAccess
|
||||||
|
import org.jetbrains.kotlin.idea.references.readWriteAccess
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.ReferenceAccess
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.readWriteAccess
|
|
||||||
|
|
||||||
public class KotlinReadWriteAccessDetector : ReadWriteAccessDetector() {
|
public class KotlinReadWriteAccessDetector : ReadWriteAccessDetector() {
|
||||||
override fun isReadWriteAccessible(element: PsiElement) = element is JetVariableDeclaration || element is JetParameter
|
override fun isReadWriteAccessible(element: PsiElement) = element is JetVariableDeclaration || element is JetParameter
|
||||||
@@ -58,7 +58,7 @@ public class KotlinReadWriteAccessDetector : ReadWriteAccessDetector() {
|
|||||||
override fun getExpressionAccess(expression: PsiElement): ReadWriteAccessDetector.Access {
|
override fun getExpressionAccess(expression: PsiElement): ReadWriteAccessDetector.Access {
|
||||||
if (expression !is JetExpression) return ReadWriteAccessDetector.Access.Read
|
if (expression !is JetExpression) return ReadWriteAccessDetector.Access.Read
|
||||||
|
|
||||||
return when (expression.readWriteAccess()) {
|
return when (expression.readWriteAccess(useResolveForReadWrite = true)) {
|
||||||
ReferenceAccess.READ -> ReadWriteAccessDetector.Access.Read
|
ReferenceAccess.READ -> ReadWriteAccessDetector.Access.Read
|
||||||
ReferenceAccess.WRITE -> ReadWriteAccessDetector.Access.Write
|
ReferenceAccess.WRITE -> ReadWriteAccessDetector.Access.Write
|
||||||
ReferenceAccess.READ_WRITE -> ReadWriteAccessDetector.Access.ReadWrite
|
ReferenceAccess.READ_WRITE -> ReadWriteAccessDetector.Access.ReadWrite
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetProperty
|
||||||
|
// OPTIONS: usages
|
||||||
|
class C
|
||||||
|
|
||||||
|
fun C.plusAssign(p: Int) = this
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val <caret>c = C()
|
||||||
|
c += 10
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Value read (9: 5) c += 10
|
||||||
@@ -1035,6 +1035,12 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/kotlin/variable"), Pattern.compile("^(.+)\\.0\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/findUsages/kotlin/variable"), Pattern.compile("^(.+)\\.0\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("plusAssignFun.0.kt")
|
||||||
|
public void testPlusAssignFun() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/variable/plusAssignFun.0.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("readAccess.0.kt")
|
@TestMetadata("readAccess.0.kt")
|
||||||
public void testReadAccess() throws Exception {
|
public void testReadAccess() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/variable/readAccess.0.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/variable/readAccess.0.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user