C#: Add class for making synthetic parameter entities.

This commit is contained in:
Michael Nebel
2026-02-04 13:21:09 +01:00
parent 60bb9a9b06
commit ab505e3281

View File

@@ -0,0 +1,94 @@
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Semmle.Extraction.CSharp.Entities
{
/// <summary>
/// Synthetic parameter for extension methods declared using the extension syntax.
/// That is, we add a synthetic parameter s to IsValid in the following example:
/// extension(string s) {
/// public bool IsValid() { ... }
/// }
///
/// Note, that we use the characteristics of the parameter of the extension type
/// to populate the database.
/// </summary>
internal class SyntheticExtensionParameter : FreshEntity, IParameter
{
private Method ExtensionMethod { get; }
private IParameterSymbol ExtensionParameter { get; }
private SyntheticExtensionParameter Original { get; }
private SyntheticExtensionParameter(Context cx, Method method, IParameterSymbol parameter, SyntheticExtensionParameter? original) : base(cx)
{
ExtensionMethod = method;
ExtensionParameter = parameter;
Original = original ?? this;
}
private static int Ordinal => 0;
private Parameter.Kind ParamKind
{
get
{
switch (ExtensionParameter.RefKind)
{
case RefKind.Ref:
return Parameter.Kind.Ref;
case RefKind.In:
return Parameter.Kind.In;
case RefKind.RefReadOnlyParameter:
return Parameter.Kind.RefReadOnly;
default:
return Parameter.Kind.None;
}
}
}
private string Name => ExtensionParameter.Name;
private bool IsSourceDeclaration => ExtensionMethod.Symbol.IsSourceDeclaration();
protected override void Populate(TextWriter trapFile)
{
PopulateNullability(trapFile, ExtensionParameter.GetAnnotatedType());
PopulateRefKind(trapFile, ExtensionParameter.RefKind);
var type = Type.Create(Context, ExtensionParameter.Type);
trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, ExtensionMethod, Original);
if (Context.OnlyScaffold)
{
return;
}
if (Context.ExtractLocation(ExtensionParameter))
{
var locations = Context.GetLocations(ExtensionParameter);
WriteLocationsToTrap(trapFile.param_location, this, locations);
}
if (IsSourceDeclaration)
{
foreach (var syntax in ExtensionParameter.DeclaringSyntaxReferences
.Select(d => d.GetSyntax())
.OfType<ParameterSyntax>()
.Where(s => s.Type is not null))
{
TypeMention.Create(Context, syntax.Type!, this, type);
}
}
}
public static SyntheticExtensionParameter Create(Context cx, Method method, IParameterSymbol parameter, SyntheticExtensionParameter? original)
{
var p = new SyntheticExtensionParameter(cx, method, parameter, original);
p.TryPopulate();
return p;
}
}
}