Skip to content

Tags: openrewrite/rewrite

Tags

v8.83.0

Toggle v8.83.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
UpgradePluginVersion: handle null resolved versions consistently (#7656)

`DependencyVersionSelector.select(...)` is `@Nullable` (e.g. when the
configured selector matches no version in the plugin's Maven metadata,
or when exotic versions trigger an internal `IllegalStateException`),
but the scanner had three branches that each handled the contract
differently:

- Literal version: passed the (possibly null) result to the second
  visitor, which already short-circuits on null. Safe.
- GString version (`id 'foo' version "$prop"`): a bare
  `assert resolvedPluginVersion != null` fired, surfacing as
  `AssertionError: null` from `UpgradePluginVersion.java:173`.
- Identifier version (`id 'foo' version someIdent`): put `null` into
  `pluginIdToNewVersion`, which then NPE'd inside
  `VersionComparator.checkVersion` when the property-file visitor
  passed it to `VersionComparator.upgrade(currentVersion, singletonList(null))`.

Apply a single rule: when `select(...)` returns `null`, leave the
build script element unchanged and do not record anything in the
accumulator. Also guard `visitEntry` against a `null` resolved version
and a blank current version on the gradle.properties side.

v8.82.1

Toggle v8.82.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Package Go RPC sources as part of the rewrite-go JAR (#7715)

* Package Go RPC sources as part of the rewrite-go JAR

* Fix the Gradle task dependencies

rewrite-go/v0.0.1

Toggle rewrite-go/v0.0.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Package Go RPC sources as part of the rewrite-go JAR (#7715)

* Package Go RPC sources as part of the rewrite-go JAR

* Fix the Gradle task dependencies

v8.82.0

Toggle v8.82.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Kotlin recipe DSL: chained-call patterns + cursor exposure in visitX …

…actions (#7708)

* Kotlin recipe DSL: chained-call patterns

Adds depth-2 chain support to the K2 plugin so authors can write
`rewrite { xs: List<T>, p -> xs.filter(p).first() } to { xs, p -> xs.first(p) }`
and similar fused-terminal rewrites in one pattern. Five recipes in
`recipes-kotlin`'s Performance category (UseFirstWithPredicate,
UseLastWithPredicate, UseCountWithPredicate, UseAnyWithPredicate,
UseNoneWithPredicate) drive the design.

K2 plugin (`RecipeIrGenerationExtension`):
  - `BeforeLambda` gained an optional `inner: BeforeLambda?` field. When set,
    `rootCall` is the outer segment and `inner` holds the inner segment with
    its own arg signatures and receiver-param binding.
  - `validateBeforeLambda` recurses one level when the root call's receiver
    is itself an `IrCall` (depth-2 chains only). Outer args must be literal
    constants in v1; lambda-param bindings come from the inner segment.
  - Substitution-source CSV switched from `Int` to `String`. Single-segment
    recipes still emit plain integer strings (`-1`, `0`, ...) for backward
    compatibility. Chains emit segment-tagged entries: `o:N` / `o:-1` for
    outer-call args / receiver, `i:N` / `i:-1` for the inner segment.
  - Matcher-spec line for a chain pattern is `<outerSpec>\t<innerSpec>` —
    the tab distinguishes it from the `\n`-separated multi-before encoding.
  - Multi-before chains are rejected at IR-extract time in v1.

Runtime (`GeneratedRecipeSupport`):
  - `methodInvocationRewrite` detects `\t` in `matcherSpecsLines` and
    branches to a new `chainMethodInvocationRewrite` that matches
    outer-then-`select-is-inner` and substitutes per the tagged CSV.

* Kotlin recipe DSL: expose `cursor` inside `visitX { node -> ... }`

Switches the visit-primitive action signature from `(Node) -> Node` to
`<Visitor>.(Node) -> Node`. The runtime visitor is now the implicit
receiver inside the lambda, so authors can read `cursor` — and any other
visitor state — without subclassing or threading a thread-local.

Why now: `rewrite-kotlin/.../HotPath.kt` already ships `Cursor.isInsideLoop()`,
`Cursor.isInsideComposable()`, `Cursor.isInsideHotPath()`, etc. — but
under the old 1-arg lambda those helpers were stranded because the DSL
never handed the author a cursor. With the receiver-style change, an
imperative recipe gates as `visitMethodInvocation { mi ->
    if (cursor.isInsideLoop()) SearchResult.found(mi, "…") else mi
}`.

Migration cost: zero. Existing 1-arg lambdas auto-promote — Kotlin
accepts `{ node -> ... }` where a `T.(P) -> R` is expected, with the
receiver implicit. All in-tree imperative recipes compile unchanged.

Implementation:
  - Codegen template (`GenerateLanguageScopesTask`) emits the new
    receiver-style signature plus a Function2-style unchecked cast
    (`((Any, Any) -> Any)`) — receiver-with function types compile to
    Function2 on the JVM. The dispatcher passes `this` as the receiver
    when invoking the action.
  - Hand-written `KotlinScope.kt` mirrors the template change across
    all ~70 visit primitives.
  - New `RecipeDslSurfaceTest` case drives a tiny Java source through
    the DSL and asserts the cursor is populated inside the action.

v8.81.17

Toggle v8.81.17's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Scala: various parser fixes for whitespace in try-catch (#7680)

* Scala: fix multiline catch

* Scala: handle semicolon in catch

v8.81.16

Toggle v8.81.16's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
RPC: strip trailing / and attempt to shutdown Pyroscope gracefully (#…

…7673)

v8.81.15

Toggle v8.81.15's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Delegate org.openrewrite.semver classes to parent in RecipeClassLoader (

#7669)

When a recipe's runtime classpath contains rewrite-core, the child
RecipeClassLoader was redefining org.openrewrite.semver.DependencyMatcher
from the recipe-side jar while the parent classloader had already defined
it from the CLI/worker classpath. Code in rewrite-maven (specifically
DependencyTreeWalker, reachable from DependencyInsight) then tripped a
JVM loader-constraint violation when its method signatures referenced
DependencyMatcher across the loader boundary, surfacing as:

  java.lang.LinkageError: loader constraint violation: loader
  URLClassLoader wants to load class org.openrewrite.semver.DependencyMatcher.
  A different class with the same name was previously loaded by
  CliRecipeClassLoader.

org.openrewrite.semver.* (DependencyMatcher, LatestRelease, Semver, etc.)
are stable rewrite-core API types intended to be shared across the recipe
classloader boundary, so add the package to PARENT_DELEGATED_PREFIXES.

v8.81.14

Toggle v8.81.14's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Stop closing recipe classloaders on CachingMavenRecipeBundleResolver …

…close (#7670)

CachingMavenRecipeBundleResolver hands out RecipeBundleReader instances
whose CliRecipeClassLoaders are retained externally -- e.g. by Recipe
instances cached in moderne-cli's RunTask.RECIPE_CACHE that get reused
across partitions in a multi-repo `mod run`. Once a Recipe has been
prepared, the JVM's class cache contains classes defined by that
classloader, and any later getResourceAsStream / inner-class load
against those classes requires the classloader's URLClassPath jar
handles to remain open.

Two close paths in the prior implementation closed those handles while
consumers still held the classloader:

1. `close()` cascaded through every cached MavenRecipeBundleResolver
   (added by #7277 to fix Windows CI file-handle leaks) -- closing the
   reader, which closed its URLClassLoader's URLClassPath.

2. `resolverFor()` compared the cached entry's bundle.getVersion()
   against the incoming bundle's version and called markEvicted() on
   mismatch, also closing the inner resolver/reader/classloader.
   MavenRecipeBundleResolver.resolve() mutates the input bundle's
   version to the dated snapshot after resolution, so any fresh
   RecipeBundle still on the requested SNAPSHOT version triggered
   eviction. The RPC PrepareRecipe handler routinely passes such fresh
   bundles back through the resolvers.

The visible symptom is inner-class NoClassDefFoundError on a
CliRecipeClassLoader whose `==` identity is unchanged but whose
URLClassPath has been closed (so findResource returns null silently;
loadClass falls back to parent which doesn't have the recipe class;
calling code sees NCDFE on `new InnerClass()`). Reproduced against
rewrite-prethink (jtokkit cl100k_base.tiktoken null →
ComprehendCodeTokenCounter$CharCountTokenizer NCDFE) and
rewrite-static-analysis (FinalClassVisitor$FinalizingVisitor NCDFE).
See moderneinc/customer-requests#2346.

Drops the lease/proxy/eviction machinery; the cache is now a plain
package-coordinate computeIfAbsent. `close()` is a no-op with a doc
explaining the ownership transfer semantics. Consumers that need
deterministic cleanup must close the readers they retain (or rely on
JVM exit for one-shot processes).

The new CachingMavenRecipeBundleResolverTest pins the contract: a
TrackingRecipeClassLoader handed out by the resolver must have
closeCount == 0 after `resolver.close()`. Confirmed the test fails
against the prior implementation (closeCount was 1).

v8.81.13

Toggle v8.81.13's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
rpc: allow sharing the in-flight Semaphore across ExecutionContexts (#…

…7647)

The cap added in #7614 was scoped per-ExecutionContext: setMaxInFlight
stored an int in the ctx message map and withInFlightSlot lazily created
a Semaphore from it. Each independent ExecutionContext therefore got its
own Semaphore, which made the cap a per-ctx cap rather than the host-wide
cap callers like Moderne SaaS and the mod CLI expect when they create one
InMemoryExecutionContext per repo and run several in parallel.

Replace the int-message + lazy-create plumbing with a Semaphore-valued
message and an explicit setInFlightSemaphore(Semaphore) setter. Callers
that want a host-wide cap construct one Semaphore at the orchestrator
level and install the same instance on every participating context. The
old setMaxInFlight(int) is kept as a convenience for the single-ctx case
but its Javadoc now spells out that it is not host-wide. withInFlightSlot
runs the work unthrottled if no Semaphore is installed, preserving the
"unbounded by default" behavior.

Adds RewriteRpcExecutionContextViewTest covering: no-op default, fresh
Semaphore from setMaxInFlight, per-ctx isolation (the misuse pattern),
true sharing across many ctx/threads, and permit release on exception.

v8.81.12

Toggle v8.81.12's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
rewrite-python: Unknown declaring-type for unattributed method calls …

…+ public SearchResult.found (#7631)

Two paired changes that together unblock ``Preconditions.check(uses_method(...), V())``
gates from failing wire-side evaluation when Python sources lack
receiver-type attribution (e.g. unit-test fixtures that don't import
the receiver).

## type_mapping

``PythonTypeMapping._get_declaring_type`` previously returned ``None``
when Ty couldn't resolve the receiver and AST inference didn't yield
a recognizable type. That left ``JavaType.Method._declaring_type`` as
``None`` for method invocations like ``my_array.tostring()`` in
unattributed sources. Java's ``MethodMatcher.matches`` accepts
``JavaType.Unknown`` receivers under wildcard patterns (``*..*``)
but rejects method types whose declaring type is null at the
``TypesInUse.hasMethodUse`` lookup level.

Now ``_get_declaring_type`` returns a non-null ``FullyQualified`` in
every case — falling back to the shared ``_UNKNOWN`` singleton — so
``HasMethod`` / ``UsesMethod`` precondition gates work against
unattributed code. The function signature changes from
``Optional[JavaType.FullyQualified]`` to ``JavaType.FullyQualified``
to document the new invariant. Resolution paths that previously
returned None now fall through to the AST-inference and Unknown
fallbacks.

## SearchResult.found

Adds a public ``SearchResult.found(tree, description=None)`` static
factory mirroring Java's ``org.openrewrite.marker.SearchResult.found``.
Returns a new tree carrying a fresh ``SearchResult`` marker — the
canonical "different tree" sentinel that ``Check`` /
``CompositePrecondition`` interpret as the gate matching. The native
``rewrite/python/search/{IsSourceFile,UsesType,UsesMethod}`` visitors
now call this instead of constructing the Markers/Marker pair by hand.