C#: Cache the Block and ExpressionBody and streamline implementation too look for both when checking whether a body is available.

This commit is contained in:
Michael Nebel
2026-02-20 09:52:26 +01:00
parent 7d7bbf2a50
commit e8427a59f5
4 changed files with 20 additions and 15 deletions

View File

@@ -70,7 +70,7 @@ namespace Semmle.Extraction.CSharp.Entities
Overrides(trapFile);
if (Symbol.FromSource() && Block is null)
if (Symbol.FromSource() && !HasBody)
{
trapFile.compiler_generated(this);
}

View File

@@ -9,9 +9,14 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal abstract class CachedSymbol<T> : CachedEntity<T> where T : class, ISymbol
{
private readonly Lazy<BlockSyntax?> blockLazy;
private readonly Lazy<ExpressionSyntax?> expressionBodyLazy;
protected CachedSymbol(Context cx, T init)
: base(cx, init)
{
blockLazy = new Lazy<BlockSyntax?>(() => GetBlock(BodyDeclaringSymbol));
expressionBodyLazy = new Lazy<ExpressionSyntax?>(() => GetExpressionBody(BodyDeclaringSymbol));
}
public virtual Type? ContainingType => Symbol.ContainingType is not null
@@ -89,29 +94,29 @@ namespace Semmle.Extraction.CSharp.Entities
protected virtual T BodyDeclaringSymbol => Symbol;
public BlockSyntax? Block
private static BlockSyntax? GetBlock(T symbol)
{
get
{
return BodyDeclaringSymbol.DeclaringSyntaxReferences
return symbol.DeclaringSyntaxReferences
.SelectMany(r => r.GetSyntax().ChildNodes())
.OfType<BlockSyntax>()
.FirstOrDefault();
}
}
public ExpressionSyntax? ExpressionBody
private static ExpressionSyntax? GetExpressionBody(T symbol)
{
get
{
return BodyDeclaringSymbol.DeclaringSyntaxReferences
return symbol.DeclaringSyntaxReferences
.SelectMany(r => r.GetSyntax().ChildNodes())
.OfType<ArrowExpressionClauseSyntax>()
.Select(arrow => arrow.Expression)
.FirstOrDefault();
}
}
public BlockSyntax? Block => blockLazy.Value;
public ExpressionSyntax? ExpressionBody => expressionBodyLazy.Value;
public bool HasBody => Block is not null || ExpressionBody is not null;
public virtual bool IsSourceDeclaration => Symbol.IsSourceDeclaration();
public override bool NeedsPopulation => Context.Defines(Symbol);

View File

@@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.Entities
return;
}
if (MakeSynthetic)
if (MakeSyntheticBody)
{
// Create a synthetic empty body for primary and default constructors.
Statements.SyntheticEmptyBlock.Create(Context, this, 0, Location);
@@ -60,7 +60,7 @@ namespace Semmle.Extraction.CSharp.Entities
// Do not extract initializers for constructed types.
// Extract initializers for constructors with a body, primary constructors
// and default constructors for classes and structs declared in source code.
if (Block is null && ExpressionBody is null && !MakeSynthetic || Context.OnlyScaffold)
if (!HasBody && !MakeSyntheticBody || Context.OnlyScaffold)
{
return;
}
@@ -211,7 +211,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
private bool IsBestSourceLocation => ReportingLocation is not null && Context.IsLocationInContext(ReportingLocation);
private bool MakeSynthetic => (IsPrimary || (IsDefault && IsBestSourceLocation)) && !Context.OnlyScaffold;
private bool MakeSyntheticBody => (IsPrimary || (IsDefault && IsBestSourceLocation)) && !Context.OnlyScaffold;
[return: NotNullIfNotNull(nameof(constructor))]
public static new Constructor? Create(Context cx, IMethodSymbol? constructor)

View File

@@ -59,7 +59,7 @@ namespace Semmle.Extraction.CSharp.Entities
Overrides(trapFile);
if (Symbol.FromSource() && Block is null)
if (Symbol.FromSource() && !HasBody)
{
trapFile.compiler_generated(this);
}