diff --git a/java/java-impl/src/com/intellij/codeInspection/TextBlockBackwardMigrationInspection.java b/java/java-impl/src/com/intellij/codeInspection/TextBlockBackwardMigrationInspection.java index b020f2163b3e..e97642b79a6c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/TextBlockBackwardMigrationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/TextBlockBackwardMigrationInspection.java @@ -1,14 +1,15 @@ // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection; +import com.intellij.application.options.CodeStyle; import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; +import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.project.Project; -import com.intellij.psi.JavaElementVisitor; -import com.intellij.psi.JavaTokenType; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiLiteralExpression; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl; -import com.siyeh.ig.PsiReplacementUtil; +import com.intellij.psi.util.PsiLiteralUtil; import com.siyeh.ig.psiutils.CommentTracker; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -53,7 +54,14 @@ public class TextBlockBackwardMigrationInspection extends AbstractBaseJavaLocalI String text = literalExpression.getTextBlockText(); if (text == null) return; String replacement = convertToConcatenation(text); - PsiReplacementUtil.replaceExpression(literalExpression, replacement, new CommentTracker()); + PsiFile file = descriptor.getPsiElement().getContainingFile(); + if (file == null) return; + CodeStyleSettings tempSettings = CodeStyle.getSettings(file); + tempSettings.getCommonSettings(JavaLanguage.INSTANCE).ALIGN_MULTILINE_BINARY_OPERATION = true; + CodeStyle.doWithTemporarySettings(project, tempSettings, () -> { + PsiElement result = new CommentTracker().replaceAndRestoreComments(literalExpression, replacement); + CodeStyleManager.getInstance(literalExpression.getProject()).reformat(result); + }); } @NotNull @@ -65,70 +73,9 @@ public class TextBlockBackwardMigrationInspection extends AbstractBaseJavaLocalI String line = lines[i]; boolean addNewLine = i != lines.length - 1; if (!addNewLine && line.isEmpty()) break; - joiner.add("\"" + escapeQuotes(line) + (addNewLine ? "\\n\"" : "\"")); + joiner.add("\"" + PsiLiteralUtil.escapeQuotes(line) + (addNewLine ? "\\n\"" : "\"")); } return joiner.toString(); } - - @NotNull - private static String escapeQuotes(@NotNull String str) { - StringBuilder sb = new StringBuilder(str.length()); - int nSlashes = 0; - int idx = 0; - while (idx < str.length()) { - char c = str.charAt(idx); - int nextIdx = parseBackSlash(str, idx); - if (nextIdx > 0) { - nSlashes++; - } - else { - if (c == '\"' && nSlashes % 2 == 0) { - sb.append('\\'); - } - nSlashes = 0; - nextIdx = idx + 1; - } - sb.append(c); - idx = nextIdx; - } - return sb.toString(); - } - - private static int parseBackSlash(@NotNull String str, int idx) { - char c = str.charAt(idx); - if (c != '\\') return -1; - int nextIdx = parseHexBackSlash(str, idx); - if (nextIdx > 0) return nextIdx; - nextIdx = parseOctalBackSlash(str, idx); - return nextIdx > 0 ? nextIdx : idx + 1; - } - - private static int parseHexBackSlash(@NotNull String str, int idx) { - int next = idx + 1; - if (next >= str.length() || str.charAt(next) != 'u') return -1; - while (str.charAt(next) == 'u') { - next++; - } - if (next + 3 >= str.length()) return -1; - try { - int code = Integer.parseInt(str.substring(next, next + 4), 16); - if (code == '\\') return next + 4; - } - catch (NumberFormatException ignored) { - } - return -1; - } - - private static int parseOctalBackSlash(@NotNull String str, int idx) { - int next = idx + 1; - if (next + 2 >= str.length()) return -1; - try { - int code = Integer.parseInt(str.substring(next, next + 3), 8); - if (code == '\\') return next + 3; - } - catch (NumberFormatException ignored) { - } - return -1; - } } } diff --git a/java/java-impl/src/inspectionDescriptions/TextBlockBackwardMigration.html b/java/java-impl/src/inspectionDescriptions/TextBlockBackwardMigration.html index ebadf62383b8..92b925abe23a 100644 --- a/java/java-impl/src/inspectionDescriptions/TextBlockBackwardMigration.html +++ b/java/java-impl/src/inspectionDescriptions/TextBlockBackwardMigration.html @@ -20,7 +20,7 @@ Example: "\n" + "hello();\n"); -

This inspection only reports if the language level is 13 Preview

+

This inspection works if the language level is 13 Preview.

New in 2019.3

\ No newline at end of file diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiLiteralUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiLiteralUtil.java index e3b9179251fe..0d673069b126 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiLiteralUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiLiteralUtil.java @@ -186,4 +186,70 @@ public class PsiLiteralUtil { q -= 3; } } + + /** + * Replaces all unescaped quotes with escaped ones. + * If text contains backslash escape sequence it's replaced with a regular backslash. + * The rest of the symbols are left unchanged. + */ + @NotNull + public static String escapeQuotes(@NotNull String str) { + StringBuilder sb = new StringBuilder(str.length()); + int nSlashes = 0; + int idx = 0; + while (idx < str.length()) { + char c = str.charAt(idx); + int nextIdx = parseBackSlash(str, idx); + if (nextIdx > 0) { + nSlashes++; + } + else { + if (c == '\"' && nSlashes % 2 == 0) { + sb.append('\\'); + } + nSlashes = 0; + nextIdx = idx + 1; + } + sb.append(c); + idx = nextIdx; + } + return sb.toString(); + } + + private static int parseBackSlash(@NotNull String str, int idx) { + char c = str.charAt(idx); + if (c != '\\') return -1; + int nextIdx = parseHexBackSlash(str, idx); + if (nextIdx > 0) return nextIdx; + nextIdx = parseOctalBackSlash(str, idx); + return nextIdx > 0 ? nextIdx : idx + 1; + } + + private static int parseHexBackSlash(@NotNull String str, int idx) { + int next = idx + 1; + if (next >= str.length() || str.charAt(next) != 'u') return -1; + while (str.charAt(next) == 'u') { + next++; + } + if (next + 3 >= str.length()) return -1; + try { + int code = Integer.parseInt(str.substring(next, next + 4), 16); + if (code == '\\') return next + 4; + } + catch (NumberFormatException ignored) { + } + return -1; + } + + private static int parseOctalBackSlash(@NotNull String str, int idx) { + int next = idx + 1; + if (next + 2 >= str.length()) return -1; + try { + int code = Integer.parseInt(str.substring(next, next + 3), 8); + if (code == '\\') return next + 3; + } + catch (NumberFormatException ignored) { + } + return -1; + } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/textBlockBackwardMigration/afterMultiLine.java b/java/java-tests/testData/inspection/textBlockBackwardMigration/afterMultiLine.java deleted file mode 100644 index 8ce64601c9d7..000000000000 --- a/java/java-tests/testData/inspection/textBlockBackwardMigration/afterMultiLine.java +++ /dev/null @@ -1,14 +0,0 @@ -// "Replace with regular string literal" "true" - -class TextBlockMigration { - - String multiLine() { - return "public static void print(Object o) {\n" + - " System.out.println(o);\n" + - "}\n" + - "\n" + - "public static void main(String[] args) {\n" + - " print(\"test\");\n" + - "}\n"; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/textBlockBackwardMigration/afterMultipleStringLiterals.java b/java/java-tests/testData/inspection/textBlockBackwardMigration/afterMultipleStringLiterals.java new file mode 100644 index 000000000000..e2d5568b70c4 --- /dev/null +++ b/java/java-tests/testData/inspection/textBlockBackwardMigration/afterMultipleStringLiterals.java @@ -0,0 +1,14 @@ +// "Replace with regular string literal" "true" + +class TextBlockMigration { + + String multipleLiterals() { + return "public static void print(Object o) {\n" + + " System.out.println(o);\n" + + "}\n" + + "\n" + + "public static void main(String[] args) {\n" + + " print(\"test\");\n" + + "}\n"; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/textBlockBackwardMigration/beforeMultiLine.java b/java/java-tests/testData/inspection/textBlockBackwardMigration/beforeMultipleStringLiterals.java similarity index 91% rename from java/java-tests/testData/inspection/textBlockBackwardMigration/beforeMultiLine.java rename to java/java-tests/testData/inspection/textBlockBackwardMigration/beforeMultipleStringLiterals.java index 916566238041..923e347d8591 100644 --- a/java/java-tests/testData/inspection/textBlockBackwardMigration/beforeMultiLine.java +++ b/java/java-tests/testData/inspection/textBlockBackwardMigration/beforeMultipleStringLiterals.java @@ -2,7 +2,7 @@ class TextBlockMigration { - String multiLine() { + String multipleLiterals() { return """ public static void print(Object o) { System.out.println(o);