Merge pull request #12807 from MathiasVP/dataflow-for-keypaths

Swift: Dataflow for keypaths
This commit is contained in:
Mathias Vorreiter Pedersen
2023-04-19 10:00:49 +01:00
committed by GitHub
12 changed files with 485 additions and 455 deletions

View File

@@ -179,3 +179,25 @@ class ApplyExprCfgNode extends ExprCfgNode {
class CallExprCfgNode extends ApplyExprCfgNode {
override CallExpr e;
}
/** A control-flow node that wraps a key-path application. */
class KeyPathApplicationExprCfgNode extends ExprCfgNode {
override KeyPathApplicationExpr e;
/**
* Gets the control-flow node that wraps the key-path of
* this control-flow element.
*/
CfgNode getKeyPath() { result.getAst() = e.getKeyPath() }
/**
* Gets the control-flow node that wraps the base of
* this control-flow element.
*/
CfgNode getBase() { result.getAst() = e.getBase() }
}
/** A control-flow node that wraps a key-path expression. */
class KeyPathExprCfgNode extends ExprCfgNode {
override KeyPathExpr e;
}

View File

@@ -58,7 +58,7 @@ module CfgScope {
}
private class KeyPathScope extends Range_ instanceof KeyPathExpr {
AstControlFlowTree tree;
KeyPathControlFlowTree tree;
KeyPathScope() { tree.getAst() = this }
@@ -76,6 +76,12 @@ module CfgScope {
final override predicate exit(ControlFlowElement last, Completion c) { last(tree, last, c) }
}
private class KeyPathControlFlowTree extends StandardPostOrderTree, KeyPathElement {
final override ControlFlowElement getChildElement(int i) {
result.asAstNode() = expr.getComponent(i)
}
}
}
/** Holds if `first` is first executed when entering `scope`. */
@@ -88,6 +94,14 @@ predicate succExit(CfgScope::Range_ scope, ControlFlowElement last, Completion c
scope.exit(last, c)
}
private class KeyPathComponentTree extends AstStandardPostOrderTree {
override KeyPathComponent ast;
final override ControlFlowElement getChildElement(int i) {
result.asAstNode() = ast.getSubscriptArgument(i).getExpr().getFullyConverted()
}
}
/**
* Control-flow for statements.
*/

View File

@@ -21,7 +21,39 @@ module Ssa {
class ExitBasicBlock = BasicBlocks::ExitBasicBlock;
class SourceVariable = VarDecl;
private newtype TSourceVariable =
TNormalSourceVariable(VarDecl v) or
TKeyPathSourceVariable(EntryNode entry) { entry.getScope() instanceof KeyPathExpr }
abstract class SourceVariable extends TSourceVariable {
abstract string toString();
VarDecl asVarDecl() { none() }
EntryNode asKeyPath() { none() }
DeclRefExpr getAnAccess() { result.getDecl() = this.asVarDecl() }
}
private class NormalSourceVariable extends SourceVariable, TNormalSourceVariable {
VarDecl v;
NormalSourceVariable() { this = TNormalSourceVariable(v) }
override string toString() { result = v.toString() }
override VarDecl asVarDecl() { result = v }
}
private class KeyPathSourceVariable extends SourceVariable, TKeyPathSourceVariable {
EntryNode enter;
KeyPathSourceVariable() { this = TKeyPathSourceVariable(enter) }
override string toString() { result = enter.toString() }
override EntryNode asKeyPath() { result = enter }
}
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
exists(AssignExpr assign |
@@ -40,17 +72,22 @@ module Ssa {
// ```
exists(NamedPattern pattern |
bb.getNode(i).getNode().asAstNode() = pattern and
v = pattern.getVarDecl() and
v.asVarDecl() = pattern.getVarDecl() and
certain = true
)
or
v instanceof ParamDecl and
bb.getNode(i).getNode().asAstNode() = v and
exists(ParamDecl p |
p = v.asVarDecl() and
bb.getNode(i).getNode().asAstNode() = p and
certain = true
)
or
bb.getNode(i) = v.asKeyPath() and
certain = true
or
// Mark the subexpression as a write of the local variable declared in the `TapExpr`.
exists(TapExpr tap |
v = tap.getVar() and
v.asVarDecl() = tap.getVar() and
bb.getNode(i).getNode().asAstNode() = tap.getSubExpr() and
certain = true
)
@@ -60,7 +97,7 @@ module Ssa {
exists(DeclRefExpr ref |
not isLValue(ref) and
bb.getNode(i).getNode().asAstNode() = ref and
v = ref.getDecl() and
v.asVarDecl() = ref.getDecl() and
certain = true
)
or
@@ -71,24 +108,26 @@ module Ssa {
)
or
exists(ExitNode exit, AbstractFunctionDecl func |
func.getAParam() = v or func.getSelfParam() = v
|
[func.getAParam(), func.getSelfParam()] = v.asVarDecl() and
bb.getNode(i) = exit and
modifiableParam(v) and
modifiableParam(v.asVarDecl()) and
bb.getScope() = func and
certain = true
)
or
// Mark the `TapExpr` as a read of the of the local variable.
exists(TapExpr tap |
v = tap.getVar() and
v.asVarDecl() = tap.getVar() and
bb.getNode(i).getNode().asAstNode() = tap and
certain = true
)
}
}
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
/**
* INTERNAL: Do not use.
*/
module SsaImpl = SsaImplCommon::Make<SsaInput>;
cached
class Definition extends SsaImpl::Definition {
@@ -97,7 +136,7 @@ module Ssa {
cached
ControlFlowNode getARead() {
exists(VarDecl v, SsaInput::BasicBlock bb, int i |
exists(SsaInput::SourceVariable v, SsaInput::BasicBlock bb, int i |
SsaImpl::ssaDefReachesRead(v, this, bb, i) and
SsaInput::variableRead(bb, i, v, true) and
result = bb.getNode(i)

View File

@@ -74,6 +74,7 @@ newtype TDataFlowCall =
TPropertyGetterCall(PropertyGetterCfgNode getter) or
TPropertySetterCall(PropertySetterCfgNode setter) or
TPropertyObserverCall(PropertyObserverCfgNode observer) or
TKeyPathCall(KeyPathApplicationExprCfgNode keyPathApplication) or
TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, Node receiver) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
@@ -89,6 +90,9 @@ class DataFlowCall extends TDataFlowCall {
/** Gets the underlying source code call, if any. */
ApplyExprCfgNode asCall() { none() }
/** Gets the underlying key-path application node, if any. */
KeyPathApplicationExprCfgNode asKeyPath() { none() }
/**
* Gets the i'th argument of call.class
* The qualifier is considered to have index `-1`.
@@ -138,6 +142,25 @@ private class NormalCall extends DataFlowCall, TNormalCall {
override Location getLocation() { result = apply.getLocation() }
}
private class KeyPathCall extends DataFlowCall, TKeyPathCall {
private KeyPathApplicationExprCfgNode apply;
KeyPathCall() { this = TKeyPathCall(apply) }
override KeyPathApplicationExprCfgNode asKeyPath() { result = apply }
override CfgNode getArgument(int i) {
i = -1 and
result = apply.getBase()
}
override DataFlowCallable getEnclosingCallable() { result = TDataFlowFunc(apply.getScope()) }
override string toString() { result = apply.toString() }
override Location getLocation() { result = apply.getLocation() }
}
class PropertyGetterCall extends DataFlowCall, TPropertyGetterCall {
private PropertyGetterCfgNode getter;

View File

@@ -40,6 +40,22 @@ private class ExprNodeImpl extends ExprNode, NodeImpl {
override DataFlowCallable getEnclosingCallable() { result = TDataFlowFunc(n.getScope()) }
}
private class KeyPathComponentNodeImpl extends TKeyPathComponentNode, NodeImpl {
KeyPathComponent component;
KeyPathComponentNodeImpl() { this = TKeyPathComponentNode(component) }
override Location getLocationImpl() { result = component.getLocation() }
override string toStringImpl() { result = component.toString() }
override DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = component.getKeyPathExpr()
}
KeyPathComponent getComponent() { result = component }
}
private class PatternNodeImpl extends PatternNode, NodeImpl {
override Location getLocationImpl() { result = pattern.getLocation() }
@@ -78,6 +94,9 @@ private module Cached {
FlowSummaryImpl::Private::summaryNodeRange(c, state)
} or
TSourceParameterNode(ParamDecl param) or
TKeyPathParameterNode(EntryNode entry) { entry.getScope() instanceof KeyPathExpr } or
TKeyPathReturnNode(ExitNode exit) { exit.getScope() instanceof KeyPathExpr } or
TKeyPathComponentNode(KeyPathComponent component) or
TSummaryParameterNode(FlowSummary::SummarizedCallable c, ParameterPosition pos) {
FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos)
} or
@@ -105,7 +124,7 @@ private module Cached {
(
nodeTo instanceof InoutReturnNode
implies
nodeTo.(InoutReturnNode).getParameter() = def.getSourceVariable()
nodeTo.(InoutReturnNode).getParameter() = def.getSourceVariable().asVarDecl()
)
}
@@ -135,7 +154,7 @@ private module Cached {
(
nodeTo instanceof InoutReturnNode
implies
nodeTo.(InoutReturnNode).getParameter() = def.getSourceVariable()
nodeTo.(InoutReturnNode).getParameter() = def.getSourceVariable().asVarDecl()
)
or
// use-use flow
@@ -198,6 +217,11 @@ private module Cached {
nodeFrom.asPattern().(TypedPattern).getSubPattern()
]
or
// Flow from the unique parameter of a key path expression to
// the first component in the chain.
nodeTo.(KeyPathComponentNodeImpl).getComponent() =
nodeFrom.(KeyPathParameterNode).getComponent(0)
or
// flow through a flow summary (extension of `SummaryModelCsv`)
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
}
@@ -311,6 +335,28 @@ private module ParameterNodes {
override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) }
}
class KeyPathParameterNode extends ParameterNodeImpl, TKeyPathParameterNode {
private EntryNode entry;
KeyPathParameterNode() { this = TKeyPathParameterNode(entry) }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
c.asSourceCallable() = entry.getScope() and pos = TThisParameter()
}
override Location getLocationImpl() { result = entry.getLocation() }
override string toStringImpl() { result = entry.toString() }
override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) }
KeyPathComponent getComponent(int i) { result = entry.getScope().(KeyPathExpr).getComponent(i) }
KeyPathComponent getAComponent() { result = this.getComponent(_) }
KeyPathExpr getKeyPathExpr() { result = entry.getScope() }
}
}
import ParameterNodes
@@ -412,6 +458,17 @@ private module ArgumentNodes {
FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos)
}
}
class KeyPathArgumentNode extends ExprNode, ArgumentNode {
private KeyPathApplicationExprCfgNode keyPath;
KeyPathArgumentNode() { keyPath.getBase() = this.getCfgNode() }
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call.asKeyPath() = keyPath and
pos = TThisArgument()
}
}
}
import ArgumentNodes
@@ -474,6 +531,24 @@ private module ReturnNodes {
override ReturnKind getKind() { result = rk }
}
class KeyPathReturnNodeImpl extends ReturnNode, TKeyPathReturnNode, NodeImpl {
ExitNode exit;
KeyPathReturnNodeImpl() { this = TKeyPathReturnNode(exit) }
override ReturnKind getKind() { result instanceof NormalReturnKind }
override ControlFlowNode getCfgNode() { result = exit }
override DataFlowCallable getEnclosingCallable() { result.asSourceCallable() = exit.getScope() }
override Location getLocationImpl() { result = exit.getLocation() }
override string toStringImpl() { result = exit.toString() }
KeyPathExpr getKeyPathExpr() { result = exit.getScope() }
}
}
import ReturnNodes
@@ -495,6 +570,16 @@ private module OutNodes {
}
}
class KeyPathOutNode extends OutNode, ExprNodeImpl {
KeyPathApplicationExprCfgNode keyPath;
KeyPathOutNode() { keyPath = this.getCfgNode() }
override DataFlowCall getCall(ReturnKind kind) {
result.asKeyPath() = keyPath and kind instanceof NormalReturnKind
}
}
class SummaryOutNode extends OutNode, SummaryNode {
SummaryOutNode() { FlowSummaryImpl::Private::summaryOutNode(_, this, _) }
@@ -658,6 +743,20 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
node2.asPattern() = pat.getSubPattern() and
c instanceof OptionalSomeContentSet
)
or
// read of a component in a key-path expression chain
exists(KeyPathComponent component, FieldDecl f |
component = node1.(KeyPathComponentNodeImpl).getComponent() and
f = component.getDeclRef() and
c.isSingleton(any(Content::FieldContent ct | ct.getField() = f))
|
// the next node is either the next element in the chain
node2.(KeyPathComponentNodeImpl).getComponent() = component.getNextComponent()
or
// or the return node, if this is the last component in the chain
not exists(component.getNextComponent()) and
node2.(KeyPathReturnNodeImpl).getKeyPathExpr() = component.getKeyPathExpr()
)
}
/**
@@ -786,6 +885,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
or
kind = TLambdaCallKind() and
receiver = call.(SummaryCall).getReceiver()
or
kind = TLambdaCallKind() and
receiver.asExpr() = call.asKeyPath().getExpr().(KeyPathApplicationExpr).getKeyPath()
}
/** Extra data-flow steps needed for lambda flow analysis. */

View File

@@ -1,4 +1,5 @@
private import codeql.swift.generated.KeyPathComponent
private import swift
class KeyPathComponent extends Generated::KeyPathComponent {
/**
@@ -35,4 +36,23 @@ class KeyPathComponent extends Generated::KeyPathComponent {
* Tuple indexing like `.1`.
*/
predicate isTupleIndexing() { getKind() = 9 }
/** Gets the underlying key-path expression which this is a component of. */
KeyPathExpr getKeyPathExpr() { result.getAComponent() = this }
/** Holds if this component is the i'th component of the underling key-path expression. */
predicate hasIndex(int i) { any(KeyPathExpr e).getComponent(i) = this }
/** Gets the next component of the underlying key-path expression. */
KeyPathComponent getNextComponent() {
exists(int i, KeyPathExpr e |
hasKeyPathExprAndIndex(e, i, this) and
hasKeyPathExprAndIndex(e, i + 1, result)
)
}
}
pragma[nomagic]
private predicate hasKeyPathExprAndIndex(KeyPathExpr e, int i, KeyPathComponent c) {
e.getComponent(i) = c
}

View File

@@ -5680,12 +5680,6 @@ cfg.swift:
# 456| var ... = ...
#-----| -> kpGet_b_x
# 456| var ... = ...
#-----| -> kpGet_b_x
# 456| kpGet_b_x
#-----| -> kpGet_bs_0_x
# 456| kpGet_b_x
#-----| -> kpGet_bs_0_x
@@ -5693,193 +5687,122 @@ cfg.swift:
#-----| match -> #keyPath(...)
# 456| #keyPath(...)
#-----| -> var ... = ...
#-----| -> exit #keyPath(...) (normal)
# 456| #keyPath(...)
#-----| -> var ... = ...
#-----| -> exit #keyPath(...) (normal)
# 456| enter #keyPath(...)
#-----| -> #keyPath(...)
#-----| -> KeyPathComponent
# 456| exit #keyPath(...)
# 456| exit #keyPath(...) (normal)
#-----| -> exit #keyPath(...)
# 457| var ... = ...
#-----| -> kpGet_bs_0_x
# 456| KeyPathComponent
#-----| -> KeyPathComponent
# 456| KeyPathComponent
#-----| -> #keyPath(...)
# 457| var ... = ...
#-----| -> kpGet_bs_0_x
# 457| var ... = ...
#-----| -> kpGet_bs_0_x
# 457| kpGet_bs_0_x
#-----| -> kpGet_mayB_force_x
# 457| kpGet_bs_0_x
#-----| -> kpGet_mayB_force_x
# 457| kpGet_bs_0_x
#-----| -> kpGet_mayB_force_x
# 457| kpGet_bs_0_x
#-----| match -> #keyPath(...)
# 457| kpGet_bs_0_x
#-----| match -> #keyPath(...)
# 457| #keyPath(...)
#-----| -> var ... = ...
# 457| #keyPath(...)
#-----| -> var ... = ...
# 457| #keyPath(...)
#-----| -> var ... = ...
#-----| -> exit #keyPath(...) (normal)
# 457| #keyPath(...)
#-----| -> var ... = ...
# 457| enter #keyPath(...)
#-----| -> #keyPath(...)
#-----| -> KeyPathComponent
# 457| exit #keyPath(...)
# 457| exit #keyPath(...) (normal)
#-----| -> exit #keyPath(...)
# 458| var ... = ...
#-----| -> kpGet_mayB_force_x
# 457| KeyPathComponent
#-----| -> 0
# 457| KeyPathComponent
#-----| -> KeyPathComponent
# 457| 0
#-----| -> KeyPathComponent
# 457| KeyPathComponent
#-----| -> #keyPath(...)
# 458| var ... = ...
#-----| -> kpGet_mayB_force_x
# 458| var ... = ...
#-----| -> kpGet_mayB_force_x
# 458| var ... = ...
#-----| -> kpGet_mayB_force_x
# 458| kpGet_mayB_force_x
#-----| -> kpGet_mayB_x
# 458| kpGet_mayB_force_x
#-----| -> kpGet_mayB_x
# 458| kpGet_mayB_force_x
#-----| -> kpGet_mayB_x
# 458| kpGet_mayB_force_x
#-----| -> kpGet_mayB_x
# 458| kpGet_mayB_force_x
#-----| match -> #keyPath(...)
# 458| kpGet_mayB_force_x
#-----| match -> #keyPath(...)
# 458| kpGet_mayB_force_x
#-----| match -> #keyPath(...)
# 458| #keyPath(...)
#-----| -> var ... = ...
# 458| #keyPath(...)
#-----| -> var ... = ...
# 458| #keyPath(...)
#-----| -> var ... = ...
# 458| #keyPath(...)
#-----| -> var ... = ...
#-----| -> exit #keyPath(...) (normal)
# 458| #keyPath(...)
#-----| -> var ... = ...
# 458| enter #keyPath(...)
#-----| -> #keyPath(...)
#-----| -> KeyPathComponent
# 458| exit #keyPath(...)
# 458| exit #keyPath(...) (normal)
#-----| -> exit #keyPath(...)
# 459| var ... = ...
#-----| -> kpGet_mayB_x
# 458| KeyPathComponent
#-----| -> KeyPathComponent
# 458| KeyPathComponent
#-----| -> KeyPathComponent
# 458| KeyPathComponent
#-----| -> #keyPath(...)
# 459| var ... = ...
#-----| -> kpGet_mayB_x
# 459| var ... = ...
#-----| -> kpGet_mayB_x
# 459| var ... = ...
#-----| -> kpGet_mayB_x
# 459| var ... = ...
#-----| -> kpGet_mayB_x
# 459| kpGet_mayB_x
#-----| -> apply_kpGet_b_x
# 459| kpGet_mayB_x
#-----| -> apply_kpGet_b_x
# 459| kpGet_mayB_x
#-----| -> apply_kpGet_b_x
# 459| kpGet_mayB_x
#-----| -> apply_kpGet_b_x
# 459| kpGet_mayB_x
#-----| -> apply_kpGet_b_x
# 459| kpGet_mayB_x
#-----| match -> #keyPath(...)
# 459| kpGet_mayB_x
#-----| match -> #keyPath(...)
# 459| kpGet_mayB_x
#-----| match -> #keyPath(...)
# 459| kpGet_mayB_x
#-----| match -> #keyPath(...)
# 459| #keyPath(...)
#-----| -> var ... = ...
# 459| #keyPath(...)
#-----| -> var ... = ...
# 459| #keyPath(...)
#-----| -> var ... = ...
# 459| #keyPath(...)
#-----| -> var ... = ...
# 459| #keyPath(...)
#-----| -> var ... = ...
#-----| -> exit #keyPath(...) (normal)
# 459| #keyPath(...)
#-----| -> var ... = ...
# 459| enter #keyPath(...)
#-----| -> #keyPath(...)
#-----| -> KeyPathComponent
# 459| exit #keyPath(...)
# 459| exit #keyPath(...) (normal)
#-----| -> exit #keyPath(...)
# 461| var ... = ...
#-----| -> apply_kpGet_b_x
# 459| KeyPathComponent
#-----| -> KeyPathComponent
# 461| var ... = ...
#-----| -> apply_kpGet_b_x
# 459| KeyPathComponent
#-----| -> KeyPathComponent
# 461| var ... = ...
#-----| -> apply_kpGet_b_x
# 461| var ... = ...
#-----| -> apply_kpGet_b_x
# 459| KeyPathComponent
# 461| var ... = ...
#-----| -> apply_kpGet_b_x
@@ -5887,401 +5810,81 @@ cfg.swift:
# 461| apply_kpGet_b_x
#-----| -> apply_kpGet_bs_0_x
# 461| apply_kpGet_b_x
#-----| -> apply_kpGet_bs_0_x
# 461| apply_kpGet_b_x
#-----| -> apply_kpGet_bs_0_x
# 461| apply_kpGet_b_x
#-----| -> apply_kpGet_bs_0_x
# 461| apply_kpGet_b_x
#-----| -> apply_kpGet_bs_0_x
# 461| apply_kpGet_b_x
#-----| match -> a
# 461| apply_kpGet_b_x
#-----| match -> a
# 461| apply_kpGet_b_x
#-----| match -> a
# 461| apply_kpGet_b_x
#-----| match -> a
# 461| apply_kpGet_b_x
#-----| match -> a
# 461| a
#-----| -> kpGet_b_x
# 461| a
#-----| -> kpGet_b_x
# 461| a
#-----| -> kpGet_b_x
# 461| a
#-----| -> kpGet_b_x
# 461| a
#-----| -> kpGet_b_x
# 461| \...[...]
#-----| -> var ... = ...
# 461| \...[...]
#-----| -> var ... = ...
# 461| \...[...]
#-----| -> var ... = ...
# 461| \...[...]
#-----| -> var ... = ...
# 461| \...[...]
#-----| -> var ... = ...
# 461| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 461| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 461| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 461| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 461| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 461| kpGet_b_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 461| kpGet_b_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 461| kpGet_b_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 461| kpGet_b_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 461| kpGet_b_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 462| var ... = ...
#-----| -> apply_kpGet_bs_0_x
# 462| var ... = ...
#-----| -> apply_kpGet_bs_0_x
# 462| var ... = ...
#-----| -> apply_kpGet_bs_0_x
# 462| var ... = ...
#-----| -> apply_kpGet_bs_0_x
# 462| var ... = ...
#-----| -> apply_kpGet_bs_0_x
# 462| apply_kpGet_bs_0_x
#-----| -> apply_kpGet_mayB_force_x
# 462| apply_kpGet_bs_0_x
#-----| -> apply_kpGet_mayB_force_x
# 462| apply_kpGet_bs_0_x
#-----| -> apply_kpGet_mayB_force_x
# 462| apply_kpGet_bs_0_x
#-----| -> apply_kpGet_mayB_force_x
# 462| apply_kpGet_bs_0_x
#-----| -> apply_kpGet_mayB_force_x
# 462| apply_kpGet_bs_0_x
#-----| match -> a
# 462| apply_kpGet_bs_0_x
#-----| match -> a
# 462| apply_kpGet_bs_0_x
#-----| match -> a
# 462| apply_kpGet_bs_0_x
#-----| match -> a
# 462| apply_kpGet_bs_0_x
#-----| match -> a
# 462| a
#-----| -> kpGet_bs_0_x
# 462| a
#-----| -> kpGet_bs_0_x
# 462| a
#-----| -> kpGet_bs_0_x
# 462| a
#-----| -> kpGet_bs_0_x
# 462| a
#-----| -> kpGet_bs_0_x
# 462| \...[...]
#-----| -> var ... = ...
# 462| \...[...]
#-----| -> var ... = ...
# 462| \...[...]
#-----| -> var ... = ...
# 462| \...[...]
#-----| -> var ... = ...
# 462| \...[...]
#-----| -> var ... = ...
# 462| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 462| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 462| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 462| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 462| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 462| kpGet_bs_0_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 462| kpGet_bs_0_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 462| kpGet_bs_0_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 462| kpGet_bs_0_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 462| kpGet_bs_0_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 463| var ... = ...
#-----| -> apply_kpGet_mayB_force_x
# 463| var ... = ...
#-----| -> apply_kpGet_mayB_force_x
# 463| var ... = ...
#-----| -> apply_kpGet_mayB_force_x
# 463| var ... = ...
#-----| -> apply_kpGet_mayB_force_x
# 463| var ... = ...
#-----| -> apply_kpGet_mayB_force_x
# 463| apply_kpGet_mayB_force_x
#-----| -> apply_kpGet_mayB_x
# 463| apply_kpGet_mayB_force_x
#-----| -> apply_kpGet_mayB_x
# 463| apply_kpGet_mayB_force_x
#-----| -> apply_kpGet_mayB_x
# 463| apply_kpGet_mayB_force_x
#-----| -> apply_kpGet_mayB_x
# 463| apply_kpGet_mayB_force_x
#-----| -> apply_kpGet_mayB_x
# 463| apply_kpGet_mayB_force_x
#-----| match -> a
# 463| apply_kpGet_mayB_force_x
#-----| match -> a
# 463| apply_kpGet_mayB_force_x
#-----| match -> a
# 463| apply_kpGet_mayB_force_x
#-----| match -> a
# 463| apply_kpGet_mayB_force_x
#-----| match -> a
# 463| a
#-----| -> kpGet_mayB_force_x
# 463| a
#-----| -> kpGet_mayB_force_x
# 463| a
#-----| -> kpGet_mayB_force_x
# 463| a
#-----| -> kpGet_mayB_force_x
# 463| a
#-----| -> kpGet_mayB_force_x
# 463| \...[...]
#-----| -> var ... = ...
# 463| \...[...]
#-----| -> var ... = ...
# 463| \...[...]
#-----| -> var ... = ...
# 463| \...[...]
#-----| -> var ... = ...
# 463| \...[...]
#-----| -> var ... = ...
# 463| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 463| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 463| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 463| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 463| (WritableKeyPath<A, Int>) ...
#-----| -> \...[...]
# 463| kpGet_mayB_force_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 463| kpGet_mayB_force_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 463| kpGet_mayB_force_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 463| kpGet_mayB_force_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 463| kpGet_mayB_force_x
#-----| -> (WritableKeyPath<A, Int>) ...
# 464| var ... = ...
#-----| -> apply_kpGet_mayB_x
# 464| var ... = ...
#-----| -> apply_kpGet_mayB_x
# 464| var ... = ...
#-----| -> apply_kpGet_mayB_x
# 464| var ... = ...
#-----| -> apply_kpGet_mayB_x
# 464| var ... = ...
#-----| -> apply_kpGet_mayB_x
# 464| apply_kpGet_mayB_x
#-----| -> exit test(a:) (normal)
# 464| apply_kpGet_mayB_x
# 464| apply_kpGet_mayB_x
# 464| apply_kpGet_mayB_x
# 464| apply_kpGet_mayB_x
# 464| apply_kpGet_mayB_x
#-----| match -> a
# 464| apply_kpGet_mayB_x
#-----| match -> a
# 464| apply_kpGet_mayB_x
#-----| match -> a
# 464| apply_kpGet_mayB_x
#-----| match -> a
# 464| apply_kpGet_mayB_x
#-----| match -> a
# 464| a
#-----| -> kpGet_mayB_x
# 464| a
#-----| -> kpGet_mayB_x
# 464| a
#-----| -> kpGet_mayB_x
# 464| a
#-----| -> kpGet_mayB_x
# 464| a
#-----| -> kpGet_mayB_x
# 464| \...[...]
#-----| -> var ... = ...
# 464| \...[...]
#-----| -> var ... = ...
# 464| \...[...]
#-----| -> var ... = ...
# 464| \...[...]
#-----| -> var ... = ...
# 464| \...[...]
#-----| -> var ... = ...
# 464| (KeyPath<A, Int?>) ...
#-----| -> \...[...]
# 464| (KeyPath<A, Int?>) ...
#-----| -> \...[...]
# 464| (KeyPath<A, Int?>) ...
#-----| -> \...[...]
# 464| (KeyPath<A, Int?>) ...
#-----| -> \...[...]
# 464| (KeyPath<A, Int?>) ...
#-----| -> \...[...]
# 464| kpGet_mayB_x
#-----| -> (KeyPath<A, Int?>) ...
# 464| kpGet_mayB_x
#-----| -> (KeyPath<A, Int?>) ...
# 464| kpGet_mayB_x
#-----| -> (KeyPath<A, Int?>) ...
# 464| kpGet_mayB_x
#-----| -> (KeyPath<A, Int?>) ...
# 464| kpGet_mayB_x
#-----| -> (KeyPath<A, Int?>) ...

View File

@@ -0,0 +1,24 @@
nonUniqueSetRepresentation
breakInvariant2
breakInvariant3
breakInvariant4
breakInvariant5
multipleSuccessors
| cfg.swift:33:28:33:28 | ... is ... | no-match | cfg.swift:33:49:33:60 | call to isZero(x:) |
| cfg.swift:33:28:33:28 | ... is ... | no-match | cfg.swift:35:5:37:3 | case ... |
| cfg.swift:144:10:144:10 | =~ ... | no-match | cfg.swift:144:18:144:34 | ... .&&(_:_:) ... |
| cfg.swift:144:10:144:10 | =~ ... | no-match | cfg.swift:146:5:147:14 | case ... |
| cfg.swift:515:6:515:28 | #available | false | cfg.swift:515:42:515:46 | iOS 12 |
| cfg.swift:515:6:515:28 | #available | false | cfg.swift:519:10:519:10 | x |
| file://:0:0:0:0 | $interpolation | successor | cfg.swift:40:11:40:11 | OpaqueValueExpr |
| file://:0:0:0:0 | $interpolation | successor | cfg.swift:40:12:40:12 | .appendLiteral(_:) |
| file://:0:0:0:0 | $interpolation | successor | cfg.swift:263:10:263:10 | OpaqueValueExpr |
| file://:0:0:0:0 | $interpolation | successor | cfg.swift:263:11:263:11 | .appendLiteral(_:) |
simpleAndNormalSuccessors
deadEnd
| cfg.swift:33:49:33:60 | call to isZero(x:) |
| cfg.swift:144:18:144:34 | ... .&&(_:_:) ... |
| file://:0:0:0:0 | ... = ... |
| file://:0:0:0:0 | ... = ... |
nonUniqueSplitKind
nonUniqueListOrder

View File

@@ -0,0 +1 @@
import codeql.swift.controlflow.internal.ControlFlowGraphImplShared::Consistency

View File

@@ -247,6 +247,35 @@ edges
| test.swift:549:24:549:32 | call to source3() : | test.swift:549:13:549:33 | call to MyClass.init(s:) [str] : |
| test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | test.swift:535:9:535:9 | self [str] : |
| test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | test.swift:550:13:550:43 | .str |
| test.swift:567:8:567:11 | x : | test.swift:568:14:568:14 | x : |
| test.swift:568:5:568:5 | [post] self [x] : | test.swift:567:3:569:3 | self[return] [x] : |
| test.swift:568:14:568:14 | x : | test.swift:568:5:568:5 | [post] self [x] : |
| test.swift:573:11:573:24 | call to S.init(x:) [x] : | test.swift:575:13:575:13 | s [x] : |
| test.swift:573:11:573:24 | call to S.init(x:) [x] : | test.swift:578:13:578:13 | s [x] : |
| test.swift:573:16:573:23 | call to source() : | test.swift:567:8:567:11 | x : |
| test.swift:573:16:573:23 | call to source() : | test.swift:573:11:573:24 | call to S.init(x:) [x] : |
| test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:14:574:14 | KeyPathComponent [x] : |
| test.swift:574:14:574:14 | KeyPathComponent [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : |
| test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : |
| test.swift:575:13:575:13 | s [x] : | test.swift:575:13:575:25 | \\...[...] |
| test.swift:577:36:577:38 | enter #keyPath(...) [x] : | test.swift:577:38:577:38 | KeyPathComponent [x] : |
| test.swift:577:38:577:38 | KeyPathComponent [x] : | test.swift:577:36:577:38 | exit #keyPath(...) : |
| test.swift:578:13:578:13 | s [x] : | test.swift:577:36:577:38 | enter #keyPath(...) [x] : |
| test.swift:578:13:578:13 | s [x] : | test.swift:578:13:578:32 | \\...[...] |
| test.swift:584:8:584:11 | s [x] : | test.swift:585:14:585:14 | s [x] : |
| test.swift:585:5:585:5 | [post] self [s, x] : | test.swift:584:3:586:3 | self[return] [s, x] : |
| test.swift:585:14:585:14 | s [x] : | test.swift:585:5:585:5 | [post] self [s, x] : |
| test.swift:590:11:590:24 | call to S.init(x:) [x] : | test.swift:591:18:591:18 | s [x] : |
| test.swift:590:16:590:23 | call to source() : | test.swift:567:8:567:11 | x : |
| test.swift:590:16:590:23 | call to source() : | test.swift:590:11:590:24 | call to S.init(x:) [x] : |
| test.swift:591:12:591:19 | call to S2.init(s:) [s, x] : | test.swift:593:13:593:13 | s2 [s, x] : |
| test.swift:591:18:591:18 | s [x] : | test.swift:584:8:584:11 | s [x] : |
| test.swift:591:18:591:18 | s [x] : | test.swift:591:12:591:19 | call to S2.init(s:) [s, x] : |
| test.swift:592:11:592:17 | enter #keyPath(...) [s, x] : | test.swift:592:15:592:15 | KeyPathComponent [s, x] : |
| test.swift:592:15:592:15 | KeyPathComponent [s, x] : | test.swift:592:17:592:17 | KeyPathComponent [x] : |
| test.swift:592:17:592:17 | KeyPathComponent [x] : | test.swift:592:11:592:17 | exit #keyPath(...) : |
| test.swift:593:13:593:13 | s2 [s, x] : | test.swift:592:11:592:17 | enter #keyPath(...) [s, x] : |
| test.swift:593:13:593:13 | s2 [s, x] : | test.swift:593:13:593:26 | \\...[...] |
nodes
| file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : |
| file://:0:0:0:0 | .str : | semmle.label | .str : |
@@ -514,6 +543,36 @@ nodes
| test.swift:549:24:549:32 | call to source3() : | semmle.label | call to source3() : |
| test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | semmle.label | call to Self.init(contentsOfFile:) [str] : |
| test.swift:550:13:550:43 | .str | semmle.label | .str |
| test.swift:567:3:569:3 | self[return] [x] : | semmle.label | self[return] [x] : |
| test.swift:567:8:567:11 | x : | semmle.label | x : |
| test.swift:568:5:568:5 | [post] self [x] : | semmle.label | [post] self [x] : |
| test.swift:568:14:568:14 | x : | semmle.label | x : |
| test.swift:573:11:573:24 | call to S.init(x:) [x] : | semmle.label | call to S.init(x:) [x] : |
| test.swift:573:16:573:23 | call to source() : | semmle.label | call to source() : |
| test.swift:574:11:574:14 | enter #keyPath(...) [x] : | semmle.label | enter #keyPath(...) [x] : |
| test.swift:574:11:574:14 | exit #keyPath(...) : | semmle.label | exit #keyPath(...) : |
| test.swift:574:14:574:14 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : |
| test.swift:575:13:575:13 | s [x] : | semmle.label | s [x] : |
| test.swift:575:13:575:25 | \\...[...] | semmle.label | \\...[...] |
| test.swift:577:36:577:38 | enter #keyPath(...) [x] : | semmle.label | enter #keyPath(...) [x] : |
| test.swift:577:36:577:38 | exit #keyPath(...) : | semmle.label | exit #keyPath(...) : |
| test.swift:577:38:577:38 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : |
| test.swift:578:13:578:13 | s [x] : | semmle.label | s [x] : |
| test.swift:578:13:578:32 | \\...[...] | semmle.label | \\...[...] |
| test.swift:584:3:586:3 | self[return] [s, x] : | semmle.label | self[return] [s, x] : |
| test.swift:584:8:584:11 | s [x] : | semmle.label | s [x] : |
| test.swift:585:5:585:5 | [post] self [s, x] : | semmle.label | [post] self [s, x] : |
| test.swift:585:14:585:14 | s [x] : | semmle.label | s [x] : |
| test.swift:590:11:590:24 | call to S.init(x:) [x] : | semmle.label | call to S.init(x:) [x] : |
| test.swift:590:16:590:23 | call to source() : | semmle.label | call to source() : |
| test.swift:591:12:591:19 | call to S2.init(s:) [s, x] : | semmle.label | call to S2.init(s:) [s, x] : |
| test.swift:591:18:591:18 | s [x] : | semmle.label | s [x] : |
| test.swift:592:11:592:17 | enter #keyPath(...) [s, x] : | semmle.label | enter #keyPath(...) [s, x] : |
| test.swift:592:11:592:17 | exit #keyPath(...) : | semmle.label | exit #keyPath(...) : |
| test.swift:592:15:592:15 | KeyPathComponent [s, x] : | semmle.label | KeyPathComponent [s, x] : |
| test.swift:592:17:592:17 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : |
| test.swift:593:13:593:13 | s2 [s, x] : | semmle.label | s2 [s, x] : |
| test.swift:593:13:593:26 | \\...[...] | semmle.label | \\...[...] |
subpaths
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:31:75:32 | [post] &... : |
| test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : |
@@ -551,6 +610,12 @@ subpaths
| test.swift:549:13:549:33 | call to MyClass.init(s:) [str] : | test.swift:535:9:535:9 | self [str] : | file://:0:0:0:0 | .str : | test.swift:549:13:549:35 | .str |
| test.swift:549:24:549:32 | call to source3() : | test.swift:536:10:536:13 | s : | test.swift:536:5:538:5 | self[return] [str] : | test.swift:549:13:549:33 | call to MyClass.init(s:) [str] : |
| test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | test.swift:535:9:535:9 | self [str] : | file://:0:0:0:0 | .str : | test.swift:550:13:550:43 | .str |
| test.swift:573:16:573:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:573:11:573:24 | call to S.init(x:) [x] : |
| test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | test.swift:575:13:575:25 | \\...[...] |
| test.swift:578:13:578:13 | s [x] : | test.swift:577:36:577:38 | enter #keyPath(...) [x] : | test.swift:577:36:577:38 | exit #keyPath(...) : | test.swift:578:13:578:32 | \\...[...] |
| test.swift:590:16:590:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:590:11:590:24 | call to S.init(x:) [x] : |
| test.swift:591:18:591:18 | s [x] : | test.swift:584:8:584:11 | s [x] : | test.swift:584:3:586:3 | self[return] [s, x] : | test.swift:591:12:591:19 | call to S2.init(s:) [s, x] : |
| test.swift:593:13:593:13 | s2 [s, x] : | test.swift:592:11:592:17 | enter #keyPath(...) [s, x] : | test.swift:592:11:592:17 | exit #keyPath(...) : | test.swift:593:13:593:26 | \\...[...] |
#select
| test.swift:7:15:7:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:7:15:7:15 | t1 | result |
| test.swift:9:15:9:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:9:15:9:15 | t1 | result |
@@ -621,3 +686,6 @@ subpaths
| test.swift:544:17:544:17 | .str | test.swift:543:20:543:28 | call to source3() : | test.swift:544:17:544:17 | .str | result |
| test.swift:549:13:549:35 | .str | test.swift:549:24:549:32 | call to source3() : | test.swift:549:13:549:35 | .str | result |
| test.swift:550:13:550:43 | .str | test.swift:543:20:543:28 | call to source3() : | test.swift:550:13:550:43 | .str | result |
| test.swift:575:13:575:25 | \\...[...] | test.swift:573:16:573:23 | call to source() : | test.swift:575:13:575:25 | \\...[...] | result |
| test.swift:578:13:578:32 | \\...[...] | test.swift:573:16:573:23 | call to source() : | test.swift:578:13:578:32 | \\...[...] | result |
| test.swift:593:13:593:26 | \\...[...] | test.swift:590:16:590:23 | call to source() : | test.swift:593:13:593:26 | \\...[...] | result |

View File

@@ -601,3 +601,64 @@
| test.swift:560:7:560:7 | n | test.swift:560:7:560:7 | SSA def(n) |
| test.swift:560:11:560:11 | 0 | test.swift:560:7:560:7 | n |
| test.swift:561:36:561:36 | n | test.swift:561:35:561:36 | &... |
| test.swift:565:7:565:7 | self | test.swift:565:7:565:7 | SSA def(self) |
| test.swift:567:3:567:3 | SSA def(self) | test.swift:568:5:568:5 | self |
| test.swift:567:3:567:3 | self | test.swift:567:3:567:3 | SSA def(self) |
| test.swift:567:8:567:11 | SSA def(x) | test.swift:568:14:568:14 | x |
| test.swift:567:8:567:11 | x | test.swift:567:8:567:11 | SSA def(x) |
| test.swift:568:5:568:5 | [post] self | test.swift:567:3:569:3 | self[return] |
| test.swift:568:5:568:5 | self | test.swift:567:3:569:3 | self[return] |
| test.swift:573:7:573:7 | SSA def(s) | test.swift:575:13:575:13 | s |
| test.swift:573:7:573:7 | s | test.swift:573:7:573:7 | SSA def(s) |
| test.swift:573:11:573:24 | call to S.init(x:) | test.swift:573:7:573:7 | s |
| test.swift:574:7:574:7 | SSA def(f) | test.swift:575:24:575:24 | f |
| test.swift:574:7:574:7 | f | test.swift:574:7:574:7 | SSA def(f) |
| test.swift:574:11:574:14 | #keyPath(...) | test.swift:574:7:574:7 | f |
| test.swift:574:11:574:14 | enter #keyPath(...) | test.swift:574:14:574:14 | KeyPathComponent |
| test.swift:575:13:575:13 | s | test.swift:578:13:578:13 | s |
| test.swift:577:7:577:7 | SSA def(inferred) | test.swift:578:24:578:24 | inferred |
| test.swift:577:7:577:7 | inferred | test.swift:577:7:577:7 | SSA def(inferred) |
| test.swift:577:7:577:32 | ... as ... | test.swift:577:7:577:7 | inferred |
| test.swift:577:36:577:38 | #keyPath(...) | test.swift:577:7:577:32 | ... as ... |
| test.swift:577:36:577:38 | enter #keyPath(...) | test.swift:577:38:577:38 | KeyPathComponent |
| test.swift:582:7:582:7 | self | test.swift:582:7:582:7 | SSA def(self) |
| test.swift:584:3:584:3 | SSA def(self) | test.swift:585:5:585:5 | self |
| test.swift:584:3:584:3 | self | test.swift:584:3:584:3 | SSA def(self) |
| test.swift:584:8:584:11 | SSA def(s) | test.swift:585:14:585:14 | s |
| test.swift:584:8:584:11 | s | test.swift:584:8:584:11 | SSA def(s) |
| test.swift:585:5:585:5 | [post] self | test.swift:584:3:586:3 | self[return] |
| test.swift:585:5:585:5 | self | test.swift:584:3:586:3 | self[return] |
| test.swift:590:7:590:7 | SSA def(s) | test.swift:591:18:591:18 | s |
| test.swift:590:7:590:7 | s | test.swift:590:7:590:7 | SSA def(s) |
| test.swift:590:11:590:24 | call to S.init(x:) | test.swift:590:7:590:7 | s |
| test.swift:591:7:591:7 | SSA def(s2) | test.swift:593:13:593:13 | s2 |
| test.swift:591:7:591:7 | s2 | test.swift:591:7:591:7 | SSA def(s2) |
| test.swift:591:12:591:19 | call to S2.init(s:) | test.swift:591:7:591:7 | s2 |
| test.swift:592:7:592:7 | SSA def(f) | test.swift:593:25:593:25 | f |
| test.swift:592:7:592:7 | f | test.swift:592:7:592:7 | SSA def(f) |
| test.swift:592:11:592:17 | #keyPath(...) | test.swift:592:7:592:7 | f |
| test.swift:592:11:592:17 | enter #keyPath(...) | test.swift:592:15:592:15 | KeyPathComponent |
| test.swift:597:9:597:9 | SSA def(array) | test.swift:599:15:599:15 | array |
| test.swift:597:9:597:9 | array | test.swift:597:9:597:9 | SSA def(array) |
| test.swift:597:17:597:26 | [...] | test.swift:597:9:597:9 | array |
| test.swift:598:9:598:9 | SSA def(f) | test.swift:599:30:599:30 | f |
| test.swift:598:9:598:9 | f | test.swift:598:9:598:9 | SSA def(f) |
| test.swift:598:13:598:22 | #keyPath(...) | test.swift:598:9:598:9 | f |
| test.swift:598:13:598:22 | enter #keyPath(...) | test.swift:598:20:598:22 | KeyPathComponent |
| test.swift:603:7:603:7 | self | test.swift:603:7:603:7 | SSA def(self) |
| test.swift:605:3:605:3 | SSA def(self) | test.swift:606:5:606:5 | self |
| test.swift:605:3:605:3 | self | test.swift:605:3:605:3 | SSA def(self) |
| test.swift:605:8:605:12 | SSA def(s) | test.swift:606:14:606:14 | s |
| test.swift:605:8:605:12 | s | test.swift:605:8:605:12 | SSA def(s) |
| test.swift:606:5:606:5 | [post] self | test.swift:605:3:607:3 | self[return] |
| test.swift:606:5:606:5 | self | test.swift:605:3:607:3 | self[return] |
| test.swift:611:9:611:9 | SSA def(s) | test.swift:612:29:612:29 | s |
| test.swift:611:9:611:9 | s | test.swift:611:9:611:9 | SSA def(s) |
| test.swift:611:13:611:26 | call to S.init(x:) | test.swift:611:9:611:9 | s |
| test.swift:612:9:612:9 | SSA def(s2) | test.swift:614:15:614:15 | s2 |
| test.swift:612:9:612:9 | s2 | test.swift:612:9:612:9 | SSA def(s2) |
| test.swift:612:14:612:30 | call to S2_Optional.init(s:) | test.swift:612:9:612:9 | s2 |
| test.swift:613:9:613:9 | SSA def(f) | test.swift:614:27:614:27 | f |
| test.swift:613:9:613:9 | f | test.swift:613:9:613:9 | SSA def(f) |
| test.swift:613:13:613:29 | #keyPath(...) | test.swift:613:9:613:9 | f |
| test.swift:613:13:613:29 | enter #keyPath(...) | test.swift:613:26:613:26 | KeyPathComponent |

View File

@@ -560,3 +560,56 @@ func inoutConstructor() {
var n = 0
sink(arg: InoutConstructorClass(&n))
}
struct S {
let x: Int
init(x: Int) {
self.x = x
}
}
func testKeyPath() {
let s = S(x: source())
let f = \S.x
sink(arg: s[keyPath: f]) // $ flow=573
let inferred : KeyPath<S, Int> = \.x
sink(arg: s[keyPath: inferred]) // $ flow=573
}
struct S2 {
let s: S
init(s: S) {
self.s = s
}
}
func testNestedKeyPath() {
let s = S(x: source())
let s2 = S2(s: s)
let f = \S2.s.x
sink(arg: s2[keyPath: f]) // $ flow=590
}
func testArrayKeyPath() {
let array = [source()]
let f = \[Int].[0]
sink(arg: array[keyPath: f]) // $ MISSING: flow=597
}
struct S2_Optional {
let s: S?
init(s: S?) {
self.s = s
}
}
func testOptionalKeyPath() {
let s = S(x: source())
let s2 = S2_Optional(s: s)
let f = \S2_Optional.s?.x
sink(opt: s2[keyPath: f]) // $ MISSING: flow=611
}