From c68cd58f705fd32de6fa1e998d6b485daedf50aa Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 4 Feb 2026 13:19:29 +0100 Subject: [PATCH] C#: Add parameter marker interface, allow a type to a parent for parameter and make it possible to specify a parameter position offset. --- .../Entities/IParameter.cs | 9 ++++++ .../Entities/Parameter.cs | 28 +++++++++++++------ .../Semmle.Extraction.CSharp/Trap/Tuples.cs | 4 +-- 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/IParameter.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IParameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IParameter.cs new file mode 100644 index 00000000000..d3f3a04c08f --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IParameter.cs @@ -0,0 +1,9 @@ +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Marker interface for parameter entities. + /// + internal interface IParameter : IEntity + { + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index 49ef9a4a6e9..9cca0683f00 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -7,16 +7,23 @@ using Semmle.Extraction.CSharp.Populators; namespace Semmle.Extraction.CSharp.Entities { - internal class Parameter : CachedSymbol, IExpressionParentEntity + internal class Parameter : CachedSymbol, IExpressionParentEntity, IParameter { protected IEntity? Parent { get; set; } protected Parameter Original { get; } + private int PositionOffset { get; set; } - protected Parameter(Context cx, IParameterSymbol init, IEntity? parent, Parameter? original) + private Parameter(Context cx, IParameterSymbol init, IEntity? parent, Parameter? original, int positionOffset) : base(cx, init) { Parent = parent; Original = original ?? this; + PositionOffset = positionOffset; + } + + protected Parameter(Context cx, IParameterSymbol init, IEntity? parent, Parameter? original) + : this(cx, init, parent, original, 0) + { } public override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.GetSymbolLocation(); @@ -32,7 +39,7 @@ namespace Semmle.Extraction.CSharp.Entities RefReadOnly = 6 } - protected virtual int Ordinal => Symbol.Ordinal; + protected virtual int Ordinal => Symbol.Ordinal + PositionOffset; private Kind ParamKind { @@ -55,23 +62,25 @@ namespace Semmle.Extraction.CSharp.Entities if (Ordinal == 0) { if (Symbol.ContainingSymbol is IMethodSymbol method && method.IsExtensionMethod) + { return Kind.This; + } } return Kind.None; } } } - public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) + public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null, int positionOffset = 0) { var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param); - return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, parent, original)); + return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, parent, original, positionOffset)); } public static Parameter Create(Context cx, IParameterSymbol param) { var cachedSymbol = cx.GetPossiblyCachedParameterSymbol(param); - return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, null, null)); + return ParameterFactory.Instance.CreateEntity(cx, cachedSymbol, (cachedSymbol, null, null, 0)); } public override void WriteId(EscapingTextWriter trapFile) @@ -79,6 +88,9 @@ namespace Semmle.Extraction.CSharp.Entities if (Parent is null) Parent = Method.Create(Context, Symbol.ContainingSymbol as IMethodSymbol); + if (Parent is null && Symbol.ContainingSymbol is INamedTypeSymbol type && type.IsExtension) + Parent = Type.Create(Context, type); + if (Parent is null) throw new InternalError(Symbol, "Couldn't get parent of symbol."); @@ -194,11 +206,11 @@ namespace Semmle.Extraction.CSharp.Entities return syntax?.Default; } - private class ParameterFactory : CachedEntityFactory<(IParameterSymbol, IEntity?, Parameter?), Parameter> + private class ParameterFactory : CachedEntityFactory<(IParameterSymbol, IEntity?, Parameter?, int), Parameter> { public static ParameterFactory Instance { get; } = new ParameterFactory(); - public override Parameter Create(Context cx, (IParameterSymbol, IEntity?, Parameter?) init) => new Parameter(cx, init.Item1, init.Item2, init.Item3); + public override Parameter Create(Context cx, (IParameterSymbol, IEntity?, Parameter?, int) init) => new Parameter(cx, init.Item1, init.Item2, init.Item3, init.Item4); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs index b789eaa2e9c..c1d082bbee2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Trap/Tuples.cs @@ -292,10 +292,10 @@ namespace Semmle.Extraction.CSharp internal static void overrides(this TextWriter trapFile, Method overriding, Method overridden) => trapFile.WriteTuple("overrides", overriding, overridden); - internal static void param_location(this TextWriter trapFile, Parameter param, Location location) => + internal static void param_location(this TextWriter trapFile, IParameter param, Location location) => trapFile.WriteTuple("param_location", param, location); - internal static void @params(this TextWriter trapFile, Parameter param, string name, Type type, int child, Parameter.Kind mode, IEntity method, Parameter originalDefinition) => + internal static void @params(this TextWriter trapFile, IParameter param, string name, Type type, int child, Parameter.Kind mode, IEntity method, IParameter originalDefinition) => trapFile.WriteTuple("params", param, name, type, child, (int)mode, method, originalDefinition); internal static void parent_namespace(this TextWriter trapFile, IEntity type, Namespace parent) =>