C#: Add extractor support for object initializer methods.

This commit is contained in:
Anders Schack-Mulligen
2025-11-25 15:52:34 +01:00
parent a7066ec758
commit 9414cfbd03
5 changed files with 93 additions and 4 deletions

View File

@@ -74,6 +74,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
case SyntaxKind.BaseConstructorInitializer:
initializerType = Symbol.ContainingType.BaseType!;
ExtractObjectInitCall(trapFile);
break;
case SyntaxKind.ThisConstructorInitializer:
initializerType = Symbol.ContainingType;
@@ -90,10 +91,12 @@ namespace Semmle.Extraction.CSharp.Entities
var primaryInfo = Context.GetSymbolInfo(primaryInitializer);
var primarySymbol = primaryInfo.Symbol;
ExtractObjectInitCall(trapFile);
ExtractSourceInitializer(trapFile, primarySymbol?.ContainingType, (IMethodSymbol?)primarySymbol, primaryInitializer.ArgumentList, primaryInitializer.GetLocation());
}
else if (Symbol.MethodKind is MethodKind.Constructor)
{
ExtractObjectInitCall(trapFile);
var baseType = Symbol.ContainingType.BaseType;
if (baseType is null)
{
@@ -127,6 +130,27 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
private void ExtractObjectInitCall(TextWriter trapFile)
{
var target = ObjectInitMethod.Create(Context, ContainingType!);
var type = Context.Compilation.GetSpecialType(SpecialType.System_Void);
var info = new ExpressionInfo(Context,
AnnotatedTypeSymbol.CreateNotAnnotated(type),
Location,
Kinds.ExprKind.METHOD_INVOCATION,
this,
-2,
isCompilerGenerated: true,
null);
var obinitCall = new Expression(info);
trapFile.expr_call(obinitCall, target);
Expressions.This.CreateImplicit(Context, Symbol.ContainingType, Location, obinitCall, -1);
}
private void ExtractSourceInitializer(TextWriter trapFile, ITypeSymbol? type, IMethodSymbol? symbol, ArgumentListSyntax arguments, Microsoft.CodeAnalysis.Location location)
{
var initInfo = new ExpressionInfo(Context,

View File

@@ -0,0 +1,9 @@
namespace Semmle.Extraction.CSharp.Entities
{
/// <summary>
/// Marker interface for method entities.
/// </summary>
public interface IMethodEntity : IEntity
{
}
}

View File

@@ -9,7 +9,7 @@ using Semmle.Extraction.CSharp.Populators;
namespace Semmle.Extraction.CSharp.Entities
{
internal abstract class Method : CachedSymbol<IMethodSymbol>, IExpressionParentEntity, IStatementParentEntity
internal abstract class Method : CachedSymbol<IMethodSymbol>, IExpressionParentEntity, IStatementParentEntity, IMethodEntity
{
protected Method(Context cx, IMethodSymbol init)
: base(cx, init) { }

View File

@@ -0,0 +1,56 @@
using System.IO;
using Microsoft.CodeAnalysis;
namespace Semmle.Extraction.CSharp.Entities
{
internal sealed class ObjectInitMethod : CachedEntity, IMethodEntity
{
Type ContainingType { get; }
private ObjectInitMethod(Context cx, Type containingType)
: base(cx)
{
this.ContainingType = containingType;
}
public string Name => "<object initializer>";
public static ObjectInitMethod Create(Context cx, Type containingType)
{
return ObjectInitMethodFactory.Instance.CreateEntity(cx, (typeof(ObjectInitMethod), containingType), containingType);
}
public override void Populate(TextWriter trapFile)
{
var returnType = Type.Create(Context, Context.Compilation.GetSpecialType(SpecialType.System_Void));
trapFile.methods(this, Name, ContainingType, returnType.TypeRef, this);
trapFile.compiler_generated(this);
trapFile.method_location(this, Context.CreateLocation(ReportingLocation));
}
public override void WriteId(EscapingTextWriter trapFile)
{
trapFile.WriteSubId(ContainingType);
trapFile.Write(".");
trapFile.Write(Name);
trapFile.Write(";method");
}
public override Microsoft.CodeAnalysis.Location? ReportingLocation => ContainingType.ReportingLocation;
public override bool NeedsPopulation => true;
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
private class ObjectInitMethodFactory : CachedEntityFactory<Type, ObjectInitMethod>
{
public static ObjectInitMethodFactory Instance { get; } = new ObjectInitMethodFactory();
public override ObjectInitMethod Create(Context cx, Type containingType) =>
new ObjectInitMethod(cx, containingType);
}
}
}

View File

@@ -175,7 +175,7 @@ namespace Semmle.Extraction.CSharp
internal static void expr_argument_name(this TextWriter trapFile, Expression expr, string name) =>
trapFile.WriteTuple("expr_argument_name", expr, name);
internal static void expr_call(this TextWriter trapFile, Expression expr, Method target) =>
internal static void expr_call(this TextWriter trapFile, Expression expr, IMethodEntity target) =>
trapFile.WriteTuple("expr_call", expr, target);
internal static void expr_flowstate(this TextWriter trapFile, Expression expr, int flowState) =>
@@ -247,10 +247,10 @@ namespace Semmle.Extraction.CSharp
internal static void localvars(this TextWriter trapFile, LocalVariable key, VariableKind kind, string name, int @var, Type type, Expression expr) =>
trapFile.WriteTuple("localvars", key, (int)kind, name, @var, type, expr);
internal static void method_location(this TextWriter trapFile, Method method, Location location) =>
internal static void method_location(this TextWriter trapFile, IMethodEntity method, Location location) =>
trapFile.WriteTuple("method_location", method, location);
internal static void methods(this TextWriter trapFile, Method method, string name, Type declType, Type retType, Method originalDefinition) =>
internal static void methods(this TextWriter trapFile, IMethodEntity method, string name, Type declType, Type retType, IMethodEntity originalDefinition) =>
trapFile.WriteTuple("methods", method, name, declType, retType, originalDefinition);
internal static void modifiers(this TextWriter trapFile, Label entity, string modifier) =>