Skip to content

Commit

Permalink
Merge branch 'main' into groovy-parser-parenthesis-pt3
Browse files Browse the repository at this point in the history
  • Loading branch information
Laurens-W authored Dec 19, 2024
2 parents f8f03e3 + e5d9337 commit 6d2f360
Show file tree
Hide file tree
Showing 20 changed files with 916 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.FileAttributes;
import org.openrewrite.PrintOutputCapture;
import org.openrewrite.internal.EncodingDetectingInputStream;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaParsingException;
import org.openrewrite.java.JavaPrinter;
import org.openrewrite.java.internal.JavaTypeCache;
import org.openrewrite.java.marker.OmitParentheses;
import org.openrewrite.java.tree.*;
Expand Down Expand Up @@ -191,6 +193,16 @@ public J visitAssignment(AssignmentTree node, Space fmt) {
typeMapping.type(node));
}

@Override
public J visitErroneous(ErroneousTree node, Space fmt) {
String erroneousNode = source.substring(((JCTree) node).getStartPosition(), ((JCTree) node).getEndPosition(endPosTable));
return new J.Erroneous(
randomId(),
fmt,
Markers.EMPTY,
erroneousNode);
}

@Override
public J visitBinary(BinaryTree node, Space fmt) {
Expression left = convert(node.getLeftOperand());
Expand Down Expand Up @@ -1439,6 +1451,22 @@ public J visitUnary(UnaryTree node, Space fmt) {

@Override
public J visitVariable(VariableTree node, Space fmt) {
JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) node;
if ("<error>".equals(jcVariableDecl.getName().toString())) {
int startPos = jcVariableDecl.getStartPosition();
int endPos = jcVariableDecl.getEndPosition(endPosTable);

if (startPos == endPos) {
endPos = startPos + 1;
}
String erroneousNode = source.substring(startPos, endPos);
return new J.Erroneous(
randomId(),
fmt,
Markers.EMPTY,
erroneousNode
);
}
return hasFlag(node.getModifiers(), Flags.ENUM) ?
visitEnumVariable(node, fmt) :
visitVariables(singletonList(node), fmt); // method arguments cannot be multi-declarations
Expand Down Expand Up @@ -1619,10 +1647,43 @@ private <J2 extends J> JRightPadded<J2> convert(Tree t, Function<Tree, Space> su
J2 j = convert(t);
@SuppressWarnings("ConstantConditions") JRightPadded<J2> rightPadded = j == null ? null :
new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY);
cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it
int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace());
if (idx >= 0) {
rightPadded = (JRightPadded<J2>) JRightPadded.build(getErroneous(List.of(rightPadded)));
}
// Cursor hasn't been updated but points at the end of erroneous node already
// This means that error node start position == end position
// Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor
// Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the
// same from the JC compiler.
if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) {
cursor += ((J.Erroneous) rightPadded.getElement()).getText().length();
} else {
cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it
}
return rightPadded;
}

private <J2 extends J> J.Erroneous getErroneous(List<JRightPadded<J2>> converted) {
PrintOutputCapture p = new PrintOutputCapture<>(0);
new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p);
return new J.Erroneous(
org.openrewrite.Tree.randomId(),
EMPTY,
Markers.EMPTY,
p.getOut()
);
}

private static int findFirstNonWhitespaceChar(String s) {
for (int i = 0; i < s.length(); i++) {
if (!Character.isWhitespace(s.charAt(i))) {
return i;
}
}
return -1;
}

private long lineNumber(Tree tree) {
return source.substring(0, ((JCTree) tree).getStartPosition()).chars().filter(c -> c == '\n').count() + 1;
}
Expand Down Expand Up @@ -1687,19 +1748,47 @@ private Space statementDelim(@Nullable Tree t) {
t instanceof JCNewClass ||
t instanceof JCReturn ||
t instanceof JCThrow ||
t instanceof JCUnary ||
t instanceof JCExpressionStatement ||
t instanceof JCVariableDecl) {
t instanceof JCUnary) {
return sourceBefore(";");
}

if (t instanceof JCLabeledStatement) {
return statementDelim(((JCLabeledStatement) t).getStatement());
}

if (t instanceof JCExpressionStatement) {
ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression();
if (expTree instanceof ErroneousTree) {
return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList());
} else {
return sourceBefore(";");
}
}

if (t instanceof JCVariableDecl) {
JCTree.JCVariableDecl varTree = (JCTree.JCVariableDecl) t;
if ("<error>".contentEquals(varTree.getName())) {
int start = varTree.vartype.getEndPosition(endPosTable);
int end = varTree.getEndPosition(endPosTable);
String whitespace = source.substring(start, end);
if (whitespace.contains("\n")) {
return EMPTY;
} else {
return Space.build(source.substring(start, end), Collections.emptyList());
}
}
return sourceBefore(";");
}

if (t instanceof JCMethodDecl) {
JCMethodDecl m = (JCMethodDecl) t;
return sourceBefore(m.body == null || m.defaultValue != null ? ";" : "");
if (m.body == null || m.defaultValue != null) {
String suffix = source.substring(cursor, positionOfNext(";", null));
int idx = findFirstNonWhitespaceChar(suffix);
return sourceBefore(idx >= 0 ? "" : ";");
} else {
return sourceBefore("");
}
}

return EMPTY;
Expand All @@ -1724,6 +1813,10 @@ private List<JRightPadded<Statement>> convertStatements(@Nullable List<? extends
List<JRightPadded<Statement>> converted = new ArrayList<>(treesGroupedByStartPosition.size());
for (List<? extends Tree> treeGroup : treesGroupedByStartPosition.values()) {
if (treeGroup.size() == 1) {
Tree t = treeGroup.get(0);
int startPosition = ((JCTree) t).getStartPosition();
if (cursor > startPosition)
continue;
converted.add(convert(treeGroup.get(0), suffix));
} else {
// multi-variable declarations are split into independent overlapping JCVariableDecl's by the OpenJDK AST
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.FileAttributes;
import org.openrewrite.PrintOutputCapture;
import org.openrewrite.internal.EncodingDetectingInputStream;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaParsingException;
import org.openrewrite.java.JavaPrinter;
import org.openrewrite.java.internal.JavaTypeCache;
import org.openrewrite.java.marker.CompactConstructor;
import org.openrewrite.java.marker.OmitParentheses;
Expand Down Expand Up @@ -199,6 +201,16 @@ public J visitAssignment(AssignmentTree node, Space fmt) {
typeMapping.type(node));
}

@Override
public J visitErroneous(ErroneousTree node, Space fmt) {
String erroneousNode = source.substring(((JCTree) node).getStartPosition(), ((JCTree) node).getEndPosition(endPosTable));
return new J.Erroneous(
randomId(),
fmt,
Markers.EMPTY,
erroneousNode);
}

@Override
public J visitBinary(BinaryTree node, Space fmt) {
Expression left = convert(node.getLeftOperand());
Expand Down Expand Up @@ -1521,6 +1533,22 @@ public J visitUnary(UnaryTree node, Space fmt) {

@Override
public J visitVariable(VariableTree node, Space fmt) {
JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) node;
if ("<error>".equals(jcVariableDecl.getName().toString())) {
int startPos = jcVariableDecl.getStartPosition();
int endPos = jcVariableDecl.getEndPosition(endPosTable);

if (startPos == endPos) {
endPos = startPos + 1; // For cases where the error node is a single character like "/"
}
String erroneousNode = source.substring(startPos, endPos);
return new J.Erroneous(
randomId(),
fmt,
Markers.EMPTY,
erroneousNode
);
}
return hasFlag(node.getModifiers(), Flags.ENUM) ?
visitEnumVariable(node, fmt) :
visitVariables(singletonList(node), fmt); // method arguments cannot be multi-declarations
Expand Down Expand Up @@ -1732,11 +1760,45 @@ private void reportJavaParsingException(Throwable ex) {
return null;
}
J2 j = convert(t);
JRightPadded<J2> rightPadded = new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY);
cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it
@SuppressWarnings("ConstantConditions") JRightPadded<J2> rightPadded = j == null ? null :
new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY);
int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace());
if (idx >= 0) {
rightPadded = (JRightPadded<J2>) JRightPadded.build(getErroneous(List.of(rightPadded)));
}
// Cursor hasn't been updated but points at the end of erroneous node already
// This means that error node start position == end position
// Therefore ensure that cursor has moved to the end of erroneous node bu adding its length to the cursor
// Example `/pet` results in 2 erroeneous nodes: `/` and `pet`. The `/` node would have start and end position the
// same from the JC compiler.
if (endPos(t) == cursor && rightPadded.getElement() instanceof J.Erroneous) {
cursor += ((J.Erroneous) rightPadded.getElement()).getText().length();
} else {
cursor(max(endPos(t), cursor)); // if there is a non-empty suffix, the cursor may have already moved past it
}
return rightPadded;
}

private <J2 extends J> J.Erroneous getErroneous(List<JRightPadded<J2>> converted) {
PrintOutputCapture p = new PrintOutputCapture<>(0);
new JavaPrinter<>().visitContainer(JContainer.build(EMPTY, converted, Markers.EMPTY), JContainer.Location.METHOD_INVOCATION_ARGUMENTS, p);
return new J.Erroneous(
org.openrewrite.Tree.randomId(),
EMPTY,
Markers.EMPTY,
p.getOut()
);
}

private static int findFirstNonWhitespaceChar(String s) {
for (int i = 0; i < s.length(); i++) {
if (!Character.isWhitespace(s.charAt(i))) {
return i;
}
}
return -1;
}

private long lineNumber(Tree tree) {
return source.substring(0, ((JCTree) tree).getStartPosition()).chars().filter(c -> c == '\n').count() + 1;
}
Expand Down Expand Up @@ -1783,25 +1845,50 @@ private <J2 extends J> List<JRightPadded<J2>> convertAll(List<? extends Tree> tr

private Space statementDelim(@Nullable Tree t) {
switch (t.getKind()) {
case CONTINUE:
case RETURN:
case BREAK:
case ASSERT:
case ASSIGNMENT:
case BREAK:
case CONTINUE:
case DO_WHILE_LOOP:
case IMPORT:
case METHOD_INVOCATION:
case NEW_CLASS:
case RETURN:
case THROW:
return sourceBefore(";");
case EXPRESSION_STATEMENT:
ExpressionTree expTree = ((ExpressionStatementTree) t).getExpression();
if (expTree instanceof ErroneousTree) {
return Space.build(source.substring(((JCTree) expTree).getEndPosition(endPosTable),((JCTree) t).getEndPosition(endPosTable)), Collections.emptyList());
} else {
return sourceBefore(";");
}
case VARIABLE:
JCTree.JCVariableDecl varTree = (JCTree.JCVariableDecl) t;
if ("<error>".contentEquals(varTree.getName())) {
int start = varTree.vartype.getEndPosition(endPosTable);
int end = varTree.getEndPosition(endPosTable);
String whitespace = source.substring(start, end);
if (whitespace.contains("\n")) {
return EMPTY;
} else {
return Space.build(source.substring(start, end), Collections.emptyList());
}
}
return sourceBefore(";");
case YIELD:
return sourceBefore(";");
case LABELED_STATEMENT:
return statementDelim(((JCLabeledStatement) t).getStatement());
case METHOD:
JCMethodDecl m = (JCMethodDecl) t;
return sourceBefore(m.body == null || m.defaultValue != null ? ";" : "");
if (m.body == null || m.defaultValue != null) {
String suffix = source.substring(cursor, positionOfNext(";", null));
int idx = findFirstNonWhitespaceChar(suffix);
return sourceBefore(idx >= 0 ? "" : ";");
} else {
return sourceBefore("");
}
default:
return t instanceof JCAssignOp || t instanceof JCUnary ? sourceBefore(";") : EMPTY;
}
Expand Down Expand Up @@ -1829,6 +1916,10 @@ private List<JRightPadded<Statement>> convertStatements(@Nullable List<? extends
List<JRightPadded<Statement>> converted = new ArrayList<>(treesGroupedByStartPosition.size());
for (List<? extends Tree> treeGroup : treesGroupedByStartPosition.values()) {
if (treeGroup.size() == 1) {
Tree t = treeGroup.get(0);
int startPosition = ((JCTree) t).getStartPosition();
if (cursor > startPosition)
continue;
converted.add(convert(treeGroup.get(0), suffix));
} else {
// multi-variable declarations are split into independent overlapping JCVariableDecl's by the OpenJDK AST
Expand Down
Loading

0 comments on commit 6d2f360

Please sign in to comment.