From: Bas Leijdekkers Date: Sat, 23 Apr 2016 18:43:41 +0000 (+0200) Subject: SSR: find parameterized method calls (IDEA-154740) X-Git-Tag: appcode/146.1479~1 X-Git-Url: https://git.jetbrains.org/?p=idea%2Fcommunity.git;a=commitdiff_plain;h=d9288e4b42d29a2e34a78def8b9b2756dd856db3 SSR: find parameterized method calls (IDEA-154740) --- diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java index e58dfe17f109..477987466086 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/JavaMatchingVisitor.java @@ -1041,50 +1041,94 @@ public class JavaMatchingVisitor extends JavaElementVisitor { final PsiReferenceExpression mcallRef1 = mcall.getMethodExpression(); final PsiReferenceExpression mcallRef2 = mcall2.getMethodExpression(); - final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(mcallRef1.getReferenceNameElement()); + final PsiElement patternMethodName = mcallRef1.getReferenceNameElement(); + final boolean isTypedVar = myMatchingVisitor.getMatchContext().getPattern().isTypedVar(patternMethodName); - if (!myMatchingVisitor.matchText(mcallRef1.getReferenceNameElement(), mcallRef2.getReferenceNameElement()) && !isTypedVar) { + if (!isTypedVar && !myMatchingVisitor.matchText(patternMethodName, mcallRef2.getReferenceNameElement())) { myMatchingVisitor.setResult(false); return; } - final PsiExpression qualifier = mcallRef1.getQualifierExpression(); - final PsiExpression elementQualifier = mcallRef2.getQualifierExpression(); - if (qualifier != null) { + final PsiExpression patternQualifier = mcallRef1.getQualifierExpression(); + final PsiExpression matchedQualifier = mcallRef2.getQualifierExpression(); + if (patternQualifier != null) { - if (elementQualifier != null) { - myMatchingVisitor.setResult(myMatchingVisitor.match(qualifier, elementQualifier)); + if (matchedQualifier != null) { + myMatchingVisitor.setResult(myMatchingVisitor.match(patternQualifier, matchedQualifier)); if (!myMatchingVisitor.getResult()) return; } else { final PsiMethod method = mcall2.resolveMethod(); if (method != null) { - if (qualifier instanceof PsiThisExpression) { + if (patternQualifier instanceof PsiThisExpression) { myMatchingVisitor.setResult(!method.hasModifierProperty(PsiModifier.STATIC)); return; } } - final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(qualifier); + final MatchingHandler handler = myMatchingVisitor.getMatchContext().getPattern().getHandler(patternQualifier); matchImplicitQualifier(handler, method, myMatchingVisitor.getMatchContext()); if (!myMatchingVisitor.getResult()) { return; } } } - else if (elementQualifier != null) { + else if (matchedQualifier != null) { myMatchingVisitor.setResult(false); return; } myMatchingVisitor.setResult(myMatchingVisitor.matchSons(mcall.getArgumentList(), mcall2.getArgumentList())); + if (myMatchingVisitor.getResult()) { + myMatchingVisitor.setResult(matchTypeParameters(mcallRef1, mcallRef2)); + } + if (myMatchingVisitor.getResult() && isTypedVar) { boolean res = myMatchingVisitor.getResult(); - res &= myMatchingVisitor.handleTypedElement(mcallRef1.getReferenceNameElement(), mcallRef2.getReferenceNameElement()); + res &= myMatchingVisitor.handleTypedElement(patternMethodName, mcallRef2.getReferenceNameElement()); myMatchingVisitor.setResult(res); } } + private boolean matchTypeParameters(PsiJavaCodeReferenceElement mcallRef1, PsiJavaCodeReferenceElement mcallRef2) { + final PsiReferenceParameterList patternParameterList = mcallRef1.getParameterList(); + if (patternParameterList == null) { + return true; + } + final PsiTypeElement[] patternTypeElements = patternParameterList.getTypeParameterElements(); + if (patternTypeElements.length == 0) { + return true; + } + PsiReferenceParameterList matchedParameterList = mcallRef2.getParameterList(); + if (matchedParameterList == null) { + return false; + } + if (matchedParameterList.getFirstChild() == null) { // check inferred type parameters + final JavaResolveResult resolveResult = mcallRef2.advancedResolve(false); + final PsiMethod targetMethod = (PsiMethod)resolveResult.getElement(); + if (targetMethod == null) { + return false; + } + final PsiTypeParameterList typeParameterList = targetMethod.getTypeParameterList(); + if (typeParameterList == null) { + return false; + } + final PsiTypeParameter[] typeParameters = typeParameterList.getTypeParameters(); + final PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + matchedParameterList = (PsiReferenceParameterList)matchedParameterList.copy(); + for (final PsiTypeParameter typeParameter : typeParameters) { + final PsiType type = substitutor.substitute(typeParameter); + if (type == null) { + return false; + } + final PsiTypeElement matchedTypeElement = JavaPsiFacade.getElementFactory(mcallRef1.getProject()).createTypeElement(type); + matchedParameterList.add(matchedTypeElement); + } + } + final PsiTypeElement[] matchedTypeElements = matchedParameterList.getTypeParameterElements(); + return myMatchingVisitor.matchSequentially(patternTypeElements, matchedTypeElements); + } + @Override public void visitExpressionStatement(final PsiExpressionStatement expr) { final PsiElement other = myMatchingVisitor.getElement(); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 73a8eff7fa73..1d33cca4914b 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -3443,4 +3443,23 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("any variable can be final", 3, findMatchesCount(source, "@Modifier(\"final\") '_T '_a;")); assertEquals("parameters and local variables are not instance fields", 1, findMatchesCount(source, "@Modifier(\"Instance\") '_T '_a;")); } + + public void testFindParameterizedMethodCalls() { + String source = "interface Foo {" + + " T bar();" + + " void bar2(S, T);" + + "}" + + "class X {" + + " void x(Foo foo) {" + + " foo.bar();" + + " foo.bar();" + + " String s = foo.bar();" + + " foo.bar2(1, 2);" + + " }" + + "}"; + assertEquals("find parameterized method calls 1", 1, findMatchesCount(source, "foo.bar()")); + assertEquals("find parameterized method calls 2", 2, findMatchesCount(source, "foo.bar()")); + assertEquals("find parameterized method calls 3", 3, findMatchesCount(source, "'_a.<'_b>'_c('_d*)")); + assertEquals("find parameterized method calls 4", 4, findMatchesCount(source, "'_a.<'_b+>'_c('_d*)")); + } }