Uast: KT-40578: resolve Kotlin property writes to setters (#3597)

* KT-40578: resolve Kotlin property writes to setters

* limit to non-constructor properties

* Uast: `KotlinIDERenderLogTest.testConstructors` fix

Co-authored-by: Nicolay Mitropolsky <nicolay.mitropolsky@jetbrains.com>
This commit is contained in:
Kevin Bierhoff
2020-07-28 00:03:22 -07:00
committed by GitHub
parent 5851a7dea0
commit fa8c6e7fb6
12 changed files with 187 additions and 13 deletions
@@ -26,12 +26,9 @@ import com.intellij.psi.impl.compiled.ClsTypeElementImpl
import com.intellij.psi.impl.compiled.SignatureParsing
import com.intellij.psi.impl.compiled.StubBuildingVisitor
import com.intellij.psi.util.PsiTypesUtil
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
import org.jetbrains.kotlin.asJava.findFacadeClass
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.asJava.toLightElements
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalTypeOrSubtype
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.descriptors.*
@@ -334,7 +331,7 @@ internal fun resolveToDeclaration(sourcePsi: KtExpression): PsiElement? =
}
internal fun resolveToDeclaration(sourcePsi: KtExpression, declarationDescriptor: DeclarationDescriptor): PsiElement? {
declarationDescriptor.toSource()?.getMaybeLightElement()?.let { return it }
declarationDescriptor.toSource()?.getMaybeLightElement(sourcePsi)?.let { return it }
var declarationDescriptor = declarationDescriptor
if (declarationDescriptor is ImportedFromObjectCallableDescriptor<*>) {
@@ -446,8 +443,8 @@ private fun resolveDeserialized(
if (propertySignature != null) {
with(propertySignature) {
when {
hasSetter() && accessHint?.isWrite == true -> setter // treat += etc. as write as was done elsewhere
hasGetter() && accessHint?.isRead != false -> getter
hasSetter() && accessHint?.isWrite != false -> setter
else -> null // it should have been handled by the previous case
}
}?.let { methodSignature ->
@@ -513,7 +510,12 @@ private fun KotlinType.containsLocalTypes(): Boolean {
return arguments.any { !it.isStarProjection && it.type.containsLocalTypes() }
}
private fun PsiElement.getMaybeLightElement(): PsiElement? {
private fun PsiElement.getMaybeLightElement(sourcePsi: KtExpression? = null): PsiElement? {
if (this is KtProperty && sourcePsi?.readWriteAccess()?.isWrite == true) {
with(getAccessorLightMethods()) {
(setter ?: backingField)?.let { return it } // backingField is for val property assignments in init blocks
}
}
return when (this) {
is KtDeclaration -> {
val lightElement = toLightElements().firstOrNull()
@@ -69,3 +69,12 @@ String -> USimpleNameReferenceExpression (identifier = String)
s -> USimpleNameReferenceExpression (identifier = s)
local -> USimpleNameReferenceExpression (identifier = local)
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
AWithFieldInit -> UClass (name = AWithFieldInit)
i -> UParameter (name = i)
Int -> USimpleNameReferenceExpression (identifier = Int)
a -> UField (name = a)
String -> USimpleNameReferenceExpression (identifier = String)
a -> USimpleNameReferenceExpression (identifier = a)
= -> USimpleNameReferenceExpression (identifier = =)
i -> USimpleNameReferenceExpression (identifier = i)
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
+8 -1
View File
@@ -71,4 +71,11 @@ class AWithSecondaryInit {
local.toString()
}
}
}
class AWithFieldInit(i: Int) {
val a: String
init {
a = i.toString()
}
}
+17 -1
View File
@@ -158,4 +158,20 @@ UFile (package = )
USimpleNameReferenceExpression (identifier = local)
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
UIdentifier (Identifier (toString))
USimpleNameReferenceExpression (identifier = toString, resolvesTo = null)
USimpleNameReferenceExpression (identifier = toString, resolvesTo = null)
UClass (name = AWithFieldInit)
UField (name = a)
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
UMethod (name = getA)
UMethod (name = AWithFieldInit)
UParameter (name = i)
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
UBlockExpression
UBlockExpression
UBinaryExpression (operator = =)
USimpleNameReferenceExpression (identifier = a)
UQualifiedReferenceExpression
USimpleNameReferenceExpression (identifier = i)
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
UIdentifier (Identifier (toString))
USimpleNameReferenceExpression (identifier = toString, resolvesTo = null)
+16
View File
@@ -159,3 +159,19 @@ UFile (package = )
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
UIdentifier (Identifier (toString))
USimpleNameReferenceExpression (identifier = toString, resolvesTo = null)
UClass (name = AWithFieldInit)
UField (name = a)
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
UMethod (name = getA)
UMethod (name = AWithFieldInit)
UParameter (name = i)
UAnnotation (fqName = org.jetbrains.annotations.NotNull)
UBlockExpression
UBlockExpression
UBinaryExpression (operator = =)
USimpleNameReferenceExpression (identifier = a)
UQualifiedReferenceExpression
USimpleNameReferenceExpression (identifier = i)
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))
UIdentifier (Identifier (toString))
USimpleNameReferenceExpression (identifier = toString, resolvesTo = null)
@@ -42,3 +42,9 @@ s -> USimpleNameReferenceExpression (identifier = s) from KtNameReferenceExpress
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
local -> USimpleNameReferenceExpression (identifier = local) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
Int -> USimpleNameReferenceExpression (identifier = Int) from KtNameReferenceExpression
String -> USimpleNameReferenceExpression (identifier = String) from KtNameReferenceExpression
a -> USimpleNameReferenceExpression (identifier = a) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtDotQualifiedExpression
i -> USimpleNameReferenceExpression (identifier = i) from KtNameReferenceExpression
toString -> UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0)) from KtNameReferenceExpression
@@ -79,3 +79,13 @@ public final class AWithSecondaryInit {
local.toString()
}
}
public final class AWithFieldInit {
@org.jetbrains.annotations.NotNull private final var a: java.lang.String
public final fun getA() : java.lang.String = UastEmptyExpression
public fun AWithFieldInit(@org.jetbrains.annotations.NotNull i: int) {
{
a = i.toString()
}
}
}
+10
View File
@@ -79,3 +79,13 @@ public final class AWithSecondaryInit {
local.toString()
}
}
public final class AWithFieldInit {
@org.jetbrains.annotations.NotNull private final var a: java.lang.String
public final fun getA() : java.lang.String = UastEmptyExpression
public fun AWithFieldInit(@org.jetbrains.annotations.NotNull i: int) {
{
a = i.toString()
}
}
}
+11 -4
View File
@@ -24,28 +24,28 @@ UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolve
UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String
UTypeReferenceExpression (name = int) -> USimpleNameReferenceExpression (identifier = Int) -> PsiClass:Integer: Integer
UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) -> PsiMethod:Object:
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightMethodImpl:getA: getA
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightMethodImpl:setA: setA
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = =) -> UQualifiedReferenceExpression -> null: null
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = i) -> Light Parameter: i
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolves to null) -> USimpleNameReferenceExpression (identifier = toString) -> null: null
UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String
UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) -> PsiMethod:Object:
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightMethodImpl:getA: getA
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightMethodImpl:setA: setA
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = s) -> Light Parameter: s
UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolves to PsiMethod:println) -> USimpleNameReferenceExpression (identifier = println) -> PsiMethod:println: println
UTypeReferenceExpression (name = int) -> USimpleNameReferenceExpression (identifier = Int) -> PsiClass:Integer: Integer
UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) -> PsiMethod:Object:
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightMethodImpl:getA: getA
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightMethodImpl:setA: setA
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = =) -> UQualifiedReferenceExpression -> null: null
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = i) -> Light Parameter: i
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolves to null) -> USimpleNameReferenceExpression (identifier = toString) -> null: null
UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String
UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 0)) -> PsiMethod:Object:
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightMethodImpl:getA: getA
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightMethodImpl:setA: setA
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = s) -> Light Parameter: s
UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String
@@ -53,3 +53,10 @@ UBlockExpression -> UCallExpression (kind = UastCallKind(name='constructor_call'
UBlockExpression -> UQualifiedReferenceExpression -> PsiMethod:toString: toString
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = local) -> LightVariableBuilder:local: local
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolves to PsiMethod:toString) -> USimpleNameReferenceExpression (identifier = toString) -> PsiMethod:toString: toString
UTypeReferenceExpression (name = int) -> USimpleNameReferenceExpression (identifier = Int) -> PsiClass:Integer: Integer
UTypeReferenceExpression (name = java.lang.String) -> USimpleNameReferenceExpression (identifier = String) -> PsiClass:String: String
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = a) -> KtLightFieldForSourceDeclaration:a: a
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = =) -> UQualifiedReferenceExpression -> null: null
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = i) -> Light Parameter: i
UCallExpression (kind = UastCallKind(name='method_call'), argCount = 0))(resolves to null) -> USimpleNameReferenceExpression (identifier = toString) -> null: null
+30
View File
@@ -0,0 +1,30 @@
class A(init: Int) {
private var privateProp = 0 // accesses should be field accesses
var mutableProp: Int
init {
mutableProp = init
}
fun add(x: Int): Int {
val result = privateProp
privateProp = x
return privateProp
}
}
fun properties() {
val a = A(17)
val x = -a.mutableProp
a.mutableProp = 1
a.mutableProp += x
++a.mutableProp
a.mutableProp--
}
fun A.ext() {
val x = -mutableProp
mutableProp = 1
mutableProp += x
++mutableProp
mutableProp--
}
@@ -0,0 +1,58 @@
UTypeReferenceExpression (name = int) -> USimpleNameReferenceExpression (identifier = Int) -> PsiClass:Integer: Integer
UTypeReferenceExpression (name = int) -> USimpleNameReferenceExpression (identifier = Int) -> PsiClass:Integer: Integer
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = init) -> Light Parameter: init
UTypeReferenceExpression (name = int) -> USimpleNameReferenceExpression (identifier = Int) -> PsiClass:Integer: Integer
UTypeReferenceExpression (name = int) -> USimpleNameReferenceExpression (identifier = Int) -> PsiClass:Integer: Integer
ULocalVariable (name = result) -> USimpleNameReferenceExpression (identifier = privateProp) -> KtLightFieldForSourceDeclaration:privateProp: privateProp
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = privateProp) -> KtLightFieldForSourceDeclaration:privateProp: privateProp
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = x) -> Light Parameter: x
UReturnExpression -> USimpleNameReferenceExpression (identifier = privateProp) -> KtLightFieldForSourceDeclaration:privateProp: privateProp
UCallExpression (kind = UastCallKind(name='constructor_call'), argCount = 1))(resolves to KtLightMethodImpl:A) -> USimpleNameReferenceExpression (identifier = A) -> KtLightMethodImpl:A: A
UPrefixExpression (operator = -) -> USimpleNameReferenceExpression (identifier = -) -> null: null
UPrefixExpression (operator = -) -> UQualifiedReferenceExpression -> KtLightMethodImpl:getMutableProp: getMutableProp
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = a) -> LightVariableBuilder:a: a
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:getMutableProp: getMutableProp
UBinaryExpression (operator = =) -> UQualifiedReferenceExpression -> KtLightMethodImpl:setMutableProp: setMutableProp
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = a) -> LightVariableBuilder:a: a
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = +=) -> UQualifiedReferenceExpression -> KtLightMethodImpl:setMutableProp: setMutableProp
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = a) -> LightVariableBuilder:a: a
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UBinaryExpression (operator = +=) -> USimpleNameReferenceExpression (identifier = +=) -> null: null
UBinaryExpression (operator = +=) -> USimpleNameReferenceExpression (identifier = x) -> LightVariableBuilder:x: x
UPrefixExpression (operator = ++) -> USimpleNameReferenceExpression (identifier = ++) -> null: null
UPrefixExpression (operator = ++) -> UQualifiedReferenceExpression -> KtLightMethodImpl:setMutableProp: setMutableProp
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = a) -> LightVariableBuilder:a: a
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UPostfixExpression (operator = --) -> UQualifiedReferenceExpression -> KtLightMethodImpl:setMutableProp: setMutableProp
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = a) -> LightVariableBuilder:a: a
UQualifiedReferenceExpression -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UPostfixExpression (operator = --) -> USimpleNameReferenceExpression (identifier = --) -> null: null
UTypeReferenceExpression (name = A) -> USimpleNameReferenceExpression (identifier = A) -> KtLightClassImpl:class A(init: Int) {
private var privateProp = 0 // accesses should be field accesses
var mutableProp: Int
init {
mutableProp = init
}
fun add(x: Int): Int {
val result = privateProp
privateProp = x
return privateProp
}
}: A
UPrefixExpression (operator = -) -> USimpleNameReferenceExpression (identifier = -) -> null: null
UPrefixExpression (operator = -) -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:getMutableProp: getMutableProp
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UBinaryExpression (operator = =) -> USimpleNameReferenceExpression (identifier = =) -> null: null
UBinaryExpression (operator = +=) -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UBinaryExpression (operator = +=) -> USimpleNameReferenceExpression (identifier = +=) -> null: null
UBinaryExpression (operator = +=) -> USimpleNameReferenceExpression (identifier = x) -> LightVariableBuilder:x: x
UPrefixExpression (operator = ++) -> USimpleNameReferenceExpression (identifier = ++) -> null: null
UPrefixExpression (operator = ++) -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UPostfixExpression (operator = --) -> USimpleNameReferenceExpression (identifier = mutableProp) -> KtLightMethodImpl:setMutableProp: setMutableProp
UPostfixExpression (operator = --) -> USimpleNameReferenceExpression (identifier = --) -> null: null
@@ -33,4 +33,7 @@ class KotlinUastResolveEverythingTest : AbstractKotlinResolveEverythingTest() {
@Test
fun testResolve() = doTest("Resolve")
@Test
fun testPropertyReferences() = doTest("PropertyReferences")
}