Skip to content

Fix Kotlin parser handling of unresolved callable references#7469

Merged
knutwannheden merged 1 commit intomainfrom
fix-kotlin-unresolved-callable-reference
Apr 24, 2026
Merged

Fix Kotlin parser handling of unresolved callable references#7469
knutwannheden merged 1 commit intomainfrom
fix-kotlin-unresolved-callable-reference

Conversation

@knutwannheden
Copy link
Copy Markdown
Contributor

Motivation

Parsing the buildSrc/build.gradle.kts file from the google/dagger repo fails with a print idempotency error:

java.lang.IllegalStateException: buildSrc/build.gradle.kts is not print idempotent.
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
@@ -28,3 +28,4 @@
 lint {
   baseline = file("lint-baseline.xml")
 }
+

The root cause is KotlinTreeParserVisitor#visitCallableReferenceExpression. It was checking the FIR mapping of the callable reference's right-hand-side name (expression.getCallableReference()). When the receiver type is unresolved — e.g. JavaLanguageVersion::of in a .gradle.kts parsed without the full Gradle classpath — the RHS maps to FirErrorNamedReferenceImpl, even though the whole expression still maps cleanly to FirCallableReferenceAccess. The visitor threw, the whole KtScript declaration bubbled up into J.Unknown, and the J.Unknown PSI text range (which included the trailing \n) then got duplicated against the file-level EOF space — producing the extra blank line on print.

Summary

  • KotlinTreeParserVisitor#visitCallableReferenceExpression now validates the expression-level FIR (FirCallableReferenceAccess) rather than the RHS-name FIR, and uses the RHS FIR only for optional type resolution; types remain null when the reference is unresolved, consistent with other unresolved-type paths.
  • Re-enables the previously @Disabled MemberReferenceTest#firCallableReferenceAccess regression test.
  • Adds CompilationUnitTest#unresolvedCallableReference (.kts path) and GradleParserTest#kotlinDslWithUnresolvedCallableReference (Gradle entry point) covering the reproduction.

Test plan

  • MemberReferenceTest#firCallableReferenceAccess (re-enabled) passes
  • New CompilationUnitTest#unresolvedCallableReference passes
  • New GradleParserTest#kotlinDslWithUnresolvedCallableReference passes
  • Full rewrite-kotlin test suite passes
  • Full rewrite-gradle test suite passes

`visitCallableReferenceExpression` looked up the FIR for the callable
reference's right-hand side (`expression.getCallableReference()`) to
decide whether to accept the reference. When the type is unresolved
(e.g. `JavaLanguageVersion::of` in a `.gradle.kts` parsed without the
full Gradle classpath), the RHS maps to `FirErrorNamedReferenceImpl`
even though the whole expression still maps cleanly to
`FirCallableReferenceAccess`. The visitor then threw, the declaration
bubbled up into `J.Unknown`, and its PSI text range (which includes the
trailing newline) got duplicated against the file's EOF space, causing
a print idempotency failure.

Check the FIR mapping of the whole expression for validity instead, and
use the reference-level FIR only for optional type resolution. Types
simply remain `null` when the reference cannot be resolved, which
matches how other unresolved-type scenarios are handled.

Re-enables the previously `@Disabled` `firCallableReferenceAccess`
regression test.
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Apr 24, 2026
@knutwannheden knutwannheden merged commit 39006a6 into main Apr 24, 2026
1 check passed
@knutwannheden knutwannheden deleted the fix-kotlin-unresolved-callable-reference branch April 24, 2026 18:49
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant