SSR: existing templates can have properties on Complete Match (enables e.g. more advanced html/xml patterns)

This commit is contained in:
Bas Leijdekkers
2015-03-05 11:43:46 +01:00
parent 676d79ed06
commit 01b9c80c63
5 changed files with 38 additions and 12 deletions
@@ -41,7 +41,7 @@ class JavaPredefinedConfigurations {
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.ifs"),"if ('_Condition) {\n '_ThenStatement*;\n} else {\n '_ElseStatement*;\n}",OPERATOR_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.switches"),"switch('_Condition) {\n '_Statement*;\n}",OPERATOR_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.foreaches"), "for ('_Type '_Variable : '_Expression) {\n '_Statement*;\n}", OPERATOR_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.logging.without.if"),"LOG.debug('_params*:[!within( \"if('_a) { '_st*; }\" )]);",OPERATOR_TYPE),
createSearchTemplateInfo(SSRBundle.message("predefined.configuration.logging.without.if"),"[!within( \"if('_a) { 'st*; }\" )]LOG.debug('_params*);",OPERATOR_TYPE),
// Class based
createSearchTemplateInfo(
@@ -212,6 +212,7 @@ public class XmlStructuralSearchProfile extends StructuralSearchProfile {
createSearchTemplateInfo("xml attribute value", "<'_tag '_attribute=\"'value\"/>", HTML_XML, StdFileTypes.XML),
createSearchTemplateInfo("html attribute value", "<'_tag '_attribute='value />", HTML_XML, StdFileTypes.HTML),
createSearchTemplateInfo("xml/html tag value", "<table>'_content*</table>", HTML_XML, StdFileTypes.HTML),
createSearchTemplateInfo("li not contained in ul/ol", "[!within( \"<'_tag:[regex( \"ul|ol\" )] />\" )]<li />", HTML_XML, StdFileTypes.HTML)
};
}
}
@@ -35,6 +35,7 @@ class StringToConstraintsTransformer {
@NonNls private static final String CONTAINS = "contains";
@NonNls private static final String WITHIN = "within";
@SuppressWarnings("AssignmentToForLoopParameter")
static void transformOldPattern(MatchOptions options) {
final String pattern = options.getSearchPattern();
@@ -44,12 +45,22 @@ class StringToConstraintsTransformer {
int anonymousTypedVarsCount = 0;
boolean targetFound = false;
for(int index=0;index < pattern.length();++index) {
final int length = pattern.length();
for(int index=0; index < length; ++index) {
char ch = pattern.charAt(index);
if (index == 0 && ch == '[') {
if (miscBuffer == null) miscBuffer = new StringBuilder();
else miscBuffer.setLength(0);
final MatchVariableConstraint constraint = new MatchVariableConstraint();
constraint.setName(Configuration.CONTEXT_VAR_NAME);
index = eatTypedVarCondition(0, pattern, miscBuffer, constraint);
options.addVariableConstraint(constraint);
if (index == length) break;
ch = pattern.charAt(index);
}
if (ch=='\'') {
// doubling '
final int length = pattern.length();
if (index + 1 < length &&
pattern.charAt(index + 1)=='\''
) {
@@ -97,9 +108,8 @@ class StringToConstraintsTransformer {
buf.append(ch);
}
boolean anonymous = false;
if (miscBuffer.length() == 0) throw new MalformedPatternException(SSRBundle.message("error.expected.character"));
boolean anonymous = false;
if (miscBuffer.charAt(0)=='_') {
anonymous = true;
@@ -215,9 +225,6 @@ class StringToConstraintsTransformer {
}
if (constraintCreated) {
if (constraint.getWithinConstraint().length() > 0) {
constraint.setName(Configuration.CONTEXT_VAR_NAME);
}
options.addVariableConstraint(constraint);
}
@@ -430,6 +437,9 @@ class StringToConstraintsTransformer {
constraint.setContainsConstraint(script );
consumed = true;
} else if (option.equalsIgnoreCase(WITHIN)) {
if (!Configuration.CONTEXT_VAR_NAME.equals(constraint.getName())) {
throw new MalformedPatternException("Within constraint is only applicable to Complete Match");
}
if (hasNot) constraint.setInvertWithinConstraint(true);
String script = getSingleParameter(m, SSRBundle.message("script.should.be.delimited.with.spaces.error.message"));
@@ -2807,8 +2807,8 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
"while(true) {\n" +
" int c = 2;\n" +
"}";
String s2 = "'_type 'a:[within( \"if ('_a) { '_st*; }\" )] = '_b;";
String s2_2 = "'_type 'a:[!within( \"if ('_a) { '_st*; }\" )] = '_b;";
String s2 = "[within( \"if ('_a) { '_st*; }\" )]'_type 'a = '_b;";
String s2_2 = "[!within( \"if ('_a) { '_st*; }\" )]'_type 'a = '_b;";
assertEquals(2,findMatchesCount(s1, s2));
assertEquals(1,findMatchesCount(s1, s2_2));
@@ -2847,7 +2847,7 @@ public class StructuralSearchTest extends StructuralSearchTestCase {
" }" +
" }" +
"}";
String s4 = "LOG.debug('_params*:[!within( \"if('_a) { 'st*; }\" )]);";
String s4 = "[!within( \"if('_a) { 'st*; }\" )]LOG.debug('_params*);";
assertEquals(7,findMatchesCount(s3, s4));
}
@@ -8,6 +8,8 @@ import com.intellij.structuralsearch.plugin.ui.Configuration;
import org.junit.Before;
import org.junit.Test;
import java.util.Set;
import static org.junit.Assert.assertEquals;
/**
@@ -132,9 +134,22 @@ public class StringToConstraintsTransformerTest {
assertEquals("$a$::$b$", myOptions.getSearchPattern());
}
@Test
public void testCompleteMatchConditions() {
test("[within( \"if('_a) { 'st*; }\" )]1+1");
assertEquals("1+1", myOptions.getSearchPattern());
final MatchVariableConstraint constraint = myOptions.getVariableConstraint(Configuration.CONTEXT_VAR_NAME);
assertEquals("\"if('_a) { 'st*; }\"", constraint.getWithinConstraint());
}
@Test(expected = MalformedPatternException.class)
public void testBadWithin() {
test("'_type 'a:[within( \"if ('_a) { '_st*; }\" )] = '_b;");
}
@Test
public void testScriptEscaping() {
test("'_type 'a:[within( \"if ('_a:[regex( .*e.* )\\]) { '_st*; }\" )] = '_b;");
test("[within( \"if ('_a:[regex( .*e.* )\\]) { '_st*; }\" )]'_type 'a = '_b;");
assertEquals("$type$ $a$ = $b$;", myOptions.getSearchPattern());
final MatchVariableConstraint constraint = myOptions.getVariableConstraint(Configuration.CONTEXT_VAR_NAME);
assertEquals("\"if ('_a:[regex( .*e.* )]) { '_st*; }\"", constraint.getWithinConstraint());