Skip to content

Commit 4df9cd8

Browse files
authored
Merge pull request github#17658 from hvitved/shared/cfg-conditional-splitting
Shared `ConditionalCompletionSplitting` implementation
2 parents b18f8d3 + bdb793b commit 4df9cd8

File tree

10 files changed

+411
-229
lines changed

10 files changed

+411
-229
lines changed

csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y)
5353
private module CfgInput implements CfgShared::InputSig<Location> {
5454
private import ControlFlowGraphImpl as Impl
5555
private import Completion as Comp
56-
private import Splitting as Splitting
5756
private import SuccessorType as ST
5857
private import semmle.code.csharp.Caching
5958

@@ -80,10 +79,6 @@ private module CfgInput implements CfgShared::InputSig<Location> {
8079
Impl::scopeLast(scope, last, c)
8180
}
8281

83-
class SplitKindBase = Splitting::TSplitKind;
84-
85-
class Split = Splitting::Split;
86-
8782
class SuccessorType = ST::SuccessorType;
8883

8984
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
@@ -102,7 +97,21 @@ private module CfgInput implements CfgShared::InputSig<Location> {
10297
}
10398
}
10499

105-
import CfgShared::Make<Location, CfgInput>
100+
private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> {
101+
private import Splitting as S
102+
103+
class SplitKindBase = S::TSplitKind;
104+
105+
class Split = S::Split;
106+
}
107+
108+
private module ConditionalCompletionSplittingInput implements
109+
CfgShared::ConditionalCompletionSplittingInputSig<Location, CfgInput, CfgSplittingInput>
110+
{
111+
import Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplittingInput
112+
}
113+
114+
import CfgShared::MakeWithSplitting<Location, CfgInput, CfgSplittingInput, ConditionalCompletionSplittingInput>
106115

107116
/**
108117
* A compilation.

csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll

Lines changed: 46 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
*/
66

77
import csharp
8-
private import Completion
8+
private import Completion as Comp
9+
private import Comp
910
private import ControlFlowGraphImpl
1011
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg
1112
private import semmle.code.csharp.controlflow.internal.PreSsa
@@ -260,100 +261,77 @@ module ConditionalCompletionSplitting {
260261

261262
ConditionalCompletionSplit() { this = TConditionalCompletionSplit(completion) }
262263

264+
ConditionalCompletion getCompletion() { result = completion }
265+
263266
override string toString() { result = completion.toString() }
264267
}
265268

266-
private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
269+
private class ConditionalCompletionSplitKind_ extends SplitKind, TConditionalCompletionSplitKind {
267270
override int getListOrder() { result = InitializerSplitting::getNextListOrder() }
268271

269272
override predicate isEnabled(AstNode cfe) { this.appliesTo(cfe) }
270273

271274
override string toString() { result = "ConditionalCompletion" }
272275
}
273276

274-
int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
277+
module ConditionalCompletionSplittingInput {
278+
private import Completion as Comp
275279

276-
private class ConditionalCompletionSplitImpl extends SplitImpl instanceof ConditionalCompletionSplit
277-
{
278-
ConditionalCompletion completion;
280+
class ConditionalCompletion = Comp::ConditionalCompletion;
279281

280-
ConditionalCompletionSplitImpl() { this = TConditionalCompletionSplit(completion) }
282+
class ConditionalCompletionSplitKind extends ConditionalCompletionSplitKind_, TSplitKind { }
281283

282-
override ConditionalCompletionSplitKind getKind() { any() }
284+
class ConditionalCompletionSplit = ConditionalCompletionSplitting::ConditionalCompletionSplit;
283285

284-
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
285-
succ(pred, succ, c) and
286-
last(succ, _, completion) and
286+
bindingset[parent, parentCompletion]
287+
predicate condPropagateExpr(
288+
AstNode parent, ConditionalCompletion parentCompletion, AstNode child,
289+
ConditionalCompletion childCompletion
290+
) {
291+
child = parent.(LogicalNotExpr).getOperand() and
292+
childCompletion.getDual() = parentCompletion
293+
or
294+
childCompletion = parentCompletion and
287295
(
288-
last(succ.(LogicalNotExpr).getOperand(), pred, c) and
289-
completion.(BooleanCompletion).getDual() = c
296+
child = parent.(LogicalAndExpr).getAnOperand()
290297
or
291-
last(succ.(LogicalAndExpr).getAnOperand(), pred, c) and
292-
completion = c
298+
child = parent.(LogicalOrExpr).getAnOperand()
293299
or
294-
last(succ.(LogicalOrExpr).getAnOperand(), pred, c) and
295-
completion = c
300+
parent = any(ConditionalExpr ce | child = [ce.getThen(), ce.getElse()])
296301
or
297-
succ =
298-
any(ConditionalExpr ce |
299-
last([ce.getThen(), ce.getElse()], pred, c) and
300-
completion = c
301-
)
302+
child = parent.(SwitchExpr).getACase()
302303
or
303-
succ =
304+
child = parent.(SwitchCaseExpr).getBody()
305+
or
306+
parent =
304307
any(NullCoalescingExpr nce |
305-
exists(Expr operand |
306-
last(operand, pred, c) and
307-
completion = c
308-
|
309-
if c instanceof NullnessCompletion
310-
then operand = nce.getRightOperand()
311-
else operand = nce.getAnOperand()
312-
)
308+
if childCompletion instanceof NullnessCompletion
309+
then child = nce.getRightOperand()
310+
else child = nce.getAnOperand()
313311
)
312+
)
313+
or
314+
child = parent.(NotPatternExpr).getPattern() and
315+
childCompletion.getDual() = parentCompletion
316+
or
317+
child = parent.(IsExpr).getPattern() and
318+
parentCompletion.(BooleanCompletion).getValue() =
319+
childCompletion.(MatchingCompletion).getValue()
320+
or
321+
childCompletion = parentCompletion and
322+
(
323+
child = parent.(AndPatternExpr).getAnOperand()
314324
or
315-
last(succ.(SwitchExpr).getACase(), pred, c) and
316-
completion = c
317-
or
318-
last(succ.(SwitchCaseExpr).getBody(), pred, c) and
319-
completion = c
320-
or
321-
last(succ.(NotPatternExpr).getPattern(), pred, c) and
322-
completion.(MatchingCompletion).getDual() = c
323-
or
324-
last(succ.(IsExpr).getPattern(), pred, c) and
325-
completion.(BooleanCompletion).getValue() = c.(MatchingCompletion).getValue()
326-
or
327-
last(succ.(AndPatternExpr).getAnOperand(), pred, c) and
328-
completion = c
329-
or
330-
last(succ.(OrPatternExpr).getAnOperand(), pred, c) and
331-
completion = c
325+
child = parent.(OrPatternExpr).getAnOperand()
332326
or
333-
last(succ.(RecursivePatternExpr).getAChildExpr(), pred, c) and
334-
completion = c
327+
child = parent.(RecursivePatternExpr).getAChildExpr()
335328
or
336-
last(succ.(PropertyPatternExpr).getPattern(_), pred, c) and
337-
completion = c
329+
child = parent.(PropertyPatternExpr).getPattern(_)
338330
)
339331
}
340-
341-
override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }
342-
343-
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
344-
this.appliesTo(pred) and
345-
succ(pred, succ, c) and
346-
if c instanceof ConditionalCompletion then completion = c else any()
347-
}
348-
349-
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
350-
this.appliesTo(last) and
351-
scopeLast(scope, last, c) and
352-
if c instanceof ConditionalCompletion then completion = c else any()
353-
}
354-
355-
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
356332
}
333+
334+
int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
357335
}
358336

359337
module AssertionSplitting {

ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ class AstNode extends Ast::AstNode {
2222
private module CfgInput implements CfgShared::InputSig<Location> {
2323
private import ControlFlowGraphImpl as Impl
2424
private import Completion as Comp
25-
private import Splitting as Splitting
2625
private import codeql.ruby.CFG as Cfg
2726

2827
class AstNode = Impl::AstNode;
@@ -45,10 +44,6 @@ private module CfgInput implements CfgShared::InputSig<Location> {
4544
scope.(Impl::CfgScopeImpl).exit(last, c)
4645
}
4746

48-
class SplitKindBase = Splitting::TSplitKind;
49-
50-
class Split = Splitting::Split;
51-
5247
class SuccessorType = Cfg::SuccessorType;
5348

5449
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
@@ -67,7 +62,21 @@ private module CfgInput implements CfgShared::InputSig<Location> {
6762
}
6863
}
6964

70-
import CfgShared::Make<Location, CfgInput>
65+
private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> {
66+
private import Splitting as S
67+
68+
class SplitKindBase = S::TSplitKind;
69+
70+
class Split = S::Split;
71+
}
72+
73+
private module ConditionalCompletionSplittingInput implements
74+
CfgShared::ConditionalCompletionSplittingInputSig<Location, CfgInput, CfgSplittingInput>
75+
{
76+
import Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplittingInput
77+
}
78+
79+
import CfgShared::MakeWithSplitting<Location, CfgInput, CfgSplittingInput, ConditionalCompletionSplittingInput>
7180

7281
abstract class CfgScopeImpl extends AstNode {
7382
abstract predicate entry(AstNode first);

ruby/ql/lib/codeql/ruby/controlflow/internal/Splitting.qll

Lines changed: 34 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
*/
44

55
private import codeql.ruby.AST as Ast
6-
private import Completion
6+
private import Completion as Comp
7+
private import Comp
78
private import ControlFlowGraphImpl
89
private import SuccessorTypes
910
private import codeql.ruby.controlflow.ControlFlowGraph
@@ -31,7 +32,7 @@ class Split extends TSplit {
3132
string toString() { none() }
3233
}
3334

34-
private module ConditionalCompletionSplitting {
35+
module ConditionalCompletionSplitting {
3536
/**
3637
* A split for conditional completions. For example, in
3738
*
@@ -51,67 +52,61 @@ private module ConditionalCompletionSplitting {
5152

5253
ConditionalCompletionSplit() { this = TConditionalCompletionSplit(completion) }
5354

55+
ConditionalCompletion getCompletion() { result = completion }
56+
5457
override string toString() { result = completion.toString() }
5558
}
5659

57-
private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
60+
private class ConditionalCompletionSplitKind_ extends SplitKind, TConditionalCompletionSplitKind {
5861
override int getListOrder() { result = 0 }
5962

6063
override predicate isEnabled(AstNode n) { this.appliesTo(n) }
6164

6265
override string toString() { result = "ConditionalCompletion" }
6366
}
6467

65-
int getNextListOrder() { result = 1 }
68+
module ConditionalCompletionSplittingInput {
69+
private import Completion as Comp
6670

67-
private class ConditionalCompletionSplitImpl extends SplitImpl instanceof ConditionalCompletionSplit
68-
{
69-
ConditionalCompletion completion;
71+
class ConditionalCompletion = Comp::ConditionalCompletion;
7072

71-
ConditionalCompletionSplitImpl() { this = TConditionalCompletionSplit(completion) }
73+
class ConditionalCompletionSplitKind extends ConditionalCompletionSplitKind_, TSplitKind { }
7274

73-
override ConditionalCompletionSplitKind getKind() { any() }
75+
class ConditionalCompletionSplit = ConditionalCompletionSplitting::ConditionalCompletionSplit;
7476

75-
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
76-
succ(pred, succ, c) and
77-
last(succ, _, completion) and
77+
bindingset[parent, parentCompletion]
78+
predicate condPropagateExpr(
79+
AstNode parent, ConditionalCompletion parentCompletion, AstNode child,
80+
ConditionalCompletion childCompletion
81+
) {
82+
child = parent.(Ast::NotExpr).getOperand() and
83+
childCompletion.(BooleanCompletion).getDual() = parentCompletion
84+
or
85+
childCompletion = parentCompletion and
7886
(
79-
last(succ.(Ast::NotExpr).getOperand(), pred, c) and
80-
completion.(BooleanCompletion).getDual() = c
81-
or
82-
last(succ.(Ast::LogicalAndExpr).getAnOperand(), pred, c) and
83-
completion = c
87+
child = parent.(Ast::LogicalAndExpr).getAnOperand()
8488
or
85-
last(succ.(Ast::LogicalOrExpr).getAnOperand(), pred, c) and
86-
completion = c
89+
child = parent.(Ast::LogicalOrExpr).getAnOperand()
8790
or
88-
last(succ.(Ast::StmtSequence).getLastStmt(), pred, c) and
89-
completion = c
91+
child = parent.(Ast::StmtSequence).getLastStmt()
9092
or
91-
last(succ.(Ast::ConditionalExpr).getBranch(_), pred, c) and
92-
completion = c
93+
child = parent.(Ast::ConditionalExpr).getBranch(_)
9394
)
94-
or
95-
succ(pred, succ, c) and
96-
succ instanceof Ast::WhenClause and
97-
completion = c
9895
}
96+
}
9997

100-
override predicate hasEntryScope(CfgScope scope, AstNode succ) { none() }
98+
int getNextListOrder() { result = 1 }
10199

102-
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
103-
this.appliesTo(pred) and
100+
private class ConditionalCompletionSplitImpl extends SplitImplementations::ConditionalCompletionSplitting::ConditionalCompletionSplitImpl
101+
{
102+
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
103+
super.hasEntry(pred, succ, c)
104+
or
105+
// a non-standard case is needed for `when` clauses
104106
succ(pred, succ, c) and
105-
if c instanceof ConditionalCompletion then completion = c else any()
106-
}
107-
108-
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
109-
this.appliesTo(last) and
110-
succExit(scope, last, c) and
111-
if c instanceof ConditionalCompletion then completion = c else any()
107+
succ instanceof Ast::WhenClause and
108+
c = this.getCompletion()
112109
}
113-
114-
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
115110
}
116111
}
117112

rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ private import codeql.rust.controlflow.ControlFlowGraph as Cfg
77
private module CfgInput implements InputSig<Location> {
88
private import rust as Rust
99
private import Completion as C
10-
private import Splitting as S
1110

1211
class AstNode = Rust::AstNode;
1312

@@ -24,10 +23,6 @@ private module CfgInput implements InputSig<Location> {
2423

2524
CfgScope getCfgScope(AstNode n) { result = Scope::scopeOfAst(n) }
2625

27-
class SplitKindBase = S::TSplitKind;
28-
29-
class Split = S::Split;
30-
3126
class SuccessorType = Cfg::SuccessorType;
3227

3328
/** Gets a successor type that matches completion `c`. */
@@ -51,7 +46,22 @@ private module CfgInput implements InputSig<Location> {
5146
predicate scopeLast(CfgScope scope, AstNode last, Completion c) { scope.scopeLast(last, c) }
5247
}
5348

54-
private module CfgImpl = Make<Location, CfgInput>;
49+
private module CfgSplittingInput implements SplittingInputSig<Location, CfgInput> {
50+
private import Splitting as S
51+
52+
class SplitKindBase = S::TSplitKind;
53+
54+
class Split = S::Split;
55+
}
56+
57+
private module ConditionalCompletionSplittingInput implements
58+
ConditionalCompletionSplittingInputSig<Location, CfgInput, CfgSplittingInput>
59+
{
60+
import Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplittingInput
61+
}
62+
63+
private module CfgImpl =
64+
MakeWithSplitting<Location, CfgInput, CfgSplittingInput, ConditionalCompletionSplittingInput>;
5565

5666
import CfgImpl
5767

0 commit comments

Comments
 (0)