C#: Extract .Slice method call when using a span in conjunction with a range.#21877
C#: Extract .Slice method call when using a span in conjunction with a range.#21877michaelnebel wants to merge 13 commits into
.Slice method call when using a span in conjunction with a range.#21877Conversation
4eec760 to
9167814
Compare
There was a problem hiding this comment.
Pull request overview
This PR improves the C# extractor’s handling of element-access expressions that use range syntax (for example, a[0..3]) when Roslyn lowers them into method calls (for example, Slice(...)). The goal is to preserve the source-level “indexer access” shape by still recording an indexer as the call target, improving database-quality telemetry.
Changes:
- Added extractor special-casing to recover an indexer symbol even when Roslyn binds the element access to a method symbol.
- Updated the Telemetry/DatabaseQuality query test inputs and expected outputs to reflect the improved extraction.
- Added a C# library change note documenting the analysis-impacting extraction improvement.
Show a summary per file
| File | Description |
|---|---|
| csharp/ql/test/query-tests/Telemetry/DatabaseQuality/Quality.cs | Updates test code to treat range element access as properly-targeted indexer calls. |
| csharp/ql/test/query-tests/Telemetry/DatabaseQuality/NoTarget.expected | Removes expected “missing call target” results now that targets are extracted. |
| csharp/ql/test/query-tests/Telemetry/DatabaseQuality/IsNotOkayCall.expected | Eliminates expected “not ok” call-target results for the fixed cases. |
| csharp/ql/lib/change-notes/2026-05-21-spanaccess-range.md | Documents the extraction change as a minor analysis improvement. |
| csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs | Implements the new symbol recovery logic for range-based element access. |
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 1
hvitved
left a comment
There was a problem hiding this comment.
I'm not convinced that extracting the indexer is what we want; what about extracting the Roslyn-resolved targets instead and treating the index expressions as ordinary method calls?
Yes, I also considered that, but thought it would be better to extract something that more closely resembles the syntax instead of what it is being translated into. If I were to query our code and asking for uses of indexers, then I would expect cases like |
9167814 to
ee734c9
Compare
…guments, when using indexers in conjunction with ranges on spans and strings.
ee734c9 to
8d0575c
Compare
.Slice method call when using a span in conjunction with a range.
Improves the extraction of span access with range expressions (such as
a[1..3]).Roslyn translates
a[1..3]intoa.Slice(1,3 - 1)for spans (and something similar for strings).In this PR we introduce some special handling in the extractor for such cases
awe extract aa.Slicemethod call.a.Slice.Roslyn translates as follows
a[x..y]is translated toa.Slice(x, y - x).a[..y]is translated toa.Slice(0, y)a[x..]is translated toa.Slice(x, a.Length - x).a[..]is translated toa.Slice(0, a.Length).It is also possible to use read from the end as well (e.g.
^2).a[x..^y]translates intoa.Slice(x, a.Length - y - x).Furthermore, it is worth noting that the range endpoints could be the result of a method call.
This means that if we want to fully synthesize
var a = f()[m() .. ^3], we would need to synthesizeFor simplicity reasons, we choose to extract as follows
a[x..y]is translated toa.Slice(x, y).a[..y]is translated toa.Slice(0, y)a[x..]is translated toa.Slice(x, ^0).a[..]is translated toa.Slice(0, ^0).This will make it possible to calculate the correct start index and length arguments in the QL side (if needed).
Similar to span access with range expressions, it is also possible to use range expressions in conjunction with strings. If
sis a string, thens[1..3]translates intos.Substring(1, 3 - 1). This is also handled in this PR.