Skip to content

Commit 40abf74

Browse files
authored
javac and ECJ handle Unicode ignorable character in method names differently during reflection (#4770)
* Exclude the ignorable characters from identifier, both for identifiers with and without Unicode characters. #4770
1 parent 53be7c0 commit 40abf74

File tree

2 files changed

+259
-13
lines changed
  • org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser
  • org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression

2 files changed

+259
-13
lines changed

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Scanner.java

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -460,19 +460,43 @@ public void checkTaskTag(int commentStart, int commentEnd) throws InvalidInputEx
460460
public char[] getCurrentIdentifierSource() {
461461
//return the token REAL source (aka unicodes are precomputed)
462462
if (this.withoutUnicodePtr != 0) {
463-
//0 is used as a fast test flag so the real first char is in position 1
464-
char[] result = new char[this.withoutUnicodePtr];
465-
System.arraycopy(
466-
this.withoutUnicodeBuffer,
467-
1,
468-
result,
469-
0,
470-
this.withoutUnicodePtr);
471-
return result;
463+
// //0 is used as a fast test flag so the real first char is in position 1
464+
return getIdentifierIgnoringIgnorable(this.withoutUnicodeBuffer, 1, this.withoutUnicodePtr);
472465
}
473466
int length = this.currentPosition - this.startPosition;
474467
if (length == this.eofPosition) return this.source;
475-
return this.deduplication.sharedCopyOfRange(this.source, this.startPosition, this.currentPosition);
468+
return getIdentifierIgnoringIgnorable(this.source, this.startPosition, this.currentPosition - this.startPosition);
469+
}
470+
public char[] getIdentifierIgnoringIgnorable(char[] originalSource, int start, int length) {
471+
472+
if (length <= 0) return CharOperation.NO_CHAR;
473+
474+
int ignorableCount = 0;
475+
int end = start + length;
476+
for (int i = start; i < end; i++) {
477+
if (Character.isIdentifierIgnorable(originalSource[i])) {
478+
ignorableCount++;
479+
}
480+
}
481+
482+
// If nothing to remove, return a shared copy of the original
483+
if (ignorableCount == 0) {
484+
return this.deduplication.sharedCopyOfRange(originalSource, start, end);
485+
}
486+
487+
int newLength = length - ignorableCount;
488+
if (newLength <= 0) return CharOperation.NO_CHAR;
489+
490+
char[] compacted = new char[newLength];
491+
int newEnd = 0;
492+
for (int i = start; i < end; i++) {
493+
char c = originalSource[i];
494+
if (!Character.isIdentifierIgnorable(c)) {
495+
compacted[newEnd++] = c;
496+
}
497+
}
498+
// Return a deduplicated/shared copy of the compacted result
499+
return this.deduplication.sharedCopyOfRange(compacted, 0, newEnd);
476500
}
477501

478502
public int getCurrentTokenEndPosition(){

org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/ScannerTest.java

Lines changed: 225 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ public void test045() {
959959
* }
960960
* }
961961
*/
962-
this.runConformTest(
962+
this.runNegativeTest(
963963
new String[] {
964964
"_X.java",
965965
"import java.lang.reflect.Field;\n" +
@@ -993,7 +993,122 @@ public void test045() {
993993
" }\n" +
994994
"}"
995995
},
996-
"SUCCESS");
996+
"----------\n" +
997+
"1. ERROR in _X.java (at line 5)\n" +
998+
" String i\\u0001;\n" +
999+
" ^^^^^^^\n" +
1000+
"Duplicate local variable i\n" +
1001+
"----------\n" +
1002+
"2. ERROR in _X.java (at line 6)\n" +
1003+
" String i\\u0002;\n" +
1004+
" ^^^^^^^\n" +
1005+
"Duplicate local variable i\n" +
1006+
"----------\n" +
1007+
"3. ERROR in _X.java (at line 7)\n" +
1008+
" String i\\u0003;\n" +
1009+
" ^^^^^^^\n" +
1010+
"Duplicate local variable i\n" +
1011+
"----------\n" +
1012+
"4. ERROR in _X.java (at line 8)\n" +
1013+
" String i\\u0004;\n" +
1014+
" ^^^^^^^\n" +
1015+
"Duplicate local variable i\n" +
1016+
"----------\n" +
1017+
"5. ERROR in _X.java (at line 9)\n" +
1018+
" String i\\u0005;\n" +
1019+
" ^^^^^^^\n" +
1020+
"Duplicate local variable i\n" +
1021+
"----------\n" +
1022+
"6. ERROR in _X.java (at line 10)\n" +
1023+
" String i\\u0006;\n" +
1024+
" ^^^^^^^\n" +
1025+
"Duplicate local variable i\n" +
1026+
"----------\n" +
1027+
"7. ERROR in _X.java (at line 11)\n" +
1028+
" String i\\u0007;\n" +
1029+
" ^^^^^^^\n" +
1030+
"Duplicate local variable i\n" +
1031+
"----------\n" +
1032+
"8. ERROR in _X.java (at line 12)\n" +
1033+
" String i\\u0008;\n" +
1034+
" ^^^^^^^\n" +
1035+
"Duplicate local variable i\n" +
1036+
"----------\n" +
1037+
"9. ERROR in _X.java (at line 13)\n" +
1038+
" String i\\u000e;\n" +
1039+
" ^^^^^^^\n" +
1040+
"Duplicate local variable i\n" +
1041+
"----------\n" +
1042+
"10. ERROR in _X.java (at line 14)\n" +
1043+
" String i\\u000f;\n" +
1044+
" ^^^^^^^\n" +
1045+
"Duplicate local variable i\n" +
1046+
"----------\n" +
1047+
"11. ERROR in _X.java (at line 15)\n" +
1048+
" String i\\u0010;\n" +
1049+
" ^^^^^^^\n" +
1050+
"Duplicate local variable i\n" +
1051+
"----------\n" +
1052+
"12. ERROR in _X.java (at line 16)\n" +
1053+
" String i\\u0011;\n" +
1054+
" ^^^^^^^\n" +
1055+
"Duplicate local variable i\n" +
1056+
"----------\n" +
1057+
"13. ERROR in _X.java (at line 17)\n" +
1058+
" String i\\u0012;\n" +
1059+
" ^^^^^^^\n" +
1060+
"Duplicate local variable i\n" +
1061+
"----------\n" +
1062+
"14. ERROR in _X.java (at line 18)\n" +
1063+
" String i\\u0013;\n" +
1064+
" ^^^^^^^\n" +
1065+
"Duplicate local variable i\n" +
1066+
"----------\n" +
1067+
"15. ERROR in _X.java (at line 19)\n" +
1068+
" String i\\u0014;\n" +
1069+
" ^^^^^^^\n" +
1070+
"Duplicate local variable i\n" +
1071+
"----------\n" +
1072+
"16. ERROR in _X.java (at line 20)\n" +
1073+
" String i\\u0015;\n" +
1074+
" ^^^^^^^\n" +
1075+
"Duplicate local variable i\n" +
1076+
"----------\n" +
1077+
"17. ERROR in _X.java (at line 21)\n" +
1078+
" String i\\u0016;\n" +
1079+
" ^^^^^^^\n" +
1080+
"Duplicate local variable i\n" +
1081+
"----------\n" +
1082+
"18. ERROR in _X.java (at line 22)\n" +
1083+
" String i\\u0017;\n" +
1084+
" ^^^^^^^\n" +
1085+
"Duplicate local variable i\n" +
1086+
"----------\n" +
1087+
"19. ERROR in _X.java (at line 23)\n" +
1088+
" String i\\u0018;\n" +
1089+
" ^^^^^^^\n" +
1090+
"Duplicate local variable i\n" +
1091+
"----------\n" +
1092+
"20. ERROR in _X.java (at line 24)\n" +
1093+
" String i\\u0019;\n" +
1094+
" ^^^^^^^\n" +
1095+
"Duplicate local variable i\n" +
1096+
"----------\n" +
1097+
"21. ERROR in _X.java (at line 25)\n" +
1098+
" String i\\u001a;\n" +
1099+
" ^^^^^^^\n" +
1100+
"Duplicate local variable i\n" +
1101+
"----------\n" +
1102+
"22. ERROR in _X.java (at line 26)\n" +
1103+
" String i\\u001b;\n" +
1104+
" ^^^^^^^\n" +
1105+
"Duplicate local variable i\n" +
1106+
"----------\n" +
1107+
"23. ERROR in _X.java (at line 27)\n" +
1108+
" String i\\u007f;\n" +
1109+
" ^^^^^^^\n" +
1110+
"Duplicate local variable i\n" +
1111+
"----------\n");
9971112
}
9981113
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=264950
9991114
public void test046() {
@@ -1881,5 +1996,112 @@ public void testIssue4674() {
18811996
assertTrue("Should not have InvalidInputException", false);
18821997
}
18831998
}
1884-
1999+
public void testIssue4001_1() {
2000+
this.runConformTest(
2001+
new String[] {
2002+
"X.java",
2003+
"""
2004+
public class X {
2005+
String fieldWithUnicode\u0001Char = "";
2006+
public static void main(String[] args) {
2007+
try {
2008+
Class<?> clazz = Class.forName("X");
2009+
java.lang.reflect.Method method = clazz.getDeclaredMethod("methodWithUnicode\u0001Char");
2010+
System.out.println("Method found: " + method.getName());
2011+
} catch (ClassNotFoundException e) {
2012+
System.out.println("Class not found.");
2013+
} catch (NoSuchMethodException e) {
2014+
System.out.println("Method not found.");
2015+
}
2016+
try {
2017+
Class<?> clazz = Class.forName("X");
2018+
java.lang.reflect.Field field = clazz.getDeclaredField("fieldWithUnicode\u0001Char");
2019+
System.out.println("Field found: " + field.getName());
2020+
} catch (ClassNotFoundException e) {
2021+
System.out.println("Class not found.");
2022+
} catch (NoSuchFieldException e) {
2023+
System.out.println("Field not found.");
2024+
}
2025+
}
2026+
public static void methodWithUnicode\u0001Char() {
2027+
}
2028+
}""",
2029+
},
2030+
"Method not found.\n" +
2031+
"Field not found.");
2032+
}
2033+
public void testIssue4001_2() {
2034+
this.runConformTest(
2035+
new String[] {
2036+
"X.java",
2037+
"""
2038+
public class X {
2039+
String fieldWithUnicode\u0001Char = "";
2040+
public static void main(String[] args) {
2041+
try {
2042+
Class<?> clazz = Class.forName("X");
2043+
java.lang.reflect.Method method = clazz.getDeclaredMethod("methodWithUnicodeChar");
2044+
System.out.println("Method found: " + method.getName());
2045+
method.invoke(null);
2046+
} catch (ClassNotFoundException e) {
2047+
System.out.println("Class not found.");
2048+
} catch (NoSuchMethodException e) {
2049+
System.out.println("Method not found.");
2050+
} catch (Exception e) {
2051+
e.printStackTrace();
2052+
}
2053+
try {
2054+
Class<?> clazz = Class.forName("X");
2055+
java.lang.reflect.Field field = clazz.getDeclaredField("fieldWithUnicodeChar");
2056+
System.out.println("Field found: " + field.getName());
2057+
} catch (ClassNotFoundException e) {
2058+
System.out.println("Class not found.");
2059+
} catch (NoSuchFieldException e) {
2060+
System.out.println("Field not found.");
2061+
}
2062+
}
2063+
public static void methodWithUnicode\u0001Char() {
2064+
String fieldWithUnicode\u0001Char = "Hello";
2065+
System.out.println(fieldWithUnicodeChar);
2066+
}
2067+
}""",
2068+
},
2069+
"Method found: methodWithUnicodeChar\n" +
2070+
"Hello\n" +
2071+
"Field found: fieldWithUnicodeChar");
2072+
}
2073+
public void testIssue4001_3() {
2074+
this.runConformTest(
2075+
new String[] {
2076+
"X.java",
2077+
"""
2078+
public class X {
2079+
String fieldWithUnicode\u0001Char = "";
2080+
public static void main(String[] args) {
2081+
try {
2082+
Class<?> clazz = Class.forName("X");
2083+
java.lang.reflect.Method method = clazz.getDeclaredMethod("methodWithUnicodeChar");
2084+
System.out.println("Method found: " + method.getName());
2085+
} catch (ClassNotFoundException e) {
2086+
System.out.println("Class not found.");
2087+
} catch (NoSuchMethodException e) {
2088+
System.out.println("Method not found.");
2089+
}
2090+
try {
2091+
Class<?> clazz = Class.forName("X");
2092+
java.lang.reflect.Field method = clazz.getDeclaredField("fieldWithUnicodeChar");
2093+
System.out.println("Field found: " + method.getName());
2094+
} catch (ClassNotFoundException e) {
2095+
System.out.println("Class not found.");
2096+
} catch (NoSuchFieldException e) {
2097+
System.out.println("Field not found.");
2098+
}
2099+
}
2100+
public static void methodWithUnicode\u0001Char() {
2101+
}
2102+
}""",
2103+
},
2104+
"Method found: methodWithUnicodeChar\n" +
2105+
"Field found: fieldWithUnicodeChar");
2106+
}
18852107
}

0 commit comments

Comments
 (0)