SSR: implement explicit support for repeated variables (IDEA-195166)

This commit is contained in:
Bas Leijdekkers
2018-07-06 22:00:55 +02:00
parent 6051d470a1
commit 3eb243cfe5
5 changed files with 70 additions and 7 deletions
@@ -56,7 +56,18 @@ public class MatchContext {
}
public MatchResultImpl getPreviousResult() {
return previousResults.isEmpty() ? null : previousResults.peek();
if (previousResults.isEmpty()) {
return null;
}
else {
int index = previousResults.size() - 1;
MatchResultImpl result = previousResults.get(index); // may contain nulls
while (result == null && index > 0) {
index--;
result = previousResults.get(index);
}
return result;
}
}
public MatchResultImpl getResult() {
@@ -136,6 +136,19 @@ public final class MatchResultImpl extends MatchResult {
return null;
}
public static MatchResultImpl findChildDeep(MatchResult match , String name) {
for (MatchResult child : match.getChildren()) {
if (name.equals(child.getName())) {
return (MatchResultImpl)child;
}
final MatchResultImpl deep = findChildDeep(child, name);
if (deep != null) {
return deep;
}
}
return null;
}
public MatchResult removeChild(String typedVar) {
// @todo this could be performance bottleneck, replace with hash lookup!
for (int i = 0, size = myChildren.size(); i < size; i++) {
@@ -424,7 +424,6 @@ public class PatternCompiler {
final int segmentsCount = template.getSegmentsCount();
final String text = template.getTemplateText();
int prevOffset = 0;
final Set<String> seen = ContainerUtil.newTroveSet();
final Set<String> variableNames = ContainerUtil.newTroveSet();
for(int i = 0; i < segmentsCount; i++) {
@@ -439,8 +438,12 @@ public class PatternCompiler {
final String compiledName = prefix + name;
buf.append(text, prevOffset, offset).append(compiledName);
variableNames.add(name);
if (seen.add(compiledName)) {
final boolean repeated = !variableNames.add(name);
final SubstitutionHandler existing = (SubstitutionHandler)result.getHandler(compiledName);
if (existing != null) {
existing.setRepeatedVar(repeated);
}
else {
// the same variable can occur multiple times in a single template
// no need to process it more than once
@@ -460,6 +463,7 @@ public class PatternCompiler {
constraint.getMaxCount(),
constraint.isGreedy()
);
handler.setRepeatedVar(repeated);
if (constraint.isWithinHierarchy()) {
handler.setSubtype(true);
@@ -39,6 +39,7 @@ public class SubstitutionHandler extends MatchingHandler {
private int matchedOccurs;
private int totalMatchedOccurs = -1;
private MatchResultImpl myNestedResult;
private boolean myRepeatedVar = false;
private static final NodeFilter VARS_DELIM_FILTER = new NodeFilter() {
@Override
@@ -95,6 +96,10 @@ public class SubstitutionHandler extends MatchingHandler {
return findRegExpPredicate(getPredicate());
}
public void setRepeatedVar(boolean repeatedVar) {
myRepeatedVar = repeatedVar;
}
private static RegExpPredicate findRegExpPredicate(MatchPredicate start) {
if (start==null) return null;
if (start instanceof RegExpPredicate) return (RegExpPredicate)start;
@@ -111,7 +116,10 @@ public class SubstitutionHandler extends MatchingHandler {
return null;
}
private static boolean validateOneMatch(final PsiElement match, int start, int end, final MatchResult result, final MatchContext matchContext) {
private boolean validateOneMatch(final PsiElement match, int start, int end, final MatchResult result, final MatchContext matchContext) {
if (!myRepeatedVar) {
return true;
}
if (match != null) {
if (start == 0 && end == -1 && result.getStart() == 0 && result.getEnd() == -1) {
return matchContext.getMatcher().match(match, result.getMatch());
@@ -134,8 +142,11 @@ public class SubstitutionHandler extends MatchingHandler {
MatchResult result = context.hasResult() ? context.getResult().findChild(name) : null;
if (result == null && context.getPreviousResult() != null) {
result = context.getPreviousResult().findChild(name);
if (result == null) {
final MatchResultImpl previous = context.getPreviousResult();
if (previous != null) {
result = MatchResultImpl.findChildDeep(previous, name);
}
}
if (result != null) {
@@ -3092,4 +3092,28 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
assertEquals("should find defaults", 3, findMatchesCount(in, "default:"));
assertEquals("should find cases", 8, findMatchesCount(in, "case '_a :"));
}
public void testRepeatedVars() {
String in = "class SomePageObject {\n" +
" @FindBy(name = \"first-name\")\n" +
" private WebElement name;\n" +
"\n" +
" @FindBy(name = \"first-name\")\n" +
" private WebElement firstName;\n" +
"}" +
"class SomePageObject2 {\n" +
" @FindBy(name = \"last-name\")\n" +
" private WebElement name;\n" +
"\n" +
" @FindBy(name = \"first-name\")\n" +
" private WebElement firstName;\n" +
"}";
assertEquals("find repeated annotation value", 1, findMatchesCount(in, "class '_Class {\n" +
" @FindBy(name='_value)\n" +
" '_FieldType '_field = '_init?;\n" +
" @FindBy(name='_value)\n" +
" '_FieldType2 'field2 = '_init2?;\n" +
"}"));
}
}