Skip to content

Jdt missing subtrees #388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 19, 2025
124 changes: 124 additions & 0 deletions gen.jdt/src/main/java/com/github/gumtreediff/gen/jdt/JdtVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public class JdtVisitor extends AbstractJdtVisitor {
private static final Type PREFIX_EXPRESSION_OPERATOR = type("PREFIX_EXPRESSION_OPERATOR");
private static final Type POSTFIX_EXPRESSION_OPERATOR = type("POSTFIX_EXPRESSION_OPERATOR");
private static final Type TAG_NAME = type("TAG_NAME");
private static final Type TYPE_INHERITANCE_KEYWORD = type("TYPE_INHERITANCE_KEYWORD");
private static final Type PERMITS_KEYWORD = type("PERMITS_KEYWORD");
private static final Type THROWS_KEYWORD = type("THROWS_KEYWORD");

private static final Type ARRAY_INITIALIZER = nodeAsSymbol(ASTNode.ARRAY_INITIALIZER);
private static final Type SIMPLE_NAME = nodeAsSymbol(ASTNode.SIMPLE_NAME);
Expand Down Expand Up @@ -154,10 +157,64 @@ else if (n instanceof PostfixExpression)
handlePostVisit((PostfixExpression) n);
else if (n instanceof ArrayCreation)
handlePostVisit((ArrayCreation) n);
else if (n instanceof MethodDeclaration)
handlePostVisit((MethodDeclaration) n);
else if (n instanceof RecordDeclaration)
handlePostVisit((RecordDeclaration) n);
else if (n instanceof EnumDeclaration)
handlePostVisit((EnumDeclaration) n);

popNode();
}

private void handlePostVisit(EnumDeclaration n) {
if (!n.superInterfaceTypes().isEmpty()) {
handleImplementsKeywordForDeclarations(n);
}
}

private void handlePostVisit(RecordDeclaration n) {
if (!n.superInterfaceTypes().isEmpty()) {
handleImplementsKeywordForDeclarations(n);
}
}

private void handleImplementsKeywordForDeclarations(AbstractTypeDeclaration n) {
String keyword = "implements";
Tree keywordSubtree = context.createTree(TYPE_INHERITANCE_KEYWORD, keyword);
Tree t = this.trees.peek();
if (t == null || t.getChildren() == null) return;
PosAndLength keywordPl = searchKeywordPosition(n, keyword);
keywordSubtree.setPos(keywordPl.pos);
keywordSubtree.setLength(keywordPl.length);
int index = 0;
for (Tree c : t.getChildren()) {
if (c.getType() != SIMPLE_NAME)
index++;
else {
index += 1;
break;
}
}
t.insertChild(keywordSubtree, index);
}

private void handlePostVisit(MethodDeclaration n) {
//Add throws keyword in case of having any exceptions
if (!n.thrownExceptionTypes().isEmpty()) {
String keyword = "throws";
Tree t = this.trees.peek();
if (t == null || t.getChildren() == null) return;
Tree keywordSubtree = context.createTree(THROWS_KEYWORD, keyword);
PosAndLength keywordPl = searchKeywordPosition(n, keyword);
keywordSubtree.setPos(keywordPl.pos);
keywordSubtree.setLength(keywordPl.length);
int index = t.getChildren().size() - 1;
index -= n.thrownExceptionTypes().size();
t.insertChild(keywordSubtree, index);
}
}

private void handlePostVisit(ArrayCreation c) {
Tree t = this.trees.peek();
if (t.getChild(1).getType() == ARRAY_INITIALIZER)
Expand Down Expand Up @@ -313,6 +370,73 @@ private void handlePostVisit(TypeDeclaration d) {
break;
}
t.insertChild(s, index);
index += 2;
if (d.getSuperclassType() != null)
{
String keyword = "extends";
Tree keywordSubtree = context.createTree(TYPE_INHERITANCE_KEYWORD, keyword);
PosAndLength keywordPl = searchKeywordPosition(d, keyword);
keywordSubtree.setPos(keywordPl.pos);
keywordSubtree.setLength(keywordPl.length);
t.insertChild(keywordSubtree, index);
index += 1 + 1; //There is only one superclass always (can be simplified to 2)
}
if (!d.superInterfaceTypes().isEmpty()) {
String keyword = "implements";
Tree keywordSubtree = context.createTree(TYPE_INHERITANCE_KEYWORD, keyword);
PosAndLength keywordPl = searchKeywordPosition(d, keyword);
keywordSubtree.setPos(keywordPl.pos);
keywordSubtree.setLength(keywordPl.length);
t.insertChild(keywordSubtree, index);
//There might be more than one interface
index += 1 + d.superInterfaceTypes().size();
}
if (!d.permittedTypes().isEmpty())
{
String keyword = "permits";
Tree keywordSubtree = context.createTree(PERMITS_KEYWORD, keyword);
PosAndLength keywordPl = searchKeywordPosition(d, keyword);
keywordSubtree.setPos(keywordPl.pos);
keywordSubtree.setLength(keywordPl.length);
t.insertChild(keywordSubtree, index);
}
}

private PosAndLength searchKeywordPosition(ASTNode d, String keyword) {
int start = d.getStartPosition();
int end = start + d.getLength();
scanner.resetTo(start, end);
int pos = 0;
int length = 0;

try {
while (true) {
int token = scanner.getNextToken();
if (token == ITerminalSymbols.TokenNameEOF)
break;
if ((keyword.equals("implements") && token == ITerminalSymbols.TokenNameimplements)
|| (keyword.equals("extends") && token == ITerminalSymbols.TokenNameextends)
|| (keyword.equals("throws") && token == ITerminalSymbols.TokenNamethrows)
) {
pos = scanner.getCurrentTokenStartPosition();
length = scanner.getCurrentTokenEndPosition() - pos + 1;
break;
}
// Fallback for 'permits' (not tokenized in older JDT versions)
if (token == ITerminalSymbols.TokenNameIdentifier) {
char[] tokenChars = scanner.getCurrentTokenSource();
if (String.valueOf(tokenChars).equals(keyword)) {
pos = scanner.getCurrentTokenStartPosition();
length = scanner.getCurrentTokenEndPosition() - pos + 1;
break;
}
}
}
} catch (InvalidInputException e) {
throw new SyntaxException(null, null, e);
}

return new PosAndLength(pos, length);
}

private PosAndLength searchTypeDeclarationKindPosition(TypeDeclaration d) {
Expand Down
Loading