Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 76af2d2

Browse files
authored
Merge pull request #249 from hvitved/csharp/cfg/boolean-splitting
Approved by calumgrant
2 parents 68dae60 + 98db3f8 commit 76af2d2

28 files changed

Lines changed: 3650 additions & 389 deletions
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Improvements to C# analysis
2+
3+
## General improvements
4+
5+
* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead.
6+
7+
## New queries
8+
9+
| **Query** | **Tags** | **Purpose** |
10+
|-----------------------------|-----------|--------------------------------------------------------------------|
11+
| *@name of query (Query ID)* | *Tags* |*Aim of the new query and whether it is enabled by default or not* |
12+
13+
## Changes to existing queries
14+
15+
| **Query** | **Expected impact** | **Change** |
16+
|----------------------------|------------------------|------------------------------------------------------------------|
17+
| *@name of query (Query ID)*| *Impact on results* | *How/why the query has changed* |
18+
19+
20+
## Changes to QL libraries

csharp/ql/src/semmle/code/csharp/Assignable.qll

Lines changed: 29 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -446,16 +446,25 @@ class AssignableDefinition extends TAssignableDefinition {
446446
* the definitions of `x` and `y` in `M(out x, out y)` and `(x, y) = (0, 1)`
447447
* relate to the same call to `M` and assignment node, respectively.
448448
*/
449-
ControlFlow::Node getAControlFlowNode() { none() }
449+
ControlFlow::Node getAControlFlowNode() {
450+
result = this.getExpr().getAControlFlowNode()
451+
}
452+
453+
/**
454+
* Gets the underlying expression that updates the targeted assignable when
455+
* reached, if any.
456+
*
457+
* Not all definitions have an associated expression, for example implicit
458+
* parameter definitions.
459+
*/
460+
Expr getExpr() { none() }
450461

451462
/** DEPRECATED: Use `getAControlFlowNode()` instead. */
452463
deprecated
453464
ControlFlow::Node getControlFlowNode() { result = this.getAControlFlowNode() }
454465

455466
/** Gets the enclosing callable of this definition. */
456-
Callable getEnclosingCallable() {
457-
result = this.getAControlFlowNode().getBasicBlock().getCallable()
458-
}
467+
Callable getEnclosingCallable() { result = this.getExpr().getEnclosingCallable() }
459468

460469
/**
461470
* Gets the assigned expression, if any. For example, the expression assigned
@@ -581,7 +590,7 @@ class AssignableDefinition extends TAssignableDefinition {
581590

582591
/** Gets the location of this assignable definition. */
583592
Location getLocation() {
584-
result = this.getAControlFlowNode().getLocation()
593+
result = this.getExpr().getLocation()
585594
}
586595
}
587596

@@ -602,9 +611,7 @@ module AssignableDefinitions {
602611
result = a
603612
}
604613

605-
override ControlFlow::Node getAControlFlowNode() {
606-
result = a.getAControlFlowNode()
607-
}
614+
override Expr getExpr() { result = a }
608615

609616
override Expr getSource() {
610617
result = a.getRValue() and
@@ -633,30 +640,19 @@ module AssignableDefinitions {
633640
result = ae
634641
}
635642

636-
private Expr getLeaf() {
637-
result = leaf
638-
}
639-
640643
/**
641644
* Gets the evaluation order of this definition among the other definitions
642645
* in the compound tuple assignment. For example, in `(x, (y, z)) = ...` the
643646
* orders of the definitions of `x`, `y`, and `z` are 0, 1, and 2, respectively.
644647
*/
645648
int getEvaluationOrder() {
646-
exists(ControlFlow::BasicBlock bb, int i |
647-
bb.getNode(i).getElement() = leaf |
648-
i = rank[result + 1](int j, TupleAssignmentDefinition def |
649-
bb.getNode(j).getElement() = def.getLeaf() and
650-
ae = def.getAssignment()
651-
|
652-
j
653-
)
649+
leaf = rank[result + 1](Expr leaf0 |
650+
exists(TTupleAssignmentDefinition(ae, leaf0)) |
651+
leaf0 order by leaf0.getLocation().getStartLine(), leaf0.getLocation().getStartColumn()
654652
)
655653
}
656654

657-
override ControlFlow::Node getAControlFlowNode() {
658-
result = ae.getAControlFlowNode()
659-
}
655+
override Expr getExpr() { result = ae }
660656

661657
override Expr getSource() {
662658
result = getTupleSource(this) // need not exist
@@ -700,9 +696,7 @@ module AssignableDefinitions {
700696
)
701697
}
702698

703-
override ControlFlow::Node getAControlFlowNode() {
704-
result = this.getCall().getAControlFlowNode()
705-
}
699+
override Expr getExpr() { result = this.getCall() }
706700

707701
override predicate isCertain() {
708702
not isUncertainRefCall(this.getCall(), this.getTargetAccess())
@@ -732,9 +726,7 @@ module AssignableDefinitions {
732726
result = mo
733727
}
734728

735-
override ControlFlow::Node getAControlFlowNode() {
736-
result = mo.getAControlFlowNode()
737-
}
729+
override Expr getExpr() { result = mo }
738730

739731
override string toString() {
740732
result = mo.toString()
@@ -756,9 +748,7 @@ module AssignableDefinitions {
756748
result = lvde
757749
}
758750

759-
override ControlFlow::Node getAControlFlowNode() {
760-
result = lvde.getAControlFlowNode()
761-
}
751+
override Expr getExpr() { result = lvde }
762752

763753
override string toString() {
764754
result = lvde.toString()
@@ -785,6 +775,10 @@ module AssignableDefinitions {
785775
result = p.getCallable().getEntryPoint()
786776
}
787777

778+
override Callable getEnclosingCallable() {
779+
result = p.getCallable()
780+
}
781+
788782
override string toString() {
789783
result = p.toString()
790784
}
@@ -809,9 +803,7 @@ module AssignableDefinitions {
809803
result = aoe
810804
}
811805

812-
override ControlFlow::Node getAControlFlowNode() {
813-
result = aoe.getAControlFlowNode()
814-
}
806+
override Expr getExpr() { result = aoe }
815807

816808
override string toString() {
817809
result = aoe.toString()
@@ -833,9 +825,7 @@ module AssignableDefinitions {
833825
result = ipe.getVariableDeclExpr()
834826
}
835827

836-
override ControlFlow::Node getAControlFlowNode() {
837-
result = this.getDeclaration().getAControlFlowNode()
838-
}
828+
override Expr getExpr() { result = this.getDeclaration() }
839829

840830
override Expr getSource() {
841831
result = ipe.getExpr()
@@ -870,9 +860,7 @@ module AssignableDefinitions {
870860
result = tc.getVariableDeclExpr()
871861
}
872862

873-
override ControlFlow::Node getAControlFlowNode() {
874-
result = this.getDeclaration().getAControlFlowNode()
875-
}
863+
override Expr getExpr() { result = this.getDeclaration() }
876864

877865
override Expr getSource() {
878866
result = any(SwitchStmt ss | ss.getATypeCase() = tc).getCondition()
@@ -906,10 +894,6 @@ module AssignableDefinitions {
906894
result = a
907895
}
908896

909-
override ControlFlow::Node getAControlFlowNode() {
910-
none() // initializers are currently not part of the CFG
911-
}
912-
913897
override Expr getSource() {
914898
result = e
915899
}

csharp/ql/src/semmle/code/csharp/Element.qll

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -57,24 +57,3 @@ class Element extends DotNet::Element, @element {
5757
exists(Element parent | parent.getChild(result) = this)
5858
}
5959
}
60-
61-
/**
62-
* Gets the "best" location for element `e`. Where an element has locations in
63-
* source and assemblies, choose the source location. If there are multiple assembly
64-
* locations, choose only one.
65-
*/
66-
cached
67-
private Location bestLocation(Element e) {
68-
result = e.getALocation().(SourceLocation) and
69-
(mustHaveLocationInFile(e, _) implies mustHaveLocationInFile(e, result.getFile()))
70-
or
71-
(
72-
hasNoSourceLocation(e)
73-
and
74-
result = min(Location l | l = e.getALocation() | l order by l.getFile().toString())
75-
)
76-
}
77-
78-
private predicate hasNoSourceLocation(Element e) {
79-
not e.getALocation() instanceof SourceLocation
80-
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,29 @@ private cached module Cached {
370370
t = getTopLevelDeclaringType(d) or d = t or d = p
371371
)
372372
}
373+
374+
private predicate hasNoSourceLocation(Element e) {
375+
not e.getALocation() instanceof SourceLocation
376+
}
377+
378+
/**
379+
* Gets the "best" location for element `e`. Where an element has locations in
380+
* source and assemblies, choose the source location. If there are multiple assembly
381+
* locations, choose only one.
382+
*/
383+
cached
384+
Location bestLocationCached(Element e) {
385+
result = e.getALocation().(SourceLocation) and
386+
(mustHaveLocationInFile(e, _) implies mustHaveLocationInFile(e, result.getFile()))
387+
or
388+
(
389+
hasNoSourceLocation(e)
390+
and
391+
result = min(Location l | l = e.getALocation() | l order by l.getFile().toString())
392+
)
393+
}
373394
}
374395
private import Cached
375396

376397
predicate mustHaveLocationInFile = mustHaveLocationInFileCached/2;
398+
predicate bestLocation = bestLocationCached/1;

csharp/ql/src/semmle/code/csharp/Stmt.qll

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -173,17 +173,7 @@ class SwitchStmt extends SelectionStmt, @switch_stmt {
173173
* }
174174
* ```
175175
*/
176-
cached
177-
CaseStmt getCase(int i) {
178-
exists(int index, int rankIndex |
179-
result = getChildStmt(index) and
180-
rankIndex = i + 1 and
181-
index = rank[rankIndex](int j, CaseStmt cs |
182-
cs = this.getChildStmt(j) |
183-
j
184-
)
185-
)
186-
}
176+
CaseStmt getCase(int i) { result = SwithStmtInternal::getCase(this, i) }
187177

188178
/** Gets a case of this `switch` statement. */
189179
CaseStmt getACase() { result = this.getCase(_) }
@@ -221,29 +211,45 @@ class SwitchStmt extends SelectionStmt, @switch_stmt {
221211
* Note that each non-`default` case is a labeled statement, so the statement
222212
* that follows is a child of the labeled statement, and not the `switch` block.
223213
*/
214+
Stmt getStmt(int i) { result = SwithStmtInternal::getStmt(this, i) }
215+
216+
/** Gets a statement in the body of this `switch` statement. */
217+
Stmt getAStmt() { result = this.getStmt(_) }
218+
}
219+
220+
private cached module SwithStmtInternal {
224221
cached
225-
Stmt getStmt(int i) {
222+
CaseStmt getCase(SwitchStmt ss, int i) {
226223
exists(int index, int rankIndex |
227-
result = getChildStmt(index) and
224+
result = ss.getChildStmt(index) and
225+
rankIndex = i + 1 and
226+
index = rank[rankIndex](int j, CaseStmt cs |
227+
cs = ss.getChildStmt(j) |
228+
j
229+
)
230+
)
231+
}
232+
233+
cached
234+
Stmt getStmt(SwitchStmt ss, int i) {
235+
exists(int index, int rankIndex |
236+
result = ss.getChildStmt(index) and
228237
rankIndex = i + 1 and
229238
index = rank[rankIndex](int j, Stmt s |
230239
// `getChild` includes both labeled statements and the targeted
231240
// statements of labeled statement as separate children, but we
232241
// only want the labeled statement
233-
s = getLabeledStmt(j) |
242+
s = getLabeledStmt(ss, j) |
234243
j
235244
)
236245
)
237246
}
238247

239-
private Stmt getLabeledStmt(int i) {
240-
result = this.getChildStmt(i) and
248+
private Stmt getLabeledStmt(SwitchStmt ss, int i) {
249+
result = ss.getChildStmt(i) and
241250
not result = any(ConstCase cc).getStmt() and
242251
not result = any(TypeCase tc).getStmt()
243252
}
244-
245-
/** Gets a statement in the body of this `switch` statement. */
246-
Stmt getAStmt() { result = this.getStmt(_) }
247253
}
248254

249255
/**

0 commit comments

Comments
 (0)