Rework foreach_stmt_info extraction

This commit is contained in:
Tamas Vajk
2021-02-04 11:19:05 +01:00
parent 7c506f445c
commit 63b0fe10e4
6 changed files with 70 additions and 22 deletions

View File

@@ -8,6 +8,15 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
{
internal class ForEach : Statement<ForEachStatementSyntax>
{
internal enum ForeachSymbolType
{
GetEnumeratorMethod = 1,
CurrentProperty,
MoveNextMethod,
DisposeMethod,
ElementType
}
private ForEach(Context cx, ForEachStatementSyntax stmt, IStatementParentEntity parent, int child)
: base(cx, stmt, StmtKind.FOREACH, parent, child) { }
@@ -33,13 +42,44 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
Statement.Create(cx, Stmt.Statement, this, 2);
var info = semanticModel.GetForEachStatementInfo(Stmt);
var getEnumerator = Method.Create(cx, info.GetEnumeratorMethod);
var currentProp = Property.Create(cx, info.CurrentProperty);
var moveNext = Method.Create(cx, info.MoveNextMethod);
var dispose = Method.Create(cx, info.DisposeMethod);
var elementType = Type.Create(cx, info.ElementType);
trapFile.foreach_stmt_info(this, elementType, getEnumerator, moveNext, dispose, currentProp, info.IsAsynchronous);
if (info.Equals(default))
{
cx.ExtractionError("Could not get foreach statement info", null, Location.Create(cx, this.ReportingLocation), severity: Util.Logging.Severity.Info);
return;
}
trapFile.foreach_stmt_info(this, info.IsAsynchronous);
if (info.GetEnumeratorMethod != null)
{
var m = Method.Create(cx, info.GetEnumeratorMethod);
trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.GetEnumeratorMethod);
}
if (info.MoveNextMethod != null)
{
var m = Method.Create(cx, info.MoveNextMethod);
trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.MoveNextMethod);
}
if (info.DisposeMethod != null)
{
var m = Method.Create(cx, info.DisposeMethod);
trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.DisposeMethod);
}
if (info.CurrentProperty != null)
{
var p = Property.Create(cx, info.CurrentProperty);
trapFile.foreach_stmt_desugar(this, p, ForeachSymbolType.CurrentProperty);
}
if (info.ElementType != null)
{
var t = Type.Create(cx, info.ElementType);
trapFile.foreach_stmt_desugar(this, t, ForeachSymbolType.ElementType);
}
}
}

View File

@@ -53,10 +53,15 @@ namespace Semmle.Extraction.CSharp
trapFile.WriteTuple("catch_type", @catch, type, explicityCaught ? 1 : 2);
}
internal static void foreach_stmt_info(this TextWriter trapFile, Entities.Statements.ForEach @foreach, Type element, Method getEnumerator,
Method moveNext, Method dispose, Property current, bool isAsync)
internal static void foreach_stmt_info(this TextWriter trapFile, Entities.Statements.ForEach @foreach, bool isAsync)
{
trapFile.WriteTuple("foreach_stmt_info", @foreach, element, getEnumerator, moveNext, dispose, current, isAsync ? 2 : 1);
trapFile.WriteTuple("foreach_stmt_info", @foreach, isAsync ? 2 : 1);
}
internal static void foreach_stmt_desugar(this TextWriter trapFile, Entities.Statements.ForEach @foreach, IEntity entity,
Entities.Statements.ForEach.ForeachSymbolType type)
{
trapFile.WriteTuple("foreach_stmt_desugar", @foreach, entity, (int)type);
}
internal static void commentblock(this TextWriter trapFile, CommentBlock k)

View File

@@ -44,7 +44,7 @@ predicate potentiallyAccessedByForEach(Method m) {
m.hasName("GetEnumerator") and
m.getDeclaringType().getABaseType+().hasQualifiedName("System.Collections.IEnumerable")
or
foreach_stmt_info(_, _, m, _, _, _, _)
foreach_stmt_desugar(_, m, 1)
}
predicate isRecursivelyLiveExpression(Expr e) {

View File

@@ -583,25 +583,25 @@ class ForeachStmt extends LoopStmt, @foreach_stmt {
Expr getIterableExpr() { result = this.getChild(1) }
/** Gets the called `GetEnumerator` method. */
Method getGetEnumerator() { foreach_stmt_info(this, _, result, _, _, _, _) }
Method getGetEnumerator() { foreach_stmt_desugar(this, result, 1) }
/** Gets the called `MoveNext` or `MoveNextAsync` method. */
Method getMoveNext() { foreach_stmt_info(this, _, _, result, _, _, _) }
Method getMoveNext() { foreach_stmt_desugar(this, result, 3) }
/** Gets the called `Dispose` or `DisposeAsync` method. */
Method getDispose() { foreach_stmt_info(this, _, _, _, result, _, _) }
Method getDispose() { foreach_stmt_desugar(this, result, 4) }
/** Gets the called `Current` property. */
Property getCurrent() { foreach_stmt_info(this, _, _, _, _, result, _) }
Property getCurrent() { foreach_stmt_desugar(this, result, 2) }
/**
* Gets the intermediate type to which the `Current` property is converted before
* being converted to the iteration variable type.
*/
Type getElementType() { foreach_stmt_info(this, result, _, _, _, _, _) }
Type getElementType() { foreach_stmt_desugar(this, result, 5) }
/** Holds if this `foreach` statement is asynchronous. */
predicate isAsync() { foreach_stmt_info(this, _, _, _, _, _, 2) }
predicate isAsync() { foreach_stmt_info(this, 2) }
override string toString() { result = "foreach (... ... in ...) ..." }

View File

@@ -984,13 +984,16 @@ catch_type(
foreach_stmt_info(
unique int id: @foreach_stmt ref,
int element_type_id: @type_or_ref ref,
int getenumerator_id: @method ref,
int movenext_id: @method ref,
int dispose_id: @method ref,
int current_id: @property ref,
int kind: int ref /* non-async = 1, async = 2 */);
@foreach_symbol = @method | @property | @type_or_ref;
#keyset[id, kind]
foreach_stmt_desugar(
int id: @foreach_stmt ref,
int symbol: @foreach_symbol ref,
int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
/** EXPRESSIONS **/
expressions(

View File

@@ -1,2 +1,2 @@
description: Add 'foreach_stmt_info' relation.
description: Add 'foreach_stmt_info' and 'foreach_stmt_desugar' relations.
compatibility: backwards