Skip to content

Commit 7ded3cb

Browse files
author
Greg Adams
authored
handle utf surrogate character literals (#438)
resolves #405
1 parent 41daed1 commit 7ded3cb

File tree

5 files changed

+42
-18
lines changed

5 files changed

+42
-18
lines changed

rewrite-java-11/src/main/java/org/openrewrite/java/Java11ParserVisitor.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -689,13 +689,26 @@ public J visitLambdaExpression(LambdaExpressionTree node, Space fmt) {
689689
return new J.Lambda(randomId(), fmt, Markers.EMPTY, params, arrow, body, type(node));
690690
}
691691

692+
public final static int SURR_FIRST = 0xD800;
693+
public final static int SURR_LAST = 0xDFFF;
694+
692695
@Override
693696
public J visitLiteral(LiteralTree node, Space fmt) {
694697
cursor(endPos(node));
695698
Object value = node.getValue();
696699
JavaType.Primitive type = primitive(((JCTree.JCLiteral) node).typetag);
700+
if (value instanceof Character) {
701+
char c = (Character) value;
702+
if (c >= SURR_FIRST && c <= SURR_LAST) {
703+
String valueSource = source.substring(((JCLiteral) node).getStartPosition(), endPos(node));
704+
int escapeIndex = valueSource.indexOf("\\u");
705+
return new J.Literal(randomId(), fmt, Markers.EMPTY, null, null,
706+
new J.Literal.ModifiedUtf8Surrogate(valueSource.substring(0, escapeIndex),
707+
valueSource.substring(escapeIndex)), type);
708+
}
709+
}
697710
return new J.Literal(randomId(), fmt, Markers.EMPTY, value,
698-
source.substring(((JCLiteral) node).getStartPosition(), endPos(node)), type);
711+
source.substring(((JCLiteral) node).getStartPosition(), endPos(node)), null, type);
699712
}
700713

701714
@Override

rewrite-java/src/main/java/org/openrewrite/java/JavaPrinter.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,12 @@ public J visitLambda(Lambda lambda, P p) {
690690
public J visitLiteral(Literal literal, P p) {
691691
visitSpace(literal.getPrefix(), Space.Location.LITERAL_PREFIX, p);
692692
StringBuilder acc = getPrinter();
693-
acc.append(literal.getValueSource());
693+
Literal.ModifiedUtf8Surrogate modifiedUtf8Surrogate = literal.getModifiedUtf8Surrogate();
694+
if (modifiedUtf8Surrogate != null) {
695+
acc.append(modifiedUtf8Surrogate.getEscapeSequence()).append(modifiedUtf8Surrogate.getCodePoint());
696+
} else {
697+
acc.append(literal.getValueSource());
698+
}
694699
return literal;
695700
}
696701

rewrite-java/src/main/java/org/openrewrite/java/tree/J.java

+16-14
Original file line numberDiff line numberDiff line change
@@ -2612,6 +2612,7 @@ public Parameters withParams(List<JRightPadded<J>> parameters) {
26122612
@EqualsAndHashCode(callSuper = false, onlyExplicitlyIncluded = true)
26132613
@Data
26142614
final class Literal implements J, Expression {
2615+
26152616
@EqualsAndHashCode.Include
26162617
UUID id;
26172618

@@ -2626,8 +2627,13 @@ final class Literal implements J, Expression {
26262627
Object value;
26272628

26282629
@With
2630+
@Nullable
26292631
String valueSource;
26302632

2633+
@With
2634+
@Nullable
2635+
ModifiedUtf8Surrogate modifiedUtf8Surrogate;
2636+
26312637
/**
26322638
* Including String literals
26332639
*/
@@ -2640,7 +2646,7 @@ public Literal withType(@Nullable JavaType type) {
26402646
return this;
26412647
}
26422648
if (type instanceof JavaType.Primitive) {
2643-
return new Literal(id, prefix, markers, value, valueSource, (JavaType.Primitive) type);
2649+
return new Literal(id, prefix, markers, value, valueSource, modifiedUtf8Surrogate, (JavaType.Primitive) type);
26442650
}
26452651
return this;
26462652
}
@@ -2655,23 +2661,19 @@ public Coordinates.Literal getCoordinates() {
26552661
return new Coordinates.Literal(this);
26562662
}
26572663

2658-
public <T> String transformValue(Function<T, Object> transform) {
2659-
Matcher valueMatcher = Pattern.compile("(.*)" + Pattern.quote(value == null ? "null" : value.toString()) + "(.*)")
2660-
.matcher(printTrimmed().replace("\\", ""));
2661-
if (valueMatcher.find()) {
2662-
String prefix = valueMatcher.group(1);
2663-
String suffix = valueMatcher.group(2);
2664-
2665-
//noinspection unchecked
2666-
return prefix + transform.apply((T) value) + suffix;
2667-
}
2668-
throw new IllegalStateException("Encountered a literal `" + this + "` that could not be transformed");
2669-
}
2670-
26712664
@Override
26722665
public String toString() {
26732666
return "Literal(" + LiteralToString.toString(this) + ")";
26742667
}
2668+
2669+
@Value
2670+
public static class ModifiedUtf8Surrogate {
2671+
@With
2672+
String escapeSequence;
2673+
2674+
@With
2675+
String codePoint;
2676+
}
26752677
}
26762678

26772679
@ToString

rewrite-test/src/main/kotlin/org/openrewrite/java/search/SemanticallyEqualTest.kt

+5
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ interface SemanticallyEqualTest {
284284
Markers.EMPTY,
285285
true,
286286
"true",
287+
null,
287288
JavaType.Primitive.Boolean
288289
),
289290
Markers.EMPTY
@@ -348,6 +349,7 @@ interface SemanticallyEqualTest {
348349
Markers.EMPTY,
349350
0,
350351
"0",
352+
null,
351353
JavaType.Primitive.Int
352354
)
353355
)
@@ -363,6 +365,7 @@ interface SemanticallyEqualTest {
363365
Markers.EMPTY,
364366
"thisString",
365367
"thisString",
368+
null,
366369
JavaType.Primitive.String
367370
)
368371
)
@@ -378,6 +381,7 @@ interface SemanticallyEqualTest {
378381
Markers.EMPTY,
379382
null,
380383
"null",
384+
null,
381385
JavaType.Primitive.String
382386
)
383387
)
@@ -393,6 +397,7 @@ interface SemanticallyEqualTest {
393397
Markers.EMPTY,
394398
0,
395399
"0",
400+
null,
396401
JavaType.Primitive.Int
397402
)
398403
)

rewrite-test/src/main/kotlin/org/openrewrite/java/tree/MethodDeclarationTest.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,7 @@ interface MethodDeclarationTest : JavaTreeTest {
100100
}
101101

102102
@Test()
103-
@Disabled("Issue #405")
104-
fun unicodeCharacterLiterals(jp: JavaParser) = assertParsePrintAndProcess(jp, CompilationUnit,
103+
fun modifiedUtf8SurrogateCharacterLiterals(jp: JavaParser) = assertParsePrintAndProcess(jp, CompilationUnit,
105104
"""
106105
public class A {
107106
private boolean isSockJsSpecialChar(char ch) {

0 commit comments

Comments
 (0)