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

fix #3859 UnsupportedOperationException when trying to resolve a type… #3873

Merged
merged 2 commits into from
Jan 27, 2023

Conversation

abego
Copy link
Contributor

@abego abego commented Jan 24, 2023

This fixes the issue #3859

This commit contains just the fix. Additional refactorings are planned for a later commit/PR.

* first Node that returns make {@code isAcceptedParentNode} evaluate to
* {@code true}.
*/
public static Node demandParentNode(Node node, Predicate<Node> isAcceptedParentNode) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done by recursion instead of using a loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jlerbsc, you are right, it can be done by recursion.

However I would prefer to keep it in the loop form, as it is easy to understand and straight forward. Using recursion in a functional language is typically a good idea (and sometimes even necessary). However I would use recursion in Java only when it provides a better solution than the imperative solution, especially as the Java runtime does not provide recursion-related optimisations (like tail call elimination) to make recursion comparable to loops performance-wise. Also taking Java's stack architecture into account using recursion typically requires additional thinking if this recursion may not potentially lead to a stack overflow (not in our case, but think of a loop with 100000 iterations replaced with an equivalent recursive implementation).

If you think this method must get a recursive implementation please explain where you see the benefits. Otherwise I would leave the method as it is

* Returns {@code true} when the Node to be tested is not an
* {@link EnclosedExpr}, {@code false} otherwise.
*/
private static final Predicate<Node> IS_NOT_ENCLOSED_EXPR = n -> !(n instanceof EnclosedExpr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if n is an expression you can write n.isEnclosedExpr() instead of using instanceof.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work.

Assume I change the implementation to

private static final Predicate<Expression> IS_NOT_ENCLOSED_EXPR = n -> !(n.isEnclosedExpr());

As the Predicate is used as a parameter to the new demandParentNode(Node, Predicate<Node>) it would require me to change that method to demandParentNode(Node, Predicate<Expression>). However in the implementation of demandParentNode we assume the result of a demandParentNode call is tested against the predicate , and that result is a Node.

Or did I missed something.

@@ -255,6 +263,9 @@ protected final Optional<Value> solveWithAsValue(SymbolDeclarator symbolDeclarat
private int pos(MethodCallExpr callExpr, Expression param) {
int i = 0;
for (Expression p : callExpr.getArguments()) {
while (p instanceof EnclosedExpr) {
p = ((EnclosedExpr) p).getInner();
Copy link
Collaborator

@jlerbsc jlerbsc Jan 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here p is an expression so you can write n.isEnclosedExpr() and use p.asEnclosedExpr() instead of casting the expression.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Will change this to

            while (p.isEnclosedExpr()) {
                p = p.asEnclosedExpr().getInner();
            }

if (call.getArguments().get(i) == node) return i;
Expression expression = call.getArguments().get(i);
while (expression instanceof EnclosedExpr) {
expression = ((EnclosedExpr) expression).getInner();
Copy link
Collaborator

@jlerbsc jlerbsc Jan 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here argument "expression" is an expression so you can write n.isEnclosedExpr() and use p.asEnclosedExpr() instead of casting the expression.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, agreed.

" foo((s->print(s)));\n" +
" }\n" +
"}\n";
ParserConfiguration configuration = new ParserConfiguration()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some time this can be written more simply

CompilationUnit cu = JavaParserAdapter.of(createParserWithResolver(defaultTypeSolver())).parse(code);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I didn't know that.

Will change accordingly

@jlerbsc jlerbsc merged commit 3c7be13 into javaparser:master Jan 27, 2023
@jlerbsc jlerbsc added this to the next release milestone Jan 27, 2023
@jlerbsc jlerbsc added the PR: Fixed A PR that offers a fix or correction label Jan 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR: Fixed A PR that offers a fix or correction
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants