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)) }
|
||||
}
|
||||
|
||||
// ----------- 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 -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
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.idea.findUsages.UsageTypeEnum.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.references.JetArrayAccessReference
|
||||
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.idea.references.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
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.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.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.ReferenceAccess
|
||||
import org.jetbrains.kotlin.psi.psiUtil.readWriteAccess
|
||||
|
||||
public class JetReferenceContributor() : PsiReferenceContributor() {
|
||||
public override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||
@@ -36,7 +34,7 @@ public class JetReferenceContributor() : PsiReferenceContributor() {
|
||||
registerMultiProvider(javaClass<JetNameReferenceExpression>()) {
|
||||
if (it.getReferencedNameElementType() != JetTokens.IDENTIFIER) return@registerMultiProvider emptyArray()
|
||||
|
||||
when (it.readWriteAccess()) {
|
||||
when (it.readWriteAccess(useResolveForReadWrite = false)) {
|
||||
ReferenceAccess.READ -> arrayOf(SyntheticPropertyAccessorReference.Getter(it))
|
||||
ReferenceAccess.WRITE -> arrayOf(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 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.kdoc.KDocReference
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
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.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.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.emptyOrSingletonList
|
||||
@@ -132,3 +140,40 @@ val JetElement.mainReference: 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.PsiReference
|
||||
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.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.ReferenceAccess
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.readWriteAccess
|
||||
|
||||
public class KotlinReadWriteAccessDetector : ReadWriteAccessDetector() {
|
||||
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 {
|
||||
if (expression !is JetExpression) return ReadWriteAccessDetector.Access.Read
|
||||
|
||||
return when (expression.readWriteAccess()) {
|
||||
return when (expression.readWriteAccess(useResolveForReadWrite = true)) {
|
||||
ReferenceAccess.READ -> ReadWriteAccessDetector.Access.Read
|
||||
ReferenceAccess.WRITE -> ReadWriteAccessDetector.Access.Write
|
||||
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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testReadAccess() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/variable/readAccess.0.kt");
|
||||
|
||||
Reference in New Issue
Block a user