From ec532d504c6783b812b338fb2bb5e8bed86fd409 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 31 Jul 2023 12:35:12 +0200 Subject: [PATCH] Java: update inspection for string templates (IDEA-326944) "Non-Basic Latin character" inspection GitOrigin-RevId: 5f6d355d4a5d653d88d43fee5b91bc9c45990a28 --- .../source/tree/java/PsiTemplateImpl.java | 8 +- .../i18n/ConvertToBasicLatinInspection.java | 82 +++++++++++++++---- .../convertToBasicLatin/StringTemplate1.java | 7 ++ .../StringTemplate1_after.java | 7 ++ .../convertToBasicLatin/StringTemplate2.java | 7 ++ .../StringTemplate2_after.java | 7 ++ .../convertToBasicLatin/StringTemplate3.java | 7 ++ .../StringTemplate3_after.java | 7 ++ .../convertToBasicLatin/StringTemplate4.java | 6 ++ .../StringTemplate4_after.java | 6 ++ .../convertToBasicLatin/StringTemplate5.java | 6 ++ .../StringTemplate5_after.java | 6 ++ .../convertToBasicLatin/StringTemplate6.java | 6 ++ .../StringTemplate6_after.java | 6 ++ .../ConvertToBasicLatinTest.java | 6 ++ 15 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate1.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate1_after.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate2.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate2_after.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate3.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate3_after.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate4.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate4_after.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate5.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate5_after.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate6.java create mode 100644 plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate6_after.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTemplateImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTemplateImpl.java index b8566dac8bf5..26b46f63415e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTemplateImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiTemplateImpl.java @@ -31,8 +31,8 @@ public final class PsiTemplateImpl extends ExpressionPsiElement implements PsiTe public @NotNull List<@NotNull PsiFragment> getFragments() { final List result = new ArrayList<>(); final PsiElement @NotNull [] children = getChildren(); - for (int i = 0, length = children.length; i < length; i += 2) { - result.add((PsiFragment)children[i]); + for (PsiElement child : children) { + if (child instanceof PsiFragment) result.add((PsiFragment)child); } return result; } @@ -41,8 +41,8 @@ public final class PsiTemplateImpl extends ExpressionPsiElement implements PsiTe public @NotNull List<@NotNull PsiExpression> getEmbeddedExpressions() { final List result = new ArrayList<>(); final PsiElement @NotNull [] children = getChildren(); - for (int i = 1, length = children.length; i < length; i += 2) { - result.add((PsiExpression)children[i]); + for (PsiElement child : children) { + if (child instanceof PsiExpression) result.add((PsiExpression)child); } return result; } diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/ConvertToBasicLatinInspection.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/ConvertToBasicLatinInspection.java index 6bbe44547fed..1ba228fbf588 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/ConvertToBasicLatinInspection.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/ConvertToBasicLatinInspection.java @@ -14,6 +14,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.xml.XmlEntityDecl; import com.intellij.psi.xml.XmlFile; @@ -56,6 +57,12 @@ public class ConvertToBasicLatinInspection extends AbstractBaseJavaLocalInspecti handle(expression); } + @Override + public void visitFragment(@NotNull PsiFragment fragment) { + super.visitFragment(fragment); + handle(fragment); + } + @Override public void visitDocComment(@NotNull PsiDocComment comment) { super.visitDocComment(comment); @@ -66,7 +73,7 @@ public class ConvertToBasicLatinInspection extends AbstractBaseJavaLocalInspecti private abstract static class Handler { @NotNull - PsiElement getSubstitution(@NotNull Project project, @NotNull PsiElement element) { + PsiElement buildReplacement(@NotNull Project project, @NotNull PsiElement element) { String text = element.getText(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < text.length(); i++) { @@ -79,7 +86,7 @@ public class ConvertToBasicLatinInspection extends AbstractBaseJavaLocalInspecti } } PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - return getSubstitution(factory, element, sb.toString()); + return buildReplacement(factory, element, sb.toString()); } protected static boolean isBasicLatin(char ch) { @@ -89,14 +96,14 @@ public class ConvertToBasicLatinInspection extends AbstractBaseJavaLocalInspecti protected abstract void convert(@NotNull StringBuilder sb, char ch); @NotNull - protected abstract PsiElement getSubstitution(@NotNull PsiElementFactory factory, @NotNull PsiElement element, @NotNull String newText); + protected abstract PsiElement buildReplacement(@NotNull PsiElementFactory factory, @NotNull PsiElement element, @NotNull String newText); } private static class LiteralHandler extends Handler { @Override - protected @NotNull PsiElement getSubstitution(@NotNull PsiElementFactory factory, - @NotNull PsiElement element, - @NotNull String newText) { + protected @NotNull PsiElement buildReplacement(@NotNull PsiElementFactory factory, + @NotNull PsiElement element, + @NotNull String newText) { return factory.createExpressionFromText(newText, element.getParent()); } @@ -106,14 +113,56 @@ public class ConvertToBasicLatinInspection extends AbstractBaseJavaLocalInspecti } } + private static class FragmentHandler extends LiteralHandler { + @Override + protected @NotNull PsiElement buildReplacement(@NotNull PsiElementFactory factory, + @NotNull PsiElement element, + @NotNull String newText) { + PsiFragment fragment = (PsiFragment)element; + IElementType tokenType = fragment.getTokenType(); + int index; + if (tokenType == JavaTokenType.TEXT_BLOCK_TEMPLATE_BEGIN) { + newText += "}\"\"\""; + index = 0; + } + else if (tokenType == JavaTokenType.TEXT_BLOCK_TEMPLATE_MID) { + newText = "\"\"\"\n\\{" + newText + "}\"\"\""; + index = 1; + } + else if (tokenType == JavaTokenType.TEXT_BLOCK_TEMPLATE_END) { + newText = "\"\"\"\n\\{" + newText; + index = 1; + } + else if (tokenType == JavaTokenType.STRING_TEMPLATE_BEGIN) { + newText += "}\""; + index = 0; + } + else if (tokenType == JavaTokenType.STRING_TEMPLATE_MID) { + newText = "\"\\{" + newText + "}\""; + index = 1; + } + else if (tokenType == JavaTokenType.STRING_TEMPLATE_END) { + newText = "\"\\{" + newText; + index = 1; + } + else { + throw new AssertionError(); + } + PsiTemplateExpression expression = (PsiTemplateExpression)factory.createExpressionFromText(newText, element); + PsiTemplate template = expression.getTemplate(); + assert template != null; + return template.getFragments().get(index); + } + } + private static class DocCommentHandler extends Handler { private static Int2ObjectMap ourEntities; @Override @NotNull - PsiElement getSubstitution(@NotNull Project project, @NotNull PsiElement element) { + PsiElement buildReplacement(@NotNull Project project, @NotNull PsiElement element) { loadEntities(project); - return ourEntities != null ? super.getSubstitution(project, element) : element; + return ourEntities != null ? super.buildReplacement(project, element) : element; } @Override @@ -128,9 +177,9 @@ public class ConvertToBasicLatinInspection extends AbstractBaseJavaLocalInspecti } @Override - protected @NotNull PsiElement getSubstitution(@NotNull PsiElementFactory factory, - @NotNull PsiElement element, - @NotNull String newText) { + protected @NotNull PsiElement buildReplacement(@NotNull PsiElementFactory factory, + @NotNull PsiElement element, + @NotNull String newText) { return factory.createCommentFromText(newText, element.getParent()); } @@ -203,12 +252,13 @@ public class ConvertToBasicLatinInspection extends AbstractBaseJavaLocalInspecti else if (element instanceof PsiComment) { handler = new CommentHandler(); } - else { - handler = null; + else if (element instanceof PsiFragment) { + handler = new FragmentHandler(); } - if (handler == null) return; - final PsiElement newElement = handler.getSubstitution(project, element); - element.replace(newElement); + else { + return; + } + element.replace(handler.buildReplacement(project, element)); } } } \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate1.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate1.java new file mode 100644 index 000000000000..5fa2f07eb1fb --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate1.java @@ -0,0 +1,7 @@ +class StringTemplate1 { + + String x() { + return STR.""" + ©\{}"""; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate1_after.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate1_after.java new file mode 100644 index 000000000000..260702aba90e --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate1_after.java @@ -0,0 +1,7 @@ +class StringTemplate1 { + + String x() { + return STR.""" + \u00A9\{}"""; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate2.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate2.java new file mode 100644 index 000000000000..52a360b6e399 --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate2.java @@ -0,0 +1,7 @@ +class StringTemplate1 { + + String x() { + return STR. """ + \{}©"""; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate2_after.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate2_after.java new file mode 100644 index 000000000000..cbfd0e04bc67 --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate2_after.java @@ -0,0 +1,7 @@ +class StringTemplate1 { + + String x() { + return STR.""" + \{}\u00A9"""; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate3.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate3.java new file mode 100644 index 000000000000..7da5f774d39a --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate3.java @@ -0,0 +1,7 @@ +class StringTemplate1 { + + String x() { + return STR. """ + \{}©\{}"""; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate3_after.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate3_after.java new file mode 100644 index 000000000000..7fe79229941c --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate3_after.java @@ -0,0 +1,7 @@ +class StringTemplate1 { + + String x() { + return STR.""" + \{}\u00A9\{}"""; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate4.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate4.java new file mode 100644 index 000000000000..d4e61d4ce92c --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate4.java @@ -0,0 +1,6 @@ +class StringTemplate1 { + + String x() { + return STR."©\{}"; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate4_after.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate4_after.java new file mode 100644 index 000000000000..299a1fe215eb --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate4_after.java @@ -0,0 +1,6 @@ +class StringTemplate1 { + + String x() { + return STR."\u00A9\{}"; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate5.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate5.java new file mode 100644 index 000000000000..850cb8e5dc12 --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate5.java @@ -0,0 +1,6 @@ +class StringTemplate1 { + + String x() { + return STR."\{}©"; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate5_after.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate5_after.java new file mode 100644 index 000000000000..aaa073581c03 --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate5_after.java @@ -0,0 +1,6 @@ +class StringTemplate1 { + + String x() { + return STR."\{}\u00A9"; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate6.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate6.java new file mode 100644 index 000000000000..e245adaccac2 --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate6.java @@ -0,0 +1,6 @@ +class StringTemplate1 { + + String x() { + return STR."\{}©\{}"; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate6_after.java b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate6_after.java new file mode 100644 index 000000000000..d262d749a34a --- /dev/null +++ b/plugins/java-i18n/testData/quickFix/convertToBasicLatin/StringTemplate6_after.java @@ -0,0 +1,6 @@ +class StringTemplate1 { + + String x() { + return STR."\{}\u00A9\{}"; + } +} \ No newline at end of file diff --git a/plugins/java-i18n/testSrc/com/intellij/codeInspection/ConvertToBasicLatinTest.java b/plugins/java-i18n/testSrc/com/intellij/codeInspection/ConvertToBasicLatinTest.java index 4ed6b9d7ef5d..83134a240a73 100644 --- a/plugins/java-i18n/testSrc/com/intellij/codeInspection/ConvertToBasicLatinTest.java +++ b/plugins/java-i18n/testSrc/com/intellij/codeInspection/ConvertToBasicLatinTest.java @@ -23,6 +23,12 @@ public class ConvertToBasicLatinTest extends LightJavaCodeInsightFixtureTestCase public void testCharLiteral() { doTest(); } public void testStringLiteral() { doTest(); } public void testTextBlock() { doTest(); } + public void testStringTemplate1() { doTest(); } + public void testStringTemplate2() { doTest(); } + public void testStringTemplate3() { doTest(); } + public void testStringTemplate4() { doTest(); } + public void testStringTemplate5() { doTest(); } + public void testStringTemplate6() { doTest(); } public void testPlainComment() { doTest(); } public void testDocComment() { doTest(); } public void testDocTag() { doTest(); }