[Lombok] Bug fixes part 2 - #7624
Open
Ivan Kochurkin (KvanTTT) wants to merge 16 commits into
Open
Conversation
…th companion blocks KT-88367
An interface holds no state to generate from and no constructor to
generate, and an annotation class can hold no member at all, so
`checkLombokAnnotations` reports `ANNOTATION_HAS_NO_EFFECT` for both.
Only `@ToString` and `@EqualsAndHashCode` acted on that, though; the
rest generated anyway, and not just uselessly:
- `@Log` put a companion object holding `log` into either kind, which
made the warning a lie - the logger was there and callable.
- `@NoArgsConstructor` put a `constructor()` into an interface, which
the backend refuses outright ("Interface must not have
constructors").
- `@Builder` generated a companion object, a `builder()` factory and a
builder class whose `build()` had no constructor to call, crashing
IR generation on an interface with "Sequence is empty.".
Extract the condition `ToStringGenerator`/`EqualsAndHashCodeGenerator`
already duplicated into `isUnsupportedLombokTarget`, and consult it at
the one choke point of each remaining generator: `isCompanionNeeded`,
shared by all three annotations that generate a companion object;
`LoggerGenerator` for the `log` property itself, which a user-declared
companion or `lombok.log.fieldIsStatic=false` reaches without going
through companion generation; `addIfNonClashing` for the constructor and
its static factory; and `extractBuilderWithDeclarations`, the funnel
every builder entry point goes through.
The two generators that take a companion object into account consult the
annotated class rather than the symbol being generated for, since for a
static member the latter is the companion object, which is neither an
interface nor an annotation class.
`@Builder` on a member function of an interface is deliberately left
alone: it builds whatever that function returns and is a legitimate
case, so only the class-level annotation is dropped.
That leaves `@Builder` a silent no-op on an interface and on an
annotation class: nothing is generated any more, but nothing is reported
either, because it allows the broad `KotlinTarget.CLASS` rather than
`CLASS_ONLY`. Narrowing that would also start warning about `@Builder`
on an enum and on an object, so it is postponed to a separate commit and
recorded as a TODO for now.
^KT-87871 Fixed
^KT-88701 Fixed
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tead of `CLASS` It prevents silent no-ops on unsupported Kotlin declarations such as annotation classes, objects, enums, and interfaces.
Code Owners
PR commands for maintainers
|
…de` was applied to a enum class" KT-88507
`java.lang.Enum` declares `equals` and `hashCode` final, so the ones
`@EqualsAndHashCode` generated didn't merely misbehave - the enum failed
verification and never loaded:
java.lang.VerifyError: class Color overrides final method
java.lang.Enum.equals(Ljava/lang/Object;)Z
Drop `KotlinTarget.ENUM_CLASS` from the annotation's allowed targets so
`ANNOTATION_HAS_NO_EFFECT` is reported, and stop the generator at the
same class kinds it already skips. This is where Lombok itself draws the
line: `HandleEqualsAndHashCode` checks `isClass`, which excludes an
interface, an enum, an annotation class and a record, and reports
"@EqualsAndHashCode is only supported on a class.". `@ToString` keeps
`ENUM_CLASS`, matching Lombok's `isClassOrEnum` check for it - only
`toString` is non-final in `Enum`.
`@Builder` needed the generator half of the same treatment. Reporting
alone left it a warning that lies, since a builder was still generated
and its `build()` called a constructor signature that doesn't exist - an
enum constructor takes the synthetic name and ordinal parameters - so it
failed with `NoSuchMethodError` at run time. Both annotations now share
`isUnsupportedLombokTargetOrEnumClass`, an enum class on top of
`isUnsupportedLombokTarget`; the predicate stays separate because `@Log`
and `@ToString` support an enum fine.
The box test that reproduced the `VerifyError` no longer needs
`IGNORE_BACKEND_K2`, and asserts instead that the enum keeps the
identity comparison it inherits.
^KT-88507 Fixed
^KT-87871
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An object is a single instance, so the identity comparison it already inherits is exactly what a generated `equals` amounts to, and a generated `hashCode` over its properties only weakens it - two calls on the one instance must agree, which identity gives for free. Lombok draws the same line: `HandleEqualsAndHashCode` checks `isClass`, and an object has no Java counterpart that check would accept. Drop `KotlinTarget.OBJECT` from the annotation's allowed targets, so both a standalone and a companion object are reported as `ANNOTATION_HAS_NO_EFFECT`, and generate nothing for either. With this, `@Builder` and `@EqualsAndHashCode` accept exactly one class kind between them, so replace `isUnsupportedLombokTargetOrEnumClass` - which had grown a name that listed its members rather than describing them - with `isPlainClass`, a single `classKind == ClassKind.CLASS`. That is precisely Lombok's own `isClass`, and it reads as the requirement it is at both use sites. A local class stays a plain class: it is supported by `@EqualsAndHashCode`, and for `@Builder` it is `isCompanionNeeded` that rules it out, since a local class can't hold the companion object a `builder()` needs. For `@Builder` this also drops the nested builder class that an annotated object still got. Nothing could reach it - its constructor was private and no `builder()` factory was generated, an object never getting a companion object - so this removes a declaration rather than changing what any code could call. ^KT-88614 Fixed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`lombok.log.fieldIsStatic` alone decides whether the logger is static, so putting a log annotation on a companion object rather than on the class holding it buys nothing - and with `fieldIsStatic=false` it did nothing whatsoever: `LoggerGenerator` dropped the annotation and no checker said a word about it. Replace `KotlinTarget.OBJECT` with `KotlinTarget.STANDALONE_OBJECT` in the allowed targets shared by all eight log annotations. `OBJECT` is the umbrella target that covers a companion object as well, and `COMPANION_OBJECT_LIST` and `OBJECT_LIST` differ precisely in their first entry, so the narrower target excludes a companion object while keeping a standalone one. `checkLombokAnnotations` consults no config, so `ANNOTATION_HAS_NO_EFFECT` is reported for either `fieldIsStatic` value - the same move that already prohibited `@Builder` and `@EqualsAndHashCode` on the kinds they generate nothing for. `LoggerGenerator` no longer looks at a log annotation on the companion object itself, only at the one on the class around it, so nothing is generated and the warning is not a lie. When both carry `@Log`, the one on the class keeps working: an inert annotation must not suppress one that has an effect. `FirLombokLogChecker` returns early for a companion object, which would otherwise be reported `LOG_PROPERTY_ALREADY_EXISTS` for a logger that is never generated. The logger a companion object does hold, generated from the annotation on its class, is still checked when that class is visited, `loggerContainer` being its companion object then. The box test keeps the annotated companion object, without the `log` usages it can no longer resolve, so codegen is still exercised. The diagnostics test for `fieldIsStatic=false` gains the companion object case it lacked, which is the reproducer of the issue. ^KT-88288 Fixed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… generator They are irrelevant or soon-to-be-deprecated in Lombok No new test data added because it's already covered by `diagnostics/kotlin/equalsAndHashCode.kt` ^KT-88620 Fixed
They are irrelevant or soon-to-be-deprecated in Lombok
Ivan Kochurkin (KvanTTT)
force-pushed
the
ikochurkin/lombok-bug-fixes-2
branch
from
August 20, 2026 21:43
67e60dc to
c03a54e
Compare
to support subtyping correctly ^KT-54072 Fixed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A value class *is* its underlying value: there is no instance to initialize field by field, and its constructors compile to static `constructor-impl` functions that must return that value. The generated constructor only called the superclass one, so `JvmInlineClassLowering` left its `INSTANCE_INITIALIZER_CALL` in place and the JVM backend failed with "Unexpected IR element found during code generation". `KotlinTarget` sees `@JvmInline value class` as a plain `CLASS`, so the `CLASS_ONLY` entry matched and the annotation was accepted. A value class cannot be expressed as a target at all, so `ImplementedAnnotationsInfo` states it separately with `isSupportedOnValueClass` and `ANNOTATION_HAS_NO_EFFECT` renders "value class" as the ineffective target. `AbstractConstructorGeneratorPart` bails out for one too, keeping the checker and the generator in agreement; the guard is deliberately not folded into `isUnsupportedLombokTarget`, which is shared with `@Log` and `@ToString` - both of which do work on a value class. Generating `C()` as `C(0)` was considered instead, but it needs a `this(...)`-delegating constructor rather than the super-call shape the generator builds, and `force`'s null-for-reference-types rule is unsound for a non-null Kotlin property. Lombok itself rejects `@NoArgsConstructor` on records for the same reason. ^KT-88705 Fixed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.