Skip to content

Commit 9907e0d

Browse files
committed
C#: Implement new lambda flow interface
1 parent 6e69b63 commit 9907e0d

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ private module Cached {
7676
} or
7777
TSummaryCall(FlowSummary::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver) {
7878
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
79-
}
79+
} or
80+
TLambdaSynthCall(Node creation) { lambdaCreation(creation, _, _) }
8081

8182
/** Gets a viable run-time target for the call `call`. */
8283
cached
@@ -497,6 +498,24 @@ class SummaryCall extends DelegateDataFlowCall, TSummaryCall {
497498
override Location getLocation() { result = c.getLocation() }
498499
}
499500

501+
class LambdaSynthCall extends DataFlowCall, TLambdaSynthCall {
502+
private NodeImpl creation;
503+
504+
LambdaSynthCall() { this = TLambdaSynthCall(creation) }
505+
506+
override DataFlowCallable getARuntimeTarget() { none() }
507+
508+
override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() }
509+
510+
override DataFlow::Node getNode() { none() }
511+
512+
override DataFlowCallable getEnclosingCallable() { result = creation.getEnclosingCallableImpl() }
513+
514+
override string toString() { result = "[lambda] call to " + creation }
515+
516+
override Location getLocation() { result = creation.getLocation() }
517+
}
518+
500519
/** A parameter position. */
501520
class ParameterPosition extends TParameterPosition {
502521
/** Gets the underlying integer position, if any. */

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,8 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
767767
VariableCapture::valueStep(nodeFrom, nodeTo)
768768
or
769769
nodeTo = nodeFrom.(LocalFunctionCreationNode).getAnAccess(true)
770+
or
771+
delegateCreationStep(nodeFrom, nodeTo)
770772
) and
771773
model = ""
772774
or
@@ -1150,6 +1152,8 @@ private module Cached {
11501152
TCapturedVariableContent(VariableCapture::CapturedVariable v) or
11511153
TDelegateCallArgumentContent(int i) {
11521154
i = [0 .. max(any(DelegateLikeCall dc).getNumberOfArguments()) - 1]
1155+
or
1156+
i = -1
11531157
} or
11541158
TDelegateCallReturnContent()
11551159

@@ -2928,6 +2932,38 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
29282932
exists(kind)
29292933
}
29302934

2935+
/** Holds if `creation` is an expression that creates a delegate for `c`. */
2936+
predicate lambdaCreation(
2937+
Node creation, LambdaCallKind kind, DataFlowCallable c, DataFlowCall synthCall
2938+
) {
2939+
lambdaCreation(creation, kind, c) and
2940+
synthCall = TLambdaSynthCall(creation)
2941+
}
2942+
2943+
Content getLambdaReturnContent(LambdaCallKind kind, ReturnKind rk) {
2944+
result = TDelegateCallReturnContent() and
2945+
exists(kind) and
2946+
rk = TNormalReturnKind()
2947+
}
2948+
2949+
Content getLambdaArgumentContent(LambdaCallKind kind, ArgumentPosition pos) {
2950+
(
2951+
result = TDelegateCallArgumentContent(pos.getPosition())
2952+
or
2953+
result = TDelegateCallArgumentContent(-1) and
2954+
pos.isDelegateSelf()
2955+
) and
2956+
exists(kind)
2957+
}
2958+
2959+
predicate isLambdaInstanceParameter(ParameterNode p) {
2960+
exists(DataFlowCallable c, ParameterPosition ppos |
2961+
lambdaCreation(_, _, c) and
2962+
isParameterNode(p, c, ppos) and
2963+
ppos.isDelegateSelf()
2964+
)
2965+
}
2966+
29312967
private predicate isLocalFunctionCallReceiver(
29322968
LocalFunctionCall call, LocalFunctionAccess receiver, LocalFunction f
29332969
) {

0 commit comments

Comments
 (0)