diff --git a/build.gradle.kts b/build.gradle.kts
index d8b5f48297..e59a089ccb 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -60,8 +60,6 @@ dependencies {
testImplementation("org.assertj:assertj-core:latest.release")
- testImplementation("com.google.errorprone:error_prone_annotations:latest.release")
-
testRuntimeOnly("com.fasterxml.jackson.datatype:jackson-datatype-jsr353")
testRuntimeOnly("com.fasterxml.jackson.core:jackson-core")
testRuntimeOnly("com.fasterxml.jackson.core:jackson-databind")
diff --git a/src/main/java/org/openrewrite/java/migrate/InlineMethodCalls.java b/src/main/java/org/openrewrite/java/migrate/InlineMethodCalls.java
deleted file mode 100644
index 08e2e147b5..0000000000
--- a/src/main/java/org/openrewrite/java/migrate/InlineMethodCalls.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright 2025 the original author or authors.
- *
- * Licensed under the Moderne Source Available License (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://docs.moderne.io/licensing/moderne-source-available-license
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openrewrite.java.migrate;
-
-import lombok.AccessLevel;
-import lombok.Getter;
-import lombok.Value;
-import org.jspecify.annotations.Nullable;
-import org.openrewrite.Cursor;
-import org.openrewrite.ExecutionContext;
-import org.openrewrite.Recipe;
-import org.openrewrite.TreeVisitor;
-import org.openrewrite.java.JavaParser;
-import org.openrewrite.java.JavaTemplate;
-import org.openrewrite.java.JavaVisitor;
-import org.openrewrite.java.tree.*;
-
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static java.util.Collections.emptySet;
-import static java.util.Objects.requireNonNull;
-import static java.util.stream.Collectors.toMap;
-import static java.util.stream.Collectors.toSet;
-
-public class InlineMethodCalls extends Recipe {
-
- private static final String INLINE_ME = "InlineMe";
-
- @Override
- public String getDisplayName() {
- return "Inline methods annotated with `@InlineMe`";
- }
-
- @Override
- public String getDescription() {
- return "Apply inlinings defined by Error Prone's [`@InlineMe` annotation](https://errorprone.info/docs/inlineme).";
- }
-
- @Override
- public TreeVisitor, ExecutionContext> getVisitor() {
- // XXX Preconditions can not yet pick up the `@InlineMe` annotation on methods used
- return new JavaVisitor() {
- @Override
- public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
- J.MethodInvocation mi = (J.MethodInvocation) super.visitMethodInvocation(method, ctx);
- InlineMeValues values = findInlineMeValues(mi.getMethodType());
- if (values == null) {
- return mi;
- }
- Template template = values.template(mi);
- if (template == null) {
- return mi;
- }
- removeAndAddImports(method, values.getImports(), values.getStaticImports());
- J replacement = JavaTemplate.builder(template.getString())
- .contextSensitive()
- .imports(values.getImports().toArray(new String[0]))
- .staticImports(values.getStaticImports().toArray(new String[0]))
- .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
- .build()
- .apply(updateCursor(mi), mi.getCoordinates().replace(), template.getParameters());
- return avoidMethodSelfReferences(mi, replacement);
- }
-
- @Override
- public J visitNewClass(J.NewClass newClass, ExecutionContext ctx) {
- J.NewClass nc = (J.NewClass) super.visitNewClass(newClass, ctx);
- InlineMeValues values = findInlineMeValues(nc.getConstructorType());
- if (values == null) {
- return nc;
- }
- Template template = values.template(nc);
- if (template == null) {
- return nc;
- }
- removeAndAddImports(newClass, values.getImports(), values.getStaticImports());
- J replacement = JavaTemplate.builder(template.getString())
- .contextSensitive()
- .imports(values.getImports().toArray(new String[0]))
- .staticImports(values.getStaticImports().toArray(new String[0]))
- .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
- .build()
- .apply(updateCursor(nc), nc.getCoordinates().replace(), template.getParameters());
- return avoidMethodSelfReferences(nc, replacement);
- }
-
- private @Nullable InlineMeValues findInlineMeValues(JavaType.@Nullable Method methodType) {
- if (methodType == null) {
- return null;
- }
- List parameterNames = methodType.getParameterNames();
- if (!parameterNames.isEmpty() && "arg0".equals(parameterNames.get(0))) {
- return null; // We need `-parameters` before we're able to substitute parameters in the template
- }
-
- List annotations = methodType.getAnnotations();
- for (JavaType.FullyQualified annotation : annotations) {
- if (INLINE_ME.equals(annotation.getClassName())) {
- return InlineMeValues.parse((JavaType.Annotation) annotation);
- }
- }
- return null;
- }
-
- private void removeAndAddImports(MethodCall method, Set templateImports, Set templateStaticImports) {
- Set originalImports = findOriginalImports(method);
-
- // Remove regular and static imports that are no longer needed
- for (String originalImport : originalImports) {
- if (!templateImports.contains(originalImport) &&
- !templateStaticImports.contains(originalImport)) {
- maybeRemoveImport(originalImport);
- }
- }
-
- // Add new regular imports needed by the template
- for (String importStr : templateImports) {
- if (!originalImports.contains(importStr)) {
- maybeAddImport(importStr);
- }
- }
-
- // Add new static imports needed by the template
- for (String staticImport : templateStaticImports) {
- if (!originalImports.contains(staticImport)) {
- int lastDot = staticImport.lastIndexOf('.');
- if (0 < lastDot) {
- maybeAddImport(
- staticImport.substring(0, lastDot),
- staticImport.substring(lastDot + 1));
- }
- }
- }
- }
-
- private Set findOriginalImports(MethodCall method) {
- // Collect all regular and static imports used in the original method call
- return new JavaVisitor>() {
- @Override
- public @Nullable JavaType visitType(@Nullable JavaType javaType, Set strings) {
- JavaType jt = super.visitType(javaType, strings);
- if (jt instanceof JavaType.FullyQualified) {
- strings.add(((JavaType.FullyQualified) jt).getFullyQualifiedName());
- }
- return jt;
- }
-
- @Override
- public J visitMethodInvocation(J.MethodInvocation methodInvocation, Set staticImports) {
- J.MethodInvocation mi = (J.MethodInvocation) super.visitMethodInvocation(methodInvocation, staticImports);
- // Check if this is a static method invocation without a select (meaning it might be statically imported)
- JavaType.Method methodType = mi.getMethodType();
- if (mi.getSelect() == null && methodType != null && methodType.hasFlags(Flag.Static)) {
- staticImports.add(String.format("%s.%s",
- methodType.getDeclaringType().getFullyQualifiedName(),
- methodType.getName()));
- }
- return mi;
- }
-
- @Override
- public J visitIdentifier(J.Identifier identifier, Set staticImports) {
- J.Identifier id = (J.Identifier) super.visitIdentifier(identifier, staticImports);
- // Check if this is a static field reference
- JavaType.Variable fieldType = id.getFieldType();
- if (fieldType != null && fieldType.hasFlags(Flag.Static)) {
- if (fieldType.getOwner() instanceof JavaType.FullyQualified) {
- staticImports.add(String.format("%s.%s",
- ((JavaType.FullyQualified) fieldType.getOwner()).getFullyQualifiedName(),
- fieldType.getName()));
- }
- }
- return id;
- }
- }.reduce(method, new HashSet<>());
- }
-
- private J avoidMethodSelfReferences(MethodCall original, J replacement) {
- JavaType.Method replacementMethodType = replacement instanceof MethodCall ?
- ((MethodCall) replacement).getMethodType() : null;
- if (replacementMethodType == null) {
- return replacement;
- }
-
- Cursor cursor = getCursor();
- while ((cursor = cursor.getParent()) != null) {
- Object value = cursor.getValue();
-
- JavaType.Method cursorMethodType;
- if (value instanceof MethodCall) {
- cursorMethodType = ((MethodCall) value).getMethodType();
- } else if (value instanceof J.MethodDeclaration) {
- cursorMethodType = ((J.MethodDeclaration) value).getMethodType();
- } else {
- continue;
- }
- if (TypeUtils.isOfType(replacementMethodType, cursorMethodType)) {
- return original;
- }
- }
- return replacement;
- }
- };
- }
-
- @Value
- private static class InlineMeValues {
- private static final Pattern TEMPLATE_IDENTIFIER = Pattern.compile("#\\{(\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*):any\\(.*?\\)}");
-
- @Getter(AccessLevel.NONE)
- String replacement;
-
- Set imports;
- Set staticImports;
-
- static InlineMeValues parse(JavaType.Annotation annotation) {
- Map collect = annotation.getValues().stream().collect(toMap(
- e -> ((JavaType.Method) e.getElement()).getName(),
- JavaType.Annotation.ElementValue::getValue
- ));
- // Parse imports and static imports from the annotation values
- return new InlineMeValues(
- (String) collect.get("replacement"),
- parseImports(collect.get("imports")),
- parseImports(collect.get("staticImports")));
- }
-
- private static Set parseImports(@Nullable Object importsValue) {
- if (importsValue instanceof List) {
- return ((List>) importsValue).stream()
- .map(Object::toString)
- .collect(toSet());
- }
- return emptySet();
- }
-
- @Nullable
- Template template(MethodCall original) {
- JavaType.Method methodType = original.getMethodType();
- if (methodType == null) {
- return null;
- }
- String templateString = createTemplateString(original, replacement, methodType.getParameterNames());
- List parameters = createParameters(templateString, original);
- return new Template(templateString, parameters.toArray(new Object[0]));
- }
-
- private static String createTemplateString(MethodCall original, String replacement, List originalParameterNames) {
- String templateString = original instanceof J.MethodInvocation &&
- ((J.MethodInvocation) original).getSelect() == null &&
- replacement.startsWith("this.") ?
- replacement.replaceFirst("^this.\\b", "") :
- replacement.replaceAll("\\bthis\\b", "#{this:any()}");
- for (String parameterName : originalParameterNames) {
- // Replace parameter names with their values in the templateString
- templateString = templateString.replaceAll(
- String.format("\\b%s\\b", parameterName),
- String.format("#{%s:any()}", parameterName)); // TODO 2nd, 3rd etc should use shorthand `#{a}`
- }
- return templateString;
- }
-
- private static List createParameters(String templateString, MethodCall original) {
- Map lookup = new HashMap<>();
- if (original instanceof J.MethodInvocation) {
- Expression select = ((J.MethodInvocation) original).getSelect();
- if (select != null) {
- lookup.put("this", select);
- }
- }
- List originalParameterNames = requireNonNull(original.getMethodType()).getParameterNames();
- for (int i = 0; i < originalParameterNames.size(); i++) {
- String originalName = originalParameterNames.get(i);
- Expression originalValue = original.getArguments().get(i);
- lookup.put(originalName, originalValue);
- }
- List parameters = new ArrayList<>();
- Matcher matcher = TEMPLATE_IDENTIFIER.matcher(templateString);
- while (matcher.find()) {
- Expression o = lookup.get(matcher.group(1));
- if (o != null) {
- parameters.add(o);
- }
- }
- return parameters;
- }
- }
-
- @Value
- private static class Template {
- String string;
- Object[] parameters;
- }
-}
diff --git a/src/main/resources/META-INF/rewrite/no-guava.yml b/src/main/resources/META-INF/rewrite/no-guava.yml
index 87863a9a47..adbfd4680c 100644
--- a/src/main/resources/META-INF/rewrite/no-guava.yml
+++ b/src/main/resources/META-INF/rewrite/no-guava.yml
@@ -121,7 +121,7 @@ preconditions:
- org.openrewrite.analysis.search.FindMethods:
methodPattern: com.google.common..* *(..)
recipeList:
- - org.openrewrite.java.migrate.InlineMethodCalls
+ - org.openrewrite.java.InlineMethodCalls
---
type: specs.openrewrite.org/v1beta/recipe
diff --git a/src/test/java/org/openrewrite/java/migrate/InlineMethodCallsTest.java b/src/test/java/org/openrewrite/java/migrate/InlineMethodCallsTest.java
deleted file mode 100644
index a046b214e9..0000000000
--- a/src/test/java/org/openrewrite/java/migrate/InlineMethodCallsTest.java
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright 2025 the original author or authors.
- *
- * Licensed under the Moderne Source Available License (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://docs.moderne.io/licensing/moderne-source-available-license
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.openrewrite.java.migrate;
-
-import org.junit.jupiter.api.Test;
-import org.openrewrite.DocumentExample;
-import org.openrewrite.java.JavaParser;
-import org.openrewrite.test.RecipeSpec;
-import org.openrewrite.test.RewriteTest;
-
-import static org.openrewrite.java.Assertions.java;
-
-class InlineMethodCallsTest implements RewriteTest {
-
- @Override
- public void defaults(RecipeSpec spec) {
- spec.recipe(new InlineMethodCalls())
- .parser(JavaParser.fromJavaVersion().classpath("guava", "error_prone_annotations"));
- }
-
- @DocumentExample
- @Test
- void inlineMeSimple() {
- //language=java
- rewriteRun(
- java(
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class Lib {
- @Deprecated
- @InlineMe(replacement = "this.replacement()")
- public void deprecated() {}
- public void replacement() {}
-
- public static void usage(Lib lib) {
- lib.deprecated();
- }
- }
- """,
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class Lib {
- @Deprecated
- @InlineMe(replacement = "this.replacement()")
- public void deprecated() {}
- public void replacement() {}
-
- public static void usage(Lib lib) {
- lib.replacement();
- }
- }
- """
- )
- );
- }
-
- @Test
- void inlineMeNonStatic() {
- //language=java
- rewriteRun(
- java(
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class Lib {
- @Deprecated
- @InlineMe(replacement = "this.replacement()")
- public void deprecated() {}
- public void replacement() {}
-
- public void usage() {
- deprecated();
- }
- }
- """,
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class Lib {
- @Deprecated
- @InlineMe(replacement = "this.replacement()")
- public void deprecated() {}
- public void replacement() {}
-
- public void usage() {
- replacement();
- }
- }
- """
- )
- );
- }
-
- @Test
- void inlineMeChained() {
- //language=java
- rewriteRun(
- java(
- """
- import com.google.errorprone.annotations.InlineMe;
- import java.time.Duration;
-
- class Lib {
- private final Duration deadline;
-
- public Duration getDeadline() {
- return deadline;
- }
-
- @Deprecated
- @InlineMe(replacement = "this.getDeadline().toMillis()")
- public long getDeadlineMillis() {
- return getDeadline().toMillis();
- }
-
- long usage() {
- return getDeadlineMillis();
- }
- }
- """,
- """
- import com.google.errorprone.annotations.InlineMe;
- import java.time.Duration;
-
- class Lib {
- private final Duration deadline;
-
- public Duration getDeadline() {
- return deadline;
- }
-
- @Deprecated
- @InlineMe(replacement = "this.getDeadline().toMillis()")
- public long getDeadlineMillis() {
- return getDeadline().toMillis();
- }
-
- long usage() {
- return getDeadline().toMillis();
- }
- }
- """
- )
- );
- }
-
- @Test
- void instanceMethodWithImports() {
- //language=java
- rewriteRun(
- java(
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class MyClass {
- private java.time.Duration deadline;
-
- public void setDeadline(java.time.Duration deadline) {
- this.deadline = deadline;
- }
-
- @Deprecated
- @InlineMe(
- replacement = "this.setDeadline(Duration.ofMillis(millis))",
- imports = {"java.time.Duration"})
- public void setDeadline(long millis) {
- setDeadline(java.time.Duration.ofMillis(millis));
- }
-
- void usage() {
- setDeadline(1000L);
- }
- }
- """,
- """
- import com.google.errorprone.annotations.InlineMe;
-
- import java.time.Duration;
-
- class MyClass {
- private Duration deadline;
-
- public void setDeadline(Duration deadline) {
- this.deadline = deadline;
- }
-
- @Deprecated
- @InlineMe(
- replacement = "this.setDeadline(Duration.ofMillis(millis))",
- imports = {"java.time.Duration"})
- public void setDeadline(long millis) {
- setDeadline(Duration.ofMillis(millis));
- }
-
- void usage() {
- setDeadline(Duration.ofMillis(1000L));
- }
- }
- """
- )
- );
- }
-
- @Test
- void staticMethodReplacement() {
- //language=java
- rewriteRun(
- java(
- """
- package com.google.frobber;
-
- import com.google.errorprone.annotations.InlineMe;
-
- class Frobber {
-
- public static Frobber fromName(String name) {
- return new Frobber();
- }
-
- @Deprecated
- @InlineMe(
- replacement = "Frobber.fromName(name)",
- imports = {"com.google.frobber.Frobber"})
- public static Frobber create(String name) {
- return fromName(name);
- }
-
- void usage() {
- Frobber f = Frobber.create("test");
- }
- }
- """,
- """
- package com.google.frobber;
-
- import com.google.errorprone.annotations.InlineMe;
-
- class Frobber {
-
- public static Frobber fromName(String name) {
- return new Frobber();
- }
-
- @Deprecated
- @InlineMe(
- replacement = "Frobber.fromName(name)",
- imports = {"com.google.frobber.Frobber"})
- public static Frobber create(String name) {
- return fromName(name);
- }
-
- void usage() {
- Frobber f = Frobber.fromName("test");
- }
- }
- """
- )
- );
- }
-
- @Test
- void constructorToFactoryMethod() {
- //language=java
- rewriteRun(
- java(
- """
- package com.google.frobber;
-
- import com.google.errorprone.annotations.InlineMe;
- import com.google.errorprone.annotations.InlineMeValidationDisabled;
-
- class MyClass {
-
- @InlineMeValidationDisabled
- @Deprecated
- @InlineMe(
- replacement = "MyClass.create()",
- imports = {"com.google.frobber.MyClass"})
- public MyClass() {
- }
-
- public static MyClass create() {
- return new MyClass();
- }
-
- void usage() {
- MyClass obj = new MyClass();
- }
- }
- """,
- """
- package com.google.frobber;
-
- import com.google.errorprone.annotations.InlineMe;
- import com.google.errorprone.annotations.InlineMeValidationDisabled;
-
- class MyClass {
-
- @InlineMeValidationDisabled
- @Deprecated
- @InlineMe(
- replacement = "MyClass.create()",
- imports = {"com.google.frobber.MyClass"})
- public MyClass() {
- }
-
- public static MyClass create() {
- return new MyClass();
- }
-
- void usage() {
- MyClass obj = MyClass.create();
- }
- }
- """
- )
- );
- }
-
- @Test
- void multipleParameters() {
- //language=java
- rewriteRun(
- java(
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class Calculator {
-
- public int addAndMultiply(int a, int b, int c) {
- return (a + b) * c;
- }
-
- @Deprecated
- @InlineMe(replacement = "this.addAndMultiply(x, y, z)")
- public int compute(int x, int y, int z) {
- return addAndMultiply(x, y, z);
- }
-
- void foo(Calculator calc) {
- int result = calc.compute(1, 2, 3);
- }
- }
- """,
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class Calculator {
-
- public int addAndMultiply(int a, int b, int c) {
- return (a + b) * c;
- }
-
- @Deprecated
- @InlineMe(replacement = "this.addAndMultiply(x, y, z)")
- public int compute(int x, int y, int z) {
- return addAndMultiply(x, y, z);
- }
-
- void foo(Calculator calc) {
- int result = calc.addAndMultiply(1, 2, 3);
- }
- }
- """
- )
- );
- }
-
- @Test
- void nestedMethodCalls() {
- //language=java
- rewriteRun(
- java(
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class Builder {
-
- public Builder withName(String name) {
- return this;
- }
-
- public Builder withAge(int age) {
- return this;
- }
-
- @Deprecated
- @InlineMe(replacement = "this.withName(name).withAge(age)")
- public Builder configure(String name, int age) {
- return withName(name).withAge(age);
- }
-
- void foo(Builder builder) {
- builder.configure("John", 30);
- }
- }
- """,
- """
- import com.google.errorprone.annotations.InlineMe;
-
- class Builder {
-
- public Builder withName(String name) {
- return this;
- }
-
- public Builder withAge(int age) {
- return this;
- }
-
- @Deprecated
- @InlineMe(replacement = "this.withName(name).withAge(age)")
- public Builder configure(String name, int age) {
- return withName(name).withAge(age);
- }
-
- void foo(Builder builder) {
- builder.withName("John").withAge(30);
- }
- }
- """
- )
- );
- }
-}
diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaInlineMeMethods.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaInlineMeMethodsTest.java
similarity index 97%
rename from src/test/java/org/openrewrite/java/migrate/guava/NoGuavaInlineMeMethods.java
rename to src/test/java/org/openrewrite/java/migrate/guava/NoGuavaInlineMeMethodsTest.java
index a39c82d524..d91488b760 100644
--- a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaInlineMeMethods.java
+++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaInlineMeMethodsTest.java
@@ -22,7 +22,7 @@
import static org.openrewrite.java.Assertions.java;
-class NoGuavaInlineMeMethods implements RewriteTest {
+class NoGuavaInlineMeMethodsTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {