Skip to content

Add expression type in JavaTemplate #5384

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 11 commits into from
May 28, 2025

Conversation

fmodesto
Copy link
Contributor

@fmodesto fmodesto commented May 5, 2025

What's changed?

Added support for explicit setting expressionType in JavaTemplate

  • Enables better matching in templates
  • Incidentally adds support for MemberReference and Lambda expressions in context-free templates

Have you considered any alternatives or workarounds?

It is possible to write code that doesn't require setting the expression type.

  • Omitting diamond operators (<>)
  • Specifying generic types in method invocations

However, this approach presents challenges:

  • Difficult to implement this type inference in rewrite-templating
  • Or requires users to understand non-standard workarounds

Checklist

  • I've added unit tests to cover both positive and negative cases
  • I've read and applied the recipe conventions and best practices
  • I've used the IntelliJ IDEA auto-formatter on affected files

@timtebeek timtebeek requested a review from knutwannheden May 5, 2025 17:57
@timtebeek timtebeek added the enhancement New feature or request label May 5, 2025
@timtebeek timtebeek moved this from In Progress to Ready to Review in OpenRewrite May 5, 2025
@timtebeek
Copy link
Member

Thanks again! Looking at the overlap in changes I think this PR should go first, right?

@fmodesto
Copy link
Contributor Author

Thanks again! Looking at the overlap in changes I think this PR should go first, right?

Yes, that should go first. It adds some of the functionality removed in #5394.
This one should add expression type only.

@fmodesto fmodesto marked this pull request as draft May 18, 2025 20:33
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Some suggestions could not be made:

  • rewrite-java-tck/src/main/java/org/openrewrite/java/tree/TypeUtilsTest.java
    • lines 18-18

}

@Test
@ExpectedToFail
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 one it's more to showcase a scenario we are not handling, even if the apply had arguments, T is not really a parameter, and #{type:any(T)} would not match a JavaType

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could have some other kind of argument. #{type(T)} where instead of using __P__.<T>any() we could add the TypeUtils.toString() that would also make the test above pass, being an argument the containing would match.

Copy link
Contributor

Choose a reason for hiding this comment

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

I've considered doing exactly this before, but I didn't yet see a use case for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have try this templates in error-prone refaster and they work. But I haven't found any use on the Picnic tests.

  static final class RefToLambda<T> {
    @BeforeTemplate
    Function<T, String> before() {
      return T::toString;
    }

    @AfterTemplate
    Function<T, String> after() {
      return e -> e.toString();
    }
  }

  static final class LambdaToRef<T> {
    @BeforeTemplate
    Function<T, String> before() {
      return e -> e.toString();
    }

    @AfterTemplate
    Function<T, String> after() {
      return T::toString;
    }
  }

---

  ImmutableSet<Function<Object, String>> testRefToLambda() {
    return ImmutableSet.of(
        Object::toString);
  }

  ImmutableSet<Function<Object, String>> testLambdaToRef() {
    return ImmutableSet.of(
        e -> e.toString());
  }

Copy link
Contributor

Choose a reason for hiding this comment

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

I remember the use case now. Having a #{type()} construct could indeed help here, but I don't yet see how we would be using that from a Refaster recipe. The problem as I see it is that there wouldn't be any corresponding parameter in the before template, so how do we correctly generate the recipe to set that parameter?

@fmodesto fmodesto marked this pull request as ready for review May 21, 2025 21:55
@timtebeek timtebeek requested a review from knutwannheden May 27, 2025 21:04
@timtebeek timtebeek merged commit b91cf62 into openrewrite:main May 28, 2025
2 checks passed
@github-project-automation github-project-automation bot moved this from Ready to Review to Done in OpenRewrite May 28, 2025
@timtebeek
Copy link
Member

Thanks again @fmodesto ! We'll keep an eye on any effects downstream, but I know you've already checked that as well. 🙏🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants