Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared ConditionalCompletionSplitting implementation #17658

Merged
merged 4 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y)
private module CfgInput implements CfgShared::InputSig<Location> {
private import ControlFlowGraphImpl as Impl
private import Completion as Comp
private import Splitting as Splitting
private import SuccessorType as ST
private import semmle.code.csharp.Caching

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

class SplitKindBase = Splitting::TSplitKind;

class Split = Splitting::Split;

class SuccessorType = ST::SuccessorType;

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

import CfgShared::Make<Location, CfgInput>
private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> {
private import Splitting as S

class SplitKindBase = S::TSplitKind;

class Split = S::Split;
}

private module ConditionalCompletionSplittingInput implements
CfgShared::ConditionalCompletionSplittingInputSig<Location, CfgInput, CfgSplittingInput>
{
import Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplittingInput
}

import CfgShared::MakeWithSplitting<Location, CfgInput, CfgSplittingInput, ConditionalCompletionSplittingInput>

/**
* A compilation.
Expand Down
114 changes: 46 additions & 68 deletions csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
*/

import csharp
private import Completion
private import Completion as Comp
private import Comp
private import ControlFlowGraphImpl
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg
private import semmle.code.csharp.controlflow.internal.PreSsa
Expand Down Expand Up @@ -260,100 +261,77 @@ module ConditionalCompletionSplitting {

ConditionalCompletionSplit() { this = TConditionalCompletionSplit(completion) }

ConditionalCompletion getCompletion() { result = completion }

override string toString() { result = completion.toString() }
}

private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
private class ConditionalCompletionSplitKind_ extends SplitKind, TConditionalCompletionSplitKind {
override int getListOrder() { result = InitializerSplitting::getNextListOrder() }

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

override string toString() { result = "ConditionalCompletion" }
}

int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
module ConditionalCompletionSplittingInput {
private import Completion as Comp

private class ConditionalCompletionSplitImpl extends SplitImpl instanceof ConditionalCompletionSplit
{
ConditionalCompletion completion;
class ConditionalCompletion = Comp::ConditionalCompletion;

ConditionalCompletionSplitImpl() { this = TConditionalCompletionSplit(completion) }
class ConditionalCompletionSplitKind extends ConditionalCompletionSplitKind_, TSplitKind { }

override ConditionalCompletionSplitKind getKind() { any() }
class ConditionalCompletionSplit = ConditionalCompletionSplitting::ConditionalCompletionSplit;

override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
succ(pred, succ, c) and
last(succ, _, completion) and
bindingset[parent, parentCompletion]
predicate condPropagateExpr(
AstNode parent, ConditionalCompletion parentCompletion, AstNode child,
ConditionalCompletion childCompletion
) {
child = parent.(LogicalNotExpr).getOperand() and
childCompletion.getDual() = parentCompletion
or
childCompletion = parentCompletion and
(
last(succ.(LogicalNotExpr).getOperand(), pred, c) and
completion.(BooleanCompletion).getDual() = c
child = parent.(LogicalAndExpr).getAnOperand()
or
last(succ.(LogicalAndExpr).getAnOperand(), pred, c) and
completion = c
child = parent.(LogicalOrExpr).getAnOperand()
or
last(succ.(LogicalOrExpr).getAnOperand(), pred, c) and
completion = c
parent = any(ConditionalExpr ce | child = [ce.getThen(), ce.getElse()])
or
succ =
any(ConditionalExpr ce |
last([ce.getThen(), ce.getElse()], pred, c) and
completion = c
)
child = parent.(SwitchExpr).getACase()
or
succ =
child = parent.(SwitchCaseExpr).getBody()
or
parent =
any(NullCoalescingExpr nce |
exists(Expr operand |
last(operand, pred, c) and
completion = c
|
if c instanceof NullnessCompletion
then operand = nce.getRightOperand()
else operand = nce.getAnOperand()
)
if childCompletion instanceof NullnessCompletion
then child = nce.getRightOperand()
else child = nce.getAnOperand()
)
)
or
child = parent.(NotPatternExpr).getPattern() and
childCompletion.getDual() = parentCompletion
or
child = parent.(IsExpr).getPattern() and
parentCompletion.(BooleanCompletion).getValue() =
childCompletion.(MatchingCompletion).getValue()
or
childCompletion = parentCompletion and
(
child = parent.(AndPatternExpr).getAnOperand()
or
last(succ.(SwitchExpr).getACase(), pred, c) and
completion = c
or
last(succ.(SwitchCaseExpr).getBody(), pred, c) and
completion = c
or
last(succ.(NotPatternExpr).getPattern(), pred, c) and
completion.(MatchingCompletion).getDual() = c
or
last(succ.(IsExpr).getPattern(), pred, c) and
completion.(BooleanCompletion).getValue() = c.(MatchingCompletion).getValue()
or
last(succ.(AndPatternExpr).getAnOperand(), pred, c) and
completion = c
or
last(succ.(OrPatternExpr).getAnOperand(), pred, c) and
completion = c
child = parent.(OrPatternExpr).getAnOperand()
or
last(succ.(RecursivePatternExpr).getAChildExpr(), pred, c) and
completion = c
child = parent.(RecursivePatternExpr).getAChildExpr()
or
last(succ.(PropertyPatternExpr).getPattern(_), pred, c) and
completion = c
child = parent.(PropertyPatternExpr).getPattern(_)
)
}

override predicate hasEntryScope(CfgScope scope, AstNode first) { none() }

override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
this.appliesTo(pred) and
succ(pred, succ, c) and
if c instanceof ConditionalCompletion then completion = c else any()
}

override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
this.appliesTo(last) and
scopeLast(scope, last, c) and
if c instanceof ConditionalCompletion then completion = c else any()
}

override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
}

int getNextListOrder() { result = InitializerSplitting::getNextListOrder() + 1 }
}

module AssertionSplitting {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class AstNode extends Ast::AstNode {
private module CfgInput implements CfgShared::InputSig<Location> {
private import ControlFlowGraphImpl as Impl
private import Completion as Comp
private import Splitting as Splitting
private import codeql.ruby.CFG as Cfg

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

class SplitKindBase = Splitting::TSplitKind;

class Split = Splitting::Split;

class SuccessorType = Cfg::SuccessorType;

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

import CfgShared::Make<Location, CfgInput>
private module CfgSplittingInput implements CfgShared::SplittingInputSig<Location, CfgInput> {
private import Splitting as S

class SplitKindBase = S::TSplitKind;

class Split = S::Split;
}

private module ConditionalCompletionSplittingInput implements
CfgShared::ConditionalCompletionSplittingInputSig<Location, CfgInput, CfgSplittingInput>
{
import Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplittingInput
}

import CfgShared::MakeWithSplitting<Location, CfgInput, CfgSplittingInput, ConditionalCompletionSplittingInput>

abstract class CfgScopeImpl extends AstNode {
abstract predicate entry(AstNode first);
Expand Down
73 changes: 34 additions & 39 deletions ruby/ql/lib/codeql/ruby/controlflow/internal/Splitting.qll
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
*/

private import codeql.ruby.AST as Ast
private import Completion
private import Completion as Comp
private import Comp
private import ControlFlowGraphImpl
private import SuccessorTypes
private import codeql.ruby.controlflow.ControlFlowGraph
Expand Down Expand Up @@ -31,7 +32,7 @@
string toString() { none() }
}

private module ConditionalCompletionSplitting {
module ConditionalCompletionSplitting {
/**
* A split for conditional completions. For example, in
*
Expand All @@ -51,67 +52,61 @@

ConditionalCompletionSplit() { this = TConditionalCompletionSplit(completion) }

ConditionalCompletion getCompletion() { result = completion }

Check warning on line 55 in ruby/ql/lib/codeql/ruby/controlflow/internal/Splitting.qll

View workflow job for this annotation

GitHub Actions / qldoc

Missing QLdoc for member-predicate Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplit::getCompletion/0

override string toString() { result = completion.toString() }
}

private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
private class ConditionalCompletionSplitKind_ extends SplitKind, TConditionalCompletionSplitKind {
override int getListOrder() { result = 0 }

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

override string toString() { result = "ConditionalCompletion" }
}

int getNextListOrder() { result = 1 }
module ConditionalCompletionSplittingInput {
private import Completion as Comp

private class ConditionalCompletionSplitImpl extends SplitImpl instanceof ConditionalCompletionSplit
{
ConditionalCompletion completion;
class ConditionalCompletion = Comp::ConditionalCompletion;

ConditionalCompletionSplitImpl() { this = TConditionalCompletionSplit(completion) }
class ConditionalCompletionSplitKind extends ConditionalCompletionSplitKind_, TSplitKind { }

override ConditionalCompletionSplitKind getKind() { any() }
class ConditionalCompletionSplit = ConditionalCompletionSplitting::ConditionalCompletionSplit;

override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
succ(pred, succ, c) and
last(succ, _, completion) and
bindingset[parent, parentCompletion]
predicate condPropagateExpr(
AstNode parent, ConditionalCompletion parentCompletion, AstNode child,
ConditionalCompletion childCompletion
) {
child = parent.(Ast::NotExpr).getOperand() and
childCompletion.(BooleanCompletion).getDual() = parentCompletion
or
childCompletion = parentCompletion and
(
last(succ.(Ast::NotExpr).getOperand(), pred, c) and
completion.(BooleanCompletion).getDual() = c
or
last(succ.(Ast::LogicalAndExpr).getAnOperand(), pred, c) and
completion = c
child = parent.(Ast::LogicalAndExpr).getAnOperand()
or
last(succ.(Ast::LogicalOrExpr).getAnOperand(), pred, c) and
completion = c
child = parent.(Ast::LogicalOrExpr).getAnOperand()
or
last(succ.(Ast::StmtSequence).getLastStmt(), pred, c) and
completion = c
child = parent.(Ast::StmtSequence).getLastStmt()
or
last(succ.(Ast::ConditionalExpr).getBranch(_), pred, c) and
completion = c
child = parent.(Ast::ConditionalExpr).getBranch(_)
)
or
succ(pred, succ, c) and
succ instanceof Ast::WhenClause and
completion = c
}
}

override predicate hasEntryScope(CfgScope scope, AstNode succ) { none() }
int getNextListOrder() { result = 1 }

override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
this.appliesTo(pred) and
private class ConditionalCompletionSplitImpl extends SplitImplementations::ConditionalCompletionSplitting::ConditionalCompletionSplitImpl
{
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
super.hasEntry(pred, succ, c)
or
// a non-standard case is needed for `when` clauses
succ(pred, succ, c) and
if c instanceof ConditionalCompletion then completion = c else any()
}

override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
this.appliesTo(last) and
succExit(scope, last, c) and
if c instanceof ConditionalCompletion then completion = c else any()
succ instanceof Ast::WhenClause and
c = this.getCompletion()
}

override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ private import codeql.rust.controlflow.ControlFlowGraph as Cfg
private module CfgInput implements InputSig<Location> {
private import rust as Rust
private import Completion as C
private import Splitting as S

class AstNode = Rust::AstNode;

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

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

class SplitKindBase = S::TSplitKind;

class Split = S::Split;

class SuccessorType = Cfg::SuccessorType;

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

private module CfgImpl = Make<Location, CfgInput>;
private module CfgSplittingInput implements SplittingInputSig<Location, CfgInput> {
private import Splitting as S

class SplitKindBase = S::TSplitKind;

class Split = S::Split;
}

private module ConditionalCompletionSplittingInput implements
ConditionalCompletionSplittingInputSig<Location, CfgInput, CfgSplittingInput>
{
import Splitting::ConditionalCompletionSplitting::ConditionalCompletionSplittingInput
}

private module CfgImpl =
MakeWithSplitting<Location, CfgInput, CfgSplittingInput, ConditionalCompletionSplittingInput>;

import CfgImpl

Expand Down
Loading
Loading