Search code examples
openrewrite

Openrewrite: how do I replace a method with 2 parameters `foo(a, b)` by 2 methods with 1 parameter each `foo(a).bar(b)`?


I want to convert

x.foo(a, b);

into

x.foo(a).bar(b);

I can easily match for acme.X foo(acme.A, acme.B), but how do I build a JavaTemplate that can do that replacement for me?

When I run

@Override
protected TreeVisitor<?, ExecutionContext> getVisitor() {
    return new JavaIsoVisitor<>() {

        private final JavaTemplate template = JavaTemplate.builder(this::getCursor,
                "foo(#{any(java.lang.String)}).bar(#{any(java.lang.String)})")
                .build();

        @Override
        public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
            J.MethodInvocation m = super.visitMethodInvocation(method, executionContext);
            if (....matches(method)) {
                List<Expression> arguments = m.getArguments();
                m = m.withTemplate(template, m.getCoordinates().replace(), arguments.get(0), arguments.get(1));
            }
            return m;
        }
    };
}

I get

foo(a).bar(b);

instead of

x.foo(a).bar(b);

Solution

  • This worked for me (credit to Patrick Way on slack):

    private static final MethodMatcher MATCHER =
            new MethodMatcher("org.optaplanner.core.api.score.stream.ConstraintStream " +
                    "penalize(java.lang.String, org.optaplanner.core.api.score.Score)");
    
    @Override
    protected TreeVisitor<?, ExecutionContext> getVisitor() {
        return new JavaIsoVisitor<>() {
    
            private final JavaTemplate template = JavaTemplate.builder(() -> getCursor().getParentOrThrow(),
                    "#{any(org.optaplanner.core.api.score.stream.ConstraintStream)}" +
                            ".penalize(#{any(org.optaplanner.core.api.score.Score)})" +
                            ".asConstraint(#{any(java.lang.String)})"
            ).build();
    
            @Override
            public Expression visitExpression(Expression expression, ExecutionContext executionContext) {
                Expression e = super.visitExpression(expression, executionContext);
                if (MATCHER.matches(e)){
                    J.MethodInvocation mi = (J.MethodInvocation) e;
                    e = e.withTemplate(template,
                            e.getCoordinates().replace(), mi.getSelect(),
                            mi.getArguments().get(1), mi.getArguments().get(0));
                }
                return e;
            }
        };
    }