Uast: constructor-param pattern (IDEA-184848)

This commit is contained in:
Nicolay Mitropolsky
2018-04-11 11:28:18 +03:00
parent f9e7bc12f9
commit e2952306e9
2 changed files with 72 additions and 4 deletions
@@ -5,10 +5,7 @@
package com.intellij.patterns.uast
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.ObjectPattern
import com.intellij.patterns.PatternCondition
import com.intellij.patterns.StandardPatterns
import com.intellij.patterns.*
import com.intellij.patterns.StandardPatterns.string
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiClassType
@@ -47,6 +44,14 @@ open class UElementPattern<T : UElement, Self : UElementPattern<T, Self>>(clazz:
fun inCall(callPattern: ElementPattern<UCallExpression>) =
filter { it.getUCallExpression()?.let { callPattern.accepts(it) } ?: false }
fun callParameter(parameterIndex: Int, callPattern: ElementPattern<UCallExpression>) =
filter {
val call = it.getUCallExpression() as? UCallExpressionEx ?: return@filter false
call.getArgumentForParameter(parameterIndex) == it && callPattern.accepts(call)
}
fun constructorParameter(parameterIndex: Int, classFQN: String) = callParameter(parameterIndex, callExpression().constructor(classFQN))
class Capture<T : UElement>(clazz: Class<T>) : UElementPattern<T, Capture<T>>(clazz)
}
@@ -59,6 +64,13 @@ class UCallExpressionPattern : UElementPattern<UCallExpression, UCallExpressionP
fun withMethodName(namePattern: ElementPattern<String>) = filter { it.methodName?.let { namePattern.accepts(it) } ?: false }
fun constructor(classPattern: ElementPattern<PsiClass>) = filter {
val psiMethod = it.resolve() ?: return@filter false;
psiMethod.isConstructor && classPattern.accepts(psiMethod.containingClass)
}
fun constructor(className: String) = constructor(PsiJavaPatterns.psiClass().withQualifiedName(className))
}
class ULiteralExpressionPattern : UElementPattern<ULiteralExpression, ULiteralExpressionPattern>(ULiteralExpression::class.java) {
@@ -0,0 +1,56 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.patterns.uast
import com.intellij.patterns.ElementPattern
import com.intellij.patterns.PsiJavaPatterns
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.jetbrains.uast.UElement
import org.jetbrains.uast.toUElement
import org.junit.Test
class UastPatternsTest : LightCodeInsightFixtureTestCase() {
@Test
fun testCallParameters() {
val psiClass = myFixture.addClass("""
class MyClass {
MyClass(String a, String b, String c){}
MyClass foo(){
String a = "justString";
String b = new String("string-ctor-param");
java.lang.System.out.println("method-param");
return new MyClass("1ctor-prm", "2ctor-param", a);
}
}
""".trimIndent())
assertAccepted(psiClass, literalExpression(),
"\"method-param\"", "\"string-ctor-param\"", "\"justString\"", "\"1ctor-prm\"", "\"2ctor-param\"")
assertAccepted(psiClass, literalExpression().inCall(callExpression()),
"\"string-ctor-param\"", "\"method-param\"", "\"1ctor-prm\"", "\"2ctor-param\"")
assertAccepted(psiClass, literalExpression().inCall(
callExpression().constructor(PsiJavaPatterns.psiClass())), "\"string-ctor-param\"", "\"1ctor-prm\"", "\"2ctor-param\"")
assertAccepted(psiClass, literalExpression().callParameter(0, callExpression()),
"\"string-ctor-param\"", "\"1ctor-prm\"", "\"method-param\"")
assertAccepted(psiClass, literalExpression().constructorParameter(0, "MyClass"), "\"1ctor-prm\"")
}
private fun assertAccepted(psiClass: PsiElement,
pattern: ULiteralExpressionPattern,
vararg expected: String) {
assertSameElements(getAcceptedElements(psiClass, pattern).map { it.sourcePsi?.text ?: "null" },
*expected)
}
private fun getAcceptedElements(psiClass: PsiElement,
pattern: ElementPattern<out UElement>): List<UElement> =
PsiTreeUtil.collectElements(psiClass, { true }).mapNotNull { it.toUElement() }.filter { pattern.accepts(it) }
}