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 7d03916c6329..bc6d3912cfe6 100644 --- a/uast/uast-common/src/com/intellij/patterns/uast/UastPatterns.kt +++ b/uast/uast-common/src/com/intellij/patterns/uast/UastPatterns.kt @@ -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>(clazz: fun inCall(callPattern: ElementPattern) = filter { it.getUCallExpression()?.let { callPattern.accepts(it) } ?: false } + fun callParameter(parameterIndex: Int, callPattern: ElementPattern) = + 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(clazz: Class) : UElementPattern>(clazz) } @@ -59,6 +64,13 @@ class UCallExpressionPattern : UElementPattern) = filter { it.methodName?.let { namePattern.accepts(it) } ?: false } + fun constructor(classPattern: ElementPattern) = 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::class.java) { diff --git a/uast/uast-tests/test/com/intellij/patterns/uast/UastPatternsTest.kt b/uast/uast-tests/test/com/intellij/patterns/uast/UastPatternsTest.kt new file mode 100644 index 000000000000..a90cbc1025cf --- /dev/null +++ b/uast/uast-tests/test/com/intellij/patterns/uast/UastPatternsTest.kt @@ -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): List = + PsiTreeUtil.collectElements(psiClass, { true }).mapNotNull { it.toUElement() }.filter { pattern.accepts(it) } + +} \ No newline at end of file