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

Find Refaster style recipes as well #4693

Merged
merged 1 commit into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static class Row {

public enum RecipeType {
Java,
Refaster,
Yaml
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,24 @@
import org.openrewrite.DocumentExample;
import org.openrewrite.java.JavaParser;
import org.openrewrite.table.RewriteRecipeSource;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

import static org.assertj.core.api.Assertions.assertThat;
import static org.openrewrite.java.Assertions.java;

class FindRecipesTest implements RewriteTest {

@Override
public void defaults(RecipeSpec spec) {
spec.recipe(new FindRecipes()).parser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()));
}

@DocumentExample
@Test
void findRecipes() {
rewriteRun(
spec -> spec
.recipe(new FindRecipes())
.parser(JavaParser.fromJavaVersion()
.classpath(JavaParser.runtimeClasspath()))
.dataTable(RewriteRecipeSource.Row.class, rows -> {
assertThat(rows).hasSize(1);
RewriteRecipeSource.Row row = rows.get(0);
Expand Down Expand Up @@ -66,7 +69,7 @@ class MyRecipe extends Recipe {
public String getDisplayName() {
return "My recipe";
}

@Override
public String getDescription() {
return "This is my recipe.";
Expand All @@ -85,19 +88,19 @@ class /*~~>*/MyRecipe extends Recipe {
description = "A method pattern that is used to find matching method declarations/invocations.",
example = "org.mockito.Matchers anyVararg()")
String methodPattern;

@Option(displayName = "New access level",
description = "New method access level to apply to the method, like \\"public\\".",
example = "public",
valid = {"private", "protected", "package", "public"},
required = false)
String newAccessLevel;

@Override
public String getDisplayName() {
return "My recipe";
}

@Override
public String getDescription() {
return "This is my recipe.";
Expand All @@ -111,7 +114,6 @@ public String getDescription() {
@Test
void returnInLambda() {
rewriteRun(
spec -> spec.recipe(new FindRecipes()),
java(
"""
import java.util.function.UnaryOperator;
Expand All @@ -126,4 +128,50 @@ class SomeTest {
)
);
}

@Test
void findRefasterRecipe() {
rewriteRun(
spec -> spec.parser(JavaParser.fromJavaVersion().dependsOn(
"""
package org.openrewrite.java.template;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
public @interface RecipeDescriptor {
String name();
String description();
}
"""
))
.dataTable(RewriteRecipeSource.Row.class, rows -> {
assertThat(rows).hasSize(1);
RewriteRecipeSource.Row row = rows.get(0);
assertThat(row.getDisplayName()).isEqualTo("Some refaster rule");
assertThat(row.getDescription()).isEqualTo("This is a refaster rule.");
}),
java(
"""
import org.openrewrite.java.template.RecipeDescriptor;

@RecipeDescriptor(
name = "Some refaster rule",
description = "This is a refaster rule."
)
class SomeRefasterRule {
}
""",
"""
import org.openrewrite.java.template.RecipeDescriptor;

/*~~>*/@RecipeDescriptor(
name = "Some refaster rule",
description = "This is a refaster rule."
)
class SomeRefasterRule {
}
"""
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ValueNode;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.*;
import org.openrewrite.java.AnnotationMatcher;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.MethodMatcher;
Expand Down Expand Up @@ -55,6 +53,65 @@ public String getDescription() {

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
TreeVisitor<?, ExecutionContext> findRefasterRecipes = findRefasterRecipes();
TreeVisitor<?, ExecutionContext> findImperativeRecipes = findImperativeRecipes();
return new TreeVisitor<Tree, ExecutionContext>() {
@Override
public @Nullable Tree preVisit(@NonNull Tree tree, ExecutionContext ctx) {
stopAfterPreVisit();
tree = findRefasterRecipes.visit(tree, ctx);
tree = findImperativeRecipes.visit(tree, ctx);
return tree;
}
};
}

private TreeVisitor<?, ExecutionContext> findRefasterRecipes() {
String recipeDescriptor = "org.openrewrite.java.template.RecipeDescriptor";
AnnotationMatcher annotationMatcher = new AnnotationMatcher("@" + recipeDescriptor);
return Preconditions.check(new UsesType<>(recipeDescriptor, false), new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);
for (J.Annotation annotation : cd.getLeadingAnnotations()) {
if (annotationMatcher.matches(annotation)) {
String name = null;
String description = null;
for (Expression argument : annotation.getArguments()) {
if (argument instanceof J.Assignment) {
J.Assignment assignment = (J.Assignment) argument;
if (assignment.getVariable() instanceof J.Identifier) {
String simpleName = ((J.Identifier) assignment.getVariable()).getSimpleName();
if ("name".equals(simpleName)) {
if (assignment.getAssignment() instanceof J.Literal) {
name = (String) ((J.Literal) assignment.getAssignment()).getValue();
}
} else if ("description".equals(simpleName)) {
if (assignment.getAssignment() instanceof J.Literal) {
description = (String) ((J.Literal) assignment.getAssignment()).getValue();
}
}
}
}
}
if (name != null && description != null) {
recipeSource.insertRow(ctx, new RewriteRecipeSource.Row(
name,
description,
RewriteRecipeSource.RecipeType.Refaster,
cd.printTrimmed(getCursor()),
"[]"
));
return SearchResult.found(cd);
}
}
}
return cd;
}
});
}

private TreeVisitor<?, ExecutionContext> findImperativeRecipes() {
MethodMatcher getDisplayName = new MethodMatcher("org.openrewrite.Recipe getDisplayName()", true);
MethodMatcher getDescription = new MethodMatcher("org.openrewrite.Recipe getDescription()", true);
AnnotationMatcher optionAnnotation = new AnnotationMatcher("@org.openrewrite.Option");
Expand Down