From 420ffef1376121e82f245f7a334eab8f78684707 Mon Sep 17 00:00:00 2001 From: Stephan Schroevers Date: Sat, 17 Dec 2022 17:17:22 +0100 Subject: [PATCH 1/3] Fix JDK 20-ea build compatibility --- .../errorprone/refaster/UEnhancedForLoop.java | 103 ++++++++++++------ pom.xml | 1 + 2 files changed, 73 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java b/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java index 6993f0c5b24..18f7d5774e1 100644 --- a/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java +++ b/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java @@ -19,16 +19,14 @@ import static com.google.errorprone.refaster.Unifier.unifications; import com.google.auto.value.AutoValue; +import com.google.common.base.VerifyException; import com.google.errorprone.util.RuntimeVersion; import com.sun.source.tree.EnhancedForLoopTree; import com.sun.source.tree.Tree; import com.sun.source.tree.TreeVisitor; -import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; -import com.sun.tools.javac.tree.JCTree.JCExpression; -import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.tree.JCTree.JCVariableDecl; -import com.sun.tools.javac.tree.TreeMaker; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; /** * A {@link UTree} representation of a {@link EnhancedForLoopTree}. @@ -39,7 +37,69 @@ abstract class UEnhancedForLoop extends USimpleStatement implements EnhancedForLoopTree { public static UEnhancedForLoop create( UVariableDecl variable, UExpression elements, UStatement statement) { - return new AutoValue_UEnhancedForLoop(variable, elements, (USimpleStatement) statement); + // On JDK 20 and above the `EnhancedForLoopTree` interface contains a additional method + // `getDeclarationKind()`, referencing a type not available prior to JDK 20. AutoValue + // generates a corresponding field and accessor for this property. Here we find and invoke the + // generated constructor with the appropriate arguments, depending on context. + // See https://github.com/openjdk/jdk20/commit/2cb64a75578ccc15a1dfc8c2843aa11d05ca8aa7. + // TODO: Simplify this logic once JDK 19 and older are no longer supported. + return isCompiledWithJdk20Plus() + ? createJdk20PlusEnhancedForLoop(variable, elements, statement) + : createPreJdk20EnhancedForLoop(variable, elements, statement); + } + + private static boolean isCompiledWithJdk20Plus() { + return Arrays.stream(AutoValue_UEnhancedForLoop.class.getDeclaredMethods()) + .anyMatch(m -> "getDeclarationKind".equals(m.getName())); + } + + private static UEnhancedForLoop createPreJdk20EnhancedForLoop( + UVariableDecl variable, UExpression elements, UStatement statement) { + try { + return AutoValue_UEnhancedForLoop.class + .getDeclaredConstructor(UVariableDecl.class, UExpression.class, USimpleStatement.class) + .newInstance(variable, elements, statement); + } catch (IllegalAccessException + | InstantiationException + | InvocationTargetException + | NoSuchMethodException e) { + throw new LinkageError(e.getMessage(), e); + } + } + + private static UEnhancedForLoop createJdk20PlusEnhancedForLoop( + UVariableDecl variable, UExpression elements, UStatement statement) { + Object declarationKind = getVariableDeclarationKind(); + try { + return AutoValue_UEnhancedForLoop.class + .getDeclaredConstructor( + declarationKind.getClass(), + UVariableDecl.class, + UExpression.class, + USimpleStatement.class) + .newInstance(declarationKind, variable, elements, statement); + } catch (IllegalAccessException + | InstantiationException + | InvocationTargetException + | NoSuchMethodException e) { + throw new LinkageError(e.getMessage(), e); + } + } + + private static Object getVariableDeclarationKind() { + Class declarationKind; + try { + declarationKind = Class.forName("com.sun.source.tree.EnhancedForLoopTree$DeclarationKind"); + } catch (ClassNotFoundException e) { + throw new VerifyException("Cannot load `EnhancedForLoopTree.DeclarationKind` enum", e); + } + return Arrays.stream(declarationKind.getEnumConstants()) + .filter(v -> "VARIABLE".equals(v.toString())) + .findFirst() + .orElseThrow( + () -> + new VerifyException( + "Enum value `EnhancedForLoopTree.DeclarationKind.VARIABLE` not found")); } @Override @@ -68,31 +128,12 @@ public Kind getKind() { @Override public JCEnhancedForLoop inline(Inliner inliner) throws CouldNotResolveImportException { - return makeForeachLoop( - inliner.maker(), - getVariable().inline(inliner), - getExpression().inline(inliner), - getStatement().inline(inliner)); - } - - private static JCEnhancedForLoop makeForeachLoop( - TreeMaker maker, JCVariableDecl variable, JCExpression expression, JCStatement statement) { - try { - if (RuntimeVersion.isAtLeast20()) { - return (JCEnhancedForLoop) - TreeMaker.class - .getMethod("ForeachLoop", JCTree.class, JCExpression.class, JCStatement.class) - .invoke(maker, variable, expression, statement); - } else { - return (JCEnhancedForLoop) - TreeMaker.class - .getMethod( - "ForeachLoop", JCVariableDecl.class, JCExpression.class, JCStatement.class) - .invoke(maker, variable, expression, statement); - } - } catch (ReflectiveOperationException e) { - throw new LinkageError(e.getMessage(), e); - } + return inliner + .maker() + .ForeachLoop( + getVariable().inline(inliner), + getExpression().inline(inliner), + getStatement().inline(inliner)); } @Override diff --git a/pom.xml b/pom.xml index d9f2d78b615..515f8b7edb6 100644 --- a/pom.xml +++ b/pom.xml @@ -159,6 +159,7 @@ 11 + --add-exports=java.base/jdk.internal.javac=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED From 26876c9c4d9b0d6b74041d80c75af93e41302d02 Mon Sep 17 00:00:00 2001 From: Stephan Schroevers Date: Sun, 18 Dec 2022 10:00:05 +0100 Subject: [PATCH 2/3] Simplify `catch` clause --- .../google/errorprone/refaster/UEnhancedForLoop.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java b/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java index 18f7d5774e1..386cb8718c3 100644 --- a/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java +++ b/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java @@ -59,10 +59,7 @@ private static UEnhancedForLoop createPreJdk20EnhancedForLoop( return AutoValue_UEnhancedForLoop.class .getDeclaredConstructor(UVariableDecl.class, UExpression.class, USimpleStatement.class) .newInstance(variable, elements, statement); - } catch (IllegalAccessException - | InstantiationException - | InvocationTargetException - | NoSuchMethodException e) { + } catch (ReflectiveOperationException e) { throw new LinkageError(e.getMessage(), e); } } @@ -78,10 +75,7 @@ private static UEnhancedForLoop createJdk20PlusEnhancedForLoop( UExpression.class, USimpleStatement.class) .newInstance(declarationKind, variable, elements, statement); - } catch (IllegalAccessException - | InstantiationException - | InvocationTargetException - | NoSuchMethodException e) { + } catch (ReflectiveOperationException e) { throw new LinkageError(e.getMessage(), e); } } From 0b534d2e76ff377499348fea3b33666a9987a291 Mon Sep 17 00:00:00 2001 From: Stephan Schroevers Date: Tue, 20 Dec 2022 10:45:22 +0100 Subject: [PATCH 3/3] Revert the `UEnhancedForLoop#inline` changes --- .../errorprone/refaster/UEnhancedForLoop.java | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java b/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java index 386cb8718c3..803a322dda6 100644 --- a/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java +++ b/core/src/main/java/com/google/errorprone/refaster/UEnhancedForLoop.java @@ -24,8 +24,12 @@ import com.sun.source.tree.EnhancedForLoopTree; import com.sun.source.tree.Tree; import com.sun.source.tree.TreeVisitor; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; -import java.lang.reflect.InvocationTargetException; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.TreeMaker; import java.util.Arrays; /** @@ -122,12 +126,31 @@ public Kind getKind() { @Override public JCEnhancedForLoop inline(Inliner inliner) throws CouldNotResolveImportException { - return inliner - .maker() - .ForeachLoop( - getVariable().inline(inliner), - getExpression().inline(inliner), - getStatement().inline(inliner)); + return makeForeachLoop( + inliner.maker(), + getVariable().inline(inliner), + getExpression().inline(inliner), + getStatement().inline(inliner)); + } + + private static JCEnhancedForLoop makeForeachLoop( + TreeMaker maker, JCVariableDecl variable, JCExpression expression, JCStatement statement) { + try { + if (RuntimeVersion.isAtLeast20()) { + return (JCEnhancedForLoop) + TreeMaker.class + .getMethod("ForeachLoop", JCTree.class, JCExpression.class, JCStatement.class) + .invoke(maker, variable, expression, statement); + } else { + return (JCEnhancedForLoop) + TreeMaker.class + .getMethod( + "ForeachLoop", JCVariableDecl.class, JCExpression.class, JCStatement.class) + .invoke(maker, variable, expression, statement); + } + } catch (ReflectiveOperationException e) { + throw new LinkageError(e.getMessage(), e); + } } @Override