Skip to content

Skip UseEnumSetOf empty conversion for static fields to avoid circular class-init (#1157)#1161

Merged
timtebeek merged 2 commits into
mainfrom
tim/1157-enumset-circular-init
Jul 1, 2026
Merged

Skip UseEnumSetOf empty conversion for static fields to avoid circular class-init (#1157)#1161
timtebeek merged 2 commits into
mainfrom
tim/1157-enumset-circular-init

Conversation

@timtebeek

@timtebeek timtebeek commented Jul 1, 2026

Copy link
Copy Markdown
Member

UseEnumSetOf rewrites an empty Set.of() to EnumSet.noneOf(E.class). In a static field initializer, EnumSet.noneOf reflectively reads E's constants during class initialization. When two enums have a circular static dependency (one enum's constants carry a value from a sibling enum that also holds an EnumSet.noneOf(...) static field), this can re-enter a not-yet-initialized enum and throw a misleading ClassCastException("... not an enum") at runtime — even though the code compiles cleanly.

Fix

Skip the empty Set.of()EnumSet.noneOf(E.class) conversion when the assignment target is a static field. Static field initializers run during <clinit>, which is the only place the re-entrant class-init hazard exists; local variables and instance fields are unaffected and still convert (e.g. the existing dontHaveArgs test). The non-empty Set.of(E.X, ...) case is untouched since it does not use the reflective noneOf path.

Skip conversion for empty Set.of() in static field initializers to avoid ClassCastException.
@timtebeek timtebeek merged commit 5f18964 into main Jul 1, 2026
1 check passed
@timtebeek timtebeek deleted the tim/1157-enumset-circular-init branch July 1, 2026 13:04
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Jul 1, 2026
@protocol7

Copy link
Copy Markdown

Quick as usual, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

UseEnumSetOf introduces circular class-init ClassCastException

2 participants