зеркало из https://github.com/github/codeql.git
Swift: Create a custom IPA type for 'ControlFlowElement's and fixup various type annotations.
This commit is contained in:
Родитель
67572bb770
Коммит
ab268514a1
|
@ -3,6 +3,7 @@
|
|||
private import swift
|
||||
private import ControlFlowGraph
|
||||
private import internal.ControlFlowGraphImpl
|
||||
private import internal.ControlFlowElements
|
||||
private import CfgNodes
|
||||
private import SuccessorTypes
|
||||
|
||||
|
@ -198,8 +199,18 @@ private module JoinBlockPredecessors {
|
|||
|
||||
private predicate idOf(AstNode x, int y) = equivalenceRelation(id/2)(x, y)
|
||||
|
||||
private AstNode projctToAst(ControlFlowElement n) {
|
||||
result = n.asAstNode()
|
||||
or
|
||||
isPropertyGetterElement(n, _, result)
|
||||
or
|
||||
isPropertySetterElement(n, _, result)
|
||||
or
|
||||
isPropertyObserverElement(n, _, result)
|
||||
}
|
||||
|
||||
int getId(JoinBlockPredecessor jbp) {
|
||||
idOf(jbp.getFirstNode().(AstCfgNode).getNode(), result)
|
||||
idOf(projctToAst(jbp.getFirstNode().(AstCfgNode).getNode()), result)
|
||||
or
|
||||
idOf(jbp.(EntryBasicBlock).getScope(), result)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ private import swift
|
|||
private import BasicBlocks
|
||||
private import ControlFlowGraph
|
||||
private import internal.ControlFlowGraphImpl
|
||||
private import internal.ControlFlowElements
|
||||
private import internal.Splitting
|
||||
|
||||
/** An entry node for a given scope. */
|
||||
|
@ -66,11 +67,11 @@ class ExitNode extends ControlFlowNode, TExitNode {
|
|||
*/
|
||||
class AstCfgNode extends ControlFlowNode, TElementNode {
|
||||
private Splits splits;
|
||||
private AstNode n;
|
||||
private ControlFlowElement n;
|
||||
|
||||
AstCfgNode() { this = TElementNode(_, n, splits) }
|
||||
|
||||
final override AstNode getNode() { result = n }
|
||||
final override ControlFlowElement getNode() { result = n }
|
||||
|
||||
override Location getLocation() { result = n.getLocation() }
|
||||
|
||||
|
@ -96,7 +97,7 @@ class AstCfgNode extends ControlFlowNode, TElementNode {
|
|||
class ExprCfgNode extends AstCfgNode {
|
||||
Expr e;
|
||||
|
||||
ExprCfgNode() { e = this.getNode() }
|
||||
ExprCfgNode() { e = this.getNode().asAstNode() }
|
||||
|
||||
/** Gets the underlying expression. */
|
||||
Expr getExpr() { result = e }
|
||||
|
|
|
@ -6,13 +6,14 @@ private import SuccessorTypes
|
|||
private import internal.ControlFlowGraphImpl
|
||||
private import internal.Completion
|
||||
private import internal.Scope
|
||||
private import internal.ControlFlowElements
|
||||
|
||||
/** An AST node with an associated control-flow graph. */
|
||||
class CfgScope extends Scope instanceof CfgScope::Range_ {
|
||||
/** Gets the CFG scope that this scope is nested under, if any. */
|
||||
final CfgScope getOuterCfgScope() {
|
||||
exists(AstNode parent |
|
||||
parent = getParent(this) and
|
||||
exists(ControlFlowElement parent |
|
||||
parent.asAstNode() = getParentOfAst(this) and
|
||||
result = getCfgScope(parent)
|
||||
)
|
||||
}
|
||||
|
@ -31,7 +32,7 @@ class ControlFlowNode extends TCfgNode {
|
|||
string toString() { none() }
|
||||
|
||||
/** Gets the AST node that this node corresponds to, if any. */
|
||||
AstNode getNode() { none() }
|
||||
ControlFlowElement getNode() { none() }
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation() { none() }
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
private import swift
|
||||
private import codeql.swift.controlflow.ControlFlowGraph
|
||||
private import ControlFlowElements
|
||||
private import ControlFlowGraphImpl
|
||||
private import SuccessorTypes
|
||||
|
||||
|
@ -41,8 +42,8 @@ private predicate completionIsValidForStmt(Stmt stmt, Completion c) {
|
|||
|
||||
/** A completion of a statement or an expression. */
|
||||
abstract class Completion extends TCompletion {
|
||||
private predicate isValidForSpecific(AstNode n) {
|
||||
completionIsValidForStmt(n, this)
|
||||
private predicate isValidForSpecific(ControlFlowElement n) {
|
||||
completionIsValidForStmt(n.asAstNode(), this)
|
||||
or
|
||||
mustHaveBooleanCompletion(n) and
|
||||
(
|
||||
|
@ -52,22 +53,24 @@ abstract class Completion extends TCompletion {
|
|||
this = TBooleanCompletion(_)
|
||||
)
|
||||
or
|
||||
mustHaveMatchingCompletion(n) and
|
||||
mustHaveMatchingCompletion(n.asAstNode()) and
|
||||
(
|
||||
exists(boolean value | isMatchingConstant(n, value) | this = TMatchingCompletion(value))
|
||||
exists(boolean value | isMatchingConstant(n.asAstNode(), value) |
|
||||
this = TMatchingCompletion(value)
|
||||
)
|
||||
or
|
||||
not isMatchingConstant(n, _) and
|
||||
not isMatchingConstant(n.asAstNode(), _) and
|
||||
this = TMatchingCompletion(_)
|
||||
)
|
||||
or
|
||||
mustHaveThrowCompletion(n, this)
|
||||
mustHaveThrowCompletion(n.asAstNode(), this)
|
||||
}
|
||||
|
||||
/** Holds if this completion is valid for node `n`. */
|
||||
predicate isValidFor(AstNode n) {
|
||||
predicate isValidFor(ControlFlowElement n) {
|
||||
this.isValidForSpecific(n)
|
||||
or
|
||||
mayHaveThrowCompletion(n, this)
|
||||
mayHaveThrowCompletion(n.asAstNode(), this)
|
||||
or
|
||||
not any(Completion c).isValidForSpecific(n) and
|
||||
this = TSimpleCompletion()
|
||||
|
@ -87,25 +90,35 @@ abstract class Completion extends TCompletion {
|
|||
}
|
||||
|
||||
/** Holds if node `n` has the Boolean constant value `value`. */
|
||||
private predicate isBooleanConstant(AstNode n, boolean value) {
|
||||
private predicate isBooleanConstant(ControlFlowElement n, boolean value) {
|
||||
mustHaveBooleanCompletion(n) and
|
||||
value = n.(BooleanLiteralExpr).getValue()
|
||||
value = n.asAstNode().(BooleanLiteralExpr).getValue()
|
||||
or
|
||||
// Boolean consants hidden inside conversions are also
|
||||
// constants that resolve to the same value.
|
||||
isBooleanConstant(n.getResolveStep(), value)
|
||||
exists(ControlFlowElement parent |
|
||||
parent.asAstNode() = n.asAstNode().getResolveStep() and
|
||||
isBooleanConstant(parent, value)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a normal completion of `n` must be a Boolean completion.
|
||||
*/
|
||||
private predicate mustHaveBooleanCompletion(AstNode n) { inBooleanContext(n) }
|
||||
private predicate mustHaveBooleanCompletion(ControlFlowElement n) { inBooleanContext(n) }
|
||||
|
||||
/**
|
||||
* Holds if `n` is used in a Boolean context. That is, the value
|
||||
* that `n` evaluates to determines a true/false branch successor.
|
||||
*/
|
||||
private predicate inBooleanContext(AstNode n) {
|
||||
private predicate inBooleanContext(ControlFlowElement n) {
|
||||
astInBooleanContext(n.asAstNode()) or
|
||||
astInBooleanContext(n.(PropertyGetterElement).getRef()) or
|
||||
astInBooleanContext(n.(PropertySetterElement).getAssignExpr()) or
|
||||
astInBooleanContext(n.(PropertyObserverElement).getAssignExpr())
|
||||
}
|
||||
|
||||
private predicate astInBooleanContext(AstNode n) {
|
||||
n = any(ConditionElement condElem).getFullyUnresolved()
|
||||
or
|
||||
n = any(StmtCondition stmtCond).getFullyUnresolved()
|
||||
|
@ -115,30 +128,30 @@ private predicate inBooleanContext(AstNode n) {
|
|||
exists(LogicalAndExpr parent |
|
||||
n = parent.getLeftOperand().getFullyConverted()
|
||||
or
|
||||
inBooleanContext(parent) and
|
||||
astInBooleanContext(parent) and
|
||||
n = parent.getRightOperand().getFullyConverted()
|
||||
)
|
||||
or
|
||||
exists(LogicalOrExpr parent |
|
||||
n = parent.getLeftOperand().getFullyConverted()
|
||||
or
|
||||
inBooleanContext(parent) and
|
||||
astInBooleanContext(parent) and
|
||||
n = parent.getRightOperand().getFullyConverted()
|
||||
)
|
||||
or
|
||||
n = any(NotExpr parent | inBooleanContext(parent)).getOperand().getFullyConverted()
|
||||
n = any(NotExpr parent | astInBooleanContext(parent)).getOperand().getFullyConverted()
|
||||
or
|
||||
exists(IfExpr ifExpr |
|
||||
ifExpr.getCondition().getFullyConverted() = n
|
||||
or
|
||||
inBooleanContext(ifExpr) and
|
||||
astInBooleanContext(ifExpr) and
|
||||
n = ifExpr.getBranch(_).getFullyConverted()
|
||||
)
|
||||
or
|
||||
exists(ForEachStmt foreach | n = foreach.getWhere().getFullyConverted())
|
||||
or
|
||||
exists(Exprs::Conversions::ConversionOrIdentityTree parent |
|
||||
inBooleanContext(parent) and
|
||||
astInBooleanContext(parent.getAst()) and
|
||||
parent.convertsFrom(n)
|
||||
)
|
||||
}
|
||||
|
@ -477,3 +490,18 @@ class ThrowCompletion extends TThrowCompletion, Completion {
|
|||
|
||||
override string toString() { result = "throw" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Hold if `c` represents normal evaluation of a statement or an
|
||||
* expression.
|
||||
*/
|
||||
predicate completionIsNormal(Completion c) { c instanceof NormalCompletion }
|
||||
|
||||
/**
|
||||
* Hold if `c` represents simple (normal) evaluation of a statement or an
|
||||
* expression.
|
||||
*/
|
||||
predicate completionIsSimple(Completion c) { c instanceof SimpleCompletion }
|
||||
|
||||
/** Holds if `c` is a valid completion for `e`. */
|
||||
predicate completionIsValidFor(Completion c, ControlFlowElement e) { c.isValidFor(e) }
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
private import swift
|
||||
|
||||
cached
|
||||
newtype TControlFlowElement =
|
||||
TAstElement(AstNode n) or
|
||||
TPropertyGetterElement(Decl accessor, Expr ref) { isPropertyGetterElement(accessor, ref) } or
|
||||
TPropertySetterElement(AccessorDecl accessor, AssignExpr assign) {
|
||||
isPropertySetterElement(accessor, assign)
|
||||
} or
|
||||
TPropertyObserverElement(AccessorDecl observer, AssignExpr assign) {
|
||||
isPropertyObserverElement(observer, assign)
|
||||
}
|
||||
|
||||
predicate isLValue(Expr e) { any(AssignExpr assign).getDest() = e }
|
||||
|
||||
predicate isRValue(Expr e) { not isLValue(e) }
|
||||
|
||||
predicate ignoreAstElement(AstNode n) {
|
||||
isPropertyGetterElement(_, n)
|
||||
or
|
||||
isPropertySetterElement(_, n)
|
||||
}
|
||||
|
||||
private AccessorDecl getAnAccessorDecl(Decl d) {
|
||||
result = d.(VarDecl).getAnAccessorDecl() or
|
||||
result = d.(SubscriptDecl).getAnAccessorDecl()
|
||||
}
|
||||
|
||||
predicate isPropertyGetterElement(AccessorDecl accessor, Expr ref) {
|
||||
hasDirectToImplementationOrOrdinarySemantics(ref) and
|
||||
isRValue(ref) and
|
||||
accessor.isGetter() and
|
||||
accessor = getAnAccessorDecl([ref.(LookupExpr).getMember(), ref.(DeclRefExpr).getDecl()])
|
||||
}
|
||||
|
||||
predicate isPropertyGetterElement(PropertyGetterElement pge, AccessorDecl accessor, Expr ref) {
|
||||
pge = TPropertyGetterElement(accessor, ref)
|
||||
}
|
||||
|
||||
private predicate hasDirectToImplementationSemantics(Expr e) {
|
||||
e.(MemberRefExpr).hasDirectToImplementationSemantics()
|
||||
or
|
||||
e.(SubscriptExpr).hasDirectToImplementationSemantics()
|
||||
or
|
||||
e.(DeclRefExpr).hasDirectToImplementationSemantics()
|
||||
}
|
||||
|
||||
private predicate hasOrdinarySemantics(Expr e) {
|
||||
e.(MemberRefExpr).hasOrdinarySemantics()
|
||||
or
|
||||
e.(SubscriptExpr).hasOrdinarySemantics()
|
||||
or
|
||||
e.(DeclRefExpr).hasOrdinarySemantics()
|
||||
}
|
||||
|
||||
private predicate hasDirectToImplementationOrOrdinarySemantics(Expr e) {
|
||||
hasDirectToImplementationSemantics(e) or hasOrdinarySemantics(e)
|
||||
}
|
||||
|
||||
predicate isPropertySetterElement(AccessorDecl accessor, AssignExpr assign) {
|
||||
exists(Expr lhs | lhs = assign.getDest() |
|
||||
hasDirectToImplementationOrOrdinarySemantics(lhs) and
|
||||
accessor.isSetter() and
|
||||
isLValue(lhs) and
|
||||
accessor = getAnAccessorDecl([lhs.(LookupExpr).getMember(), lhs.(DeclRefExpr).getDecl()])
|
||||
)
|
||||
}
|
||||
|
||||
predicate isPropertySetterElement(
|
||||
PropertySetterElement pse, AccessorDecl accessor, AssignExpr assign
|
||||
) {
|
||||
pse = TPropertySetterElement(accessor, assign)
|
||||
}
|
||||
|
||||
predicate isPropertyObserverElement(AccessorDecl observer, AssignExpr assign) {
|
||||
exists(Expr lhs | lhs = assign.getDest() |
|
||||
hasDirectToImplementationOrOrdinarySemantics(lhs) and
|
||||
observer.isPropertyObserver() and
|
||||
isLValue(lhs) and
|
||||
observer = getAnAccessorDecl([lhs.(LookupExpr).getMember(), lhs.(DeclRefExpr).getDecl()])
|
||||
)
|
||||
}
|
||||
|
||||
predicate isPropertyObserverElement(
|
||||
PropertyObserverElement poe, AccessorDecl accessor, AssignExpr assign
|
||||
) {
|
||||
poe = TPropertyObserverElement(accessor, assign)
|
||||
}
|
||||
|
||||
class ControlFlowElement extends TControlFlowElement {
|
||||
string toString() { none() } // overriden in subclasses
|
||||
|
||||
AstNode asAstNode() { none() }
|
||||
|
||||
Location getLocation() { none() } // overriden in subclasses
|
||||
}
|
||||
|
||||
class AstElement extends ControlFlowElement, TAstElement {
|
||||
AstNode n;
|
||||
|
||||
AstElement() { this = TAstElement(n) }
|
||||
|
||||
override string toString() { result = n.toString() }
|
||||
|
||||
override AstNode asAstNode() { result = n }
|
||||
|
||||
override Location getLocation() { result = n.getLocation() }
|
||||
}
|
||||
|
||||
class PropertyGetterElement extends ControlFlowElement, TPropertyGetterElement {
|
||||
AccessorDecl accessor;
|
||||
Expr ref;
|
||||
|
||||
PropertyGetterElement() { this = TPropertyGetterElement(accessor, ref) }
|
||||
|
||||
override string toString() { result = "getter for " + ref.toString() }
|
||||
|
||||
override Location getLocation() { result = ref.getLocation() }
|
||||
|
||||
Expr getRef() { result = ref }
|
||||
|
||||
AccessorDecl getAccessorDecl() { result = accessor }
|
||||
}
|
||||
|
||||
class PropertySetterElement extends ControlFlowElement, TPropertySetterElement {
|
||||
AccessorDecl accessor;
|
||||
AssignExpr assign;
|
||||
|
||||
PropertySetterElement() { this = TPropertySetterElement(accessor, assign) }
|
||||
|
||||
override string toString() { result = "setter for " + assign }
|
||||
|
||||
override Location getLocation() { result = assign.getLocation() }
|
||||
|
||||
AccessorDecl getAccessorDecl() { result = accessor }
|
||||
|
||||
AssignExpr getAssignExpr() { result = assign }
|
||||
}
|
||||
|
||||
class PropertyObserverElement extends ControlFlowElement, TPropertyObserverElement {
|
||||
AccessorDecl observer;
|
||||
AssignExpr assign;
|
||||
|
||||
PropertyObserverElement() { this = TPropertyObserverElement(observer, assign) }
|
||||
|
||||
override string toString() {
|
||||
this.isWillSet() and
|
||||
result = "willSet observer for " + assign.toString()
|
||||
or
|
||||
this.isDidSet() and
|
||||
result = "didSet observer for " + assign.toString()
|
||||
}
|
||||
|
||||
override Location getLocation() { result = assign.getLocation() }
|
||||
|
||||
AccessorDecl getObserver() { result = observer }
|
||||
|
||||
predicate isWillSet() { observer.isWillSet() }
|
||||
|
||||
predicate isDidSet() { observer.isDidSet() }
|
||||
|
||||
AssignExpr getAssignExpr() { result = assign }
|
||||
}
|
|
@ -1,30 +1,14 @@
|
|||
private import swift as S
|
||||
private import ControlFlowGraphImpl as Impl
|
||||
private import Completion as Comp
|
||||
import Completion
|
||||
private import codeql.swift.controlflow.ControlFlowGraph as CFG
|
||||
private import Splitting as Splitting
|
||||
private import Scope
|
||||
import ControlFlowElements
|
||||
import AstControlFlowTrees
|
||||
|
||||
/** The base class for `ControlFlowTree`. */
|
||||
class ControlFlowTreeBase extends S::AstNode { }
|
||||
|
||||
class ControlFlowElement = S::AstNode;
|
||||
|
||||
class Completion = Comp::Completion;
|
||||
|
||||
/**
|
||||
* Hold if `c` represents normal evaluation of a statement or an
|
||||
* expression.
|
||||
*/
|
||||
predicate completionIsNormal(Completion c) { c instanceof Comp::NormalCompletion }
|
||||
|
||||
/**
|
||||
* Hold if `c` represents simple (normal) evaluation of a statement or an
|
||||
* expression.
|
||||
*/
|
||||
predicate completionIsSimple(Completion c) { c instanceof Comp::SimpleCompletion }
|
||||
|
||||
/** Holds if `c` is a valid completion for `e`. */
|
||||
predicate completionIsValidFor(Completion c, ControlFlowElement e) { c.isValidFor(e) }
|
||||
class ControlFlowTreeBase = ControlFlowElement;
|
||||
|
||||
class CfgScope = CFG::CfgScope;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ private module Scope {
|
|||
class TypeRange = Callable::TypeRange;
|
||||
|
||||
class Range extends AstNode, TypeRange {
|
||||
Range getOuterScope() { result = scopeOf(this) }
|
||||
Range getOuterScope() { result = scopeOfAst(this) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,14 +235,14 @@ private module Cached {
|
|||
}
|
||||
|
||||
cached
|
||||
AstNode getParent(AstNode ast) { getChild(result, _) = ast }
|
||||
AstNode getParentOfAst(AstNode ast) { getChild(result, _) = ast }
|
||||
}
|
||||
|
||||
/** Gets the enclosing scope of a node */
|
||||
cached
|
||||
AstNode scopeOf(AstNode n) {
|
||||
exists(AstNode p | p = getParent(n) |
|
||||
if p instanceof Scope then p = result else result = scopeOf(p)
|
||||
AstNode scopeOfAst(AstNode n) {
|
||||
exists(AstNode p | p = getParentOfAst(n) |
|
||||
if p instanceof Scope then p = result else result = scopeOfAst(p)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ private import swift
|
|||
private import Completion
|
||||
private import ControlFlowGraphImpl
|
||||
private import codeql.swift.controlflow.ControlFlowGraph
|
||||
private import AstControlFlowTrees
|
||||
private import ControlFlowElements
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
|
@ -37,7 +39,7 @@ private module ConditionalCompletionSplitting {
|
|||
private class ConditionalCompletionSplitKind extends SplitKind, TConditionalCompletionSplitKind {
|
||||
override int getListOrder() { result = 0 }
|
||||
|
||||
override predicate isEnabled(AstNode n) { this.appliesTo(n) }
|
||||
override predicate isEnabled(ControlFlowElement n) { this.appliesTo(n) }
|
||||
|
||||
override string toString() { result = "ConditionalCompletion" }
|
||||
}
|
||||
|
@ -45,47 +47,50 @@ private module ConditionalCompletionSplitting {
|
|||
private class ConditionalCompletionSplitImpl extends SplitImpl, ConditionalCompletionSplit {
|
||||
override ConditionalCompletionSplitKind getKind() { any() }
|
||||
|
||||
override predicate hasEntry(AstNode pred, AstNode succ, Completion c) {
|
||||
override predicate hasEntry(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
succ(pred, succ, c) and
|
||||
last(succ, _, completion) and
|
||||
(
|
||||
last(succ.(NotExpr).getOperand().getFullyConverted(), pred, c) and
|
||||
astLast(succ.asAstNode().(NotExpr).getOperand().getFullyConverted(), pred, c) and
|
||||
completion.(BooleanCompletion).getDual() = c
|
||||
or
|
||||
last(succ.(LogicalAndExpr).getAnOperand().getFullyConverted(), pred, c) and
|
||||
astLast(succ.asAstNode().(LogicalAndExpr).getAnOperand().getFullyConverted(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
last(succ.(LogicalOrExpr).getAnOperand().getFullyConverted(), pred, c) and
|
||||
astLast(succ.asAstNode().(LogicalOrExpr).getAnOperand().getFullyConverted(), pred, c) and
|
||||
completion = c
|
||||
or
|
||||
succ =
|
||||
succ.asAstNode() =
|
||||
any(IfExpr ce |
|
||||
last(ce.getBranch(_).getFullyConverted(), pred, c) and
|
||||
astLast(ce.getBranch(_).getFullyConverted(), pred, c) and
|
||||
completion = c
|
||||
)
|
||||
or
|
||||
exists(Expr e |
|
||||
succ.(Exprs::Conversions::ConversionOrIdentityTree).convertsFrom(e) and
|
||||
last(e, pred, c) and
|
||||
exists(Expr e, Exprs::Conversions::ConversionOrIdentityTree conv |
|
||||
succ.asAstNode() = conv.getAst() and
|
||||
conv.convertsFrom(e) and
|
||||
astLast(e, pred, c) and
|
||||
completion = c
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasEntryScope(CfgScope scope, AstNode succ) { none() }
|
||||
override predicate hasEntryScope(CfgScope scope, ControlFlowElement succ) { none() }
|
||||
|
||||
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||
override predicate hasExit(ControlFlowElement pred, ControlFlowElement 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) {
|
||||
override predicate hasExitScope(CfgScope scope, ControlFlowElement last, Completion c) {
|
||||
this.appliesTo(last) and
|
||||
succExit(scope, last, c) and
|
||||
if c instanceof ConditionalCompletion then completion = c else any()
|
||||
}
|
||||
|
||||
override predicate hasSuccessor(AstNode pred, AstNode succ, Completion c) { none() }
|
||||
override predicate hasSuccessor(ControlFlowElement pred, ControlFlowElement succ, Completion c) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
|
||||
private import codeql.swift.generated.expr.SubscriptExpr
|
||||
|
||||
class SubscriptExpr extends SubscriptExprBase { }
|
||||
|
|
Загрузка…
Ссылка в новой задаче