diff --git a/uast/uast-common/src/com/intellij/patterns/uast/UastPatterns.kt b/uast/uast-common/src/com/intellij/patterns/uast/UastPatterns.kt index 505dffdbe496..b85923adf6f5 100644 --- a/uast/uast-common/src/com/intellij/patterns/uast/UastPatterns.kt +++ b/uast/uast-common/src/com/intellij/patterns/uast/UastPatterns.kt @@ -52,13 +52,15 @@ open class UElementPattern>(clazz: filter { it.getUCallExpression()?.let { callPattern.accepts(it) } ?: false } fun callParameter(parameterIndex: Int, callPattern: ElementPattern): Self = - filter { - val call = it.uastParent.getUCallExpression() as? UCallExpressionEx ?: return@filter false - call.getArgumentForParameter(parameterIndex) == it && callPattern.accepts(call) - } + filter { isCallExpressionParameter(it, parameterIndex, callPattern) } fun constructorParameter(parameterIndex: Int, classFQN: String): Self = callParameter(parameterIndex, callExpression().constructor(classFQN)) + fun setterParameter(methodPattern: ElementPattern): Self = filter { + isPropertyAssignCall(it, methodPattern) || + isCallExpressionParameter(it, 0, callExpression().withAnyResolvedMethod(methodPattern)) + } + fun methodCallParameter(parameterIndex: Int, methodPattern: ElementPattern): Self = callParameter(parameterIndex, callExpression().withAnyResolvedMethod(methodPattern)) @@ -71,6 +73,25 @@ open class UElementPattern>(clazz: class Capture(clazz: Class) : UElementPattern>(clazz) } +private fun isCallExpressionParameter(argumentExpression: UElement, + parameterIndex: Int, + callPattern: ElementPattern): Boolean { + val call = argumentExpression.uastParent.getUCallExpression() as? UCallExpressionEx ?: return false + return call.getArgumentForParameter(parameterIndex) == argumentExpression && callPattern.accepts(call) +} + +private fun isPropertyAssignCall(argument: UElement, methodPattern: ElementPattern): Boolean { + val uBinaryExpression = (argument.uastParent as? UBinaryExpression) ?: return false + val leftOperand = uBinaryExpression.leftOperand + + val uastReference = when (leftOperand) { + is UQualifiedReferenceExpression -> leftOperand.selector + else -> leftOperand + } + val references = uastReference.sourcePsi?.references ?: return false // via `sourcePsi` because of KT-27385 + return references.any { methodPattern.accepts(it.resolve()) } +} + class UCallExpressionPattern : UElementPattern(UCallExpression::class.java) { fun withReceiver(classPattern: ElementPattern): UCallExpressionPattern =