diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/template/MacroParserTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/template/MacroParserTest.java index 16856971d0a7..18655337b98e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/template/MacroParserTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/template/MacroParserTest.java @@ -52,4 +52,10 @@ public class MacroParserTest extends LightIdeaTestCase { assertTrue(parameters [0] instanceof ConstantNode); assertTrue(parameters [1] instanceof ConstantNode); } + + public void testSlashEscape() { + Expression e = MacroParser.parse("\"test\\\\test\\n\\t\\f\\x\""); + Result result = assertInstanceOf(e, ConstantNode.class).calculateResult(null); + assertEquals("test\\test\n\t\fx", assertInstanceOf(result, TextResult.class).getText()); + } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/MacroParser.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/MacroParser.java index f204e4817c1d..5700498b13d2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/MacroParser.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/MacroParser.java @@ -21,10 +21,12 @@ import com.intellij.codeInsight.template.Expression; import com.intellij.codeInsight.template.Macro; import com.intellij.codeInsight.template.macro.MacroFactory; import com.intellij.lexer.Lexer; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.tree.IElementType; @VisibleForTesting public class MacroParser { + private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.template.impl.MacroParser"); //----------------------------------------------------------------------------------- public static Expression parse(String expression) { @@ -62,13 +64,11 @@ public class MacroParser { String token = getString(lexer, expression); if (tokenType == MacroTokenType.STRING_LITERAL) { advance(lexer); - - return new ConstantNode(token.substring(1, token.length() - 1).replaceAll("\\\\n", "\n"). - replaceAll("\\\\r", "\r").replaceAll("\\\\t", "\t").replaceAll("\\\\f", "\f").replaceAll("\\\\(.)", "$1")); + return new ConstantNode(parseStringLiteral(token)); } if (tokenType != MacroTokenType.IDENTIFIER) { - System.out.println("Bad macro syntax: Not identifier: " + token); + LOG.info("Bad macro syntax: Not identifier: " + token); advance(lexer); return new ConstantNode(""); } @@ -91,12 +91,31 @@ public class MacroParser { advance(lexer); parseParameters(macroCallNode, lexer, expression); if (lexer.getTokenType() != MacroTokenType.RPAREN) { - System.out.println("Bad macro syntax: ) expected: " + expression); + LOG.info("Bad macro syntax: ) expected: " + expression); } advance(lexer); return macroCallNode; } + private static String parseStringLiteral(String token) { + StringBuilder sb = new StringBuilder(token.length() - 2); + int i = 1; + while (i < token.length() - 1) { + char c = token.charAt(i); + if (c == '\\') { + c = token.charAt(++i); + if (c == 'n') sb.append('\n'); + else if (c == 't') sb.append('\t'); + else if (c == 'f') sb.append('\f'); + else sb.append(c); + } else { + sb.append(c); + } + i++; + } + return sb.toString(); + } + private static void parseParameters(MacroCallNode macroCallNode, Lexer lexer, String expression) { if (lexer.getTokenType() != MacroTokenType.RPAREN) { while (lexer.getTokenType() != null) {