mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
C#: Extract global statements
This commit is contained in:
@@ -51,6 +51,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
Overrides(trapFile);
|
||||
ExtractRefReturn(trapFile, symbol, this);
|
||||
ExtractCompilerGenerated(trapFile);
|
||||
|
||||
if (SymbolEqualityComparer.Default.Equals(symbol, Context.Compilation.GetEntryPoint(System.Threading.CancellationToken.None)))
|
||||
{
|
||||
trapFile.entry_methods(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static new OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method);
|
||||
|
||||
@@ -1,13 +1,41 @@
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal abstract class Statement : FreshEntity, IExpressionParentEntity, IStatementParentEntity
|
||||
{
|
||||
protected Statement(Context cx) : base(cx) { }
|
||||
private readonly int child;
|
||||
private readonly Kinds.StmtKind kind;
|
||||
private readonly IStatementParentEntity parent;
|
||||
|
||||
public static Statement Create(Context cx, StatementSyntax node, Statement parent, int child) =>
|
||||
protected Statement(Context cx, Kinds.StmtKind kind, IStatementParentEntity parent, int child)
|
||||
: base(cx)
|
||||
{
|
||||
this.kind = kind;
|
||||
this.parent = parent;
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
protected override void Populate(TextWriter trapFile)
|
||||
{
|
||||
trapFile.statements(this, kind);
|
||||
if (parent.IsTopLevelParent)
|
||||
{
|
||||
trapFile.stmt_parent_top_level(this, child, parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.stmt_parent(this, child, parent);
|
||||
}
|
||||
|
||||
PopulateStatement(trapFile);
|
||||
}
|
||||
|
||||
protected abstract void PopulateStatement(TextWriter trapFile);
|
||||
|
||||
public static Statement Create(Context cx, StatementSyntax node, IStatementParentEntity parent, int child) =>
|
||||
Statements.Factory.Create(cx, node, parent, child);
|
||||
|
||||
/// <summary>
|
||||
@@ -16,14 +44,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
/// </summary>
|
||||
public virtual int NumberOfStatements => 1;
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => GetStatementSyntax().GetLocation();
|
||||
|
||||
bool IExpressionParentEntity.IsTopLevelParent => false;
|
||||
|
||||
bool IStatementParentEntity.IsTopLevelParent => false;
|
||||
|
||||
protected abstract CSharpSyntaxNode GetStatementSyntax();
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,40 +8,28 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
internal abstract class Statement<TSyntax> : Statement where TSyntax : CSharpSyntaxNode
|
||||
{
|
||||
protected readonly TSyntax Stmt;
|
||||
private readonly int child;
|
||||
private readonly Kinds.StmtKind kind;
|
||||
private readonly IStatementParentEntity parent;
|
||||
private readonly Location location;
|
||||
|
||||
protected override CSharpSyntaxNode GetStatementSyntax() => Stmt;
|
||||
|
||||
protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child, Location location)
|
||||
: base(cx)
|
||||
: base(cx, kind, parent, child)
|
||||
{
|
||||
Stmt = stmt;
|
||||
this.parent = parent;
|
||||
this.child = child;
|
||||
this.location = location;
|
||||
this.kind = kind;
|
||||
cx.BindComments(this, location.symbol);
|
||||
}
|
||||
|
||||
protected sealed override void Populate(TextWriter trapFile)
|
||||
{
|
||||
trapFile.statements(this, kind);
|
||||
if (parent.IsTopLevelParent)
|
||||
trapFile.stmt_parent_top_level(this, child, parent);
|
||||
else
|
||||
trapFile.stmt_parent(this, child, parent);
|
||||
trapFile.stmt_location(this, location);
|
||||
PopulateStatement(trapFile);
|
||||
}
|
||||
|
||||
protected abstract void PopulateStatement(TextWriter trapFile);
|
||||
|
||||
protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child)
|
||||
: this(cx, stmt, kind, parent, child, cx.CreateLocation(stmt.FixedLocation())) { }
|
||||
|
||||
protected sealed override void Populate(TextWriter trapFile)
|
||||
{
|
||||
base.Populate(trapFile);
|
||||
|
||||
trapFile.stmt_location(this, location);
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => Stmt.GetLocation();
|
||||
|
||||
public override string ToString() => Label.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
|
||||
{
|
||||
internal static class Factory
|
||||
{
|
||||
internal static Statement Create(Context cx, StatementSyntax node, Statement parent, int child)
|
||||
internal static Statement Create(Context cx, StatementSyntax node, IStatementParentEntity parent, int child)
|
||||
{
|
||||
switch (node.Kind())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Statements
|
||||
{
|
||||
internal class GlobalStatementsBlock : Statement
|
||||
{
|
||||
private GlobalStatementsBlock(Context cx, Method parent)
|
||||
: base(cx, StmtKind.BLOCK, parent, 0) { }
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation
|
||||
{
|
||||
get
|
||||
{
|
||||
// We only create a `GlobalStatementsBlock` if there are global statements. This also means that the
|
||||
// entry point is going to be the generated method around those global statements
|
||||
return cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None)
|
||||
?.DeclaringSyntaxReferences
|
||||
.FirstOrDefault()
|
||||
?.GetSyntax()
|
||||
.GetLocation();
|
||||
}
|
||||
}
|
||||
|
||||
public static GlobalStatementsBlock Create(Context cx, Method parent)
|
||||
{
|
||||
var ret = new GlobalStatementsBlock(cx, parent);
|
||||
ret.TryPopulate();
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override void PopulateStatement(TextWriter trapFile)
|
||||
{
|
||||
trapFile.global_stmt_block(this);
|
||||
|
||||
trapFile.stmt_location(this, cx.CreateLocation(ReportingLocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@ using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Util.Logging;
|
||||
using Semmle.Extraction.CSharp.Entities;
|
||||
using Semmle.Extraction.CSharp.Entities.Statements;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Populators
|
||||
{
|
||||
@@ -23,6 +26,8 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
Cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this));
|
||||
}
|
||||
|
||||
ExtractGlobalStatements(compilationUnit);
|
||||
|
||||
// Gather comments:
|
||||
foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span, descendIntoTrivia: true))
|
||||
{
|
||||
@@ -39,5 +44,30 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
CommentPopulator.ExtractComment(Cx, trivia);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtractGlobalStatements(CompilationUnitSyntax compilationUnit)
|
||||
{
|
||||
var globalStatements = compilationUnit
|
||||
.ChildNodes()
|
||||
.OfType<GlobalStatementSyntax>()
|
||||
.ToList();
|
||||
|
||||
if (!globalStatements.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var entryPoint = Cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None);
|
||||
var entryMethod = Method.Create(Cx, entryPoint);
|
||||
var block = GlobalStatementsBlock.Create(Cx, entryMethod);
|
||||
|
||||
for (var i = 0; i < globalStatements.Count; i++)
|
||||
{
|
||||
if (globalStatements[i].Statement is object)
|
||||
{
|
||||
Statement.Create(Cx, globalStatements[i].Statement, block, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,12 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
throw new InternalError(node, "Unhandled top-level syntax node");
|
||||
}
|
||||
|
||||
public override void VisitGlobalStatement(GlobalStatementSyntax node)
|
||||
{
|
||||
// Intentionally left empty.
|
||||
// Global statements are handled in CompilationUnitVisitor
|
||||
}
|
||||
|
||||
public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node)
|
||||
{
|
||||
Entities.NamedType.Create(Cx, Cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(TrapFile, Parent);
|
||||
@@ -84,7 +90,7 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
{
|
||||
if (attributeLookup.Value(attribute) is AttributeData attributeData)
|
||||
{
|
||||
var ae = Semmle.Extraction.CSharp.Entities.Attribute.Create(Cx, attributeData, outputAssembly);
|
||||
var ae = Entities.Attribute.Create(Cx, attributeData, outputAssembly);
|
||||
Cx.BindComments(ae, attribute.GetLocation());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,6 +379,11 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.WriteTuple("methods", method, name, declType, retType, originalDefinition);
|
||||
}
|
||||
|
||||
internal static void entry_methods(this TextWriter trapFile, Method method)
|
||||
{
|
||||
trapFile.WriteTuple("entry_methods", method);
|
||||
}
|
||||
|
||||
internal static void modifiers(this TextWriter trapFile, Label entity, string modifier)
|
||||
{
|
||||
trapFile.WriteTuple("modifiers", entity, modifier);
|
||||
@@ -509,6 +514,11 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.WriteTuple("stackalloc_array_creation", array);
|
||||
}
|
||||
|
||||
internal static void global_stmt_block(this TextWriter trapFile, Entities.Statements.GlobalStatementsBlock block)
|
||||
{
|
||||
trapFile.WriteTuple("global_stmt_block", block);
|
||||
}
|
||||
|
||||
internal static void stmt_location(this TextWriter trapFile, Statement stmt, Location location)
|
||||
{
|
||||
trapFile.WriteTuple("stmt_location", stmt, location);
|
||||
|
||||
Reference in New Issue
Block a user