From 01fe081f368c26293b1ed8be975e03b68b0841e4 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 21 May 2026 13:12:24 +0200 Subject: [PATCH] C#: Extract the indexer as the call target when using range expressions with spans. --- .../Entities/Expressions/ElementAccess.cs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index 345e691a8a8..6f832132185 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; @@ -17,6 +18,35 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private readonly ExpressionSyntax qualifier; private readonly BracketedArgumentListSyntax argumentList; + + private IPropertySymbol? GetIndexerSymbol() + { + var symbol = Context.GetSymbolInfo(base.Syntax).Symbol; + + if (symbol is IPropertySymbol { IsIndexer: true } indexer) + return indexer; + + // In some cases, Roslyn translates the use of range expressions directly into method calls. + // E.g. `a[0..3]` is translated into `a.Slice(0, 3)`, if `a` is a `Span`. + // In this case, we want to populate the indexer access as normal (as this reflects the source code more accurately). + if (symbol is IMethodSymbol method) + { + var indexers = method + .ContainingType + .GetMembers() + .OfType() + .Where(p => p.IsIndexer); + + var intIndexer = indexers + .Where(i => i.Parameters.Length == 1 && i.Parameters[0].Type.SpecialType == SpecialType.System_Int32) + .FirstOrDefault(); + + return intIndexer; + } + + return null; + } + protected override void PopulateExpression(TextWriter trapFile) { if (Kind == ExprKind.POINTER_INDIRECTION) @@ -32,9 +62,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Create(Context, qualifier, this, -1); PopulateArguments(trapFile, argumentList, 0); - var symbolInfo = Context.GetSymbolInfo(base.Syntax); - - if (symbolInfo.Symbol is IPropertySymbol indexer) + var indexer = GetIndexerSymbol(); + if (indexer is not null) { trapFile.expr_access(this, Indexer.Create(Context, indexer)); }