From e4c940915324553a291cc3afc0c6b54c7c14d518 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 2 Apr 2024 09:05:04 -0700 Subject: [PATCH] Handle unqualified instance method names in refaster Previously unqualified methods names were being handled using logic intended for local variables, which failed to match them. Unqualified instance method names are relatively rare in templates. The motivating example was a template intended to match on an anonymous class creation, where code in the class called a method from a superclass by its simple name. PiperOrigin-RevId: 621197168 --- .../errorprone/refaster/UMethodIdent.java | 62 +++++++++++++++++++ .../errorprone/refaster/UTemplater.java | 9 +++ .../refaster/TemplateIntegrationTest.java | 5 ++ .../UnqualifiedMethodTemplateExample.java | 22 +++++++ .../UnqualifiedMethodTemplateExample.java | 24 +++++++ .../template/UnqualifiedMethodTemplate.java | 33 ++++++++++ 6 files changed, 155 insertions(+) create mode 100644 core/src/main/java/com/google/errorprone/refaster/UMethodIdent.java create mode 100644 core/src/test/java/com/google/errorprone/refaster/testdata/input/UnqualifiedMethodTemplateExample.java create mode 100644 core/src/test/java/com/google/errorprone/refaster/testdata/output/UnqualifiedMethodTemplateExample.java create mode 100644 core/src/test/java/com/google/errorprone/refaster/testdata/template/UnqualifiedMethodTemplate.java diff --git a/core/src/main/java/com/google/errorprone/refaster/UMethodIdent.java b/core/src/main/java/com/google/errorprone/refaster/UMethodIdent.java new file mode 100644 index 00000000000..d9f393059a3 --- /dev/null +++ b/core/src/main/java/com/google/errorprone/refaster/UMethodIdent.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024 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; + +import static com.google.errorprone.refaster.Unifier.unifications; + +import com.google.auto.value.AutoValue; +import com.google.errorprone.util.ASTHelpers; +import com.sun.source.tree.Tree; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.ClassSymbol; +import com.sun.tools.javac.tree.JCTree.JCExpression; + +/** Identifier representing an unqualified instant method. */ +@AutoValue +public abstract class UMethodIdent extends UIdent { + public static UMethodIdent create(UClassIdent classIdent, CharSequence member, UType memberType) { + return new AutoValue_UMethodIdent(classIdent, StringName.of(member), memberType); + } + + public static UMethodIdent create(ClassSymbol classSym, CharSequence member, UType memberType) { + return create(UClassIdent.create(classSym), member, memberType); + } + + abstract UClassIdent classIdent(); + + @Override + public abstract StringName getName(); + + abstract UType memberType(); + + @Override + public JCExpression inline(Inliner inliner) throws CouldNotResolveImportException { + return inliner.maker().Ident(getName().inline(inliner)); + } + + @Override + protected Choice defaultAction(Tree node, Unifier unifier) { + Symbol symbol = ASTHelpers.getSymbol(node); + if (symbol != null) { + return classIdent() + .unify(symbol.getEnclosingElement(), unifier) + .thenChoose(unifications(getName(), symbol.getSimpleName())) + .thenChoose(unifications(memberType(), symbol.asType())); + } + return Choice.none(); + } +} diff --git a/core/src/main/java/com/google/errorprone/refaster/UTemplater.java b/core/src/main/java/com/google/errorprone/refaster/UTemplater.java index c762497387c..b763484ba34 100644 --- a/core/src/main/java/com/google/errorprone/refaster/UTemplater.java +++ b/core/src/main/java/com/google/errorprone/refaster/UTemplater.java @@ -354,6 +354,13 @@ private UStaticIdent staticMember(Symbol symbol) { template(symbol.asType())); } + private UMethodIdent method(Symbol symbol) { + return UMethodIdent.create( + (ClassSymbol) symbol.getEnclosingElement(), + symbol.getSimpleName(), + template(symbol.asType())); + } + private static final UStaticIdent ANY_OF; private static final UStaticIdent IS_INSTANCE; private static final UStaticIdent CLAZZ; @@ -622,6 +629,8 @@ public UExpression visitIdentifier(IdentifierTree tree, Void v) { switch (sym.getKind()) { case TYPE_PARAMETER: return UTypeVarIdent.create(tree.getName()); + case METHOD: + return method(sym); default: return ULocalVarIdent.create(tree.getName()); } 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 0fa97eb22e2..b93b3743235 100644 --- a/core/src/test/java/com/google/errorprone/refaster/TemplateIntegrationTest.java +++ b/core/src/test/java/com/google/errorprone/refaster/TemplateIntegrationTest.java @@ -379,4 +379,9 @@ public void typeArgumentsMethodInvocation() throws IOException { public void memberSelectAndMethodParameterDisambiguation() throws IOException { runTest("MemberSelectAndMethodParameterDisambiguationTemplate"); } + + @Test + public void unqualifiedMethod() throws IOException { + runTest("UnqualifiedMethodTemplate"); + } } diff --git a/core/src/test/java/com/google/errorprone/refaster/testdata/input/UnqualifiedMethodTemplateExample.java b/core/src/test/java/com/google/errorprone/refaster/testdata/input/UnqualifiedMethodTemplateExample.java new file mode 100644 index 00000000000..85415708176 --- /dev/null +++ b/core/src/test/java/com/google/errorprone/refaster/testdata/input/UnqualifiedMethodTemplateExample.java @@ -0,0 +1,22 @@ +/* + * Copyright 2024 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; + +/** Test data for {@code UnqualifiedMethodTemplate}. */ +public class UnqualifiedMethodTemplateExample { + public int example() { + return hashCode(); + } +} diff --git a/core/src/test/java/com/google/errorprone/refaster/testdata/output/UnqualifiedMethodTemplateExample.java b/core/src/test/java/com/google/errorprone/refaster/testdata/output/UnqualifiedMethodTemplateExample.java new file mode 100644 index 00000000000..06fb51e7f4a --- /dev/null +++ b/core/src/test/java/com/google/errorprone/refaster/testdata/output/UnqualifiedMethodTemplateExample.java @@ -0,0 +1,24 @@ +/* + * Copyright 2024 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.Objects; + +/** Test data for {@code UnqualifiedMethodTemplate}. */ +public class UnqualifiedMethodTemplateExample { + public int example() { + return Objects.hashCode(this); + } +} diff --git a/core/src/test/java/com/google/errorprone/refaster/testdata/template/UnqualifiedMethodTemplate.java b/core/src/test/java/com/google/errorprone/refaster/testdata/template/UnqualifiedMethodTemplate.java new file mode 100644 index 00000000000..1b637f80c1b --- /dev/null +++ b/core/src/test/java/com/google/errorprone/refaster/testdata/template/UnqualifiedMethodTemplate.java @@ -0,0 +1,33 @@ +/* + * Copyright 2024 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 java.util.Objects; + +public class UnqualifiedMethodTemplate { + @BeforeTemplate + public int before() { + return hashCode(); + } + + @AfterTemplate + public int after() { + return Objects.hashCode(this); + } +}