From bc86bfde63a794e0cdaa1d6380b88c193e4f9e83 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 8 Apr 2026 00:46:02 +0200 Subject: [PATCH] [JDK26] javac 26 updated how `var` declarations are stored. Fixed the problem and added a test to confirm. --- src/core/lombok/javac/handlers/HandleVal.java | 16 +++++++++++++- .../lombok/delombok/PrettyPrinter.java | 6 ++++-- src/utils/lombok/permit/Permit.java | 21 +++++++++++++++++-- .../after-delombok/ValUndenotable.java | 10 +++++++++ .../resource/before/ValUndenotable.java | 12 +++++++++++ 5 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 test/transform/resource/after-delombok/ValUndenotable.java create mode 100644 test/transform/resource/before/ValUndenotable.java diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index 8f4b1a86..a3b3dfb7 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2021 The Project Lombok Authors. + * Copyright (C) 2010-2026 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -123,6 +123,7 @@ public class HandleVal extends JavacASTAdapter { if (localNode.getSourceVersion() >= 10) { local.vartype = null; localNode.getAst().setChanged(); + VarDeclDeclKind.setDeclKindToVar(local); return; } @@ -211,4 +212,17 @@ public class HandleVal extends JavacASTAdapter { return null; } } + + private static class VarDeclDeclKind { + private static final Field declKind = Permit.permissiveGetField(JCVariableDecl.class, "declKind"); + private static final Field typePos = Permit.permissiveGetField(JCVariableDecl.class, "typePos"); + private static final Enum DECL_KIND_VAR = Permit.enumValue(JCVariableDecl.class.getName() + "$DeclKind", "VAR"); + + private static void setDeclKindToVar(JCVariableDecl decl) { + if (declKind != null) { + Permit.permissiveSet(declKind, decl, DECL_KIND_VAR); + Permit.permissiveSet(typePos, decl, decl.pos); + } + } + } } diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index ae0ce282..f379094a 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016-2025 The Project Lombok Authors. + * Copyright (C) 2016-2026 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -714,7 +714,9 @@ public class PrettyPrinter extends JCTree.Visitor { if (tree.vartype == null || tree.vartype.pos == -1 || endPos(tree.vartype) == -1) { print("var"); } else { - print(tree.vartype); + Object kind = readObject(tree, "declKind", null); + if (kind instanceof Enum && "VAR".equals(((Enum) kind).name())) print("var"); + else print(tree.vartype); } } finally { innermostArrayBracketsAreVarargs = false; diff --git a/src/utils/lombok/permit/Permit.java b/src/utils/lombok/permit/Permit.java index 36e38bcb..2f1699bd 100644 --- a/src/utils/lombok/permit/Permit.java +++ b/src/utils/lombok/permit/Permit.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2025 The Project Lombok Authors. + * Copyright (C) 2018-2026 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,6 +36,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; // sunapi suppresses javac's warning about using Unsafe; 'all' suppresses eclipse's warning about the unspecified 'sunapi' key. Leave them both. @@ -334,6 +335,15 @@ public class Permit { } } + public static boolean permissiveSet(Field f, Object receiver, Object newValue) { + try { + set(f, receiver, newValue); + return true; + } catch (Exception ignore) { + return false; + } + } + public static void reportReflectionProblem(Throwable initError, String msg) { if (!isDebugReflection()) return; System.err.println("** LOMBOK REFLECTION issue: " + msg); @@ -348,9 +358,16 @@ public class Permit { return Permit.sneakyThrow0(t); } - @SuppressWarnings("unchecked") private static T sneakyThrow0(Throwable t) throws T { throw (T)t; } + public static Enum enumValue(String enumTypeName, String enumValueName) { + try { + Class c = Class.forName(enumTypeName); + return Enum.valueOf(c, enumValueName); + } catch (Exception e) { + return null; + } + } } diff --git a/test/transform/resource/after-delombok/ValUndenotable.java b/test/transform/resource/after-delombok/ValUndenotable.java new file mode 100644 index 00000000..bef4fa6a --- /dev/null +++ b/test/transform/resource/after-delombok/ValUndenotable.java @@ -0,0 +1,10 @@ +// version 14: +public class ValUndenotable { + public void method(int arg) { + final var x = new Object() { + void foo() { + } + }; + x.foo(); + } +} \ No newline at end of file diff --git a/test/transform/resource/before/ValUndenotable.java b/test/transform/resource/before/ValUndenotable.java new file mode 100644 index 00000000..5baa16ba --- /dev/null +++ b/test/transform/resource/before/ValUndenotable.java @@ -0,0 +1,12 @@ +// version 14: +import lombok.val; + +public class ValUndenotable { + public void method(int arg) { + val x = new Object() { + void foo() { + } + }; + x.foo(); + } +}