Summary
Tighten single-TU shared-root tracking so the analyzer only follows globals defined in the current module, then remap inline-library access locations to the outermost user callsite while preserving the original lowered IR location as relatedLocations. This fixes the std::cout noise in cpp_move_semantics_race.cpp without relying on hardcoded system-path filters, and keeps JSON/SARIF traceability intact.
Key Changes
Tighten shared-root eligibility in the IR helpers:
- Replace the current “external non-constant global” rule with “non-constant, non-thread-local global that is defined in the current module”.
- Use LLVM global-definition semantics (!isDeclaration() or equivalent definition check), not path/name heuristics.
- Keep this centralized in the existing root-resolution helper so every analysis path inherits the same policy.
Split internal access locations into two notions:
- loweredLocation: the exact instruction location as today.
- userLocation: the outermost inlinedAt callsite when debug info carries an inline chain; otherwise the lowered location.
- Keep this as an internal analysis detail; do not change the public CLI/API surface.
Add an internal location-resolution helper in the LLVM utility layer that:
- builds the raw/lowered location from the instruction’s direct DebugLoc
walks the DILocation / inlinedAt chain to compute the user-facing location
falls back cleanly when debug info is partial or absent
Preserve analysis identity on lowered locations:
- Keep deduplication and internal fact identity keyed on the lowered/raw location, not the remapped user location.
- Use the remapped user location only when emitting diagnostics and function summaries.
Emit both locations in diagnostics:
- primary diagnostic location becomes the user-facing location
original lowered location is added as a relatedLocation when it differs
pair diagnostics keep the existing conflicting-access related location and add lowered related locations for each side when needed
self-concurrent diagnostics keep the current self-related location and add the lowered location when needed
Update renderers:
- human: render all relatedLocations explicitly, using their labels, after the diagnostic body
json and sarif: no schema change, but the newly populated related locations flow through automatically
Keep everything generic:
- no hardcoded /usr/include / Homebrew / Xcode path filtering
- no stdlib mangling denylist
- no new CLI flags in this milestone
- no diagnostic dedup redesign yet
Test Plan
Add regression coverage for cpp_move_semantics_race.cpp:
- only shared_resource findings remain
- no diagnostics for _ZNSt3__14coutE
- primary human/json/sarif locations point to the fixture file, not libc++ headers
- related locations include the lowered libc++ frame for traceability
Keep existing positives passing unchanged:
- data_race_basic.c
- cpp_atomic_vs_non_atomic.cpp
- cpp_data_race_class.cpp
- cpp_shared_object_by_ref.cpp
Keep existing negatives passing unchanged:
- data_race_mutex_protected.c
- cpp_thread_local_class.cpp
Extend CLI checks to assert:
- cpp_move_semantics_race.cpp --analyze contains symbol: shared_resource
- it does not contain symbol: _ZNSt3__14coutE
- the primary location shown is in the fixture
- the human output shows labeled related locations
- Add at least one structured-output assertion that relatedLocations are populated in JSON/SARIF for the remapped inline-access case.
- Keep current human golden tests unchanged unless a newly opted-in fixture is added specifically for this behavior.
Assumptions
- TU-defined only is the chosen root policy: in single-TU mode, globals must be defined in the current module to be considered shared roots.
- User-facing remapping uses the outermost available inline callsite from LLVM debug metadata; no filesystem path heuristics are used to guess “user” vs “system”.
- The human renderer should show all related locations explicitly.
- This milestone intentionally does not include broader diagnostic deduplication or std::async support.
Summary
Tighten single-TU shared-root tracking so the analyzer only follows globals defined in the current module, then remap inline-library access locations to the outermost user callsite while preserving the original lowered IR location as relatedLocations. This fixes the std::cout noise in cpp_move_semantics_race.cpp without relying on hardcoded system-path filters, and keeps JSON/SARIF traceability intact.
Key Changes
Tighten shared-root eligibility in the IR helpers:
Split internal access locations into two notions:
Add an internal location-resolution helper in the LLVM utility layer that:
walks the DILocation / inlinedAt chain to compute the user-facing location
falls back cleanly when debug info is partial or absent
Preserve analysis identity on lowered locations:
Emit both locations in diagnostics:
original lowered location is added as a relatedLocation when it differs
pair diagnostics keep the existing conflicting-access related location and add lowered related locations for each side when needed
self-concurrent diagnostics keep the current self-related location and add the lowered location when needed
Update renderers:
json and sarif: no schema change, but the newly populated related locations flow through automatically
Keep everything generic:
Test Plan
Add regression coverage for cpp_move_semantics_race.cpp:
Keep existing positives passing unchanged:
Keep existing negatives passing unchanged:
Extend CLI checks to assert:
Assumptions