Skip to content
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

Arbitrary new line when refactoring #4395

Open
matthieu-vergne opened this issue Apr 28, 2024 · 4 comments
Open

Arbitrary new line when refactoring #4395

matthieu-vergne opened this issue Apr 28, 2024 · 4 comments
Labels
Question (JP usage) How to use JP to inspect/modify the AST - please close your question once answered!

Comments

@matthieu-vergne
Copy link
Contributor

matthieu-vergne commented Apr 28, 2024

I am currently implementing a declaration split, where a code like this:

String myParam = null;

should become like this:

String myParam;
myParam = null;

In my current use case, I have minimal formatting, so a class declaration like this:

class MyClass{void myMethod(){String myParam = null;}}

after splitting the variable declaration should become this:

class MyClass{void myMethod(){String myParam;myParam = null;}}

To do so, I start from the VariableDeclarator. One step is to remove its initializer:

variableDeclarator.removeInitializer()

Another step is to add a new assignment statement (with the initializer we removed) in the block that contains it:

Expression initializer = variableDeclaration.getInitializer().orElseThrow();
VariableDeclarationExpr exp = (VariableDeclarationExpr) variableDeclaration.getParentNode().orElseThrow();
ExpressionStmt stmt = (ExpressionStmt) exp.getParentNode().orElseThrow();
BlockStmt block = (BlockStmt) stmt.getParentNode().orElseThrow();
List<Node> childNodes = block.getChildNodes();
int index = childNodes.indexOf(stmt) + 1;
block.addStatement(index, new AssignExpr(new NameExpr(name()), initializer, Operator.ASSIGN));

My issue is that it also adds a newline in the process. So instead of having:

class MyClass{void myMethod(){String myParam;myParam = null;}}

I have:

class MyClass{void myMethod(){String myParam;myParam = null;\r\n}}

The compilation unit is setup to preserve the current syntax in order to return the code with minimal modifications:

LexicalPreservingPrinter.setup(compilationUnit);
// refactoring code
LexicalPreservingPrinter.print(compilationUnit);

Since there is no newline at all in the initial code, there is no reason to add one here.

I would expect that, by creating new expressions and statements manually like I do here, there should have no format associated to them. If I want to reproduce the format of the current code, it would seem more natural to me to take it from an existing one, either through a getter (if the format has its own class/interface) or by duplicating an existing node and updating its content.

Did I miss a setup here to avoid this newline? Otherwise, how can I get back the control over it? How is it expected to be managed in JavaParser?

@jlerbsc
Copy link
Collaborator

jlerbsc commented Apr 29, 2024

In this case, the LexicalPreservingPrinter has no way of knowing which format has been applied to the code (for example, there could be a mix of several formats). As far as I know, there is no way around this problem unless you want to develop your own printer.

I suppose the only possibility would be to retrieve the node representation after inserting it into the AST (node.getData(NODE_TEXT_DATA)) and delete the token representing the end of line.

@jlerbsc jlerbsc added the Question (JP usage) How to use JP to inspect/modify the AST - please close your question once answered! label Apr 29, 2024
@matthieu-vergne
Copy link
Contributor Author

What about the intention behind the LexicalPreservingPrinter? I understood its aim was to have the minimal modification, so it seems logical to me that no new line would be added in this case. Would such a change be beneficial for it or is its purpose actually different (motivating a separated printer)?

@jlerbsc
Copy link
Collaborator

jlerbsc commented Apr 29, 2024

The printer's intention is to retain the code format as far as possible. The pretty printer reformats the code with its own formatting rules. But it's true that when new expressions are added, we can no longer talk about preserving the format of the expression because it didn't exist before. In this case, the printer makes choices based on a syntax model.

LPP is very complex because there are so many different situations to manage. If you don't like the way it works, you can develop your own printer and integrate it into JP.

@matthieu-vergne
Copy link
Contributor Author

I suppose the only possibility would be to retrieve the node representation after inserting it into the AST (node.getData(NODE_TEXT_DATA)) and delete the token representing the end of line.

If I do that, it will fail another test with another format which is currently passing. This is not a solution, just an attempt to compromise.

LPP is very complex because there are so many different situations to manage. [...] you can develop your own printer and integrate it into JP.

I have spent hours trying to use the repository, reading stuff, configuring stuff, trying stuff around... the test suite keeps failing or passing for unknown reasons (I wanted to make a first contribution by replacing the deprecated SYSTEM_EOL). So I will give a look to the LPP and probably try something on my own, but no promise for a contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question (JP usage) How to use JP to inspect/modify the AST - please close your question once answered!
Projects
None yet
Development

No branches or pull requests

2 participants