From 347f322f4b04255c7c5ad1fe41717c83735f284d Mon Sep 17 00:00:00 2001 From: Michael Keppler Date: Mon, 26 Aug 2024 19:06:34 +0200 Subject: [PATCH] Verify equality of template signatures Make sure that all templates belonging to a recipe have the same number, order and type for all the method arguments. This avoids accidental copy/paste errors which otherwise can lead to compiling recipe code, but wrong results at runtime. Fixes #107. --- .../processor/RefasterTemplateProcessor.java | 7 ++++ .../RefasterTemplateProcessorTest.java | 12 +++++++ .../refaster/SignatureMismatchCount.java | 32 +++++++++++++++++++ .../refaster/SignatureMismatchTypes.java | 32 +++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 src/test/resources/refaster/SignatureMismatchCount.java create mode 100644 src/test/resources/refaster/SignatureMismatchTypes.java 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 05e7f45f..58d4512b 100644 --- a/src/main/java/org/openrewrite/java/template/processor/RefasterTemplateProcessor.java +++ b/src/main/java/org/openrewrite/java/template/processor/RefasterTemplateProcessor.java @@ -735,11 +735,18 @@ public RuleDescriptor(JCTree.JCClassDecl classDecl, JCCompilationUnit cu, Contex // resolve so that we can inspect the template body boolean valid = resolve(); if (valid) { + Set signatures = new HashSet<>(); for (TemplateDescriptor template : beforeTemplates) { valid &= template.validate(); + signatures.add(template.method.getParameters().stream().map(p -> p.getType().toString()).collect(Collectors.joining(","))); } if (afterTemplate != null) { valid &= afterTemplate.validate(); + signatures.add(afterTemplate.method.getParameters().stream().map(p -> p.getType().toString()).collect(Collectors.joining(","))); + } + if (signatures.size() > 1) { + printNoteOnce("@Before and @After methods of a single recipe must have the same method signature", classDecl.sym); + valid = false; } } return valid ? this : null; diff --git a/src/test/java/org/openrewrite/java/template/RefasterTemplateProcessorTest.java b/src/test/java/org/openrewrite/java/template/RefasterTemplateProcessorTest.java index e010edc2..802f937a 100644 --- a/src/test/java/org/openrewrite/java/template/RefasterTemplateProcessorTest.java +++ b/src/test/java/org/openrewrite/java/template/RefasterTemplateProcessorTest.java @@ -106,6 +106,18 @@ void stringIsEmptyPredicate() { assertEquals(0, compilation.generatedSourceFiles().size(), "Not yet supported"); } + @ParameterizedTest + @ValueSource(strings = { + "Types", + "Count", + }) + void signatureMismatch(String error) { + Compilation compilation = compileResource("refaster/SignatureMismatch" + error + ".java"); + assertThat(compilation).succeeded(); + assertThat(compilation).hadNoteContaining("must have the same method signature"); + assertEquals(0, compilation.generatedSourceFiles().size(), "Must not generate recipe for mismatched templates"); + } + private static Compilation compileResource(String resourceName) { return compileResource(resourceName, new RefasterTemplateProcessor()); } diff --git a/src/test/resources/refaster/SignatureMismatchCount.java b/src/test/resources/refaster/SignatureMismatchCount.java new file mode 100644 index 00000000..a6c9e76d --- /dev/null +++ b/src/test/resources/refaster/SignatureMismatchCount.java @@ -0,0 +1,32 @@ +/* + * 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. + */ +import com.google.errorprone.refaster.annotation.AfterTemplate; +import com.google.errorprone.refaster.annotation.BeforeTemplate; + +import java.io.File; +import java.nio.file.Path; + +public class SignatureMismatchCount { + @BeforeTemplate + String before(File file) { + return "This method has 1 parameter"; + } + + @AfterTemplate + String after() { + return "This method has 0 parameters"; + } +} diff --git a/src/test/resources/refaster/SignatureMismatchTypes.java b/src/test/resources/refaster/SignatureMismatchTypes.java new file mode 100644 index 00000000..1c32d8b3 --- /dev/null +++ b/src/test/resources/refaster/SignatureMismatchTypes.java @@ -0,0 +1,32 @@ +/* + * 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. + */ +import com.google.errorprone.refaster.annotation.AfterTemplate; +import com.google.errorprone.refaster.annotation.BeforeTemplate; + +import java.io.File; +import java.nio.file.Path; + +public class SignatureMismatchTypes { + @BeforeTemplate + String before(File file) { + return "This method has a File typed parameter"; + } + + @AfterTemplate + String after(Path path) { + return "This method has a Path typed parameter"; + } +}