Java: fix rendering of Unicode escapes in Javadoc comments (IDEA-342423)

GitOrigin-RevId: 63f994ebc05f7c0d43207ea08f037ad279a9f7ee
This commit is contained in:
Bas Leijdekkers
2025-02-16 22:58:12 +00:00
committed by intellij-monorepo-bot
parent c65665d0e9
commit ce156feab4
5 changed files with 79 additions and 63 deletions
@@ -1,3 +1,5 @@
<html><head><base href="placeholder"></head><body><div class='definition'><pre><span style="color:#000080;font-weight:bold;">class</span> <span style="color:#000000;">Test</span></pre></div><div class='content'>
a@b c@d
From A to Z
<code><span style="">\\uD83D\\uDE42</span></code>
</div><table class='sections'><p></table>
@@ -1,4 +1,6 @@
/**
* a\u0040b {@literal c\u0040d}
* From \uu0041 to \u005A
* {@code \\uD83D\\uDE42}
*/
class Test {}
@@ -201,24 +201,12 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase {
PsiClass outerClass = ((PsiJavaFile) myFile).getClasses()[0];
verifyJavaDoc(outerClass.getMethods()[0]);
}
public void testMarkdownJepExample(){
doTestMethod();
}
public void testHtmlCodeInMarkdown() {
doTestMethod();
}
public void testMarkdownJepExample(){ doTestMethod(); }
public void testHtmlCodeInMarkdown() { doTestMethod(); }
public void testMarkdownInlineCodeBlock() { doTestClass(); }
public void testEscapeHtmlCodesInCodeBlock(){
doTestClass();
}
public void testPreTagLeakBeforeCode() {
doTestClass();
}
public void testPreTagStrictBeforeCode(){
doTestClass();
}
public void testEscapeHtmlCodesInCodeBlock() { doTestClass(); }
public void testPreTagLeakBeforeCode() { doTestClass(); }
public void testPreTagStrictBeforeCode(){ doTestClass(); }
public void testRepeatableAnnotations() {
useJava8();
@@ -237,17 +225,9 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase {
verifyJavaDoc(method);
}
public void testEnumConstant1() {
doTestEnumConstant();
}
public void testEnumConstant2() {
doTestEnumConstant();
}
public void testEnumConstant3() {
doTestEnumConstant();
}
public void testEnumConstant1() { doTestEnumConstant(); }
public void testEnumConstant2() { doTestEnumConstant(); }
public void testEnumConstant3() { doTestEnumConstant(); }
public void testClickableFieldReference() {
PsiClass aClass = getTestClass();
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.util.text;
import com.intellij.ReviseWhenPortedToJDK;
@@ -2985,13 +2985,12 @@ public class StringUtil {
*/
@Contract(pure = true)
public static boolean hasUpperCaseChar(@NotNull String s) {
char[] chars = s.toCharArray();
for (char c : chars) {
if (Character.isUpperCase(c)) {
return true;
}
for (char c : s.toCharArray()) {
if (Character.isUpperCase(c)) {
return true;
}
return false;
}
return false;
}
/**
@@ -3001,34 +3000,56 @@ public class StringUtil {
*/
@Contract(pure = true)
public static boolean hasLowerCaseChar(@NotNull String s) {
char[] chars = s.toCharArray();
for (char c : chars) {
if (Character.isLowerCase(c)) {
return true;
}
for (char c : s.toCharArray()) {
if (Character.isLowerCase(c)) {
return true;
}
return false;
}
return false;
}
private static final Pattern UNICODE_CHAR = Pattern.compile("\\\\u[\\da-fA-F]{4}");
@Contract(pure = true)
public static String replaceUnicodeEscapeSequences(String text) {
if (text == null) return null;
Matcher matcher = UNICODE_CHAR.matcher(text);
if (!matcher.find()) return text; // fast path
matcher.reset();
int lastEnd = 0;
final int length = text.length();
StringBuilder sb = new StringBuilder(text.length());
while (matcher.find()) {
sb.append(text, lastEnd, matcher.start());
char c = (char)Integer.parseInt(matcher.group().substring(2), 16);
sb.append(c);
lastEnd = matcher.end();
outer:
for (int i = 0; i < length; i++) {
char c = text.charAt(i);
if (c == '\\') {
int j = i + 1;
boolean escape = true;
while (j < length && (c = text.charAt(j)) == '\\') {
escape = !escape;
j++;
}
if (!escape || c != 'u') {
sb.append(text, i, j + 1);
i = j;
continue;
}
while (j < length && (c = text.charAt(j)) == 'u') j++;
if (j > length - 4) {
sb.append(text, i, j + 1);
i = j;
continue;
}
for (int k = 0; k < 4; k++) {
if (!isHexDigit(text.charAt(j + k))) {
sb.append(text, i, j + k);
i = j + k - 1;
continue outer;
}
}
final char d = (char)Integer.parseInt(text.substring(j, j + 4), 16);
sb.append(d);
i = j + 3;
}
else {
sb.append(c);
}
}
sb.append(text.substring(lastEnd));
return sb.toString();
}
@@ -1,4 +1,4 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util.text;
import com.intellij.openapi.util.Comparing;
@@ -68,13 +68,13 @@ public class StringUtilTest {
@Test
public void doTestTrimCharSequence() {
assertEquals(StringUtil.trim((CharSequence)"").toString(), "");
assertEquals(StringUtil.trim((CharSequence)" ").toString(), "");
assertEquals(StringUtil.trim((CharSequence)" \n\t\r").toString(), "");
assertEquals(StringUtil.trim((CharSequence)"a").toString(), "a");
assertEquals(StringUtil.trim((CharSequence)" a").toString(), "a");
assertEquals(StringUtil.trim((CharSequence)"bc ").toString(), "bc");
assertEquals(StringUtil.trim((CharSequence)" b a c ").toString(), "b a c");
assertEquals("", StringUtil.trim((CharSequence)"").toString());
assertEquals("", StringUtil.trim((CharSequence)" ").toString());
assertEquals("", StringUtil.trim((CharSequence)" \n\t\r").toString());
assertEquals("a", StringUtil.trim((CharSequence)"a").toString());
assertEquals("a", StringUtil.trim((CharSequence)" a").toString());
assertEquals("bc", StringUtil.trim((CharSequence)"bc ").toString());
assertEquals("b a c", StringUtil.trim((CharSequence)" b a c ").toString());
}
@Test
@@ -894,6 +894,17 @@ public class StringUtilTest {
assertEquals("one two three four five", StringUtil.collapseWhiteSpace("\t one\ttwo three\nfour five "));
}
@Test
public void testReplaceUnicodeEscapeSequences() {
assertEquals("Z", StringUtil.replaceUnicodeEscapeSequences("\\uuu005a"));
assertEquals("ZZ", StringUtil.replaceUnicodeEscapeSequences("\\uuu005aZ"));
assertEquals("ZZZ", StringUtil.replaceUnicodeEscapeSequences("Z\\uuu005aZ"));
assertEquals("Z\\\\uuu005aZ", StringUtil.replaceUnicodeEscapeSequences("Z\\\\uuu005aZ"));
assertEquals("\\uuu005\\a\\u1\\u22\\u333", StringUtil.replaceUnicodeEscapeSequences("\\uuu005\\a\\u1\\u22\\u333"));
assertEquals("\\uA\\u1Z", StringUtil.replaceUnicodeEscapeSequences("\\u\\u0041\\u1\\u005a"));
assertEquals("\\u004", StringUtil.replaceUnicodeEscapeSequences("\\u004"));
}
@Test
public void testStripCharFilter() {
assertEquals("my-string", StringUtil.strip("\n my -string ", CharFilter.NOT_WHITESPACE_FILTER));