Skip to content

Match nested type references by either . or $ in UsesType - #8430

Merged
knutwannheden merged 1 commit into
mainfrom
usestype-exact-match-misses-dotted-nested-types
Aug 9, 2026
Merged

Match nested type references by either . or $ in UsesType#8430
knutwannheden merged 1 commit into
mainfrom
usestype-exact-match-misses-dotted-nested-types

Conversation

@knutwannheden

Copy link
Copy Markdown
Contributor

Motivation

UsesType is used as a precondition by a large fraction of search and migration recipes, so anything it rejects is invisible to the recipe behind it — the caller gets zero results rather than an error, and cannot tell "no usages" from "your type name was rejected". Its Reference.Matcher for SourceFileWithReferences (Spring XML, properties, YAML) compared the requested type name to the reference value with String.equals, while every other matching path in the same recipes goes through TypeNameMatcher, which treats . and $ as equivalent at a nested-type boundary. A nested type written the way a developer writes it — a.b.Outer.Inner — therefore never matched a reference stored in binary form, and FindTypes was gated to zero by its own precondition even though its TypeMatcher would have matched.

Note that the Java source path was already correct: TypesInUse.hasType canonicalizes the query and the trie carries a canonical alias for every $-containing FQN, and the legacy fallback compares via TypeUtils.isAssignableTo(String, JavaType). This PR closes the one remaining path where the comparison was literal.

Summary

  • UsesType.ExactMatch.matchesReference compares with TypeUtils.fullyQualifiedNamesAreEqual instead of String.equals, so a nested type matches a reference written in either form.
  • Added UsesTypeTest coverage for nested types in dotted and binary form (single and double nesting, including the mixed a.b.Outer.Mid$Inner), a top-level miss, an uppercase package segment that must not be treated as a nesting boundary, and the XML reference case.
  • Added FindTypesTest coverage asserting both forms produce the same result, on Java sources and on a Spring XML bean class.

The trie lookup is untouched, so the O(1) fast path for exact fully qualified names is unchanged.

Test plan

  • ./gradlew :rewrite-java-test:test --tests "org.openrewrite.java.search.UsesTypeTest" --tests "org.openrewrite.java.search.FindTypesTest" passes.
  • With the UsesType change reverted, FindTypesTest > nestedTypeInSpringXml [1] type = "a.b.Outer.Inner" is the single failure — the new tests fail for the intended reason.
  • ./gradlew :rewrite-java-test:test :rewrite-java:test passes in full.

`UsesType`'s `Reference.Matcher` for `SourceFileWithReferences` compared the
requested name to the reference value with `String.equals`, so a nested type
written in dotted form never matched a Spring XML/properties/YAML reference in
binary form. Recipes gated on `UsesType` — including `FindTypes`, whose own
`TypeMatcher` accepts both forms — short-circuited to zero results.

Comparing with `TypeUtils.fullyQualifiedNamesAreEqual` brings the matcher in
line with `TypeNameMatcher`, which every other matching path in these recipes
already uses.
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Aug 8, 2026
@knutwannheden
knutwannheden merged commit 80d1f1b into main Aug 9, 2026
1 check passed
@knutwannheden
knutwannheden deleted the usestype-exact-match-misses-dotted-nested-types branch August 9, 2026 05:58
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant