All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.picnic.errorprone.refasterrules.StringRulesRecipes Maven / Gradle / Ivy

There is a newer version: 0.19.1
Show newest version
package tech.picnic.errorprone.refasterrules;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.lang.NonNullApi;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.search.*;
import org.openrewrite.java.template.Primitive;
import org.openrewrite.java.template.function.*;
import org.openrewrite.java.template.internal.AbstractRefasterJavaVisitor;
import org.openrewrite.java.tree.*;

import javax.annotation.Generated;
import java.util.*;

import static org.openrewrite.java.template.internal.AbstractRefasterJavaVisitor.EmbeddingOption.*;

/**
 * OpenRewrite recipes created for Refaster template {@code tech.picnic.errorprone.refasterrules.StringRules}.
 */
@SuppressWarnings("all")
@Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
public class StringRulesRecipes extends Recipe {
    /**
     * Instantiates a new instance.
     */
    public StringRulesRecipes() {}

    @Override
    public String getDisplayName() {
        return "Refaster rules related to expressions dealing with `String`s";
    }

    @Override
    public String getDescription() {
        return "Refaster template recipes for `tech.picnic.errorprone.refasterrules.StringRules`. [Source](https://error-prone.picnic.tech/refasterrules/StringRules).";
    }

    @Override
    public List getRecipeList() {
        return Arrays.asList(
                new StringIsEmptyRecipe(),
                new StringIsNullOrEmptyRecipe(),
                new OptionalNonEmptyStringRecipe(),
                new FilterEmptyStringRecipe(),
                new JoinStringsRecipe(),
                new StringValueOfRecipe(),
                new NewStringFromCharArraySubSequenceRecipe(),
                new NewStringFromCharArrayRecipe(),
                new SubstringRemainderRecipe(),
                new Utf8EncodedLengthRecipe()
        );
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.StringIsEmpty}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class StringIsEmptyRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public StringIsEmptyRecipe() {}

        @Override
        public String getDisplayName() {
            return "Prefer `String#isEmpty()` over alternatives that consult the string's length";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class StringIsEmpty {\n    \n    @BeforeTemplate\n    boolean before(String str) {\n        return Refaster.anyOf(str.length() == 0, str.length() <= 0, str.length() < 1);\n    }\n    \n    @AfterTemplate\n    @AlsoNegation\n    boolean after(String str) {\n        return str.isEmpty();\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before$0 = JavaTemplate
                        .builder("#{str:any(java.lang.String)}.length() == 0")
                        .build();
                final JavaTemplate before$1 = JavaTemplate
                        .builder("#{str:any(java.lang.String)}.length() <= 0")
                        .build();
                final JavaTemplate before$2 = JavaTemplate
                        .builder("#{str:any(java.lang.String)}.length() < 1")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("#{str:any(java.lang.String)}.isEmpty()")
                        .build();

                @Override
                public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before$0.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES, SIMPLIFY_BOOLEANS
                        );
                    }
                    if ((matcher = before$1.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES, SIMPLIFY_BOOLEANS
                        );
                    }
                    if ((matcher = before$2.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES, SIMPLIFY_BOOLEANS
                        );
                    }
                    return super.visitMethodInvocation(elem, ctx);
                }

            };
            return Preconditions.check(
                    new UsesMethod<>("java.lang.String length(..)"),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.StringIsNullOrEmpty}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class StringIsNullOrEmptyRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public StringIsNullOrEmptyRecipe() {}

        @Override
        public String getDisplayName() {
            return "Prefer `Strings#isNullOrEmpty(String)` over the more verbose alternative";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class StringIsNullOrEmpty {\n    \n    @BeforeTemplate\n    boolean before(@Nullable\n    String str) {\n        return str == null || str.isEmpty();\n    }\n    \n    @AfterTemplate\n    @AlsoNegation\n    boolean after(String str) {\n        return Strings.isNullOrEmpty(str);\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before = JavaTemplate
                        .builder("#{str:any([email protected] String)} == null || #{str}.isEmpty()")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("com.google.common.base.Strings.isNullOrEmpty(#{str:any(java.lang.String)})")
                        .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
                        .build();

                @Override
                public J visitBinary(J.Binary elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES, SIMPLIFY_BOOLEANS
                        );
                    }
                    return super.visitBinary(elem, ctx);
                }

            };
            return Preconditions.check(
                    new UsesMethod<>("java.lang.String isEmpty(..)"),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.OptionalNonEmptyString}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class OptionalNonEmptyStringRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public OptionalNonEmptyStringRecipe() {}

        @Override
        public String getDisplayName() {
            return "Don't use the ternary operator to create an optionally-absent string";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class OptionalNonEmptyString {\n    \n    @BeforeTemplate\n    Optional before(String str) {\n        return Strings.isNullOrEmpty(str) ? Optional.empty() : Refaster.anyOf(Optional.of(str), Optional.ofNullable(str));\n    }\n    \n    @AfterTemplate\n    Optional after(String str) {\n        return Optional.ofNullable(str).filter(not(String::isEmpty));\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before$0 = JavaTemplate
                        .builder("Strings.isNullOrEmpty(str) ? Optional.empty() : java.util.Optional.of(#{str:any(java.lang.String)})")
                        .build();
                final JavaTemplate before$1 = JavaTemplate
                        .builder("Strings.isNullOrEmpty(str) ? Optional.empty() : java.util.Optional.ofNullable(#{str:any(java.lang.String)})")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("java.util.Optional.ofNullable(#{str:any(java.lang.String)}).filter(java.util.function.Predicate.not(String::isEmpty))")
                        .build();

                @Override
                public J visitTernary(J.Ternary elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before$0.matcher(getCursor())).find()) {
                        maybeRemoveImport("com.google.common.base.Strings");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    if ((matcher = before$1.matcher(getCursor())).find()) {
                        maybeRemoveImport("com.google.common.base.Strings");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitTernary(elem, ctx);
                }

            };
            return Preconditions.check(
                    Preconditions.and(
                        new UsesType<>("com.google.common.base.Strings", true),
                        new UsesType<>("java.util.Optional", true),
                        new UsesMethod<>("com.google.common.base.Strings isNullOrEmpty(..)"),
                        new UsesMethod<>("java.util.Optional empty(..)"),
                        Preconditions.or(
                            new UsesMethod<>("java.util.Optional of(..)"),
                            new UsesMethod<>("java.util.Optional ofNullable(..)")
                        )
                    ),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.FilterEmptyString}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class FilterEmptyStringRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public FilterEmptyStringRecipe() {}

        @Override
        public String getDisplayName() {
            return "Refaster template `StringRules.FilterEmptyString`";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class FilterEmptyString {\n    \n    @BeforeTemplate\n    Optional before(Optional optional) {\n        return optional.map(Strings::emptyToNull);\n    }\n    \n    @AfterTemplate\n    @UseImportPolicy(value = STATIC_IMPORT_ALWAYS)\n    Optional after(Optional optional) {\n        return optional.filter(not(String::isEmpty));\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before = JavaTemplate
                        .builder("#{optional:any(java.util.Optional)}.map(com.google.common.base.Strings::emptyToNull)")
                        .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("#{optional:any(java.util.Optional)}.filter(java.util.function.Predicate.not(String::isEmpty))")
                        .build();

                @Override
                public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before.matcher(getCursor())).find()) {
                        maybeRemoveImport("com.google.common.base.Strings");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitMethodInvocation(elem, ctx);
                }

            };
            return Preconditions.check(
                    Preconditions.and(
                        new UsesType<>("com.google.common.base.Strings", true),
                        new UsesType<>("java.util.Optional", true),
                        new UsesMethod<>("java.util.Optional map(..)")
                    ),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.JoinStrings}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class JoinStringsRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public JoinStringsRecipe() {}

        @Override
        public String getDisplayName() {
            return "Prefer `String#join(CharSequence, Iterable)` and variants over the Guava alternative";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class JoinStrings {\n    \n    @BeforeTemplate\n    String before(String delimiter, CharSequence[] elements) {\n        return Refaster.anyOf(Joiner.on(delimiter).join(elements), Arrays.stream(elements).collect(joining(delimiter)));\n    }\n    \n    @BeforeTemplate\n    String before(String delimiter, Iterable elements) {\n        return Refaster.anyOf(Joiner.on(delimiter).join(elements), Streams.stream(elements).collect(joining(delimiter)));\n    }\n    \n    @BeforeTemplate\n    String before(CharSequence delimiter, Collection elements) {\n        return elements.stream().collect(joining(delimiter));\n    }\n    \n    @AfterTemplate\n    String after(CharSequence delimiter, Iterable elements) {\n        return String.join(delimiter, elements);\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before$0 = JavaTemplate
                        .builder("com.google.common.base.Joiner.on(#{delimiter:any(java.lang.String)}).join(#{elements:anyArray(java.lang.CharSequence)})")
                        .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
                        .build();
                final JavaTemplate before$1 = JavaTemplate
                        .builder("java.util.Arrays.stream(#{elements:anyArray(java.lang.CharSequence)}).collect(java.util.stream.Collectors.joining(#{delimiter:any(java.lang.String)}))")
                        .build();
                final JavaTemplate before0$0 = JavaTemplate
                        .builder("com.google.common.base.Joiner.on(#{delimiter:any(java.lang.String)}).join(#{elements:any(java.lang.Iterable)})")
                        .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
                        .build();
                final JavaTemplate before0$1 = JavaTemplate
                        .builder("com.google.common.collect.Streams.stream(#{elements:any(java.lang.Iterable)}).collect(java.util.stream.Collectors.joining(#{delimiter:any(java.lang.String)}))")
                        .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
                        .build();
                final JavaTemplate before1 = JavaTemplate
                        .builder("#{elements:any(java.util.Collection)}.stream().collect(java.util.stream.Collectors.joining(#{delimiter:any(java.lang.CharSequence)}))")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("String.join(#{delimiter:any(java.lang.CharSequence)}, #{elements:any(java.lang.Iterable)})")
                        .build();

                @Override
                public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before$0.matcher(getCursor())).find()) {
                        maybeRemoveImport("com.google.common.base.Joiner");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0), matcher.parameter(1)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    if ((matcher = before$1.matcher(getCursor())).find()) {
                        maybeRemoveImport("java.util.Arrays");
                        maybeRemoveImport("java.util.stream.Collectors.joining");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0), matcher.parameter(1)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    if ((matcher = before0$0.matcher(getCursor())).find()) {
                        maybeRemoveImport("com.google.common.base.Joiner");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0), matcher.parameter(1)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    if ((matcher = before0$1.matcher(getCursor())).find()) {
                        maybeRemoveImport("com.google.common.collect.Streams");
                        maybeRemoveImport("java.util.stream.Collectors.joining");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0), matcher.parameter(1)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    if ((matcher = before1.matcher(getCursor())).find()) {
                        maybeRemoveImport("java.util.Collection");
                        maybeRemoveImport("java.util.stream.Collectors.joining");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(1), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitMethodInvocation(elem, ctx);
                }

            };
            return Preconditions.check(
                    Preconditions.or(
                        Preconditions.and(
                        new UsesType<>("com.google.common.base.Joiner", true),
                        new UsesMethod<>("com.google.common.base.Joiner join(..)"),
                        new UsesMethod<>("com.google.common.base.Joiner on(..)")
                    ),
                        Preconditions.and(
                        new UsesType<>("com.google.common.collect.Streams", true),
                        new UsesMethod<>("java.util.stream.Stream collect(..)"),
                        new UsesMethod<>("com.google.common.collect.Streams stream(..)"),
                        new UsesMethod<>("java.util.stream.Collectors joining(..)")
                    ),
                        Preconditions.and(
                        new UsesType<>("java.util.Collection", true),
                        new UsesMethod<>("java.util.stream.Stream collect(..)"),
                        new UsesMethod<>("java.util.Collection stream(..)"),
                        new UsesMethod<>("java.util.stream.Collectors joining(..)")
                    )
                    ),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.StringValueOf}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class StringValueOfRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public StringValueOfRecipe() {}

        @Override
        public String getDisplayName() {
            return "Prefer direct invocation of `String#valueOf(Object)` over the indirection introduced by `Objects#toString(Object)`";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class StringValueOf {\n    \n    @BeforeTemplate\n    String before(Object object) {\n        return Objects.toString(object);\n    }\n    \n    @AfterTemplate\n    String after(Object object) {\n        return String.valueOf(object);\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before = JavaTemplate
                        .builder("java.util.Objects.toString(#{object:any(java.lang.Object)})")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("String.valueOf(#{object:any(java.lang.Object)})")
                        .build();

                @Override
                public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before.matcher(getCursor())).find()) {
                        maybeRemoveImport("java.util.Objects");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitMethodInvocation(elem, ctx);
                }

            };
            return Preconditions.check(
                    Preconditions.and(
                        new UsesType<>("java.util.Objects", true),
                        new UsesMethod<>("java.util.Objects toString(..)")
                    ),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.NewStringFromCharArraySubSequence}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class NewStringFromCharArraySubSequenceRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public NewStringFromCharArraySubSequenceRecipe() {}

        @Override
        public String getDisplayName() {
            return "Prefer direct invocation of `String#String(char[], int, int)` over the indirection introduced by alternatives";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class NewStringFromCharArraySubSequence {\n    \n    @BeforeTemplate\n    String before(char[] data, int offset, int count) {\n        return Refaster.anyOf(String.valueOf(data, offset, count), String.copyValueOf(data, offset, count));\n    }\n    \n    @AfterTemplate\n    String after(char[] data, int offset, int count) {\n        return new String(data, offset, count);\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before$0 = JavaTemplate
                        .builder("String.valueOf(#{data:anyArray(char)}, #{offset:any(int)}, #{count:any(int)})")
                        .build();
                final JavaTemplate before$1 = JavaTemplate
                        .builder("String.copyValueOf(#{data:anyArray(char)}, #{offset:any(int)}, #{count:any(int)})")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("new String(#{data:anyArray(char)}, #{offset:any(int)}, #{count:any(int)})")
                        .build();

                @Override
                public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before$0.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0), matcher.parameter(1), matcher.parameter(2)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    if ((matcher = before$1.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0), matcher.parameter(1), matcher.parameter(2)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitMethodInvocation(elem, ctx);
                }

            };
            return Preconditions.check(
                    Preconditions.or(
                        new UsesMethod<>("java.lang.String valueOf(..)"),
                        new UsesMethod<>("java.lang.String copyValueOf(..)")
                    ),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.NewStringFromCharArray}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class NewStringFromCharArrayRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public NewStringFromCharArrayRecipe() {}

        @Override
        public String getDisplayName() {
            return "Prefer direct invocation of `String#String(char[])` over the indirection introduced by alternatives";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class NewStringFromCharArray {\n    \n    @BeforeTemplate\n    String before(char[] data) {\n        return Refaster.anyOf(String.valueOf(data), new String(data, 0, data.length));\n    }\n    \n    @AfterTemplate\n    String after(char[] data) {\n        return new String(data);\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before$0 = JavaTemplate
                        .builder("String.valueOf(#{data:anyArray(char)})")
                        .build();
                final JavaTemplate before$1 = JavaTemplate
                        .builder("new String(#{data:anyArray(char)}, 0, #{data}.length)")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("new String(#{data:anyArray(char)})")
                        .build();

                @Override
                public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before$0.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    if ((matcher = before$1.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitMethodInvocation(elem, ctx);
                }

            };
            return Preconditions.check(
                    Preconditions.or(
                        new UsesMethod<>("java.lang.String valueOf(..)"),
                        new UsesMethod<>("java.lang.String (..)")
                    ),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.SubstringRemainder}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class SubstringRemainderRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public SubstringRemainderRecipe() {}

        @Override
        public String getDisplayName() {
            return "Don't unnecessarily use the two-argument `String#substring(int, int)`";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class SubstringRemainder {\n    \n    @BeforeTemplate\n    String before(String str, int index) {\n        return str.substring(index, str.length());\n    }\n    \n    @AfterTemplate\n    String after(String str, int index) {\n        return str.substring(index);\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before = JavaTemplate
                        .builder("#{str:any(java.lang.String)}.substring(#{index:any(int)}, #{str}.length())")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("#{str:any(java.lang.String)}.substring(#{index:any(int)})")
                        .build();

                @Override
                public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before.matcher(getCursor())).find()) {
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0), matcher.parameter(1)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitMethodInvocation(elem, ctx);
                }

            };
            return Preconditions.check(
                    Preconditions.and(
                        new UsesMethod<>("java.lang.String substring(..)"),
                        new UsesMethod<>("java.lang.String length(..)")
                    ),
                    javaVisitor
            );
        }
    }

    /**
     * OpenRewrite recipe created for Refaster template {@code StringRules.Utf8EncodedLength}.
     */
    @SuppressWarnings("all")
    @NonNullApi
    @Generated("org.openrewrite.java.template.processor.RefasterTemplateProcessor")
    public static class Utf8EncodedLengthRecipe extends Recipe {

        /**
         * Instantiates a new instance.
         */
        public Utf8EncodedLengthRecipe() {}

        @Override
        public String getDisplayName() {
            return "Prefer `Utf8#encodedLength(CharSequence)` over less efficient alternatives";
        }

        @Override
        public String getDescription() {
            return "Recipe created for the following Refaster template:\n```java\nstatic final class Utf8EncodedLength {\n    \n    @BeforeTemplate\n    int before(String str) {\n        return str.getBytes(UTF_8).length;\n    }\n    \n    @AfterTemplate\n    int after(String str) {\n        return Utf8.encodedLength(str);\n    }\n}\n```\n.";
        }

        @Override
        public TreeVisitor getVisitor() {
            JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() {
                final JavaTemplate before = JavaTemplate
                        .builder("#{str:any(java.lang.String)}.getBytes(java.nio.charset.StandardCharsets.UTF_8).length")
                        .build();
                final JavaTemplate after = JavaTemplate
                        .builder("com.google.common.base.Utf8.encodedLength(#{str:any(java.lang.String)})")
                        .javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()))
                        .build();

                @Override
                public J visitFieldAccess(J.FieldAccess elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before.matcher(getCursor())).find()) {
                        maybeRemoveImport("java.nio.charset.StandardCharsets.UTF_8");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitFieldAccess(elem, ctx);
                }

                @Override
                public J visitIdentifier(J.Identifier elem, ExecutionContext ctx) {
                    JavaTemplate.Matcher matcher;
                    if ((matcher = before.matcher(getCursor())).find()) {
                        maybeRemoveImport("java.nio.charset.StandardCharsets.UTF_8");
                        return embed(
                                after.apply(getCursor(), elem.getCoordinates().replace(), matcher.parameter(0)),
                                getCursor(),
                                ctx,
                                SHORTEN_NAMES
                        );
                    }
                    return super.visitIdentifier(elem, ctx);
                }

            };
            return Preconditions.check(
                    new UsesMethod<>("java.lang.String getBytes(..)"),
                    javaVisitor
            );
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy