From 8190148d3ea390e57b14439d2430d51e7042ca11 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 3 Jun 2015 19:53:39 +0200 Subject: [PATCH] SSR: fix matching multiple fields in a single declaration --- .../handlers/DeclarationStatementHandler.java | 97 +++++++++++-------- .../StructuralSearchTest.java | 15 +++ 2 files changed, 69 insertions(+), 43 deletions(-) diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/DeclarationStatementHandler.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/DeclarationStatementHandler.java index 7342e96758f0..6ebf9d238c95 100644 --- a/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/DeclarationStatementHandler.java +++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/handlers/DeclarationStatementHandler.java @@ -3,10 +3,15 @@ package com.intellij.structuralsearch.impl.matcher.handlers; import com.intellij.dupLocator.iterators.ArrayBackedNodeIterator; import com.intellij.dupLocator.iterators.CountingNodeIterator; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.structuralsearch.impl.matcher.GlobalMatchingVisitor; import com.intellij.structuralsearch.impl.matcher.MatchContext; import com.intellij.structuralsearch.impl.matcher.iterators.SsrFilteringNodeIterator; +import java.util.ArrayList; +import java.util.List; + /** * Created by IntelliJ IDEA. * User: maxim @@ -17,65 +22,71 @@ import com.intellij.structuralsearch.impl.matcher.iterators.SsrFilteringNodeIter public class DeclarationStatementHandler extends MatchingHandler { private MatchingHandler myCommentHandler; - public boolean match(PsiElement patternNode,PsiElement matchedNode, MatchContext context) { + public boolean match(PsiElement patternNode, PsiElement matchedNode, MatchContext context) { if (patternNode instanceof PsiComment) { - //if (matchedNode instanceof PsiComment || matchedNode instanceof PsiClass || matchedNode instanceof PsiField) return myCommentHandler.match(patternNode, matchedNode, context); - //return false; } if (!super.match(patternNode,matchedNode,context)) return false; - boolean result; - PsiDeclarationStatement dcl = (PsiDeclarationStatement)patternNode; - + final PsiDeclarationStatement dcl = (PsiDeclarationStatement)patternNode; if (matchedNode instanceof PsiDeclarationStatement) { - result = GlobalMatchingVisitor.continueMatchingSequentially( + return GlobalMatchingVisitor.continueMatchingSequentially( new SsrFilteringNodeIterator(patternNode.getFirstChild()), new SsrFilteringNodeIterator(matchedNode.getFirstChild()), context ); - } else { - final PsiElement[] declared = dcl.getDeclaredElements(); + } + final PsiElement[] declared = dcl.getDeclaredElements(); - // declaration statement could wrap class or dcl - if (declared.length >0 && - ( ( declared[0] instanceof PsiVariable && matchedNode instanceof PsiVariable) || - ( declared[0] instanceof PsiClass && matchedNode instanceof PsiClass) - ) && - !(matchedNode.getParent() instanceof PsiDeclarationStatement) // skip twice matching for child - ) { - result = GlobalMatchingVisitor.continueMatchingSequentially( + // declaration statement could wrap class or dcl + if (declared.length > 0 && !(matchedNode.getParent() instanceof PsiDeclarationStatement) /* skip twice matching for child*/) { + if (!(matchedNode instanceof PsiField)) { + return GlobalMatchingVisitor.continueMatchingSequentially( new ArrayBackedNodeIterator(declared), - new CountingNodeIterator( - declared.length, - new SsrFilteringNodeIterator(matchedNode) - ), + new CountingNodeIterator(declared.length, new SsrFilteringNodeIterator(matchedNode)), context ); - - if (result && - declared[0] instanceof PsiVariable && matchedNode instanceof PsiField - ) { - // we may have comments behind to match! - final PsiElement[] children = dcl.getChildren(); - - final PsiElement lastChild = children[children.length - 1]; - if (lastChild instanceof PsiComment) { - final PsiElement[] fieldChildren = matchedNode.getChildren(); - - result = context.getPattern().getHandler(lastChild).match( - lastChild, - fieldChildren[fieldChildren.length-1], - context - ); - } - } - } else { - result = false; } - } - return result; + // special handling for multiple fields in single declaration + final PsiElement sibling = PsiTreeUtil.skipSiblingsBackward(matchedNode, PsiWhiteSpace.class); + if (PsiUtil.isJavaToken(sibling, JavaTokenType.COMMA)) { + return false; + } + final List matchNodes = new ArrayList(); + matchNodes.add(matchedNode); + PsiElement node = matchedNode; + node = PsiTreeUtil.skipSiblingsForward(node, PsiWhiteSpace.class); + while (PsiUtil.isJavaToken(node, JavaTokenType.COMMA)) { + node = PsiTreeUtil.skipSiblingsForward(node, PsiWhiteSpace.class); + if (node != null) { + matchNodes.add(node); + } + node = PsiTreeUtil.skipSiblingsForward(node, PsiWhiteSpace.class); + } + boolean result = GlobalMatchingVisitor.continueMatchingSequentially( + new ArrayBackedNodeIterator(declared), + new ArrayBackedNodeIterator(matchNodes.toArray(new PsiElement[matchNodes.size()])), + context + ); + + if (result && declared[0] instanceof PsiVariable) { + // we may have comments behind to match! + + final PsiElement lastChild = dcl.getLastChild(); + if (lastChild instanceof PsiComment) { + final PsiElement[] fieldChildren = matchedNode.getChildren(); + + result = context.getPattern().getHandler(lastChild).match( + lastChild, + fieldChildren[fieldChildren.length-1], + context + ); + } + } + return result; + } + return false; } public boolean shouldAdvanceTheMatchFor(PsiElement patternElement, PsiElement matchedElement) { diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java index 8a3a89298869..b93bf00a16e5 100644 --- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java +++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralSearchTest.java @@ -3262,4 +3262,19 @@ public class StructuralSearchTest extends StructuralSearchTestCase { assertEquals("find polyadic expression of 3 operands", 1, findMatchesCount(source, "'_a + '_b{2,2}")); assertEquals("find polyadic expression of >3 operands", 2, findMatchesCount(source, "'_a + '_b{2,100}")); } + + public void testMultipleFieldsInOneDeclaration() { + String source = "class A {" + + " int i;" + + " int j, k;" + + " int l, m, n;" + + " int o, p, q;" + + "}"; + assertEquals("find multiple fields in one declaration 1", 3, findMatchesCount(source, "'_a '_b{2,100};")); + assertEquals("find multiple fields in one declaration 2", 3, findMatchesCount(source, "int '_b{2,100};")); + assertEquals("find multiple fields in one declaration 2", 2, findMatchesCount(source, "int '_b{3,3};")); + assertEquals("find declarations with only one field", 1, findMatchesCount(source, "int '_a;")); + assertEquals("find all declarations", 4, findMatchesCount(source, "int '_a+;")); + assertEquals("find all fields", 9, findMatchesCount(source, "int 'a+;")); + } }