From 7cd5def1e6699e09b3d5f25c0d872e6b38d01807 Mon Sep 17 00:00:00 2001 From: Error Prone Team Date: Mon, 23 May 2022 13:19:16 -0700 Subject: [PATCH] Support void placeholder expressions in Refaster PiperOrigin-RevId: 450510643 --- .../google/errorprone/refaster/Template.java | 18 +++++++-- .../refaster/UPlaceholderExpression.java | 2 +- .../refaster/TemplateIntegrationTest.java | 5 +++ ...dExpressionPlaceholderTemplateExample.java | 30 +++++++++++++++ ...dExpressionPlaceholderTemplateExample.java | 30 +++++++++++++++ .../VoidExpressionPlaceholderTemplate.java | 38 +++++++++++++++++++ 6 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 core/src/test/java/com/google/errorprone/refaster/testdata/input/VoidExpressionPlaceholderTemplateExample.java create mode 100644 core/src/test/java/com/google/errorprone/refaster/testdata/output/VoidExpressionPlaceholderTemplateExample.java create mode 100644 core/src/test/java/com/google/errorprone/refaster/testdata/template/VoidExpressionPlaceholderTemplate.java diff --git a/core/src/main/java/com/google/errorprone/refaster/Template.java b/core/src/main/java/com/google/errorprone/refaster/Template.java index df1b5a16fd1..0fbbc435cf5 100644 --- a/core/src/main/java/com/google/errorprone/refaster/Template.java +++ b/core/src/main/java/com/google/errorprone/refaster/Template.java @@ -37,6 +37,7 @@ import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type.ForAll; import com.sun.tools.javac.code.Type.MethodType; +import com.sun.tools.javac.code.TypeTag; import com.sun.tools.javac.code.Types; import com.sun.tools.javac.comp.Attr; import com.sun.tools.javac.comp.AttrContext; @@ -139,7 +140,14 @@ protected List expectedTypes(Inliner inliner) throws CouldNotResolveImport Ordering.natural() .immutableSortedCopy( Iterables.filter(inliner.bindings.keySet(), PlaceholderExpressionKey.class))) { - result.add(key.method.returnType().inline(inliner)); + Type type = key.method.returnType().inline(inliner); + // Skip void placeholder expressions, because + // a) if the expected type is void, any actual type is acceptable + // b) these types are used as the argument types in a synthetic MethodType, and method + // argument types cannot be void + if (!type.getTag().equals(TypeTag.VOID)) { + result.add(type); + } } return List.from(result); } @@ -149,7 +157,7 @@ protected List expectedTypes(Inliner inliner) throws CouldNotResolveImport * bound to the @BeforeTemplate method parameters, concatenated with the types of the expressions * bound to expression placeholders, sorted by the name of the placeholder method. */ - protected List actualTypes(Inliner inliner) { + protected List actualTypes(Inliner inliner) throws CouldNotResolveImportException { ArrayList result = new ArrayList<>(); ImmutableList argNames = expressionArgumentTypes().keySet().asList(); for (int i = 0; i < expressionArgumentTypes().size(); i++) { @@ -177,7 +185,11 @@ protected List actualTypes(Inliner inliner) { Ordering.natural() .immutableSortedCopy( Iterables.filter(inliner.bindings.keySet(), PlaceholderExpressionKey.class))) { - result.add(inliner.getBinding(key).type); + Type keyType = key.method.returnType().inline(inliner); + // See comment in `expectedTypes` for why we skip void placeholder keys. + if (!keyType.getTag().equals(TypeTag.VOID)) { + result.add(inliner.getBinding(key).type); + } } return List.from(result); } diff --git a/core/src/main/java/com/google/errorprone/refaster/UPlaceholderExpression.java b/core/src/main/java/com/google/errorprone/refaster/UPlaceholderExpression.java index fc226f81f9c..6c579243221 100644 --- a/core/src/main/java/com/google/errorprone/refaster/UPlaceholderExpression.java +++ b/core/src/main/java/com/google/errorprone/refaster/UPlaceholderExpression.java @@ -147,7 +147,7 @@ public boolean reverify(Unifier unifier) { @Override protected Choice defaultAction(Tree node, Unifier unifier) { // for now we only match JCExpressions - if (placeholder().returnType().equals(UPrimitiveType.VOID) || !(node instanceof JCExpression)) { + if (!(node instanceof JCExpression)) { return Choice.none(); } JCExpression expr = (JCExpression) node; diff --git a/core/src/test/java/com/google/errorprone/refaster/TemplateIntegrationTest.java b/core/src/test/java/com/google/errorprone/refaster/TemplateIntegrationTest.java index f20ae9a8ad4..c928231983e 100644 --- a/core/src/test/java/com/google/errorprone/refaster/TemplateIntegrationTest.java +++ b/core/src/test/java/com/google/errorprone/refaster/TemplateIntegrationTest.java @@ -234,6 +234,11 @@ public void expressionPlaceholderAllowsIdentity() throws IOException { runTest("PlaceholderAllowsIdentityTemplate"); } + @Test + public void voidExpressionPlaceholder() throws IOException { + runTest("VoidExpressionPlaceholderTemplate"); + } + @Test public void blockPlaceholder() throws IOException { runTest("BlockPlaceholderTemplate"); diff --git a/core/src/test/java/com/google/errorprone/refaster/testdata/input/VoidExpressionPlaceholderTemplateExample.java b/core/src/test/java/com/google/errorprone/refaster/testdata/input/VoidExpressionPlaceholderTemplateExample.java new file mode 100644 index 00000000000..9128c43bdc1 --- /dev/null +++ b/core/src/test/java/com/google/errorprone/refaster/testdata/input/VoidExpressionPlaceholderTemplateExample.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 The Error Prone 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 + * + * http://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 com.google.errorprone.refaster.testdata; + +import java.util.List; + +/** Test data for {@code VoidExpressionPlaceholderTemplate}. */ +public class VoidExpressionPlaceholderTemplateExample { + public static void foo(String s) { + s.length(); + } + + public void positiveExample(List list) { + list.stream().forEach(x -> foo(x)); + } +} diff --git a/core/src/test/java/com/google/errorprone/refaster/testdata/output/VoidExpressionPlaceholderTemplateExample.java b/core/src/test/java/com/google/errorprone/refaster/testdata/output/VoidExpressionPlaceholderTemplateExample.java new file mode 100644 index 00000000000..234920701eb --- /dev/null +++ b/core/src/test/java/com/google/errorprone/refaster/testdata/output/VoidExpressionPlaceholderTemplateExample.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 The Error Prone 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 + * + * http://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 com.google.errorprone.refaster.testdata; + +import java.util.List; + +/** Test data for {@code VoidExpressionPlaceholderTemplate}. */ +public class VoidExpressionPlaceholderTemplateExample { + public static void foo(String s) { + s.length(); + } + + public void positiveExample(List list) { + list.forEach(x->foo(x)); + } +} diff --git a/core/src/test/java/com/google/errorprone/refaster/testdata/template/VoidExpressionPlaceholderTemplate.java b/core/src/test/java/com/google/errorprone/refaster/testdata/template/VoidExpressionPlaceholderTemplate.java new file mode 100644 index 00000000000..00c10f00df4 --- /dev/null +++ b/core/src/test/java/com/google/errorprone/refaster/testdata/template/VoidExpressionPlaceholderTemplate.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 The Error Prone 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 + * + * http://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 com.google.errorprone.refaster.testdata.template; + +import com.google.errorprone.refaster.annotation.AfterTemplate; +import com.google.errorprone.refaster.annotation.BeforeTemplate; +import com.google.errorprone.refaster.annotation.Placeholder; +import java.util.Collection; + +/** Test case with a void placeholder method that is used as an expression. */ +public abstract class VoidExpressionPlaceholderTemplate { + @Placeholder + abstract void consume(T t); + + @BeforeTemplate + void before(Collection collection) { + collection.stream().forEach(x -> consume(x)); + } + + @AfterTemplate + void after(Collection collection) { + collection.forEach(x -> consume(x)); + } +}