diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt index 0041c506a63..094f0160d58 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/jetPsiUtil.kt @@ -308,29 +308,6 @@ public inline fun flatMapDescendantsOfTypeVisitor(ac return forEachDescendantOfTypeVisitor { 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 { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/findUsages/UsageTypeUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/findUsages/UsageTypeUtils.kt index 58c1d494a12..f5e7a2841e6 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/findUsages/UsageTypeUtils.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/findUsages/UsageTypeUtils.kt @@ -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 } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/JetReferenceContributor.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/JetReferenceContributor.kt index 54a9b1228d9..d2c8213c554 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/JetReferenceContributor.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/JetReferenceContributor.kt @@ -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()) { 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)) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt index e7ab774c47d..98e5148bfcd 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt @@ -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() } } + +// ----------- 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 +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReadWriteAccessDetector.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReadWriteAccessDetector.kt index e07fc7f4600..6f7d080a858 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReadWriteAccessDetector.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinReadWriteAccessDetector.kt @@ -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 diff --git a/idea/testData/findUsages/kotlin/variable/plusAssignFun.0.kt b/idea/testData/findUsages/kotlin/variable/plusAssignFun.0.kt new file mode 100644 index 00000000000..471e235d1d3 --- /dev/null +++ b/idea/testData/findUsages/kotlin/variable/plusAssignFun.0.kt @@ -0,0 +1,10 @@ +// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetProperty +// OPTIONS: usages +class C + +fun C.plusAssign(p: Int) = this + +fun foo() { + val c = C() + c += 10 +} diff --git a/idea/testData/findUsages/kotlin/variable/plusAssignFun.results.txt b/idea/testData/findUsages/kotlin/variable/plusAssignFun.results.txt new file mode 100644 index 00000000000..92e10ee064a --- /dev/null +++ b/idea/testData/findUsages/kotlin/variable/plusAssignFun.results.txt @@ -0,0 +1 @@ +Value read (9: 5) c += 10 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java b/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java index 270ae56540c..a8362142c67 100644 --- a/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/findUsages/JetFindUsagesTestGenerated.java @@ -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");