From 247b885ce9d9d42f6956be704170fb2862ee356d Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 2 Oct 2015 12:07:55 +0200 Subject: [PATCH] SRR: improve java array declaration matching --- .../impl/matcher/JavaMatchingVisitor.java | 111 ++++++++---------- .../StructuralSearchTest.java | 40 ++++++- 2 files changed, 82 insertions(+), 69 deletions(-) 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 7f6a55d6f2b0..f0cb8ebb9646 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 @@ -21,7 +21,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; -import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.structuralsearch.MatchOptions; @@ -444,7 +443,6 @@ public class JavaMatchingVisitor extends JavaElementVisitor { final MatchingHandler allRemainingClassContentElementHandler = unmatchedHandlerName != null ? pattern.getHandler(unmatchedHandlerName) : null; MatchContext.MatchedElementsListener newListener = null; - assert javaPattern instanceof JavaCompiledPattern; if (allRemainingClassContentElementHandler != null) { myMatchingVisitor.getMatchContext().setMatchedElementsListener( newListener = new MatchContext.MatchedElementsListener() { @@ -686,29 +684,47 @@ public class JavaMatchingVisitor extends JavaElementVisitor { myMatchingVisitor.setResult(false); } - private static int countCStyleArrayDeclarationDims(final PsiElement type2) { - if (type2 != null) { - final PsiElement parentElement = type2.getParent(); - - if (parentElement instanceof PsiVariable) { - final PsiIdentifier psiIdentifier = ((PsiVariable)parentElement).getNameIdentifier(); - if (psiIdentifier == null) return 0; - - int count = 0; - for (PsiElement sibling = psiIdentifier.getNextSibling(); sibling != null; sibling = sibling.getNextSibling()) { - if (sibling instanceof PsiJavaToken) { - final IElementType tokenType = ((PsiJavaToken)sibling).getTokenType(); - if (tokenType == JavaTokenType.LBRACKET) ++count; - else if (tokenType != JavaTokenType.RBRACKET) break; - } - } - - return count; - } + private static int getArrayDimensions(final PsiElement element) { + if (element == null) { + return 0; + } + final PsiElement parent = element.getParent(); + if (parent instanceof PsiVariable) { + final PsiVariable variable = (PsiVariable)parent; + final PsiType type = variable.getType(); + return type.getArrayDimensions(); + } + else if (parent instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)parent; + final PsiType type = method.getReturnType(); + return (type == null) ? 0 : type.getArrayDimensions(); + } + else if (element instanceof PsiTypeElement) { + final PsiTypeElement typeElement = (PsiTypeElement)element; + final PsiType type = typeElement.getType(); + return type.getArrayDimensions(); } return 0; } + private static PsiTypeElement getInnermostComponentTypeElement(PsiTypeElement typeElement) { + PsiElement child = typeElement.getFirstChild(); + while (child instanceof PsiTypeElement) { + typeElement = (PsiTypeElement)child; + child = typeElement.getFirstChild(); + } + return typeElement; + } + + private static PsiElement getInnermostComponent(PsiElement element) { + if (!(element instanceof PsiTypeElement)) { + return element; + } + final PsiTypeElement typeElement = (PsiTypeElement)element; + final PsiJavaCodeReferenceElement referenceElement = typeElement.getInnermostComponentReferenceElement(); + return (referenceElement != null) ? referenceElement : getInnermostComponentTypeElement(typeElement); + } + private void copyResults(final MatchResultImpl ourResult) { if (ourResult.hasSons()) { for (MatchResult son : ourResult.getAllSons()) { @@ -718,25 +734,8 @@ public class JavaMatchingVisitor extends JavaElementVisitor { } private boolean matchType(final PsiElement patternType, final PsiElement matchedType) { - PsiElement patternElement = patternType; - PsiElement matchedElement = matchedType; - PsiType type1 = null; - PsiType type2 = null; - - // check for generics - if (patternType instanceof PsiTypeElement && - ((PsiTypeElement)patternType).getInnermostComponentReferenceElement() != null - ) { - patternElement = ((PsiTypeElement)patternType).getInnermostComponentReferenceElement(); - type1 = ((PsiTypeElement)patternType).getType(); - } - - if (matchedType instanceof PsiTypeElement && - ((PsiTypeElement)matchedType).getInnermostComponentReferenceElement() != null - ) { - matchedElement = ((PsiTypeElement)matchedType).getInnermostComponentReferenceElement(); - type2 = ((PsiTypeElement)matchedType).getType(); - } + PsiElement patternElement = getInnermostComponent(patternType); + PsiElement matchedElement = getInnermostComponent(matchedType); PsiElement[] typeParameters = null; if (matchedElement instanceof PsiJavaCodeReferenceElement) { @@ -757,34 +756,20 @@ public class JavaMatchingVisitor extends JavaElementVisitor { matchedElement = ((PsiMethod)matchedType).getNameIdentifier(); } - PsiReferenceParameterList list = null; if (patternElement instanceof PsiJavaCodeReferenceElement) { - list = ((PsiJavaCodeReferenceElement)patternElement).getParameterList(); - patternElement = ((PsiJavaCodeReferenceElement)patternElement).getReferenceNameElement(); - } - - if (list != null && list.getTypeParameterElements().length > 0) { - boolean result = typeParameters != null && myMatchingVisitor.matchSequentially(list.getTypeParameterElements(), typeParameters); - - if (!result) return false; - } - else { - if (matchedType instanceof PsiTypeElement) { - type2 = ((PsiTypeElement)matchedType).getType(); - - if (typeParameters == null || typeParameters.length == 0) { - final PsiJavaCodeReferenceElement innermostComponentReferenceElement = - ((PsiTypeElement)matchedType).getInnermostComponentReferenceElement(); - if (innermostComponentReferenceElement != null) matchedElement = innermostComponentReferenceElement; - } - else { - matchedElement = matchedType; + final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)patternElement; + final PsiReferenceParameterList list = referenceElement.getParameterList(); + if (list != null) { + final PsiTypeElement[] elements = list.getTypeParameterElements(); + if (elements.length > 0 && (typeParameters == null || !myMatchingVisitor.matchSequentially(elements, typeParameters))) { + return false; } } + patternElement = referenceElement.getReferenceNameElement(); } - final int patternArrayDimensions = (type1 != null ? type1.getArrayDimensions() : 0) + countCStyleArrayDeclarationDims(patternType); - final int matchedArrayDimensions = (type2 != null ? type2.getArrayDimensions() : 0) + countCStyleArrayDeclarationDims(matchedType); + final int matchedArrayDimensions = getArrayDimensions(matchedType); + final int patternArrayDimensions = getArrayDimensions(patternType); if (myMatchingVisitor.getMatchContext().getPattern().isTypedVar(patternElement)) { final SubstitutionHandler handler = (SubstitutionHandler)myMatchingVisitor.getMatchContext().getPattern().getHandler(patternElement); diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index a0ff99c09ac9..e8b23ffd922c 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -685,14 +685,42 @@ public class StructuralSearchTest extends StructuralSearchTestCase { 1, findMatchesCount(s11,s12_3) ); + } + + public void testFindArrayDeclarations() { + String source = "class A {" + + " String ss[][];" + + " int f()[] {" + + " return null;" + + " }" + + "}"; - String source = "class A { String ss[][]; }"; String target = "String[][] $s$;"; - assertEquals( - "should find multi dimensional c-style array declarations", - 1, - findMatchesCount(source, target) - ); + assertEquals("should find multi-dimensional c-style array declarations", 1, findMatchesCount(source, target)); + + String target2 = "class '_A { int[] 'f(); }"; + assertEquals("should find c-style method return type declarations", 1, findMatchesCount(source, target2)); + + String target3 = "class '_A { int 'f(); }"; + assertEquals("should not find methods with array return types",0, findMatchesCount(source, target3)); + + String source2 = "class A {" + + " void y(int... i) {}" + + " void y(String... ss) {}" + + " void y(boolean b) {}" + + "}"; + assertEquals("find ellipsis type 1", 1, findMatchesCount(source2, "String[] '_a")); + assertEquals("find ellipsis type 2", 1, findMatchesCount(source2, "int[] '_a")); + assertEquals("find ellipsis type 3", 1, findMatchesCount(source2, "class '_X { void '_m(int... '_a); }")); + assertEquals("find ellipsis type 4", 2, findMatchesCount(source2, "'_T[] '_a")); + + String source3 = "class A {" + + " private int[] is;" + + "}"; + assertEquals("find primitive array 1", 1, findMatchesCount(source3, "int[] '_a;")); + assertEquals("find primitive array 2", 1, findMatchesCount(source3, "'_T[] '_a;")); + assertEquals("find primitive array 3", 1, findMatchesCount(source3, "'_T:[regex( int )][] '_a;")); + assertEquals("find primitive array 4", 1, findMatchesCount(source3, "'_T:[regex( int\\[\\] )] '_a;")); } // @todo support back references (\1 in another reg exp or as fild member)