Skip to content

Fix addServiceListener not injected for union service type in listener attach#44594

Open
anuruddhal wants to merge 2 commits into
ballerina-platform:masterfrom
anuruddhal:fix/listener-attach-union-service-type-master
Open

Fix addServiceListener not injected for union service type in listener attach#44594
anuruddhal wants to merge 2 commits into
ballerina-platform:masterfrom
anuruddhal:fix/listener-attach-union-service-type-master

Conversation

@anuruddhal
Copy link
Copy Markdown
Member

@anuruddhal anuruddhal commented May 8, 2026

Problem

When a Ballerina listener's attach() method accepts a union service type (e.g. salesforce:Service = CdcService|PlatformEventsService), the compiler skips injecting the addServiceListener call into the listener's generated call dispatch method. This causes those services to never appear in the runtime repository, so tools that rely on env.getRepository().getArtifacts() (such as WSO2 ICP) report empty listeners/services for any non-HTTP event-driven integration.

Root cause: isListenerAttach() checked Flags.SERVICE directly on the parameter type. BUnionType never carries Flags.SERVICE on its own flags, even when every member of the union is a service type.

Fix

Introduce isServiceType(BType) that:

  • Returns true if the type directly carries Flags.SERVICE
  • Recurses into all members of a BUnionType (true only when every member is a service type)
  • Unwraps BTypeReferenceType (guards against null referredType) before recursing

isListenerAttach() is updated to delegate to isServiceType().

Related

Backport of #44592 (merged into 2201.13.x).

Summary

This pull request fixes a compiler code-generation bug that caused addServiceListener to be omitted for listener attach() methods when the attach parameter was a union of service types (e.g., CdcService|PlatformEventsService). As a result, services for such listeners were not registered in the runtime repository and were not discoverable by tools inspecting env.getRepository().getArtifacts().

Changes

File: JvmObjectGen.java

  • Replace direct flag check with a new helper method isServiceType(BType):
    • Returns true when the type directly carries the SERVICE flag.
    • For union types, returns true only if every union member is a service type (recursive).
    • For type references, unwraps the referred type (with null safety) and checks it.
  • Update isListenerAttach() to use isServiceType() and add a guard ensuring the function parameter list has at least two parameters before accessing parameters.getFirst() and emitting the generated args[1] access. This prevents unsafe runtime access to args[1] and avoids emitting an AALOAD for index 1 when the argument is not guaranteed to be present.
  • Add imports for BTypeReferenceType and BUnionType to support the new checks.

Impact

Ensures addServiceListener is injected for listeners whose attach parameter is a union of service types, so those services are correctly registered in the runtime repository and visible to repository inspection tools. Also improves codegen safety by avoiding out-of-bounds argument access during call dispatch generation.

…r attach

When a listener's attach() accepts a union service type (e.g. salesforce:Service
= CdcService|PlatformEventsService), the compiler skips injecting the
addServiceListener call because BUnionType does not carry Flags.SERVICE on its
own flags, even though every member of the union is a service type.

Introduce isServiceType() that recurses into union member types and unwraps
BTypeReferenceType before checking the SERVICE flag, so addServiceListener is
correctly injected for any listener whose attach() parameter is a union of
service types.

Fixes: https://github.com/ballerina-platform/ballerina-lang/issues/XXXXX
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2e932f2c-0ba7-429a-b935-2094192f7b8c

📥 Commits

Reviewing files that changed from the base of the PR and between d82e20a and 640f471.

📒 Files selected for processing (1)
  • compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/values/JvmObjectGen.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/values/JvmObjectGen.java

📝 Walkthrough

Walkthrough

Replaces a direct Flags.SERVICE check in JvmObjectGen with a recursive isServiceType(BType) helper that handles union members and type references; adds necessary imports and updates isListenerAttach to delegate to the new helper.

Changes

Service Type Detection Refactoring

Layer / File(s) Summary
Type Dependencies
compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/values/JvmObjectGen.java
Imports added for BTypeReferenceType and BUnionType.
Service Type Detection Helper
compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/values/JvmObjectGen.java
New private isServiceType(BType) checks SERVICE flag, treats union as service-only if all members are service, and resolves referenced types recursively.
Integration Point
compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/values/JvmObjectGen.java
isListenerAttach updated to call isServiceType(...) for its first parameter type instead of checking top-level Flags.SERVICE.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • sameerajayasoma
  • hasithaa
  • gimantha
  • MaryamZi
  • tharindu-nw

Poem

🐰 I hop through types both wide and deep,
Unions and refs no longer asleep,
From flags to roots I softly pry,
So listener attach checks no longer lie,
A tiny hop — a wiser sky.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description clearly documents the problem, root cause, and the fix with an isServiceType() helper. However, it does not follow the required template structure with explicit sections like Purpose, Approach, Samples, Remarks, and Check List. Restructure the description to match the template: add explicit 'Purpose', 'Approach', 'Samples', and 'Remarks' sections, and include the required Check List with relevant items marked.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix addServiceListener not injected for union service type in listener attach' directly describes the main bug fix in the changeset—the handling of union service types in listener attach methods.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/values/JvmObjectGen.java`:
- Around line 189-192: The isListenerAttach helper assumes
func.parameters.getFirst() exists and later injection code reads args[1]
unconditionally; add explicit arity guards: in
isListenerAttach(BIRNode.BIRFunction func) return false unless func.parameters
has at least one parameter (check size()/isEmpty()) before calling getFirst(),
and in the code path that injects/reads args[1] ensure the function parameter
count or runtime args.length is >=2 before dereferencing args[1] (or bail/skip
injection when arity is too small) so both compile-time and runtime accesses are
safe for non-attach arities.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 74b0eccd-94c0-4720-842d-3155b70df681

📥 Commits

Reviewing files that changed from the base of the PR and between f59068a and d82e20a.

📒 Files selected for processing (1)
  • compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/values/JvmObjectGen.java

isListenerAttach called getFirst() without checking whether the parameters
list was non-empty, and the injection site unconditionally read args[1] at
runtime. A single size() >= 2 guard prevents both: getFirst() is safe
(non-empty list), and the generated AALOAD at index 1 is only emitted when
the function has at least two parameters so the runtime args array is
guaranteed to contain args[1].
@codecov
Copy link
Copy Markdown

codecov Bot commented May 8, 2026

Codecov Report

❌ Patch coverage is 11.11111% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.02%. Comparing base (3211861) to head (640f471).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...ompiler/bir/codegen/split/values/JvmObjectGen.java 11.11% 5 Missing and 3 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master   #44594      +/-   ##
============================================
- Coverage     75.03%   75.02%   -0.01%     
- Complexity    58707    58708       +1     
============================================
  Files          3601     3601              
  Lines        227161   227169       +8     
  Branches      29581    29585       +4     
============================================
- Hits         170443   170439       -4     
- Misses        47215    47223       +8     
- Partials       9503     9507       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant