The `PatternMatchingInstanceof` check currently only suggests a pattern variable when the first statement inside the `if` block is a direct assignment of a cast to a new local variable (e.g., `TargetType t = (TargetType) expr;`). I'd like to extend this to also cover blocks where the same cast of the checked expression appears multiple times in the body, without being immediately assigned to a variable.

**Acceptance criteria:**

1. **Multi‑cast replacement**
   When an `if (expr instanceof TargetType)` block contains one or more casts of `expr` to `TargetType` (or a subtype of `TargetType`), the check should offer a fix that:
   - introduces a pattern variable in the `instanceof` (e.g., `if (expr instanceof TargetType target)`)
   - replaces every occurrence of the cast expression [`(TargetType) expr`] with the new pattern variable.

2. **Variable name**
   The suggested pattern variable name should be derived from the simple name of the target type, with the first letter lowercased (e.g., `TargetType` → `targetType`). Name collisions with existing identifiers in scope are a known limitation and do not need to be prevented in this initial implementation.

3. **Expression handling**
   The replacement must work for casts that appear in different syntactic positions, including:
   - `((TargetType) expr).method()`
   - `foo((TargetType) expr)`
   The fix should replace the entire parenthesised cast expression (i.e., `((TargetType) expr)`) with the variable, so that member access or method invocations remain correct.

4. **Symbol and type safety**
   The `instanceof` expression must reference a variable symbol (not an arbitrary expression), and the cast target type must be a subtype of the type tested by `instanceof`. Only casts matching this relationship should be replaced; any other casts are ignored.

5. **Guard condition**
   The `instanceof` must appear directly in the condition of an `if` statement (or as the only/final part of a `&&` chain, with no intervening statements that could prevent the relationship from holding). Inverted conditions, `||` chains, and other control structures are not required to be handled.

6. **Source version**
   The check should be available when the compilation source level is **Java 17** or later (pattern matching for `instanceof` is a standard feature of Java 17), not limited to Java 21.

The original behavior – detecting and simplifying an immediate variable declaration – must continue to work as before.

Handle a bit more in PatternMatchingInstanceof: look for more than just an immediate variable cast.


The `AssertThrowsMinimizer` refactoring should avoid hoisting expressions out of `assertThrows` when doing so would change the set of checked exceptions that the enclosing method must handle or declare. When the asserted exception type is a checked exception, only hoist an expression if it is known to throw at least one checked exception that is a subtype of the asserted type. Expressions that throw only unchecked exceptions, or checked exceptions that are not subtypes of the asserted type, must not be hoisted. For `assertThrows` with unchecked exception types, the existing hoisting behavior remains unchanged.

**Acceptance criteria:**
- An expression that throws only unchecked exceptions (e.g., `RuntimeException`) must not be hoisted when the assertion targets a checked exception (e.g., `IOException`), even if the expression is otherwise safe to evaluate.
- An expression that throws a checked exception that is an exact match or subtype of the asserted checked exception may be hoisted.
- An expression that throws a checked exception that is not a subtype of the asserted checked exception must not be hoisted.
- An expression that throws multiple checked exceptions where at least one is a subtype of the asserted exception may be hoisted.
- Hoisting decisions for `assertThrows` targeting unchecked exceptions must continue to follow the pre-existing logic (i.e., no new restrictions are applied).

Restrict hoisting in AssertThrowsMinimizer when asserting checked exceptions.


The `StatementSwitchToExpressionSwitch` checker sometimes produces nested braces when a case body is a single block statement. If a case contains only a block (e.g., `{ stmt; break; }`), the fix should unwrap the block and place its statements directly in the arrow case body, without extra braces.

**Desired behavior:**
`case 0: { foo(); break; }` → `case 0 -> foo();`
not `case 0 -> { { foo(); break; } }`

This applies to all conversion modes (direct, return, assignment). The unwrapping should only happen when the case body consists of exactly one block statement; other cases (multiple statements, or non-block single statement) are unchanged. Any trailing `break` inside the block is still removed as usual.

Improve fixes for `StatementSwitchToExpressionSwitch`


## Bug: `AssertThrowsMinimizer` suggests duplicate variable names for multiple `assertThrows` in the same method

### Current behavior
When a method contains two (or more) `assertThrows` calls whose lambdas each contain an expression that the minimizer decides to hoist into a local variable, and the suggested variable name would be the same for both (for example, both involve `Foo.builder()`), the generated fix can produce duplicate local-variable declarations, resulting in code that does not compile.

### Expected behavior
For a single method, the checker must collect *all* `assertThrows` invocations that require hoisting and produce a suggested fix where every introduced local variable has a name that is unique within that method.

More precisely:

1. **Uniqueness across hoisted variables**:
   If two hoisted expressions would naturally map to the same name (e.g. both receive the name `builder`), the fix must disambiguate them by appending a numeric suffix starting from `2` to the later occurrence, producing names like `builder2`, `builder3`, etc., as needed.

2. **No shadowing of existing identifiers**:
   Generated names must not collide with any variable, parameter, or field that is already in scope at the point where the declaration would be inserted.

3. **Method-level analysis**:
   The decision about which names are available must be made by examining all `assertThrows` calls within the enclosing method at once, so that names used for one hoisted expression are known when choosing the name for another.

_(Until this is fixed, workarounds include manually renaming one of the lambdas or disabling the check per method.)_

AssertThrowsMinimizer: process an entire method at a time to create unique variable names


The `AvoidObjectArrays` check fires on methods that declare an `Object[]` parameter, even when the same API already exposes an `Iterable`-based overload that callers can use instead. In those cases the warning is noise: the API already offers a collection alternative, and flagging the array overload adds no value and could lead to unnecessary deprecation or migration work.

### Desired behavior
* `AvoidObjectArrays` **must not** report a warning for an `Object[]` method parameter if, in the same class or any ancestor type, there exists another method with the same name, the same return type, the same static/instance modifier, and exactly one parameter whose type is `java.lang.Iterable`.
* The check **must** continue to flag `Object[]` parameters when no such `Iterable` overload exists, including when the method signature differs in any other respect (name, return type, static-ness, or number/type of other parameters).
* The check **must** correctly handle the case where the method under inspection is itself that `Iterable` overload, avoiding an infinite self-match.
* The logic for finding a matching overload should be reusable (e.g., in `ASTHelpers`), making it straightforward for other checks (like `PreferJavaTimeOverload`, which already contains similar overload-detection code) to query for overloads with a single parameter of a given type.

Don't fire `AvoidObjectArrays` if an `Iterable`-based overload exists.


Subject: AssertThrowsMinimizer does not hoist when expected exception is a supertype of RuntimeException

Observed Behavior:
The `AssertThrowsMinimizer` bugpattern correctly identifies opportunities to hoist method calls out of `assertThrows` lambdas when the called method's declared checked exceptions are compatible with the expected exception type. However, it fails to hoist calls that *only* throw unchecked exceptions (subtypes of `RuntimeException`), even when the expected exception type is `Exception` or `Throwable`, which catch all unchecked exceptions. As a result the lambda retains unnecessary code.

Example that is not hoisted today (but should be):
```java
void example() {
  assertThrows(Exception.class, () -> Hoistable.create(Hoistable.getThingUnchecked()));
}
```
where `getThingUnchecked()` is declared to throw `RuntimeException` (or no checked exceptions at all).

Expected Behavior:
The minimizer should treat an expression as potentially throwing a matching exception whenever the expected exception type is a supertype of `java.lang.RuntimeException`. Since any expression can throw a `RuntimeException`, hoisting should be allowed for any expected exception type that is assignable from `RuntimeException` (e.g., `RuntimeException`, `Exception`, `Throwable`). In the example above, the call should be hoisted:
```java
void example() {
  Object t = Hoistable.getThingUnchecked();
  assertThrows(Exception.class, () -> Hoistable.create(t));
}
```

Impact:
This omission reduces the effectiveness of the minimizer; it leaves more code inside the lambda when the code could safely be moved out, potentially making tests harder to read and error messages less precise.

Context:
The rule currently considers only *checked* exception types when deciding if an expression can be hoisted. It should additionally account for the fact that all expressions can throw unchecked exceptions, and if the expected exception type is a supertype of `RuntimeException`, the expression’s potential unchecked exceptions are covered. The fix should affect the logic that determines whether a tree “throws a subtype of” the expected exception type. The same adjustment should apply when the expected exception is `RuntimeException` itself (since it is a supertype of itself).

`RuntimeException` is a subtype of `Exception`, so acknowledge that `Exception` implicitly catches runtime exceptions.


We need to extend the `NullNeedsCastForVarargs` check to cover `UsingCorrespondence` methods in Google Truth.
These methods accept varargs but are currently missed, leading to silent bugs when a bare `null` (or an array-cast null) is passed.

## Requested Behavior

- Detect incorrect `null` usage in the following `UsingCorrespondence` methods:
  - `containsExactly` (sole parameter is varargs)
  - `containsAtLeast`, `containsAnyOf`, `containsNoneOf` (varargs is the third parameter, after the correspondence and the expected elements)

- Provide a suggested fix: replace the problematic argument with `(ElementType) null`, where `ElementType` is the component type of the method’s varargs array parameter.

## Correctness / Safety Constraints

- The element type **must** be derived from the invoked method’s parameter types (specifically the component type of the last parameter’s array type), **not** from target-type inference on the call.
  This avoids breakage when receiver type arguments are raw, wildcarded, or otherwise not inferable, and it aligns with how the compiler resolves overloads.

- The check should still flag array-cast-of-null arguments (`(E[]) null`) in these positions; those should be replaced with a proper element cast, identical to the bare-`null` case.

- Already-correct casts (e.g. `(String) null`) must not be flagged.

- The check should continue to work for existing covered methods (e.g. `containsExactly` on `IterableSubject`, `Arrays.asList`, etc.) without regressions.

Expand NullNeedsCastForVarargs to cover `UsingCorrespondence`.


# Feature request: Flag JUnit4 `TestRule` fields missing a `@Rule` annotation

## Problem
In JUnit4 test classes, fields of a type that implements `org.junit.rules.TestRule` (e.g. `TemporaryFolder`, `ErrorCollector`) must be annotated with `@org.junit.Rule`, `@ClassRule`, or an equivalent annotation for them to be applied by the test runner. When such a field is present but not annotated, the rule is silently ignored, leading to tests that pass but do not behave as intended. Neither the IDE nor the compiler emits any warning.

## Desired behavior
Add a new Error Prone check that alerts the developer when a `TestRule` field appears in a JUnit4 test class but is **not** annotated with any recognized rule or injection annotation.

### Acceptance criteria

1. **Matching fields**
   - The check scans any class that is identified as a JUnit4 test class (using the same detection as other Junit4 checks, e.g. `@RunWith(JUnit4.class)`, known base classes, etc.).
   - Within such a class, it flags an instance or class field whose type is assignable to `org.junit.rules.TestRule` (including all sub-types).
   - The field must **not** be annotated with any of `@Rule`, `@ClassRule`, `@Inject`, or `@TightRule`.
   - **Private** fields are excluded from this check, because they are already covered by unused-variable analysis and annotating them would introduce other errors.
   - Fields whose initializer explicitly indicates they are being used elsewhere (e.g., via certain factory methods that register the rule) **may** be excluded in the future, but the initial implementation should not attempt that.

2. **Suppression for manually-applied rules (heuristic)**
   - If the field’s value is referenced anywhere in the file **outside of a member-select expression** (i.e., the field is used as a value, for example passed as an argument to a method like `RuleChain.outerRule(myRule)`, assigned to another variable, or returned from a method), the check **must not** flag it.
   - Conversely, if the field is only ever used to call methods on it (e.g., `folder.newFile()`) or not referenced at all, the check should still fire.

3. **Warning message**
   - The diagnostic message should clearly explain the problem:
     `This TestRule isn't annotated with @Rule, so won't be run.`

4. **Suggested fix**
   - If the field is missing `@Rule`, the fix should insert `@org.junit.Rule` (fully qualified) immediately before the field declaration, adding the necessary import if it is not already present.

5. **Non-interference**
   - The check must produce **no false positives** where the field already carries any of the “stop” annotations listed above, even if the type implements `TestRule`.
   - It must also not flag fields that are not recognized as TestRule sub-types.

6. **Scope**
   - Apply only at the compilation-unit level, ensuring the whole class body is visible.

---

### Example (positive case)

```java
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class MyTest {
  // BUG: Missing @Rule – the TemporaryFolder will never initialise.
  public final TemporaryFolder folder = new TemporaryFolder();

  @Test public void test() { ... }
}
```

The check emits a warning and offers to add `@org.junit.Rule` before `public final TemporaryFolder`.

### Example (negative case – correctly annotated)

```java
@Rule
public final TemporaryFolder folder = new TemporaryFolder();
```

No warning.

### Example (negative case – field passed to RuleChain)

```java
public final TemporaryFolder folder = new TemporaryFolder();
@Rule
public final RuleChain chain = RuleChain.outerRule(folder);
```

No warning, because `folder` is referenced outside a member-select expression (`RuleChain.outerRule(folder)`) and thus might be manually run.

RuleNotRun: try to detect JUnit `TestRule`s that are very plausibly not being run.


**Title:** `ClassInitializationDeadlock` false positives for subtypes with all-private constructors/non-static inner classes

**Background**
The `ClassInitializationDeadlock` checker flags cases where a static field initializer in a class `A` directly creates an instance of a subtype `B` that extends `A`. The JVM’s class-loading rules mean such a cycle can cause a deadlock if `B`’s initialization also triggers `A`’s initialization.

However, current analysis is overly aggressive – it warns even when the subtype cannot actually be instantiated unless `A` has already finished initializing. This generates noise that users then have to suppress.

**Requested behavior**
Add heuristics to **suppress** the warning when the subtype cannot cause a deadlock because:

1. **All constructors and static factory methods are private** (i.e., no non‑private constructor or non‑private static method).
   Such a class cannot be instantiated outside its compilation unit, so any instantiation that triggers `B`’s initialization is guaranteed to happen inside `A`’s own code, after `A`’s static initializer has already completed. The cycle is safe.

2. **The subtype is a non‑static inner class**.
   A non‑static inner class requires an enclosing instance of `A` to be created. That instance can only exist after `A`’s initialization completes, so the deadlock cannot occur.

Additionally, the checker should avoid scanning into any nested *classes* when searching for offending static field initializers. Only static fields directly declared in the class being checked are relevant; nested classes are separate top‑level scopes and their static fields do not participate in the same initialization cycle.

These heuristics are expected to eliminate the false positive patterns reported in issue [#2062](https://github.com/google/error-prone/issues/2062). The checker should remain conservative: if there is any non‑private constructor or static method (potential factory), the warning must still fire.

Add heuristics for classes with private constructors/factories, and for non-static inner classes


The `DeprecatedVariable` bug checker crashes with an internal error when it processes a record component annotated with `@Deprecated`.

**Observed behavior**
When running Error Prone on a Java file containing a record with a `@Deprecated` component parameter, the analysis fails with a crash. For example:
```java
public record Test(@Deprecated int x) {
  public Test {
    Objects.requireNonNull(x);
  }
}
```
The crash originates in the `DeprecatedVariable` checker, which is designed to flag pointless `@Deprecated` annotations on local variables and parameters.

**Expected behavior**
- Error Prone should not crash on such code.
- The checker should **not** report a warning for the record component parameter, because `@Deprecated` annotations on record components are automatically propagated to the generated getter method where they do have an effect. Flagging them here would be a false positive.

**Impact**
This prevents projects using records from adopting the `DeprecatedVariable` check, as any record with a deprecated component will cause the analysis to fail entirely.

Fix a crash in DeprecatedVariable on synthetic record trees


The `UnnecessaryLongToIntConversion` error-prone check currently reports a warning when a `long`/`Long` is needlessly converted to `int` to be passed as a `long` parameter, but it offers no automatic fixes.
Please teach the check to produce two suggested fixes at the flagged sites:

1. **Remove the unnecessary conversion** – simply pass the original `long`/`Long` value directly, discarding the cast or method that squeezed it to `int`.
2. **Use `Longs.constrainToRange()`** – replace the conversion with a call to `Longs.constrainToRange(originalValue, Integer.MIN_VALUE, Integer.MAX_VALUE)`, adding `import com.google.common.primitives.Longs` if it isn’t already present.

The fixes must work for the three typical patterns the check detects:
* a type cast: `(int) longExpr`
* static converter methods: `Ints.checkedCast(longExpr)`, `Math.toIntExact(longExpr)`
* the instance method: `longObj.intValue()`

The fix should correctly extract the inner expression (the `long` or `Long` value) regardless of whitespace around the cast or method parentheses, and use that expression text verbatim. For instance methods, the fix retains only the receiver (`x` from `x.intValue()`). No other changes to the expression’s context should be made.

When applied, both fixes must preserve the original semantics: the first fix passes the original `long`-typed expression directly, which is safe because the parameter type is already `long`; the second fix adds an explicit range‑check that corresponds to the recommendation already mentioned in the warning’s message.

Add suggested fixes for the UnnecessaryLongToIntConversion error prone check.


**Title:** ReturnMissingNullable should recognize `Optional.orNull()` and `Optional.orElse(null)` as potentially null-returning expressions

**Current behavior (missing detection):**
The `ReturnMissingNullable` check correctly flags methods that can return `null` by examining direct null literals, conditional expressions with a null branch, etc. However, it does **not** recognize two common Optional idioms that can also produce `null`:
- `com.google.common.base.Optional.orNull()` – returns the contained value if present, else `null`.
- `java.util.Optional.orElse(null)` – returns the given default, which is `null`.

Because these expressions are not flagged, the check misses opportunities to suggest `@Nullable` annotations, and the code may hide potential NPEs.

**Expected behavior (acceptance criteria):**
1. **`Optional.orNull()` is a null-returning branch**
   Any method whose return expression is a call to `com.google.common.base.Optional.orNull()` should be treated as “definitely having a null branch” and flagged, requiring the method’s return type to be declared `@Nullable`.

2. **`Optional.orElse(null)` with a literal `null` argument is a null-returning branch**
   When the single argument to `java.util.Optional.orElse(...)` is the literal `null` (i.e., the source code writes `orElse(null)`), the call should also be treated as a definite null branch and flagged accordingly.

3. **`orElse` with a non-null argument must *not* be flagged**
   If the argument to `orElse` is any expression that is not the literal `null` (even if that expression could evaluate to `null` at runtime), the check should **not** flag it in this iteration. For example `orElse("")` or `orElse(someVariable)` should remain unflagged. (Future extensions may handle more complex null-propagating arguments, but that is out of scope for now.)

**Non-obvious edge cases & safety constraints:**
- The recognition must be scoped exactly to the two specified APIs:
  - `com.google.common.base.Optional.orNull()`
  - `java.util.Optional.orElse(Object)`
- For `orElse`, we only inspect the argument for a `null` literal; no sophisticated nullness analysis of other expressions is needed.
- Method references, lamdas that delegate to `orNull` or `orElse(null)`, etc., are not required to be handled (they can be left as future work).
- The check must not produce false positives when the return type is primitive (that’s already prevented elsewhere, but it’s worth mentioning that the null branch analysis should still be sound).

Recognize optional.orNull()/orElse(null) as having a definitely null branch.


Extend the `OptionalNotPresent` check to also flag calls to `optional.get()` inside an `if` block whose condition is `optional.isEmpty()`, when the optional is `java.util.Optional`. The condition must be the bare `isEmpty()` call (not wrapped in a logical complement or other expression), and the optional variable must not be reassigned between the condition and the `get()` call. Existing behavior for `!optional.isPresent()` (both Guava and JDK `Optional`) remains unchanged.

Handle the JDK 11 `Optional#isEmpty` is `OptionalNotPresent`


The `ImpossibleNullComparison` check (formerly summarized as “Protobuf fields cannot be null”) currently only flags null comparisons on protobuf field getters. However, there are several other common Java APIs whose return values are never null, and comparing them to null is almost certainly a bug.

**Observed problem**
Code like `optional.get() == null`, `multimap.get(key) == null`, or Guava `Optional.get() == null` compiles without any warning, yet these expressions can never be null (or are at least misleading). Developers inadvertently write such comparisons, and the check provides no diagnostic or fix.

**Expected behavior**
The checker should detect null comparisons of the following method results and offer meaningful suggested fixes:

1. `java.util.Optional.get()` and `orElseThrow()`
   ⇒ `x.get() == null` → `x.isEmpty()`
   ⇒ `x.get() != null` → `x.isPresent()`

2. `com.google.common.base.Optional.get()`
   ⇒ `x.get() == null` → `!x.isPresent()`
   ⇒ `x.get() != null` → `x.isPresent()`

3. `com.google.common.collect.Multimap.get(key)` (including subinterfaces like `ListMultimap`)
   ⇒ `map.get(key) == null` → `!map.containsKey(key)`
   ⇒ `map.get(key) != null` → `map.containsKey(key)`

The summary message should be updated to a more general statement, e.g., “This value cannot be null, and comparing it to null may be misleading.”

**Flag for incremental rollout**
Because expanding the scope could introduce new diagnostics in existing codebases, provide an opt-out flag for the newly handled APIs. Specifically, a boolean flag `ImpossibleNullComparison:MatchOptionalAndMultimap` (defaulting to `true`). When set to `false`, the check should only look at protobuf field getters as before, ignoring Optional and Multimap methods entirely.

**Edge cases / safety constraints**
- For `Multimap.get()`, the suggested fix must preserve the original key argument (`s.getSourceForNode(argument)`).
- The fix should only apply when the receiver expression tree unambiguously matches the recognized method (exact class/interface matches).
- No fix should be suggested if the matched method has a different semantics (e.g., proto getters remain unchanged).
- The flag should not affect the existing protobuf handling or the updated summary.

This expansion makes the check useful beyond protobuf code and helps catch common null-comparison mistakes with widely used Guava and JDK APIs.

Handle Optional/Multimap.get in ImpossibleNullComparison.


We want to catch a specific code smell where a developer explicitly captures a return value that is known to be ignorable into a variable named `unused`. This is misleading: if the result is ignorable, there’s no reason to bind it to a variable just to discard it.

**Proposed new check** – add a checker (initially disabled) that warns when the return value of a method or constructor directly annotated `@CanIgnoreReturnValue` is assigned to a variable whose name is exactly `unused`.

**Scope & behaviour**
- Warn on **local variable declarations** like
  `var unused = someIgnorableCall();`
  and **simple assignments** like
  `unused = someIgnorableCall();`
  when the right-hand side is a method invocation or constructor call (`new …`) where the called element carries `@CanIgnoreReturnValue`.
- The suggested fix: replace the whole declaration/assignment with a bare expression statement (e.g. `someIgnorableCall();`).
- **Name matching is exact** – only the identifier `unused` triggers the check. Variants such as `unusedFoo`, `Unused`, `_unused` are deliberately ignored.
- **Exclude** try-with-resources resource specifications. For example,
  `try (Closeable unused = getResource()) { … }`
  must not be flagged, because the variable is required for resource lifecycle management even if the resource itself is ignorable.
- Severity: `WARNING`.

**Non-goals for the initial implementation**
- No handling of qualified `this.unused` or field references.
- No inference of ignorability beyond the direct presence of `@CanIgnoreReturnValue` (i.e., we don’t try to detect “return this” patterns or void-return overrides).

**Placement**
- Add the new checker under `com.google.errorprone.bugpatterns.checkreturnvalue`, alongside `CanIgnoreReturnValueSuggester` and `NoCanIgnoreReturnValueOnClasses`.
- Register the checker in `BuiltInCheckerSuppliers` as a **disabled check** (so it can be evaluated before promoting it to enabled warnings).

Warn when assigning an ignorable method invocation to an `unused` variable (currently disabled).


Add a flag to `GuardedByChecker` (off by default) that reports errors at access sites when the lock string in a `@GuardedBy` annotation cannot be resolved. This handles cases where declaration-site diagnostics are suppressed, or the lock references a private member not visible in an interface jar. When enabled via `-XepOpt:GuardedByChecker:reportMissingGuards=true`, any access to a `@GuardedBy` member whose lock string fails to bind should produce an error containing the unresolvable lock string. Default behavior (flag omitted or false) must remain unchanged.

Report an error for uses of `@GuardedBy` members with unresolvable locks


`SuggestedFixes.qualifyType(VisitorState, SuggestedFix.Builder, TypeMirror)` crashes or produces incorrect output when given a type that contains wildcards (`?`, `? extends T`, `? super T`).
Add support for `javax.lang.model.type.WildcardType` so that it generates syntactically correct Java source: `?` for unbounded, `? extends Bound`, and `? super Bound`.

Also fix the formatting of type argument lists in declared types: insert a space after each comma (`, → , `) to match standard Java style and align with output that users will write.

Handle wildcard types in `SuggestedFixes.qualifyType`


**Feature Request: Simplify unnecessary block lambdas in `assertThrows` calls**

When writing JUnit tests, developers often use `org.junit.Assert.assertThrows` with a lambda to wrap the code that is expected to throw. A common pattern is to write a block lambda even when the body is a single expression statement:

```java
assertThrows(IOException.class, () -> {
    doSomething();
});
```

This is visually noisier than it needs to be. We want Error Prone to detect such cases and automatically suggest converting the block lambda to an expression lambda, while preserving any comments that appear inside the block.

**Acceptance criteria:**

1. **Trigger condition** – The check shall fire on calls to `org.junit.Assert.assertThrows` (any static variant) where:
   - The last argument is a lambda expression with a block body.
   - The block body contains exactly one statement.
   - That statement is an expression statement (e.g., method call, assignment, `new`, `instanceof`, etc.), but *not* a variable declaration, control-flow statement, or any other non-expression statement.

2. **Suggested fix** – The tool shall propose a fix that rewrites the block lambda to an expression lambda:
   - The surrounding braces (`{` and `}`) are removed.
   - Any line or block comments that appear **inside** the original block, either **before** the expression statement or **after** it (up to the block’s closing brace), must be preserved. The fix shall move such comments to the corresponding position relative to the expression:
     - Comments before the statement become leading comments for the expression (inserted just before the expression, separated by a newline if needed).
     - Comments after the statement become trailing comments (inserted after the expression, separated by a newline from the expression or from the closing parenthesis of `assertThrows`).
   - If there are no comments, the fix simply removes the braces with no added characters.

3. **No false positives** – The check shall **not** fire when:
   - The lambda argument is already an expression lambda (no block).
   - The block body contains zero, or more than one, statement.
   - The single statement is not an expression statement (e.g., `if`, `for`, `try`, variable declaration, `throw`, `return` inside a void lambda).
   - The method called is not `assertThrows` (e.g., `assertDoesNotThrow`, other assertion helpers) unless they match the same signature constraint in the future—initially only `assertThrows`.

4. **Severity** – Warning.

This improvement would keep test code concise while retaining any in-line documentation, aligning with best practices for lambda readability.

Discourage unnecessary block lambdas in assertThrows


**Title:** Make `InlineMeValidator` work with any annotation named `@InlineMe`, not just the built-in annotation class

**Context**
The `InlineMeInliner` bug checker already recognizes any annotation whose simple name is `InlineMe` (regardless of package) when deciding if a call should be inlined. However, the `InlineMeValidator` bug checker still requires the exact `com.google.errorprone.annotations.InlineMe` annotation type to validate that the annotation matches the method body. This asymmetry means that users who define their own `@InlineMe` annotation (with the same element contract) cannot rely on the validation error-prone provides.

**Request**
Update `InlineMeValidator` to validate any annotation present on a method that has the simple name `InlineMe`. The annotation must define:

- `String replacement()` – required
- `String[] imports()` – optional, default `{}`
- `String[] staticImports()` – optional, default `{}`

The validator should work without a compile-time dependency on the `com.google.errorprone.annotations.InlineMe` class. Tools or libraries that ship a custom `@InlineMe` annotation should get the same correctness checks regarding the annotation content vs. the inferred method-body expansion.

**Non‑obvious edge cases / safety**

- The validator must not break if the annotation contains elements beyond the three listed above (custom extension fields). For now, extra elements can be silently ignored; a future improvement may warn about them, but that is out of scope here.
- The annotation detection must be robust to different packages; use simple‑name matching only, mirroring the approach already used in the inliner.
- The fix should remain independent of the annotation class’s presence on the compilation classpath – reading attribute values must happen through raw `Attribute.Compound` rather than through a loaded annotation instance.

**Internal references**

- Bug checker class: `com.google.errorprone.bugpatterns.inlineme.Validator`
- The helper `InlineMeData` currently has `fromAnnotationInstance(InlineMe)`; the validator will need an equivalent factory that builds `InlineMeData` from symbol‑level annotation data, using the same element names.
- The `Inliner` already uses `hasDirectAnnotationWithSimpleName` to locate `@InlineMe`; the validator should adopt the same pattern.

Enable InlineMe `Validator` for any annotation with the simple name `@InlineMe`.


In the `UnusedVariable` checker, when a local variable is declared but never read, and later reassigned, one of the suggested fixes attempts to turn the reassignment into a declaration by prepending the variable’s type. This can produce invalid code when the right‑hand side of the reassignment is already a top‑level expression (for example, a method invocation, another assignment, or a `new` expression). In such cases the type‑prefix fix is not needed to make the code compile, and the result is incorrect.

**Acceptance criteria:**

1. If an unused local variable is reassigned with an expression whose tree kind is a top‑level expression (e.g. `METHOD_INVOCATION`, `ASSIGNMENT`, `NEW_CLASS`, `VARIABLE`), the `UnusedVariable` checker must **not** suggest a fix that prepends the variable’s type to the reassignment.
2. The checker may still offer the existing fixes that either discard the entire variable (and any side effects) or retain only the side‑effectful parts as standalone statements.
3. If the reassignment’s right‑hand side is *not* a top‑level expression (e.g. a simple literal, a binary operation, a cast), the type‑prepending fix may still be offered as before.
4. The decision should be based on the AST kind of the expression assigned in the reassignment, not on the kind of the statement containing it.
5. No other suggested fixes for `UnusedVariable` should regress in behaviour or correctness.

Only prepend types to UnusedVariable fixes if they need it.


We need an Error Prone check that flags `x.equals(null)` in production code and suggests replacing it with a null-comparison using `==`/`!=`.

**Background**
The `Object.equals` contract states that for any non-null `x`, `x.equals(null)` must return `false`. If `x` is `null`, the call throws `NullPointerException`. As a result, `x.equals(null)` almost never behaves as the author intended – it is either always `false` or it crashes. The intended logic is nearly always a null-check, writable as `x == null` or `x != null`.

**Requested checker behavior** (WARNING severity, FRAGILE_CODE tag)

1. **Detection**
   Flag any invocation that matches `receiver.equals(null)` where the receiver is any expression and the single argument is a null literal.

2. **Suggested fix**
   - For `receiver.equals(null)` → replace the invocation with `receiver == null`.
   - For `!receiver.equals(null)` → replace the entire negated expression with `receiver != null`. The diagnostic must be placed on the enclosing `!` expression so the fix replaces the correct tree node.

3. **Suppression in test code**
   Do **not** report when the call appears in contexts where it is plausibly testing the `equals` contract:
   - Inside a JUnit 4 test class (recognized by the existing `isJUnitTestCode` mechanism).
   - Inside a TestNG test class – a class annotated with any annotation from the `org.testng` package. (This requires extending the existing TestNG matching to also detect annotations on classes, not just methods.)
   - Inside a class that directly extends `org.junit.Assert` or `junit.framework.Assert`.
   - Inside an assertion call, specifically any expression directly enclosed by a static method invocation on `junit.framework.Assert`, `org.junit.Assert`, `com.google.common.truth.Truth`, or `com.google.common.truth.Truth8` (e.g., `assertFalse(x.equals(null))` or `Truth.assertThat(x.equals(null)).isFalse()`).

4. **Non‑matches**
   - Any argument other than a null literal: `x.equals(y)`.
   - Static equals-like methods (e.g., `Objects.equals`, `Arrays.equals`).
   - Calls where the method is not `Object.equals` (instance equals with a single `Object` parameter).

**Acceptance criteria example**
- In a plain class, `return x.equals(null);` triggers a warning with a fix to `return x == null;`.
- `if (!obj.equals(null)) { … }` triggers a warning on the `!` expression with a fix to `if (obj != null)`.
- The same code in a `@RunWith(JUnit4.class)` class or a `@Test` (TestNG) annotated class produces no warning.
- A helper extending `org.junit.Assert` containing `x.equals(null)` outside an assert call still suppresses the warning.
- `assertFalse(x.equals(null))` does **not** trigger the check.
- `x.equals(y)` for any identifier `y` is ignored.

The checker should be added to the default enabled warnings set alongside related `Equals*` checks.

Suggest comparison by value for `x.equals(null)`


**Title:** Static initialisers that capture the current time (e.g. `Instant.now()`) produce stale values

**Description**
Accessing the system clock in a static initialiser — such as a `static` field initialiser or a `static { ... }` block — records the time at class-loading. This value is then permanently baked into the class and never updated, which is almost always a bug rather than intentional caching.

For example:
```java
private static final Instant CREATED = Instant.now();   // bad
```
or equivalent calls on `java.time.InstantSource` / `com.google.common.time.TimeSource`.

Instance fields, method bodies, lambdas, and method references are **not** problematic because they execute on demand.

**Desired behaviour**
A new Error Prone check should flag calls that obtain the current time when they appear directly inside:

* the initialiser of a `static` field (unless the field type is `com.google.common.flags.Flag`, which legitimately captures the value at start‑up), and
* a `static` initialiser block.

It must **not** descend into methods, constructors, lambdas, or member references encountered within that static context, since those do not run at class-loading.

To reduce noise, the check should be suppressed for test-only targets (code already flagged as test code).

The specific APIs to detect are:
* `static` method `now()` on any class in package `java.time` (e.g. `Instant.now()`, `LocalDate.now()`, etc.)
* instance method `instant()` on any subtype of `java.time.InstantSource`
* instance method `instant()` on any subtype of `com.google.common.time.TimeSource`

**Impact**
Without this warning, developers accidentally capture clock readings at class-loading, leading to logs, timers, and decisions that silently become stale over time. The check would catch these cases at compile time and prompt developers to refactor to a more appropriate pattern (e.g. pulling the call into a method or using a `Supplier`).

TimeInStaticInitializer: flag accesses of the system time in obviously static contexts.


As a maintainer, I’d like us to close a gap in the `Immutable` checker: currently we check that lambdas implementing `@Immutable` interfaces do not capture mutable state or call instance methods on non-`@Immutable` enclosing instances, but we do **not** perform the same checks for anonymous classes that implement `@Immutable` interfaces.

**Request**:
Extend the checker so that, when an anonymous class implements an `@Immutable` interface (i.e., its direct supertype is `@Immutable`), we report the same kind of violations that we already report for lambdas:

- Closing over a local variable with a non-immutable type.
- Closing over a field (from an enclosing instance) that is not `@Immutable`.
- Invoking an instance method on a non-`@Immutable` enclosing type (capturing a mutable `this`).

**Nuances to get right**:

1. **Supertype methods should not be flagged**
   An anonymous class may extend a non-`@Immutable` superclass while also implementing the `@Immutable` interface. Calls to inherited methods (e.g., `foo()` defined in a non-`@Immutable` superclass) should **not** be considered captures of mutable state, because they belong to the anonymous class’s own type, not to an enclosing instance.
   *Behavior*: For unqualified method invocations (no explicit receiver), if the effective enclosing type of the method is the anonymous class itself (or its supertype), skip the violation.

2. **Own variables inside the anonymous class are fine**
   Mutable fields declared directly inside the anonymous class body, or mutable local variables declared inside the method body, should not trigger a capture violation (the same as we already handle in lambdas).

3. **Flag gating**
   Provide a flag `ImmutableChecker:HandleAnonymousClasses` (default `true`) so that users can temporarily disable this new check if needed, similar to how we already allow controlling related behavior.

4. **Error messages**
   The reported error should clearly indicate the anonymous class and the specific problem, analogous to the existing lambda messages (e.g., “This anonymous class implements @Immutable interface 'Foo', but …”).

This will bring anonymous class implementations in line with lambdas and improve the safety of functional-style APIs that rely on `@Immutable` implementations.

ImmutableChecker: check any variables that anonymous classes close around.


**Feature Request: Broaden `@CanIgnoreReturnValue` suggestion to builder-style methods**

The `CanIgnoreReturnValueSuggester` check already suggests the annotation for methods that literally `return this`. Many builder APIs, however, rely on abstract or interface declarations where the body is not visible, yet the contract implies the object is returned and the result can be ignored. The check should be extended to detect these “builder-looking” methods using a simple naming heuristic, while still respecting AutoValue patterns where annotation is not appropriate.

**Acceptance Criteria**

1.  **Builder method detection**
    If a method’s enclosing type has a simple name containing `Builder` (e.g., `MyClassBuilder`, `Builder`, `Foo_Builder`) **and** the method name starts with `add`, `set`, `with`, or `clear`, the checker should suggest adding `@CanIgnoreReturnValue` (and removing any `@CheckReturnValue` if present), regardless of whether the body is visible or returns `this`.
    This applies to both concrete and abstract methods in regular classes/interfaces.

2.  **AutoValue exclusion**
    AutoValue’s annotation processor handles its own builder contracts. To prevent conflicting or spurious suggestions, the checker must **not** suggest `@CanIgnoreReturnValue` for abstract methods whose enclosing type is annotated with `@AutoValue.Builder` or `@AutoBuilder` (from `com.google.auto.value`).

3.  **Precedence and existing behavior**
    The existing detection of `return this` and delegation to already-annotated methods remains unchanged and takes priority. The naming heuristic is an additional trigger: if either condition is true, the suggestion fires.

4.  **Fix correctness**
    The generated fix must properly qualify the annotation, handle removal of `@CheckReturnValue`, and handle any import conflicts, consistent with the current check’s behavior.

**Example scenarios**

| Enclosing type | Method signature | Detected? | Reason |
|----------------|------------------|-----------|--------|
| `MyBuilder` (no AutoValue) | `abstract Builder setName(String)` | ✅ | Class name contains `Builder`, method starts with `set` |
| `Builder` interface | `Builder withTimeout(Duration)` | ✅ | Name matches and prefix is `with` |
| `MyBuilder` | `Builder clone()` | ❌ | Method name does not start with allowed prefix |
| `@AutoValue.Builder class FooBuilder` | `abstract FooBuilder setName(String)` | ❌ | AutoValue builder, abstract method excluded |
| `@AutoBuilder class Bar` | `abstract Bar addItem(Item)` | ❌ | AutoBuilder, abstract method excluded |
| `Data` (plain class) | `Data setValue(int)` | ❌ | Class name does not contain “Builder” |

This behavioral expansion will reduce manual annotation effort for builder-style APIs while avoiding interference with code-generation patterns like AutoValue.

Suggest `@CanIgnoreReturnValue` on builder-looking APIs.


Bug: TryFailRefactoring (TryFailRefactoring) does not handle try-with-resources.

When a try block declares resources, the refactoring should preserve them. The suggested replacement must wrap the `assertThrows` call and any remaining catch-block statements in a retained try-with-resources block, using the original resource declarations. The closing brace for that block should be placed correctly after the refactored catch content.

Example:

```java
try (BufferedReader br = ...) {
    doSomething();
    fail();
} catch (IOException e) {
    assertThat(e)...
}
```

⇓

```java
try (BufferedReader br = ...) {
    IOException e = assertThrows(IOException.class, () -> doSomething());
    assertThat(e)...
}
```

Make the fix handle empty catch blocks as well, preserving the resource block.

Handle try-with-resources in TryFailRefactoring.


**Title:** `InstanceOfAndCastMatchWrongType` crashes with `NullPointerException` on pattern `instanceof` (e.g. record destructuring)

**Background**
The checker `InstanceOfAndCastMatchWrongType` flags casts inside `if` blocks that are incompatible with the `instanceof` type guarding the block. It currently assumes the `instanceof` always has a simple type (`instanceOfTree.getType()` returns non-null). With pattern `instanceof` (`obj instanceof Test(int x, int y)`), `getType()` returns `null`, causing an NPE.

**Desired behavior**
- The checker must not crash when the guarding `instanceof` uses a pattern.
- When an `instanceof` pattern is present, the checker should extract the type from the pattern (e.g., from the binding type of the pattern, such as the record type) and use that for the disjoint‑type check.
- A cast to the same type as the pattern (e.g. `(Test) obj` after `obj instanceof Test(int x, int y)`) must **not** be flagged.
- A cast to a disjoint type (e.g. `(String) obj`) **should** still be flagged.
- The checker must only consider the `then` branch of the `if` (not the `else` branch) and must respect existing constraints about intervening assignments and expression matching.

**Acceptance criteria** (observable behavior)
- No `NullPointerException` when analyzing `if (obj instanceof Test(int x, int y)) { … ((Test) obj).x(); … }` or similar pattern `instanceof` constructs.
- The checker reports a warning for `((String) obj).length()` inside such a block.
- The checker does **not** report a warning for `((Test) obj).x()` inside the same block.
- All existing positive and negative cases continue to work as before.

Fix NPE in InstanceOfAndCastMatchWrongType.


Allow `@GuardedBy` on static methods/fields to reference instance members of method parameters.

Currently the checker emits “static member guarded by instance” whenever a static member’s `@GuardedBy` guard references an instance field or method. That rule is correct for `this`-based guards, but it should permit guards that are rooted in a method parameter. For example:

```java
@GuardedBy("foo.lock")
static void m(Foo foo) { ... }
```

The guard expression `foo.lock` has root `foo`, which is a parameter – not an implicit `this`. Such guards are acceptable and should not be flagged. The same holds for deeper selections like `foo.getBar().lock`.

The fix should inspect the root of any `Select` guard expression chain. If that root’s symbol is a `PARAMETER`, skip the “static member guarded by instance” check. Guards that still resolve to enclosing-class instance members (e.g., bare `@GuardedBy("getLock()")` without a parameter) must continue to be rejected.

Do not apply GuardedBy static checker to parameter types


**Title:** Allow default cases on enum switches to be marked as "for version skew" so they are tolerated by `UnnecessaryDefaultInEnumSwitch` but still checked for completeness by `MissingCasesInEnumSwitch`

**Problem:**
- `UnnecessaryDefaultInEnumSwitch` reports an unnecessary default when a switch over an enum already handles every known constant. This forces developers to remove the default, leaving no compile-time safety net when the enum later gains new constants (version skew).
- `MissingCasesInEnumSwitch` does *not* report missing enum constants when a default case is present, because the default is assumed to cover them. There is no way to get both behaviors: keep a fallback for future values **and** be warned about missing current values.

**Expected Behavior:**
If a default case in an enum switch is commented with a word that indicates it exists specifically to handle version skew (e.g., a comment containing the word `skew`), the two checkers should interpret it differently:

1. **`UnnecessaryDefaultInEnumSwitch`** should **not** flag the default as unnecessary.
2. **`MissingCasesInEnumSwitch`** should **still check** that all current enum constants are handled, as if the default were absent. Missing cases should still be reported.

The heuristic should be case-insensitive and triggered by the presence of the word “skew” in a comment on or immediately preceding the default case.

**Example – accepted and checked:**
```java
switch (c) {
  case ONE:
  case TWO:
  case THREE:
    return true;
  default: // in case of library skew
    return false;
}
```
- No warning from `UnnecessaryDefaultInEnumSwitch`.
- If `THREE` is omitted, `MissingCasesInEnumSwitch` reports the missing case.

**Configuration:**
Ideally, this behavior should be configurable per checker via existing flag mechanisms (e.g., `UnnecessaryDefaultInEnumSwitch:AllowDefaultForSkew` and `MissingCasesInEnumSwitch:CheckSwitchesWithDefaultForSkew`), both defaulting to enabled.

Tolerate default cases in switches as being present to handle version skew


The `NarrowingCompoundAssignment` check should not flag compound bitwise assignments (`&=`, `|=`, `^=`) to `byte` or `short` variables when the right-hand operand is a compile-time constant whose value fully fits within the bit width of the target type. Specifically, if the constant (possibly of type `int` or `long`) shifted right by 8 (for `byte`) or 16 (for `short`) yields either `0` or a word of all-ones (i.e., `~0`), the implicit narrowing cast is safe and the diagnostic should be suppressed. This makes masks like `b |= 1` or `s &= ~1` silenceable.

Allow bit-twiddling with constants of larger integral types if all the bits fit.


Add a new Error Prone check (`UnnecessaryAsync`, warning) that flags local variables of type `AtomicBoolean`, `AtomicInteger`, `AtomicLong`, `AtomicReference`, or `ConcurrentHashMap` when they are effectively final and never escape the enclosing method. The variable must be initialized with a `new` instance of one of those types. If it never leaves the local scope (not returned, not passed as an argument to another call, not captured by a lambda/anonymous class, not assigned to another variable/field), then the concurrent type is unnecessary; using a simpler non-concurrent alternative reduces overhead and verbosity.

Edge cases:
- Only consider local variables; ignore fields.
- Require the variable to be effectively final (no reassignment after initialization) so a replacement with a non-concurrent type is safe.
- Allow method calls and field accesses on the variable itself (e.g., `atomicInt.get()`, `atomicInt.set(…)`, `map.put(…)`); these do not count as escaping.
- Any other reference to the variable (e.g., passing it as an argument, returning it, capturing in a lambda) constitutes an escape and should suppress the warning.
- Ensure nested lambdas and anonymous classes are handled correctly.

Introduce a check to flag unnecessary use of async primitives in local (and hence single-threaded) scopes.


# AutoValueSubclassLeaked: Handle AutoValue extension-generated classes missing `@Generated`

After a recent change, `AutoValueSubclassLeaked` began relying on the presence of `@Generated` annotations to recognize generated AutoValue subclasses (e.g., `AutoValue_*` or `$AutoValue_*`). However, some AutoValue extensions do not mark their generated code with `@Generated`. When such an extension generates a concrete subclass of an `@AutoValue`-annotated class (with a name matching the AutoValue prefix) but omits `@Generated`, the checker now misbehaves—either failing to treat those classes as belonging to the same file as the base `@AutoValue` class, or flagging references from those extension classes as leaks.

## Desired behavior
`AutoValueSubclassLeaked` must consider a class as an AutoValue-generated concrete class for a compilation unit if:
- Its simple name matches the standard `*AutoValue_*` pattern.
- Any supertype of that class (following the transitive superclass chain) has the `com.google.auto.value.AutoValue` annotation.

This applies regardless of whether the class carries `@Generated`. References from other files to such classes should still be reported as leaks; references from within the same compilation unit (including extension-generated code) should not.

No change to the handling of classes directly annotated with `@AutoValue` or classes that already have `@Generated`. The only change is adding the name-pattern + supertype-annotation recognition for generated classes that lack `@Generated`.

**Note:** The supertype climb must stop at `java.lang.Object`, not via an infinite loop on recursive types.

Improve handling of AutoValue extensions in AutoValueSubclassLeaked


**Title:** New Suggestion Checker: `VoidMissingNullable` – flag `Void` types missing `@Nullable`

**Problem**
Developers frequently use `java.lang.Void` (as a field type, method return type, or type argument) with the intention that it will only ever hold `null`. However, they often forget to annotate the type with `@Nullable`. Existing nullness checkers like `ReturnMissingNullable` help with method return values but do not flag unannotated `Void` in other positions (e.g., `List<Void>`, `Void field;`). This leads to incomplete nullness annotations, missed API documentation, and false positives from other nullness tools when they treat the unannotated `Void` as non-null.

**Expected Behavior**
A new Error Prone checker should flag any `Void` usage that is not already annotated as nullable and suggest adding the appropriate `@Nullable` annotation. The checker should:
- Apply to `Void` used as a field type, method return type, or type argument (including wildcard bounds like `? extends Void`, `? super Void`).
- Not apply to local variables (including `var`), since tools typically infer local nullness.
- Not apply to lambda parameters that have no explicit type (implicitly-typed lambda parameters like `v -> { … }`), as the type is often omitted.
- Respect any existing nullness annotation on the `Void` type or its enclosing declaration (e.g., `@Nullable Void`, `@org.checkerframework.checker.nullness.qual.Nullable`).
- Use the project’s configured nullable annotation (e.g., `javax.annotation.Nullable`, `org.jspecify.annotations.Nullable`) for the suggested fix, following the same mechanism as `NullnessFixes.makeFix`.
- Be classified as a `SUGGESTION` severity check.

**Impact**
Without this checker, developers must manually remember to add `@Nullable` to every `Void` usage, which is error-prone and repetitive. Automated detection and fixing will improve annotation coverage, reduce boilerplate, and align with the common practice that `Void` is always nullable.

**Examples**
**Before (flagged)**
```java
Void result;

Void compute() { return null; }

List<Void> events;
List<? extends Void> bound;
```

**After (suggested fix)**
```java
@Nullable Void result;

@Nullable Void compute() { return null; }

List<@Nullable Void> events;
List<? extends @Nullable Void> bound;
```

**Non-goals (not flagged)**
- `Void[]` (rare, and `Void[].class` presents special challenges – defer for now)
- Local variables: `Void v = null;` or `var v = (Void) null;`
- Implicit lambda parameters: `func = v -> {};`


Fix a crash in Varifier (#5521) when suggesting `var` for builder chains that start with a `new` invocation on a nested builder class (e.g. `new Test.Builder().setX(1).build()`). Ensure the checker correctly identifies the type of the builder's enclosing class when comparing against the variable's declared type, instead of using the constructor's receiver type. The suggestion should fire only when the builder's build method return type matches the variable type.


The `IdentifierName` check currently rejects all underscores in method, non‑static variable, and type names.  Underscores that separate digits (common in version‑number identifiers like `murmur3_32` or `Murmur3_32`) should be allowed.

**Acceptance criteria**
- `IdentifierName` **does not** flag a lowerCamelCase name (method or non‑static variable) when *every* underscore in the name is immediately preceded **and** followed by a digit:
  - `murmur3_32` is OK.
  - `addressV6_66_0` is OK.
- The same logic applies to type (class/interface) names: `Murmur3_32` is OK.
- Names that **start or end** with an underscore remain invalid (`_murmur3_32`, `murmur3_32_`).
- Underscores that are **not** flanked by digits remain invalid, even when a digit is on only one side (`murmur3_d`, `address_66_255`, `addressV6_66_ff`, `murmur_3_32`).
- Consecutive underscores remain invalid (`murmur3__32`).
- A static final variable that follows `UPPER_UNDERSCORE` style and contains digits adjacent to underscores (e.g., `GUAVA33_4_6`) must continue to be accepted – this already works, so no regression.
- The “possible initialism” detection (e.g., `PROBABLE_INITIALISM`) and other existing constraints remain unchanged; only the underscore rule for lower/type names is relaxed.


We need to support the JSpecify `@NullUnmarked` annotation in the logic that determines whether a symbol is in a null-marked scope. Currently, the `NullArgumentForNonNullParameter` checker and the shared `NullnessUtils.isInNullMarkedScope` utility walk up the enclosing elements and stop when they encounter a `@NullMarked` annotation (subject to a package-level trust list). They do not consider `@NullUnmarked`, so a package-level `@NullMarked` (e.g., on `package-info.java`) cannot be overridden by a `@NullUnmarked` on a specific class or method. This causes false positives in codebases that use package-level `@NullMarked` but then opt out specific types with `@NullUnmarked`, such as public Guava types in otherwise null-marked packages.

Implement the JSpecify null-marked scope semantics: when evaluating whether a symbol is in a null-marked scope, walk outward and apply the first relevant annotation found.

- If a `@NullUnmarked` annotation is reached (without a co-located `@NullMarked`), the symbol is **not** in a null-marked scope – stop and return `false`.
- If a `@NullMarked` annotation is reached (without a co-located `@NullUnmarked`), apply the existing trust checks (e.g., the `weTrustNullMarkedOn` logic) and return `true` or `false` accordingly.
- If both `@NullMarked` and `@NullUnmarked` appear on the same element, treat it as neither applied and continue walking outward.

This behavior must be applied consistently in:

- `NullArgumentForNonNullParameter.enclosingAnnotationDefaultsNonTypeVariablesToNonNull`
- `NullnessUtils.isInNullMarkedScope`

The `@NullUnmarked` annotation is `org.jspecify.annotations.NullUnmarked`. This change should allow internal Guava code (and any code using the JSpecify annotations) to safely countermand package-level `@NullMarked` and avoid false positives from `NullArgumentForNonNullParameter`.


**Title:** DoNotCallChecker should detect @DoNotCall overrides through upcasted receiver variables

**Context**
The `DoNotCallChecker` currently only inspects the declared method symbol for the `@DoNotCall` annotation. It misses cases where a method is called on a receiver that is declared as a supertype (e.g. `List`), but the object was instantiated with a subtype that overrides the method and annotates it with `@DoNotCall`. For example:

```java
List<Integer> xs = ImmutableList.of(1);
xs.add(2); // should be flagged because ImmutableList.add is @DoNotCall
```

**Desired behavior**
When evaluating a method invocation or member reference, if the receiver is a final local variable, track all concrete types assigned to that variable (via initializer or direct assignment). If all assigned types are the same, then check the type closure for any override of the called method that carries `@DoNotCall`. If such an override exists, report the standard `DoNotCall` diagnostic.

**Non‑obvious constraints & safety**
- Only apply this analysis to local variables that are effectively final (`isConsideredFinal`).
- If the variable is assigned values of *different* types (e.g., one branch assigns an `ImmutableList`, another an `ArrayList`), skip the intra‑procedural check to avoid false positives.
- Only consider non‑static, non‑synthetic overriding methods within the type closure of each assigned type.
- The existing third‑party hardcoded method matchers (e.g., `java.sql.Date`) must still work as before.
- The feature must be gated by a new flag `DoNotCallChecker:CheckAssignedTypes` (default `true`) so users can disable it if needed.

**Affected components**
- `DoNotCallChecker` – must change from per‑invocation matching to a whole‑compilation‑unit analysis to collect assignments before checking calls.
- The existing `matchMethodInvocation` / `matchMemberReference` logic should be preserved within the new scanning structure.

DoNotCallChecker: check whether DoNotCall is present on any of the overrides of the method we're calling on subclasses assigned to a variable.


Add a new Error Prone checker, `PreferInstanceofOverGetKind`, that encourages replacing `tree.getKind()` comparisons with `instanceof` checks.

**Behavior:**
- Flag binary equality/inequality (`==`/`!=`) and `.equals()`/`!.equals()` calls where the left-hand side is a `getKind()` invocation on an expression whose type is a subtype of `com.sun.source.tree.Tree`, and the right-hand side is a `Tree.Kind` enum constant.
- When the `Kind` constant maps uniquely to a single concrete `Tree` subtype (e.g., `Kind.MEMBER_SELECT` → `MemberSelectTree`), suggest replacing the entire comparison with `expr instanceof QualType` (or `!(expr instanceof QualType)` for negated cases).
- Do **not** fire for `Kind` values that do not have a 1:1 mapping to a unique tree class—specifically, any `Kind` where `Kind.asInterface()` returns `null` or where multiple `Kind` constants map to the same interface (e.g., `EQUAL_TO` and `NOT_EQUAL_TO` both map to `BinaryTree`).
- The suggested fix must correctly qualify the new tree type name and handle negation.

**Implementation notes:**
- Make the existing `INSTANCE_EQUALS` matcher in `Matchers` `public` so the checker can match `.equals()` calls.
- Register the checker in `BuiltInCheckerSuppliers` as an enabled warning.

**Severity:** WARNING

Add a check to encourage `tree instanceof FooTree` rather than `tree.getKind() == Kind.FOO`.


**Title:** Warn when a `@BugPattern` name doesn't match its enclosing checker class name

**Context:**
Error Prone checker classes use the `@BugPattern` annotation, whose `name` element conventionally matches the simple class name. Mismatches can cause confusion during debugging, documentation, and suppression.

**Request:**
Add a new built-in check, enabled by default at `WARNING` severity, that reports whenever a class extending `BugChecker` declares a `@BugPattern` annotation whose `name` attribute value does not equal the class’s simple name.

**Acceptance Criteria:**
- The check fires only for classes that are subtypes of `com.google.errorprone.bugpatterns.BugChecker`.
- If the `@BugPattern` annotation is present but contains no explicit `name` attribute, no warning should be emitted.
- The diagnostic should point to the class declaration.
- The check should be included in the standard set of enabled warnings (`ENABLED_WARNINGS`).

Add a check to complain when BugPatterns have a different name to their enclosing class.


The `Immutable` checker should correctly handle unqualified method invocations and method references inside `@Immutable` types so that it does not produce false positives.

Currently, the checker incorrectly reports immutability violations in two situations:

1. **Unqualified non-static method call in an `@Immutable` class/interface whose supertype is not `@Immutable`.**
   Example:
   ```java
   @Immutable
   interface ImmutableFunction<A, B> extends Function<A, B> {
     default <C> ImmutableFunction<A, C> andThen(ImmutableFunction<B, C> fn) {
       return x -> fn.apply(apply(x)); // false positive: `apply` is declared on mutable `Function`
     }
   }
   ```
   The checker should treat the implicit `this` as the enclosing `@Immutable` type when the enclosing class is a subtype of the method’s declaring class, rather than assuming the receiver is the declaring class itself.

2. **Method references on known immutable types used to implement an `@Immutable` functional interface.**
   Example:
   ```java
   ImmutableMap<String, String> map = ImmutableMap.of();
   test(map::get); // false positive when test expects an @Immutable functional interface
   ```
   The checker should not flag such references because the target method belongs to an immutable object. Conversely, a method reference on a mutable type (e.g., `HashMap`) should still be reported.

For unqualified invocations, determining the effective type of `this` must work through multiple levels of nesting—walking outward from the call site to find the innermost enclosing class that is a subtype of the method’s owner, not just the immediately enclosing class. For method references, the checker should leverage the existing lambda analysis to verify that the functional interface target type is `@Immutable` before suppressing the warning.

ImmutableChecker: for unqualified method invocations, bubble up the current path to work out what the effective type of the receiver is.


**Title:** `ReturnValueIgnored` does not flag discarded Guice module instances

**Description**
Constructing a Guice module (any class implementing `com.google.inject.Module`, including `AbstractModule`) without using the resulting instance is almost certainly a bug. For example:
```java
import com.google.inject.AbstractModule;
class TestModule extends AbstractModule {
  @Override protected void configure() {}
  public static void install() {
    new TestModule(); // discarded! Should be passed to createInjector or Modules.override
  }
}
```
Today, Error Prone’s `ReturnValueIgnored` check does not report this pattern. This allows modules to silently never be installed, leading to missing bindings and runtime failures.

**Expected behavior**
`ReturnValueIgnored` (or equivalently `@CheckReturnValue`) should flag any constructor call whose type is a subtype of `com.google.inject.Module`, when the return value is not used. The check should match any class that directly or indirectly implements `com.google.inject.Module`, including `AbstractModule` and anonymous inner classes.

**Impact**
Without this check, forgetting to pass a module to an injector is easy to overlook during code review. Extending the existing `ReturnValueIgnored` matchers would bring this common mistake to compile-time visibility, consistent with the rationale for many other `@CheckReturnValue` warnings.

**Additional notes**
- The check should be part of the default `ReturnValueIgnored` matcher set (no extra opt-in required) and also be individually togglable via a flag (e.g., `-XepOpt:ReturnValueIgnored:ModuleConstructors=Off` to disable).
- It should cover all direct and indirect implementations of `com.google.inject.Module`, regardless of whether the constructor is the class’s own or inherited.

Require module instances to be used after construction.


## Issue: `ConstantPatternCompile` fix duplicates regex constants and uses poor names

**Observed behavior:**
The `ConstantPatternCompile` check correctly identifies local variables initialized from `Pattern.compile` with a constant argument and suggests turning them into a constant (static final field). However, the generated fix has two shortcomings:

1. **Redundancy when the regex string is already a constant:**
   If the argument to `Pattern.compile` is a `private static final String` constant, the fix introduces a new separate `Pattern` field, leaving the original string constant orphaned. For example, given:
   ```java
   private static final String MY_REGEX = "a+";
   ...
   Pattern p = Pattern.compile(MY_REGEX);
   p.matcher(input);
   ```
   The fix creates:
   ```java
   private static final String MY_REGEX = "a+";
   private static final Pattern P = Pattern.compile(MY_REGEX);
   ...
   P.matcher(input);
   ```
   This adds unnecessary duplication and noise.

2. **Uninformative constant names:**
   The new constant is named by simply converting the local variable name to `UPPER_UNDERSCORE`, which often yields poor names like `PATTERN` (from `pattern`) or `P`. It does not take advantage of the original regex constant’s name or the usage context to produce a descriptive name.

**Expected behavior:**

- **Reuse the existing regex string constant when safe.**
  If the `Pattern.compile` argument refers to a `private` (or private‑scoped, e.g. inside a private nested class) `final` `String` constant that is used exactly once in the compilation unit (i.e. only in this `Pattern.compile` call), the fix should transform that string constant into a `Pattern` constant instead of creating a new field. All references to the local variable should be renamed to the constant’s name.
  After the fix the example above should become:
  ```java
  private static final Pattern MY_REGEX = Pattern.compile("a+");
  ...
  MY_REGEX.matcher(input);
  ```

- **Improved naming when a new field is still needed.**
  When reusing the string constant is not possible, infer the constant name using the following heuristics, applied in order:
  1. If the local variable name, after `UPPER_UNDERSCORE` conversion, is non‑trivial (length > 1 and not just `PATTERN`), use that.
  2. If the regex argument is a simple constant identifier `FOO`, use `FOO_PATTERN`.
  3. If the regex argument is a constant ending in `_REGEX` (e.g. `FOO_REGEX`), strip the suffix and use `FOO_PATTERN`.
  4. If the pattern is used exactly once in the method body, in a call to `Matcher.matcher(...)`, and the argument to `matcher` is a local variable, derive the name from that variable: e.g. `pattern.matcher(foo)` → `FOO_PATTERN`.

**Safety constraints:**

- The transformation of a string constant into a pattern constant must only occur if the symbol is **private** (including being owned by a private class) and **referenced exactly once** in the source file (the `Pattern.compile` call). This avoids changing a symbol that might be used elsewhere with `String`‑specific expectations or exposed through non‑private API.
- The naming heuristics must not introduce name collisions or overwrite existing symbols; the fix should fall back to an empty suggestion if a suitable name cannot be determined.
- Non‑static methods and inner classes should still produce valid `private final` (rather than `private static final`) constants if needed, as the current fix does.

**Impact:**
Without these improvements, developers either accept duplicated constants with poor names or must manually refactor, reducing the tool’s usefulness. The enhanced fix makes the suggestion safe, concise, and aligned with common naming conventions, increasing adoption.


The `Reachability` utility does not account for switch rules (`->`) and miscomputes fall‑through / reachability for switches that use arrow cases. This leads to incorrect suggestions in checks like `SwitchDefault`, `UnnecessaryDefaultInEnumSwitch`, and `WrongOneof` when they inspect arrow‑style switches.

Specific behavioural changes needed:

1. **Rename‑and‑fix `canCompleteNormally(CaseTree)`.**
   The callers really care whether the case can fall through into the next case. For `STATEMENT` cases the logic can stay, but a switch rule (`RULE`) never falls through; the method should be renamed `canFallThrough` and return `false` for rule cases.

2. **Update switch‑reachability per JLS 14.21 for arrow switches.**
   When the switch body consists of rules, the current `visitSwitch` logic applies the old statement‑group rules, which is wrong. An arrow switch can complete normally iff at least one of these holds:
   - no default label,
   - a rule introduces a statement expression,
   - a rule introduces a block that can complete normally,
   - a rule introduces a block containing a reachable break that exits the switch.

   For switches that mix rules and statement groups we can treat them conservatively, but the minimum is to correctly model the pure‑rules case and keep the existing logic for pure‑statement switches.

3. **Adjust callers to the renamed method and corrected semantics.**
   - `SwitchDefault`: when moving a default case to the end, the check should use `canFallThrough` to decide whether a `break;` needs to be inserted before the moved default. Arrow cases never fall through so no `break;` is needed.
   - `UnnecessaryDefaultInEnumSwitch`: uses the method to decide if the case before the default falls through; with arrow cases it never does, which affects the fix.
   - `WrongOneof`: uses the method to clear allowable getters after a non‑fall‑through case. Arrow cases always clear, matching the intended invariant.

Edge‑cases and invariants:
- Empty arrow rule (e.g., `case X -> {}`) should report `canFallThrough == false`.
- A rule with a statement expression (`case X -> 42;`) is not fall‑through‑able; `canFallThrough` returns `false`.
- The overall switch reachability must still account for `System.exit` and `throw`, consistent with how statement switches are handled.
- The method should not break existing statement‑switch reasoning; regression risk is low because the old `canCompleteNormally(CaseTree)` was only called on cases in switches already being analysed.

Handle switch block consisting of switch rules in Reachability.


The `LockNotBeforeTry` checker’s suggested fixes can reorder statements, which may break program semantics. Update the fix logic to preserve statement order:

1. When the lock is inside the `try` that releases it, **only** propose moving the lock before the `try` if the lock is the **first statement** of that `try` block. If there are statements before the lock inside the `try`, do not offer a fix (still report the warning).
2. When the lock is followed later in the same block by a `try`/finally that releases it, keep the lock statement where it is and move the `try` header (the `try {` and any text up to the first statement of the `try` body) to immediately after the lock statement. This avoids reordering any statements that may lie between the lock and the `try` block.

Net effect: the fix should never reorder statements relative to each other; only the lock acquisition moves to immediately before the releasing `try`, or the `try` header moves after the lock.

Don't re-order statements in `LockNotBeforeTry` fix


**Title:** `GetClassOnAnnotation` crashes with `NullPointerException` when applying fix suggestion on certain Annotation implementations

**Description:**
The `GetClassOnAnnotation` bug checker correctly flags `getClass()` calls on `Annotation` subtypes and should suggest replacing them with `annotationType()`. However, on some real-world code the checker crashes with a `NullPointerException` while trying to build the replacement fix. This makes the check unusable on affected files and can cause unexpected build failures.

**Steps to reproduce (conceptual):**
1. Define an interface that extends `Annotation` and contains a `default` implementation of `annotationType()`.
2. In that implementation, call `getClass()` as part of a stream pipeline or method chain (e.g., `Stream.of(getClass().getInterfaces())...`).
3. Run Error Prone with the `GetClassOnAnnotation` check enabled.
   *Observation:* A `NullPointerException` is thrown from position‑tracking code (e.g., `ErrorProneEndPosTable.getEndPosition` called with a `null` argument).

**Acceptance criteria:**
- The check must **not crash** on such code. It may either produce a valid replacement fix or fall back gracefully without crashing, but must never throw an unhandled exception.
- When a suggestion is produced, it must use the correct source positions, replacing `getClass()` with `annotationType()` without introducing syntax errors or invalid edits.
- Position‑tracking utilities must handle `null` inputs safely, for example by rejecting them early with a meaningful exception rather than propagating an ambiguous `NullPointerException`.

**Additional notes:**
The crash appears to originate from computing the end position of a receiver expression that may be `null` for certain malformed or unusual AST shapes. The fix generation logic should account for such cases, possibly by using existing utility methods that already handle edge cases (such as `renameMethodInvocation`).


Subject: float32-to-float16 cast produces NaN for overflow values instead of infinity

When I use Halide to cast a float32 value to float16 (via `cast(Float(16), x)`) and the input is outside the representable range of float16, I get a NaN result instead of the expected signed infinity. This only occurs in the Halide‑compiled path; the host‑side `float16_t` constructor correctly yields infinities for the same values.

Steps to reproduce (simplified):
1) Create a Halide pipeline that takes a float32 input, casts it to float16, and writes it to a buffer.
2) Feed the pipeline a finite float32 value larger than the largest normal float16 (e.g., 100000.0f).
3) On a target that uses the float16 emulation path (e.g., x86‑64 host), observe that the output contains a NaN, not positive infinity.

I expect that any float32 value that overflows the float16 format (positive overflow → +∞, negative overflow → -∞) is faithfully converted to the appropriate infinity, matching the behaviour of the `float16_t` constructor and the IEEE 754 recommendation for rounding to a narrower format. Currently the generated code produces a NaN, which breaks algorithms that rely on infinity sentinels and leads to incorrect finite/infinite checks downstream.

The root cause appears to be in `float32_to_float16` (src/EmulateFloat16Math.cpp). The code tests for infinity by checking if the float32 bits equal `0x7f800000` (the exact bit pattern of float32 +∞). Values that are finite but too large miss this check, and the subsequent normalization path seems to produce a mantissa‑non‑zero value with a full‑ones exponent, which is the fp16 NaN representation. The condition should instead treat anything above the overflow threshold as infinity, e.g., any float32 with an exponent large enough to guarantee overflow into the fp16 infinity codepoint.

Please adjust the overflow detection so that `float32_to_float16` emits signed infinity for any float32 value that cannot be represented as a finite float16 number, aligning with the existing C++ conversion logic in `Float16.cpp`.

Fix an issue in Halide's float16 compilation support. Add tests. (#5872)


# Storage folding should not automatically fold across vectorized access dimensions

## Summary
When a `Func` is stored with a sliding window (`store_at` + `compute_at`) and the consumer is vectorized, Halide’s automatic storage folding will fold along dimensions that are accessed vectorized, even though that causes loads and stores to scalarize. There is no way in the current schedule to disable this folding while keeping the rest of the sliding window optimization. This leads to a performance pitfall that cannot be avoided without restructuring the algorithm or abandoning vectorization.

## Steps to Reproduce
1. Define a producer `f` and a consumer `g` that uses a sliding stencil (e.g., `f(x-1) + f(x+1)`).
2. Schedule `g` with a split and vectorize the inner dimension.
3. Place `f` using `store_at(g, xo).compute_at(g, xi).vectorize(x, 8)`.
4. Generate code.

## Observed Behavior
Halide’s automatic storage folding pass folds the producer’s storage along the dimension that the consumer uses in vectorized accesses. The resulting loads/stores are scalarized, degrading performance.

The user cannot turn off this folding for that dimension alone; the folding is applied automatically whenever a power-of-two factor can be deduced from the sliding window.

## Expected Behavior
- By default, **do not** automatically fold storage along a dimension when that dimension is used in any vectorized `Provide` or `Call` (i.e., the index expression depends on a loop variable that is `Vectorized`).
- If the user has **explicitly** requested folding for that dimension via `Func::fold_storage()`, then honor the explicit request and fold regardless of vectorization.
- When automatic folding is suppressed due to this check, emit a **user warning** that:
  - States the function name and dimension that was not folded.
  - Explains that a vectorized access was detected in that dimension.
  - Includes the exact `Func::fold_storage()` call that would restore the old folding behavior, with the factor that would have been used automatically.

## Impact
- Users currently have no way to safely benefit from sliding window optimization together with vectorization; they must either accept scalarization or rewrite their schedules.
- The proposed change makes the common case (no explicit `fold_storage`) safer by avoiding a known bad transform, while providing a clear path to opt-in to the exact fold if intentionally desired.
- Long-term this is a step toward making automatic folding entirely opt-in.

## Additional Constraints
- The detection must handle vectorized accesses through `Let`/`LetStmt` bindings, following the same variable scope semantics used in the rest of the folding pass.
- The warning should only fire when the folding would have been applied automatically; explicit `fold_storage` calls should never trigger this warning and should always be respected.
- The existing detection of folding opportunities (power-of-two factors) must not be altered; only the final decision to apply the fold should be gated by the new vector-access check when no explicit factor is set.

Don't automatically fold storage along vectorized dimensions


The gradient autoscheduler generates incorrect or crashing schedules for associative reductions when the domain size is an exact multiple of the tile size, and fails with unhelpful errors for unbounded accesses or missing bound estimates.

### Observed problem
- **Incorrect schedules for reductions with rfactor**: When an update definition contains reduction variables (RVars) whose bounds are exactly equal to the fixed tile size (e.g., 8 or 64), the autoscheduler still tries to split them, fuse, and apply `rfactor`. This leads to invalid schedules because the split produces an outer loop of size 1, and the subsequent parallelization of the fused RVar cannot proceed correctly. In some cases the schedule is silently wrong; in others it causes an assertion failure inside Halide.
- **Missing parallelization after rfactor**: After successfully performing `rfactor`, the autoscheduler continues to use the original list of RVars when calling the generic parallelization step. The fused outer RVar introduced by `rfactor` is ignored, so the generated schedule does not parallelize over the right loop, leaving performance on the floor.
- **Crashes with missing bound estimates**: If a Func has no `set_estimate` calls, or the estimates array is shorter than the number of dimensions, the autoscheduler crashes inside `generate_schedule` without a clear diagnostic. The user gets a segfault or an unintelligible internal error instead of a helpful assertion.
- **Crashes for unbounded access**: When bounding inference yields an unbounded interval for any function or buffer access (e.g., because the pipeline uses a `clamp` on a reduction domain), the autoscheduler hits an assertion deep in differentiation, again without a early, clear message.

### Expected behavior
1. **Splitting decision must use a strict inequality**: RVars whose extent is ≤ tile_size should not be split or fused. They should stay as inner loops. This guarantees `rfactor` is only applied when there is at least one outer RVar with extent > tile_size, avoiding degenerate outer loops of size 1.
2. **Post‑rfactor parallelization must target the fused RVar**: After `rfactor`, the inner‑outer decomposition changes. The autoscheduler should replace the original set of RVars with the single fused RVar (and its computed outer extent) before passing them to `parallelize_vars_and_rvars`. That way the outer loop gets the intended GPU block/CPU parallel annotation.
3. **Early, clear assertions for missing estimates and unbounded access**: Before any scheduling logic runs, the autoscheduler must verify that every output Func has exactly one bound estimate per dimension, and that interval arithmetic has produced bounded bounds for every function and buffer mentioned in the pipeline. The user should see a `user_assert` message stating the function and dimension that is problematic.

### Impact
Any associative reduction pipeline where a reduction domain extent matches a tile boundary will miscompile or crash. Histogram‑like pipelines (e.g., `hist(clamp(in(r), lo, hi)) += 1`) are particularly affected because they combine a bounded clamp with a reduction. Additionally, users who omit estimates or write reductions with unbounded inferred ranges spend a long time debugging obscure internal failures.

The desired fix is a single pass through the relevant scheduling path that:
- Changes the tile‑size split guard from `>=` to `>`.
- Correctly updates the RVar list and bounds after `rfactor`.
- Inserts the two early `user_assert` checks in `generate_schedule`.

fix rfactor schedules & add histogram test


**Bug: If-then-else guards from scheduling transforms are not hoisted alongside reduction predicates**

When a reduction domain carries a predicate (via `RDom::where`) *and* the schedule applies transformations that introduce their own if-then-else guards (e.g., `apply_splits` for boundary conditions), the loop nest builder fails to treat the extra guards as “predicate containers.” Only the explicit reduction predicates are collected and later sorted toward the outermost scope. The if-then-else nodes that wrap the statement body remain deeper in the nest.

Because the guard conditions are not hoisted, downstream passes (especially `BoxesTouched`) cannot tighten the iteration bounds of variables that are constrained by those conditions outside the immediate scope of the if-then-else. This leads to unnecessarily loose bounds, which in turn can prevent vectorization or cause incorrect lane masking when a schedule combines `.where(...)` with `.unroll(...).vectorize(...).allow_race_conditions()`.

**Expected behavior**
All if-then-else statements that appear at the top of the statement nest (those without an else branch) should be peeled off and placed into the same container that holds the reduction domain predicates. After collecting let-statements and these if-guards, the combined set of if containers should be reordered together using the existing hoisting heuristic—so that *any* such guard, regardless of its origin, ends up as far outward as possible.

**Impact**
This mismatch causes Halide to generate bounds that are too wide for vectorized updates on predicated reduction domains. A concrete symptom is that a reduction with a predicate and vectorized unrolled schedule may either fail with an internal assertion during compilation or produce runtime out-of-bounds accesses because the vector stores/loads are not properly guarded by the hoisted condition.

Also sort all ifs introduced by apply_splits


**Title:** OpenGL runtime: support non-interleaved (planar) buffer layouts in `halide_opengl_copy_to_dev` / `halide_opengl_copy_to_host`

**Background:**
`halide_opengl_copy_to_dev` and `halide_opengl_copy_to_host` currently require the host buffer to be stored in an interleaved pixel layout (`stride[2] == 1` and `stride[0] == extent[2]`). Any other layout—particularly planar (channel-separated) or otherwise strided buffers—triggers an assertion failure. Real Halide pipelines routinely produce such non-interleaved buffers (e.g., after splitting a channel dimension or applying `compute_at`), making the OpenGL backend unusable for many schedules.

**Requested behavior:**
When copying between host memory and an OpenGL texture, automatically convert between the buffer’s actual memory layout and the interleaved format that `glTexSubImage2D`/`glGetTexImage` require. The conversion should be transparent to callers; no API changes.

**Detailed requirements:**

1. **Layout detection**
   - If the buffer satisfies `stride[2] == 1 && stride[0] == extent[2]` (the current interleaved condition), perform the GL call directly on `buf->host` as before.
   - Otherwise, allocate a temporary interleaved buffer large enough to hold `width × height × channels` elements of the buffer’s element type, perform the needed layout conversion, and feed that temporary buffer to the GL call.

2. **Respecting the buffer’s `min` fields**
   The buffer’s active region is defined by `extent` and the origin `min[0], min[1], min[2]`. The conversion must use these `min` values together with the actual strides to locate each pixel’s channel values; it must *not* assume the data starts at `(0,0,0)`. For example, the source index for channel `c` at pixel `(x, y)` is:
   ```
   (y - min[1]) * stride[1] + (x - min[0]) * stride[0] + (c - min[2]) * stride[2]
   ```
   (in elements). The same formula applies in reverse when copying back.

3. **Supported types**
   The conversion must handle the element sizes and corresponding GL types already allowed by `halide_opengl_dev_malloc`:
   - `uint8`  → `GL_UNSIGNED_BYTE`
   - `uint16` → `GL_UNSIGNED_SHORT`
   - `float`  → `GL_FLOAT`
   Only 1-, 3-, or 4-channel buffers need to be supported (the existing format selection for GL_RGB/GL_RGBA/GL_LUMINANCE remains adequate).

4. **Memory management**
   The temporary interleaved buffer must be freed after the GL transfer completes, on both the upload and download paths. No long-lived allocations should be retained.

5. **No regressions for interleaved buffers**
   When the buffer is already interleaved, behavior must be identical to the current implementation (direct zero-copy transfer) with no extra allocations or conversions.

**Affected code areas**
Primary change in `src/runtime/opengl.cpp`: the implementations of
- `halide_opengl_copy_to_dev`
- `halide_opengl_copy_to_host`

Ancillary refactoring to extract the texture format choice (`get_texture_format`) is acceptable as an implementation detail, but the ask is strictly about the layout-conversion capability.

**Priority / Impact**
Without this, the OpenGL backend is effectively limited to hand-crafted interleaved schedules, blocking integration with real Halide pipelines. The fix makes the backend obey the buffer’s actual layout, matching the spirit of Halide’s architecture where data layout is a scheduling decision.

Convert between different pixel layouts in copy_to_dev and copy_to_host


**Title:** Hoisted storage allocation extents are incorrect when loop variables depend on each other

**Background:**
`StorageFlattening` deduces the required allocation size for a hoisted storage realization from the interval bounds of the enclosing loop variables. Those intervals are computed via `bounds_of_expr_in_scope`.

**Problem:**
When multiple loop variables appear in an extent expression and those loop variables themselves depend on one another (e.g., through integer division, offset arithmetic, or nested `split` schedules), the present approach that inserts all loop variables into a single `Scope<Interval>` before calling `bounds_of_expr_in_scope` can produce overly large bounds or fail to resolve dependencies correctly. This leads to excessively large allocations, memory errors, or `simplify` failures in code generation.

**Expected behavior:**
Dependencies among loop variables must be resolved stepwise. The expression for an allocation extent should be progressively bounded by considering each loop variable individually, in reverse nesting order (innermost first), recomputing the bounds and updating the expression after each step. This ensures that uses of earlier (outer) variables are refined by already-computed bounds of later (inner) variables.

**Proposed implementation sketch (without dictating exact helpers):**
- Change the representation of collected loop intervals from `Scope<Interval>` to an ordered container that records the sequence in which loop variables are encountered (e.g., `vector<pair<string, Interval>>`).
- In the `Realize` visitor, when computing the bounded extent for each hoisted allocation, iterate the loop variables in reverse order. For each variable, construct a scope containing only that variable’s interval, call `bounds_of_expr_in_scope` on the current expression, and replace the expression with the resulting upper bound. The final expression is the resolved extent.
- In the `For` visitor, push the loop variable’s interval onto the ordered container when entering the loop and pop it when leaving, mirroring the existing scoping but preserving order.

**Constraints:**
- Must not break the existing handling of hoisted storages for GPU loops or host loops where variables are genuinely independent.
- The reverse-order substitution must correctly handle expressions where the same variable appears multiple times; existing simplification and CSE passes are expected to keep the expression manageable between steps.

Bound allocation extents for hoist_storage using loop variables one-by-one (#8154)


**Title:** Store forwarding and invariant lifting passes produce incorrect IR / miss opportunities; tests failing

**Background**
The invariant‑lifting pass (`LiftFixedExpressionsSingleLoop`) and the store‑forwarding pipeline (`StoreForwarding2` + `MightAliasWithAStore`) have a set of correctness and performance problems that are causing multiple tests to fail.

**Observed problems**

1. **Incorrect hoisting of let‑bindings**
   `LiftFixedExpressionsSingleLoop` currently tries to hoist any `LetStmt`/`Let` whose value is “liftable”.  This can move a let‑binding out of the loop even when the value is not truly loop‑invariant (e.g. it references loop‑varying allocas).  The pass should only inline or lift *variable‑valued* lets, and keep the rest inside the loop while preserving their scoping.

2. **Invariant components of Add/Sub are not lifted**
   Expressions like `(invariant_a + loop_varying) + invariant_b` are not lifted at all because the whole sum is considered non‑liftable.  The pass should split addition/subtraction into invariant and variant terms, lift the invariant sum, and leave the variant part in place.

3. **Aliasing detection for vector indices is too conservative**
   `MightAliasWithAStore` gives up and reports “may alias” whenever either index expression is a vector type, even when both indices are constant expressions (e.g. `Ramp` or `Broadcast`) whose lane ranges are computable.  This blocks store‑forwarding opportunities.  The check should compute extreme lane values and determine whether any lane could overlap.

4. **Store‑forwarding disables itself too early**
   `StoreForwarding2` currently inspects the *entire* rest of the block for an aliasing store and, if one exists, skips forwarding for the whole block.  Forwarding is safe for loads that appear *before* the aliasing store; only loads after it must be skipped.  The forwarding should be performed in a single forward pass that stops substituting once it encounters an interfering store.

5. **Tracing test out of sync with new pipeline events**
   The tracing infrastructure now emits `Begin pipeline` / `End pipeline` events.  The correctness test for tracing crashes because it doesn’t expect these new event types.

**Required behavior**

- `LiftFixedExpressionsSingleLoop` must not hoist a let whose value depends on an inner allocation or loop variable; it may inline a pure `Variable` let or leave the let inside the loop.
- Add and subtract nodes must be decomposed so that invariant terms are lifted together, leaving only the variant terms.
- `MightAliasWithAStore` must use lane‑extremum analysis on constant vector indices to accurately report overlap, and only conservatively assume overlap when the indices are not constant.
- Store‑forwarding from a store to later loads should succeed for all loads up to (but not including) the first subsequent store that may alias with the original store.  No whole‑block pre‑check should prevent this.
- The tracing test must accept the two new event types so that the suite passes.

**Success criteria**
After these fixes, the full test suite passes, and the compiler does not introduce invalid IR or miss invariant‑lifting and store‑forwarding opportunities in the scenarios above.

Fixes to invariant lifting and aliasing detection