getting rid of ULiteralExpression to make it possible to work in both supporting and not supporting UInjectionHost Uast-plugins

This commit is contained in:
Nicolay Mitropolsky
2019-01-16 13:45:52 +03:00
parent 76f82af717
commit a281ccf722
2 changed files with 37 additions and 10 deletions
@@ -35,6 +35,8 @@ fun injectionHostUExpression(strict: Boolean = true): UExpressionPattern<UExpres
return@filterWithContext requestedPsi is PsiLanguageInjectionHost
}
fun injectionHostOrReferenceExpression(): UExpressionPattern.Capture<UExpression> =
uExpression().filter { it is UReferenceExpression || it.isInjectionHost() }
fun callExpression(): UCallExpressionPattern = UCallExpressionPattern()
@@ -94,12 +96,12 @@ open class UElementPattern<T : UElement, Self : UElementPattern<T, Self>>(clazz:
private val constructorOrMethodCall = setOf(UastCallKind.CONSTRUCTOR_CALL, UastCallKind.METHOD_CALL)
private fun isCallExpressionParameter(argumentExpression: UElement,
private fun isCallExpressionParameter(argumentExpression: UExpression,
parameterIndex: Int,
callPattern: ElementPattern<UCallExpression>): Boolean {
val call = argumentExpression.uastParent.getUCallExpression(searchLimit = 2) as? UCallExpressionEx ?: return false
if (call.kind !in constructorOrMethodCall) return false
return call.getArgumentForParameter(parameterIndex) == argumentExpression && callPattern.accepts(call)
return call.getArgumentForParameter(parameterIndex) == unwrapPolyadic(argumentExpression) && callPattern.accepts(call)
}
private val GUARD = RecursionManager.createGuard("isPropertyAssignCall")
@@ -128,11 +130,13 @@ class UCallExpressionPattern : UElementPattern<UCallExpression, UCallExpressionP
fun withMethodName(methodName : String): UCallExpressionPattern = withMethodName(string().equalTo(methodName))
fun withAnyResolvedMethod(method: ElementPattern<out PsiMethod>): UCallExpressionPattern = filter { uCallExpression ->
when (uCallExpression) {
is UMultiResolvable -> uCallExpression.multiResolve().any { method.accepts(it.element) }
else -> uCallExpression.resolve().let { method.accepts(it) }
}
fun withAnyResolvedMethod(method: ElementPattern<out PsiMethod>): UCallExpressionPattern = withResolvedMethod(method, true)
fun withResolvedMethod(method: ElementPattern<out PsiMethod>, multiResolve: Boolean): UCallExpressionPattern = filter { uCallExpression ->
if (multiResolve && uCallExpression is UMultiResolvable)
uCallExpression.multiResolve().any { method.accepts(it.element) }
else
uCallExpression.resolve().let { method.accepts(it) }
}
fun withMethodName(namePattern: ElementPattern<String>): UCallExpressionPattern = filter { it.methodName?.let { namePattern.accepts(it) } ?: false }
@@ -186,11 +190,12 @@ open class UExpressionPattern<T : UExpression, Self : UExpressionPattern<T, Self
isCallExpressionParameter(it, 0, callExpression().withAnyResolvedMethod(methodPattern))
}
override fun methodCallParameter(parameterIndex: Int, methodPattern: ElementPattern<out PsiMethod>): Self =
callParameter(parameterIndex, callExpression().withAnyResolvedMethod(methodPattern))
@JvmOverloads
fun methodCallParameter(parameterIndex: Int, methodPattern: ElementPattern<out PsiMethod>, multiResolve: Boolean = true): Self =
callParameter(parameterIndex, callExpression().withResolvedMethod(methodPattern, multiResolve))
override fun arrayAccessParameterOf(receiverClassPattern: ElementPattern<PsiClass>): Self = filter { self ->
val aae: UArrayAccessExpression = self.uastParent as? UArrayAccessExpression ?: return@filter false
val aae: UArrayAccessExpression = unwrapPolyadic(self).uastParent as? UArrayAccessExpression ?: return@filter false
val receiverClass = (aae.receiver.getExpressionType() as? PsiClassType)?.resolve() ?: return@filter false
receiverClassPattern.accepts(receiverClass)
}
@@ -20,6 +20,8 @@ package org.jetbrains.uast
import com.intellij.psi.PsiLanguageInjectionHost
import com.intellij.psi.PsiReference
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.uast.expressions.UInjectionHost
/**
* Checks if the [UElement] is a null literal.
@@ -54,13 +56,22 @@ fun UElement.isFalseLiteral(): Boolean = this is ULiteralExpression && this.isBo
*
* @return true if the receiver is a [String] literal, false otherwise.
*/
@Deprecated("doesn't support UInjectionHost, most probably it is not what you want", ReplaceWith("isInjectionHost()"))
fun UElement.isStringLiteral(): Boolean = this is ULiteralExpression && this.isString
/**
* Checks if the [UElement] is a [PsiLanguageInjectionHost] holder.
*
* NOTE: It is a transitional function until everything will migrate to [UInjectionHost]
*/
fun UElement?.isInjectionHost(): Boolean = this is UInjectionHost || (this is UExpression && this.sourceInjectionHost != null)
/**
* Returns the [String] literal value.
*
* @return literal text if the receiver is a valid [String] literal, null otherwise.
*/
@Deprecated("doesn't support UInjectionHost, most probably it is not what you want", ReplaceWith("UExpression.evaluateString()"))
fun UElement.getValueIfStringLiteral(): String? =
if (isStringLiteral()) (this as ULiteralExpression).value as String else null
@@ -126,6 +137,17 @@ val UExpression.sourceInjectionHost: PsiLanguageInjectionHost?
val ULiteralExpression.psiLanguageInjectionHost: PsiLanguageInjectionHost?
get() = this.psi?.let { PsiTreeUtil.getParentOfType(it, PsiLanguageInjectionHost::class.java, false) }
// Workaround until everything will migrate to `UInjectionHost` from `ULiteralExpression`, see KT-27283
@ApiStatus.Experimental
fun unwrapPolyadic(uElement: UExpression): UExpression {
if (uElement is ULiteralExpression) {
val parent = uElement.uastParent
if (parent is UPolyadicExpression)
return parent
}
return uElement
}
/**
* @return all references injected into this [ULiteralExpression]
*