Skip to content

Commit 46d44ca

Browse files
committed
C#: Include parameters and their defaults in the CFG
1 parent e59c4dc commit 46d44ca

19 files changed

Lines changed: 2041 additions & 806 deletions

File tree

csharp/ql/lib/printCfg.ql

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@ external int selectedSourceColumn();
2222
private predicate selectedSourceColumnAlias = selectedSourceColumn/0;
2323

2424
module ViewCfgQueryInput implements ControlFlow::ViewCfgQueryInputSig<File> {
25+
private import semmle.code.csharp.controlflow.ControlFlowGraph
26+
2527
predicate selectedSourceFile = selectedSourceFileAlias/0;
2628

2729
predicate selectedSourceLine = selectedSourceLineAlias/0;
2830

2931
predicate selectedSourceColumn = selectedSourceColumnAlias/0;
3032

3133
predicate cfgScopeSpan(
32-
Callable scope, File file, int startLine, int startColumn, int endLine, int endColumn
34+
Ast::Callable scope, File file, int startLine, int startColumn, int endLine, int endColumn
3335
) {
3436
file = scope.getFile() and
3537
scope.getLocation().getStartLine() = startLine and

csharp/ql/lib/semmle/code/csharp/ExprOrStmtParent.qll

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ private import internal.Location
1313
* An element that can have a child statement or expression.
1414
*/
1515
class ExprOrStmtParent extends Element, @exprorstmt_parent {
16-
final override ControlFlowElement getChild(int i) {
16+
override ControlFlowElement getChild(int i) {
1717
result = this.getChildExpr(i) or
1818
result = this.getChildStmt(i)
1919
}
@@ -42,14 +42,8 @@ class ExprOrStmtParent extends Element, @exprorstmt_parent {
4242
*
4343
* An element that can have a child top-level expression.
4444
*/
45-
class TopLevelExprParent extends Element, @top_level_expr_parent {
45+
class TopLevelExprParent extends ExprOrStmtParent, @top_level_expr_parent {
4646
final override Expr getChild(int i) { result = this.getChildExpr(i) }
47-
48-
/** Gets the `i`th child expression of this element (zero-based). */
49-
final Expr getChildExpr(int i) { expr_parent_top_level_adjusted(result, i, this) }
50-
51-
/** Gets a child expression of this element, if any. */
52-
final Expr getAChildExpr() { result = this.getChildExpr(_) }
5347
}
5448

5549
/** INTERNAL: Do not use. */

csharp/ql/lib/semmle/code/csharp/PrintAst.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,9 @@ class ControlFlowElementNode extends ElementNode {
299299
not isNotNeeded(element.getParent+()) and
300300
// LambdaExpr is both a Callable and a ControlFlowElement,
301301
// print it with the more specific CallableNode
302-
not element instanceof Callable
302+
not element instanceof Callable and
303+
// Handled in `ParameterNode`
304+
not element instanceof Parameter
303305
}
304306

305307
override PrintAstNode getChild(int childIndex) {

csharp/ql/lib/semmle/code/csharp/Variable.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ class LocalScopeVariable extends Variable, @local_scope_variable {
8787
* }
8888
* ```
8989
*/
90-
class Parameter extends LocalScopeVariable, Attributable, TopLevelExprParent, @parameter {
90+
class Parameter extends LocalScopeVariable, Attributable, TopLevelExprParent, ControlFlowElement,
91+
@parameter
92+
{
9193
/** Gets the raw position of this parameter, including the `this` parameter at index 0. */
9294
final int getRawPosition() { this = this.getDeclaringElement().getRawParameter(result) }
9395

csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ private import Cfg1
1919
private import Cfg2
2020
import Public
2121

22-
/** Provides an implementation of the AST signature for C#. */
23-
private module Ast implements AstSig<Location> {
22+
/**
23+
* INTERNAL: Do not use.
24+
*
25+
* Provides an implementation of the AST signature for C#.
26+
*/
27+
module Ast implements AstSig<Location> {
2428
private import csharp as CS
2529

2630
class AstNode = ControlFlowElementOrCallable;
@@ -73,18 +77,41 @@ private module Ast implements AstSig<Location> {
7377
private AstNode getParent(AstNode n) { n = getChild(result, _) }
7478

7579
Callable getEnclosingCallable(AstNode node) {
76-
result = node.(ControlFlowElement).getEnclosingCallable() or
77-
result.(ObjectInitMethod).initializes(getParent*(node)) or
80+
result = node.(ControlFlowElement).getEnclosingCallable()
81+
or
82+
result.(ObjectInitMethod).initializes(getParent*(node))
83+
or
7884
Initializers::staticMemberInitializer(result, getParent*(node))
85+
or
86+
result = node.(Parameter).getCallable()
87+
or
88+
not skipControlFlow(node) and
89+
getParent*(node) = any(Parameter p | result = p.getCallable()).getDefaultValue()
7990
}
8091

81-
class Callable = CS::Callable;
92+
class Callable extends CS::Callable {
93+
Callable() { this.isUnboundDeclaration() }
94+
}
8295

8396
AstNode callableGetBody(Callable c) {
8497
not skipControlFlow(result) and
8598
result = c.getBody()
8699
}
87100

101+
final private class ParameterFinal = CS::Parameter;
102+
103+
class Parameter extends ParameterFinal {
104+
Expr getDefaultValue() {
105+
result = super.getDefaultValue() and
106+
getCompilation(result) = getCompilation(this)
107+
}
108+
}
109+
110+
Parameter callableGetParameter(Callable c, int i) {
111+
not skipControlFlow(result) and
112+
result = c.getParameter(i)
113+
}
114+
88115
class Stmt = CS::Stmt;
89116

90117
class Expr = CS::Expr;
@@ -232,9 +259,11 @@ private class CompilationExt extends TCompilationExt {
232259
}
233260

234261
/** Gets the compilation that source file `f` belongs to. */
235-
private CompilationExt getCompilation(File f) {
262+
bindingset[e]
263+
pragma[inline_late]
264+
private CompilationExt getCompilation(Element e) {
236265
exists(Compilation c |
237-
f = c.getAFileCompiled() and
266+
e.getALocation().getFile() = c.getAFileCompiled() and
238267
result = TCompilation(c)
239268
)
240269
or
@@ -415,12 +444,12 @@ private module Input implements InputSig1, InputSig2 {
415444
l = TLblGoto(n.(LabelStmt).getLabel())
416445
}
417446

418-
class CallableBodyPartContext = CompilationExt;
447+
class CallableContext = CompilationExt;
419448

420449
pragma[nomagic]
421-
Ast::AstNode callableGetBodyPart(Callable c, CallableBodyPartContext ctx, int index) {
450+
Ast::AstNode callableGetBodyPart(Ast::Callable c, CallableContext ctx, int index) {
422451
not Ast::skipControlFlow(result) and
423-
ctx = getCompilation(result.getFile()) and
452+
ctx = getCompilation(result) and
424453
(
425454
result = Initializers::initializedInstanceMemberOrder(c, index)
426455
or
@@ -437,9 +466,19 @@ private module Input implements InputSig1, InputSig2 {
437466
or
438467
i = 2 and result = ctor.getBody()
439468
)
469+
or
470+
not c instanceof Constructor and
471+
result = c.getBody() and
472+
index = 0
440473
)
441474
}
442475

476+
pragma[nomagic]
477+
Ast::Parameter callableGetParameter(Ast::Callable c, CallableContext ctx, int index) {
478+
result = Ast::callableGetParameter(c, index) and
479+
ctx = getCompilation(result)
480+
}
481+
443482
private Expr getQualifier(QualifiableExpr qe) {
444483
result = qe.getQualifier() or
445484
result = qe.(ExtensionMethodCall).getArgument(0)

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -918,17 +918,13 @@ private Gvn::GvnType getANonTypeParameterSubTypeRestricted(RelevantGvnType t) {
918918

919919
/** A callable with an implicit `this` parameter. */
920920
private class InstanceCallable extends Callable {
921-
private Location l;
922-
923921
InstanceCallable() {
924922
not this.(Modifiable).isStatic() and
925923
// local functions and delegate capture `this` and should therefore
926924
// not have a `this` parameter
927925
not this instanceof LocalFunction and
928926
not this instanceof AnonymousFunctionExpr
929927
}
930-
931-
Location getARelevantLocation() { result = l }
932928
}
933929

934930
/**
@@ -1019,8 +1015,7 @@ private module Cached {
10191015
} or
10201016
TInstanceParameterNode(InstanceCallable c, Location l) {
10211017
c = any(DataFlowCallable dfc).asCallable(l) and
1022-
c instanceof CallableUsedInSource and
1023-
l = c.getARelevantLocation()
1018+
c instanceof CallableUsedInSource
10241019
} or
10251020
TDelegateSelfReferenceNode(Callable c) { lambdaCreationExpr(_, c) } or
10261021
TLocalFunctionCreationNode(ControlFlowNodes::ElementNode cfn, Boolean isPostUpdate) {

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -753,13 +753,11 @@ private module Cached {
753753

754754
cached
755755
predicate implicitEntryDefinition(BasicBlock bb, Ssa::SourceVariable v) {
756-
exists(EntryBasicBlock entry, Callable c |
757-
c = entry.getEnclosingCallable() and
756+
exists(Callable c |
758757
// In case `c` has multiple bodies, we want each body to get its own implicit
759-
// entry definition. In case `c` doesn't have multiple bodies, the line below
760-
// is simply the same as `bb = entry`, because `entry.getFirstNode().getASuccessor()`
761-
// will be in the entry block.
762-
bb = entry.getFirstNode().getASuccessor().getBasicBlock() and
758+
// entry definition, so we use the basic block containing the body instead of
759+
// the entry block.
760+
bb = c.getBody().getBasicBlock() and
763761
c = v.getEnclosingCallable()
764762
|
765763
// Captured variable

csharp/ql/lib/semmlecode.csharp.dbscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1362,7 +1362,7 @@ compiler_generated(unique int id: @element ref);
13621362

13631363
/** CONTROL/DATA FLOW **/
13641364

1365-
@control_flow_element = @stmt | @expr;
1365+
@control_flow_element = @stmt | @expr | @parameter;
13661366

13671367
/* XML Files */
13681368

0 commit comments

Comments
 (0)