diff --git a/src/main/java/org/openrewrite/java/template/processor/RefasterTemplateProcessor.java b/src/main/java/org/openrewrite/java/template/processor/RefasterTemplateProcessor.java index 9a928027..15777d67 100644 --- a/src/main/java/org/openrewrite/java/template/processor/RefasterTemplateProcessor.java +++ b/src/main/java/org/openrewrite/java/template/processor/RefasterTemplateProcessor.java @@ -19,6 +19,7 @@ import com.sun.source.tree.MethodTree; import com.sun.source.tree.Tree; import com.sun.source.tree.VariableTree; +import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.TypeTag; @@ -539,9 +540,29 @@ private String generatePreconditions(List beforeTemplates, i if (method.owner.getQualifiedName().toString().startsWith("com.google.errorprone.refaster.")) { continue; } - String methodName = method.name.toString(); - methodName = methodName.equals("") ? "" : methodName; - usesVisitors.add("new UsesMethod<>(\"" + method.owner.getQualifiedName().toString() + ' ' + methodName + "(..)\")"); + StringBuilder sb = new StringBuilder(); + sb.append("new UsesMethod<>(\""); + sb.append(method.owner.getQualifiedName().toString()); + sb.append(' '); + if (method.name.toString().equals("")) { + sb.append(""); + } else { + sb.append(method.name.toString()); + } + com.sun.tools.javac.util.List parameterTypes = method.type.getParameterTypes(); + if (parameterTypes.isEmpty()) { + sb.append("()"); + } else { + if ((method.flags() & Flags.VARARGS) == 0 && parameterTypes.stream().allMatch(t -> t instanceof Type.JCPrimitiveType || t instanceof Type.ClassType)) { + StringJoiner joiner = new StringJoiner(", ", "(", ")"); + parameterTypes.forEach(t -> joiner.add(t.tsym.type.toString())); + sb.append(joiner); + } else { + sb.append("(..)"); + } + } + sb.append("\")"); + usesVisitors.add(sb.toString()); } preconditions.put(beforeTemplate.method.name.toString() + (arity == 1 ? "" : "$" + i), usesVisitors); diff --git a/src/test/java/org/openrewrite/java/template/RefasterTemplateProcessorTest.java b/src/test/java/org/openrewrite/java/template/RefasterTemplateProcessorTest.java index 18f584ab..0f34638f 100644 --- a/src/test/java/org/openrewrite/java/template/RefasterTemplateProcessorTest.java +++ b/src/test/java/org/openrewrite/java/template/RefasterTemplateProcessorTest.java @@ -85,6 +85,7 @@ void skipRecipeGeneration(String recipeName) { "ShouldSupportNestedClasses", "SimplifyTernary", "RefasterAnyOf", + "UsesMethodPrecondition", }) void nestedRecipes(String recipeName) { Compilation compilation = compileResource("refaster/" + recipeName + ".java"); diff --git a/src/test/resources/refaster/EscapesRecipes.java b/src/test/resources/refaster/EscapesRecipes.java index 599ec413..640c7de9 100644 --- a/src/test/resources/refaster/EscapesRecipes.java +++ b/src/test/resources/refaster/EscapesRecipes.java @@ -115,7 +115,7 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { Preconditions.and( new UsesType<>("com.sun.tools.javac.util.Convert", true), new UsesMethod<>("java.lang.String format(..)"), - new UsesMethod<>("com.sun.tools.javac.util.Convert quote(..)") + new UsesMethod<>("com.sun.tools.javac.util.Convert quote(java.lang.String)") ), javaVisitor ); @@ -170,7 +170,7 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { }; return Preconditions.check( - new UsesMethod<>("java.lang.String split(..)"), + new UsesMethod<>("java.lang.String split(java.lang.String)"), javaVisitor ); } diff --git a/src/test/resources/refaster/GenericsRecipes.java b/src/test/resources/refaster/GenericsRecipes.java index 29560fab..5203a338 100644 --- a/src/test/resources/refaster/GenericsRecipes.java +++ b/src/test/resources/refaster/GenericsRecipes.java @@ -110,8 +110,8 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { return Preconditions.check( Preconditions.and( new UsesType<>("java.util.List", true), - new UsesMethod<>("java.util.Iterator next(..)"), - new UsesMethod<>("java.util.List iterator(..)") + new UsesMethod<>("java.util.Iterator next()"), + new UsesMethod<>("java.util.List iterator()") ), javaVisitor ); diff --git a/src/test/resources/refaster/MatchingRecipes.java b/src/test/resources/refaster/MatchingRecipes.java index 7064ed13..a50b7808 100644 --- a/src/test/resources/refaster/MatchingRecipes.java +++ b/src/test/resources/refaster/MatchingRecipes.java @@ -138,8 +138,8 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { }; return Preconditions.check( Preconditions.and( - new UsesMethod<>("java.lang.String isEmpty(..)"), - new UsesMethod<>("java.lang.String substring(..)") + new UsesMethod<>("java.lang.String isEmpty()"), + new UsesMethod<>("java.lang.String substring(int)") ), javaVisitor ); diff --git a/src/test/resources/refaster/MethodThrowsRecipe.java b/src/test/resources/refaster/MethodThrowsRecipe.java index ede66c67..7f84a5e8 100644 --- a/src/test/resources/refaster/MethodThrowsRecipe.java +++ b/src/test/resources/refaster/MethodThrowsRecipe.java @@ -86,7 +86,7 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { new UsesType<>("java.nio.file.Files", true), new UsesType<>("java.nio.charset.StandardCharsets", true), new UsesType<>("java.nio.file.Path", true), - new UsesMethod<>("java.nio.file.Files readAllLines(..)") + new UsesMethod<>("java.nio.file.Files readAllLines(java.nio.file.Path, java.nio.charset.Charset)") ), javaVisitor ); diff --git a/src/test/resources/refaster/MultipleDereferencesRecipes.java b/src/test/resources/refaster/MultipleDereferencesRecipes.java index 5e71f8d3..590c12c3 100644 --- a/src/test/resources/refaster/MultipleDereferencesRecipes.java +++ b/src/test/resources/refaster/MultipleDereferencesRecipes.java @@ -113,7 +113,7 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { Preconditions.and( new UsesType<>("java.nio.file.Files", true), new UsesType<>("java.nio.file.Path", true), - new UsesMethod<>("java.nio.file.Files delete(..)") + new UsesMethod<>("java.nio.file.Files delete(java.nio.file.Path)") ), javaVisitor ); @@ -168,7 +168,7 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { }; return Preconditions.check( - new UsesMethod<>("java.lang.String isEmpty(..)"), + new UsesMethod<>("java.lang.String isEmpty()"), javaVisitor ); } diff --git a/src/test/resources/refaster/NestedPreconditionsRecipe.java b/src/test/resources/refaster/NestedPreconditionsRecipe.java index 0a8385d2..86c0cefa 100644 --- a/src/test/resources/refaster/NestedPreconditionsRecipe.java +++ b/src/test/resources/refaster/NestedPreconditionsRecipe.java @@ -99,11 +99,11 @@ public J visitNewClass(J.NewClass elem, ExecutionContext ctx) { Preconditions.or( Preconditions.and( new UsesType<>("java.util.HashMap", true), - new UsesMethod<>("java.util.HashMap (..)") + new UsesMethod<>("java.util.HashMap (int)") ), Preconditions.and( new UsesType<>("java.util.LinkedHashMap", true), - new UsesMethod<>("java.util.LinkedHashMap (..)") + new UsesMethod<>("java.util.LinkedHashMap (int)") ) ) ), diff --git a/src/test/resources/refaster/RefasterAnyOfRecipes.java b/src/test/resources/refaster/RefasterAnyOfRecipes.java index 0890cbd3..038b7dca 100644 --- a/src/test/resources/refaster/RefasterAnyOfRecipes.java +++ b/src/test/resources/refaster/RefasterAnyOfRecipes.java @@ -121,7 +121,7 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { }; return Preconditions.check( - new UsesMethod<>("java.lang.String length(..)"), + new UsesMethod<>("java.lang.String length()"), javaVisitor ); } @@ -193,11 +193,11 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { Preconditions.or( Preconditions.and( new UsesType<>("java.util.LinkedList", true), - new UsesMethod<>("java.util.LinkedList (..)") + new UsesMethod<>("java.util.LinkedList ()") ), Preconditions.and( new UsesType<>("java.util.Collections", true), - new UsesMethod<>("java.util.Collections emptyList(..)") + new UsesMethod<>("java.util.Collections emptyList()") ) ) ), diff --git a/src/test/resources/refaster/ShouldAddImportsRecipes.java b/src/test/resources/refaster/ShouldAddImportsRecipes.java index c6a068b4..f50b1fbc 100644 --- a/src/test/resources/refaster/ShouldAddImportsRecipes.java +++ b/src/test/resources/refaster/ShouldAddImportsRecipes.java @@ -111,7 +111,7 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { }; return Preconditions.check( - new UsesMethod<>("java.lang.String valueOf(..)"), + new UsesMethod<>("java.lang.String valueOf(java.lang.Object)"), javaVisitor ); } @@ -180,9 +180,9 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { Preconditions.or( Preconditions.and( new UsesType<>("java.util.Objects", true), - new UsesMethod<>("java.util.Objects equals(..)") + new UsesMethod<>("java.util.Objects equals(java.lang.Object, java.lang.Object)") ), - new UsesMethod<>("java.lang.Integer compare(..)") + new UsesMethod<>("java.lang.Integer compare(int, int)") ), javaVisitor ); @@ -294,8 +294,8 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { return Preconditions.check( Preconditions.and( new UsesType<>("java.nio.file.Path", true), - new UsesMethod<>("java.io.File exists(..)"), - new UsesMethod<>("java.nio.file.Path toFile(..)") + new UsesMethod<>("java.io.File exists()"), + new UsesMethod<>("java.nio.file.Path toFile()") ), javaVisitor ); diff --git a/src/test/resources/refaster/ShouldSupportNestedClassesRecipes.java b/src/test/resources/refaster/ShouldSupportNestedClassesRecipes.java index bf9a4ab4..80754825 100644 --- a/src/test/resources/refaster/ShouldSupportNestedClassesRecipes.java +++ b/src/test/resources/refaster/ShouldSupportNestedClassesRecipes.java @@ -111,7 +111,7 @@ public J visitBinary(J.Binary elem, ExecutionContext ctx) { }; return Preconditions.check( - new UsesMethod<>("java.lang.String length(..)"), + new UsesMethod<>("java.lang.String length()"), javaVisitor ); } @@ -165,7 +165,7 @@ public J visitBinary(J.Binary elem, ExecutionContext ctx) { }; return Preconditions.check( - new UsesMethod<>("java.lang.String length(..)"), + new UsesMethod<>("java.lang.String length()"), javaVisitor ); } diff --git a/src/test/resources/refaster/SimplifyBooleansRecipe.java b/src/test/resources/refaster/SimplifyBooleansRecipe.java index 46227cfb..1259fffe 100644 --- a/src/test/resources/refaster/SimplifyBooleansRecipe.java +++ b/src/test/resources/refaster/SimplifyBooleansRecipe.java @@ -83,7 +83,7 @@ public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { }; return Preconditions.check( - new UsesMethod<>("java.lang.String replaceAll(..)"), + new UsesMethod<>("java.lang.String replaceAll(java.lang.String, java.lang.String)"), javaVisitor ); } diff --git a/src/test/resources/refaster/UseStringIsEmptyRecipe.java b/src/test/resources/refaster/UseStringIsEmptyRecipe.java index 64ebc830..937438a1 100644 --- a/src/test/resources/refaster/UseStringIsEmptyRecipe.java +++ b/src/test/resources/refaster/UseStringIsEmptyRecipe.java @@ -83,7 +83,7 @@ public J visitBinary(J.Binary elem, ExecutionContext ctx) { }; return Preconditions.check( - new UsesMethod<>("java.lang.String length(..)"), + new UsesMethod<>("java.lang.String length()"), javaVisitor ); } diff --git a/src/test/resources/refaster/UsesMethodPrecondition.java b/src/test/resources/refaster/UsesMethodPrecondition.java new file mode 100644 index 00000000..04bbe8b8 --- /dev/null +++ b/src/test/resources/refaster/UsesMethodPrecondition.java @@ -0,0 +1,75 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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 foo; + +import com.google.errorprone.refaster.annotation.AfterTemplate; +import com.google.errorprone.refaster.annotation.BeforeTemplate; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.Formatter; +import java.util.List; + +public class UsesMethodPrecondition { + public static class Primitive { + @BeforeTemplate + BigDecimal before(double d) { + return new BigDecimal(d); + } + + @AfterTemplate + BigDecimal after(double d) { + return BigDecimal.valueOf(d); + } + } + + public static class Class { + @BeforeTemplate + String before(String s1, String s2) { + return s1.concat(s2); + } + + @AfterTemplate + String after(String s1, String s2) { + return s1 + s2; + } + } + + public static class Parameterized { + @BeforeTemplate + List before(String s) { + return Collections.singletonList(s); + } + + @AfterTemplate + List after(String s) { + return Arrays.asList(s); + } + } + + public static class Varargs { + @BeforeTemplate + String before(String format, String arg0) { + return new Formatter().format(format, arg0).toString(); + } + + @AfterTemplate + String after(String format, String arg0) { + return String.format(format, arg0); + } + } +} diff --git a/src/test/resources/refaster/UsesMethodPreconditionRecipes.java b/src/test/resources/refaster/UsesMethodPreconditionRecipes.java new file mode 100644 index 00000000..69338493 --- /dev/null +++ b/src/test/resources/refaster/UsesMethodPreconditionRecipes.java @@ -0,0 +1,296 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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 foo; + +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 java.util.*; + +import static org.openrewrite.java.template.internal.AbstractRefasterJavaVisitor.EmbeddingOption.*; + +/** + * OpenRewrite recipes created for Refaster template {@code foo.UsesMethodPrecondition}. + */ +@SuppressWarnings("all") +public class UsesMethodPreconditionRecipes extends Recipe { + /** + * Instantiates a new instance. + */ + public UsesMethodPreconditionRecipes() {} + + @Override + public String getDisplayName() { + return "`UsesMethodPrecondition` Refaster recipes"; + } + + @Override + public String getDescription() { + return "Refaster template recipes for `foo.UsesMethodPrecondition`."; + } + + @Override + public List getRecipeList() { + return Arrays.asList( + new PrimitiveRecipe(), + new ClassRecipe(), + new ParameterizedRecipe(), + new VarargsRecipe() + ); + } + + /** + * OpenRewrite recipe created for Refaster template {@code UsesMethodPrecondition.Primitive}. + */ + @SuppressWarnings("all") + @NonNullApi + public static class PrimitiveRecipe extends Recipe { + + /** + * Instantiates a new instance. + */ + public PrimitiveRecipe() {} + + @Override + public String getDisplayName() { + return "Refaster template `UsesMethodPrecondition.Primitive`"; + } + + @Override + public String getDescription() { + return "Recipe created for the following Refaster template:\n```java\npublic static class Primitive {\n \n @BeforeTemplate()\n BigDecimal before(double d) {\n return new BigDecimal(d);\n }\n \n @AfterTemplate()\n BigDecimal after(double d) {\n return BigDecimal.valueOf(d);\n }\n}\n```\n."; + } + + @Override + public TreeVisitor getVisitor() { + JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() { + final JavaTemplate before = JavaTemplate + .builder("new java.math.BigDecimal(#{d:any(double)})") + .build(); + final JavaTemplate after = JavaTemplate + .builder("java.math.BigDecimal.valueOf(#{d:any(double)})") + .build(); + + @Override + public J visitNewClass(J.NewClass 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 + ); + } + return super.visitNewClass(elem, ctx); + } + + }; + return Preconditions.check( + Preconditions.and( + new UsesType<>("java.math.BigDecimal", true), + new UsesMethod<>("java.math.BigDecimal (double)") + ), + javaVisitor + ); + } + } + + /** + * OpenRewrite recipe created for Refaster template {@code UsesMethodPrecondition.Class}. + */ + @SuppressWarnings("all") + @NonNullApi + public static class ClassRecipe extends Recipe { + + /** + * Instantiates a new instance. + */ + public ClassRecipe() {} + + @Override + public String getDisplayName() { + return "Refaster template `UsesMethodPrecondition.Class`"; + } + + @Override + public String getDescription() { + return "Recipe created for the following Refaster template:\n```java\npublic static class Class {\n \n @BeforeTemplate()\n String before(String s1, String s2) {\n return s1.concat(s2);\n }\n \n @AfterTemplate()\n String after(String s1, String s2) {\n return s1 + s2;\n }\n}\n```\n."; + } + + @Override + public TreeVisitor getVisitor() { + JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() { + final JavaTemplate before = JavaTemplate + .builder("#{s1:any(java.lang.String)}.concat(#{s2:any(java.lang.String)})") + .build(); + final JavaTemplate after = JavaTemplate + .builder("#{s1:any(java.lang.String)} + #{s2:any(java.lang.String)}") + .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( + new UsesMethod<>("java.lang.String concat(java.lang.String)"), + javaVisitor + ); + } + } + + /** + * OpenRewrite recipe created for Refaster template {@code UsesMethodPrecondition.Parameterized}. + */ + @SuppressWarnings("all") + @NonNullApi + public static class ParameterizedRecipe extends Recipe { + + /** + * Instantiates a new instance. + */ + public ParameterizedRecipe() {} + + @Override + public String getDisplayName() { + return "Refaster template `UsesMethodPrecondition.Parameterized`"; + } + + @Override + public String getDescription() { + return "Recipe created for the following Refaster template:\n```java\npublic static class Parameterized {\n \n @BeforeTemplate()\n List before(String s) {\n return Collections.singletonList(s);\n }\n \n @AfterTemplate()\n List after(String s) {\n return Arrays.asList(s);\n }\n}\n```\n."; + } + + @Override + public TreeVisitor getVisitor() { + JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() { + final JavaTemplate before = JavaTemplate + .builder("java.util.Collections.singletonList(#{s:any(java.lang.String)})") + .build(); + final JavaTemplate after = JavaTemplate + .builder("java.util.Arrays.asList(#{s:any(java.lang.String)})") + .build(); + + @Override + public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { + JavaTemplate.Matcher matcher; + if ((matcher = before.matcher(getCursor())).find()) { + maybeRemoveImport("java.util.Collections"); + 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.Collections", true), + new UsesType<>("java.util.List", true), + new UsesMethod<>("java.util.Collections singletonList(..)") + ), + javaVisitor + ); + } + } + + /** + * OpenRewrite recipe created for Refaster template {@code UsesMethodPrecondition.Varargs}. + */ + @SuppressWarnings("all") + @NonNullApi + public static class VarargsRecipe extends Recipe { + + /** + * Instantiates a new instance. + */ + public VarargsRecipe() {} + + @Override + public String getDisplayName() { + return "Refaster template `UsesMethodPrecondition.Varargs`"; + } + + @Override + public String getDescription() { + return "Recipe created for the following Refaster template:\n```java\npublic static class Varargs {\n \n @BeforeTemplate()\n String before(String format, String arg0) {\n return new Formatter().format(format, arg0).toString();\n }\n \n @AfterTemplate()\n String after(String format, String arg0) {\n return String.format(format, arg0);\n }\n}\n```\n."; + } + + @Override + public TreeVisitor getVisitor() { + JavaVisitor javaVisitor = new AbstractRefasterJavaVisitor() { + final JavaTemplate before = JavaTemplate + .builder("new java.util.Formatter().format(#{format:any(java.lang.String)}, #{arg0:any(java.lang.String)}).toString()") + .build(); + final JavaTemplate after = JavaTemplate + .builder("String.format(#{format:any(java.lang.String)}, #{arg0:any(java.lang.String)})") + .build(); + + @Override + public J visitMethodInvocation(J.MethodInvocation elem, ExecutionContext ctx) { + JavaTemplate.Matcher matcher; + if ((matcher = before.matcher(getCursor())).find()) { + maybeRemoveImport("java.util.Formatter"); + 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 UsesType<>("java.util.Formatter", true), + new UsesMethod<>("java.util.Formatter toString()"), + new UsesMethod<>("java.util.Formatter format(..)"), + new UsesMethod<>("java.util.Formatter ()") + ), + javaVisitor + ); + } + } + +}