@@ -39,17 +39,15 @@ predicate isArgumentNode(ArgumentNode arg, DataFlowCall c, ArgumentPosition pos)
3939}
4040
4141/**
42- * Gets the control flow node used for data flow purposes for the primary constructor
42+ * Gets a control flow node used for data flow purposes for the primary constructor
4343 * parameter access `pa`.
4444 */
45- private ControlFlow:: Node getPrimaryConstructorParameterCfn ( ParameterAccess pa ) {
45+ private ControlFlow:: Node getAPrimaryConstructorParameterCfn ( ParameterAccess pa ) {
4646 pa .getTarget ( ) .getCallable ( ) instanceof PrimaryConstructor and
4747 (
48- pa instanceof ParameterRead and
49- result = pa .getAControlFlowNode ( )
48+ result = pa .( ParameterRead ) .getAControlFlowNode ( )
5049 or
51- pa instanceof ParameterWrite and
52- exists ( AssignExpr ae | pa = ae .getLValue ( ) and result = ae .getAControlFlowNode ( ) )
50+ pa = any ( AssignableDefinition def | result = def .getAControlFlowNode ( ) ) .getTargetAccess ( )
5351 )
5452}
5553
@@ -141,9 +139,10 @@ private module ThisFlow {
141139 or
142140 n .asExprAtNode ( cfn ) = any ( Expr e | e instanceof ThisAccess or e instanceof BaseAccess )
143141 or
144- exists ( InstanceParameterAccessNode pan | pan = n |
145- pan .getUnderlyingControlFlowNode ( ) = cfn and pan .isPreUpdate ( )
146- )
142+ n =
143+ any ( InstanceParameterAccessNode pan |
144+ pan .getUnderlyingControlFlowNode ( ) = cfn and pan .isPreUpdate ( )
145+ )
147146 }
148147
149148 private predicate thisAccess ( Node n , BasicBlock bb , int i ) {
@@ -230,7 +229,7 @@ CIL::DataFlowNode asCilDataFlowNode(Node node) {
230229
231230/** Provides predicates related to local data flow. */
232231module LocalFlow {
233- private class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
232+ class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
234233 LocalExprStepConfiguration ( ) { this = "LocalExprStepConfiguration" }
235234
236235 override predicate candidate (
@@ -955,7 +954,7 @@ private module Cached {
955954 } or
956955 TFlowInsensitiveFieldNode ( FieldOrProperty f ) { f .isFieldLike ( ) } or
957956 TInstanceParameterAccessNode ( ControlFlow:: Node cfn , boolean isPostUpdate ) {
958- exists ( ParameterAccess pa | cfn = getPrimaryConstructorParameterCfn ( pa ) |
957+ exists ( ParameterAccess pa | cfn = getAPrimaryConstructorParameterCfn ( pa ) |
959958 isPostUpdate = false
960959 or
961960 pa instanceof ParameterWrite and isPostUpdate = true
@@ -1795,6 +1794,19 @@ class FlowSummaryNode extends NodeImpl, TFlowSummaryNode {
17951794
17961795/**
17971796 * A data-flow node used to model reading and writing of primary constructor parameters.
1797+ * For example, in
1798+ * ```csharp
1799+ * public class C(object o)
1800+ * {
1801+ * public object GetParam() => o; // (1)
1802+ *
1803+ * public void SetParam(object value) => o = value; // (2)
1804+ * }
1805+ * ```
1806+ * the first access to o (1) is modeled as this.o_backing_field and
1807+ * the second access to o (2) is modeled as this.o_backing_field = value.
1808+ * Both models need a pre-update this node, and the latter need an additional post-update this access,
1809+ * all of which are represented by an InstanceParameterAccessNode node.
17981810 */
17991811class InstanceParameterAccessNode extends NodeImpl , TInstanceParameterAccessNode {
18001812 private ControlFlow:: Node cfn ;
@@ -1803,7 +1815,7 @@ class InstanceParameterAccessNode extends NodeImpl, TInstanceParameterAccessNode
18031815
18041816 InstanceParameterAccessNode ( ) {
18051817 this = TInstanceParameterAccessNode ( cfn , isPostUpdate ) and
1806- exists ( ParameterAccess pa | cfn = getPrimaryConstructorParameterCfn ( pa ) and pa .getTarget ( ) = p )
1818+ exists ( ParameterAccess pa | cfn = getAPrimaryConstructorParameterCfn ( pa ) and pa .getTarget ( ) = p )
18071819 }
18081820
18091821 override DataFlowCallable getEnclosingCallableImpl ( ) {
@@ -1836,6 +1848,16 @@ class InstanceParameterAccessNode extends NodeImpl, TInstanceParameterAccessNode
18361848
18371849/**
18381850 * A data-flow node used to synthesize the body of a primary constructor.
1851+ *
1852+ * For example, in
1853+ * ```csharp
1854+ * public class C(object o) { }
1855+ * ```
1856+ * we synthesize the primary constructor for C as
1857+ * ```csharp
1858+ * public C(object o) => this.o_backing_field = o;
1859+ * ```
1860+ * The synthesized (pre/post-update) this access is represented an PrimaryConstructorThisAccessNode node.
18391861 */
18401862class PrimaryConstructorThisAccessNode extends NodeImpl , TPrimaryConstructorThisAccessNode {
18411863 private Parameter p ;
@@ -2000,13 +2022,25 @@ private PropertyContent getResultContent() {
20002022 result .getProperty ( ) = any ( SystemThreadingTasksTaskTClass c_ ) .getResultProperty ( )
20012023}
20022024
2003- private predicate primaryConstructorParameterStore ( Node node1 , ContentSet c , Node node2 ) {
2004- exists ( AssignExpr ae , ParameterWrite pa , PrimaryConstructor constructor |
2005- ae .getLValue ( ) = pa and
2006- pa .getTarget ( ) = constructor .getAParameter ( ) and
2007- node1 .asExpr ( ) = ae .getRValue ( ) and
2008- node2 = TInstanceParameterAccessNode ( ae .getAControlFlowNode ( ) , true ) and
2009- c .( PrimaryConstructorParameterContent ) .getParameter ( ) = pa .getTarget ( )
2025+ private predicate primaryConstructorParameterStore (
2026+ Node node1 , PrimaryConstructorParameterContent c , Node node2
2027+ ) {
2028+ exists ( ControlFlow:: Node cfn , Parameter p |
2029+ node2 = TInstanceParameterAccessNode ( cfn , true ) and
2030+ c .getParameter ( ) = p
2031+ |
2032+ // direct assignment
2033+ exists ( LocalFlow:: LocalExprStepConfiguration conf , AssignableDefinition def |
2034+ conf .hasDefPath ( _, node1 .( ExprNode ) .getControlFlowNode ( ) , def , cfn ) and
2035+ p = def .getTarget ( )
2036+ )
2037+ or
2038+ // indirect assignment (for example as an `out` argument)
2039+ exists ( Ssa:: ExplicitDefinition def |
2040+ def = node1 .( SsaDefinitionExtNode ) .getDefinitionExt ( ) and
2041+ p = def .getSourceVariable ( ) .getAssignable ( ) and
2042+ cfn = def .getControlFlowNode ( )
2043+ )
20102044 )
20112045}
20122046
@@ -2147,10 +2181,12 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
21472181 node2 .asExpr ( ) .( AwaitExpr ) .getExpr ( ) = node1 .asExpr ( ) and
21482182 c = getResultContent ( )
21492183 or
2150- exists ( InstanceParameterAccessNode n | n = node1 |
2151- n .getUnderlyingControlFlowNode ( ) = node2 .( ExprNode ) .getControlFlowNode ( ) and
2152- n .getParameter ( ) = c .( PrimaryConstructorParameterContent ) .getParameter ( )
2153- ) and
2184+ node1 =
2185+ any ( InstanceParameterAccessNode n |
2186+ n .getUnderlyingControlFlowNode ( ) = node2 .( ExprNode ) .getControlFlowNode ( ) and
2187+ n .getParameter ( ) = c .( PrimaryConstructorParameterContent ) .getParameter ( ) and
2188+ n .isPreUpdate ( )
2189+ ) and
21542190 node2 .asExpr ( ) instanceof ParameterRead
21552191 or
21562192 // node1 = (..., node2, ...)
@@ -2216,9 +2252,7 @@ predicate clearsContent(Node n, ContentSet c) {
22162252 not f .isRef ( )
22172253 )
22182254 or
2219- exists ( Node n1 |
2220- primaryConstructorParameterStore ( _, c , n1 ) and n = n1 .( PostUpdateNode ) .getPreUpdateNode ( )
2221- )
2255+ n = any ( PostUpdateNode n1 | primaryConstructorParameterStore ( _, c , n1 ) ) .getPreUpdateNode ( )
22222256}
22232257
22242258/**
@@ -2512,11 +2546,11 @@ module PostUpdateNodes {
25122546 private class InstanceParameterAccessPostUpdateNode extends PostUpdateNode ,
25132547 InstanceParameterAccessNode
25142548 {
2515- private ControlFlow:: Node cfg ;
2549+ private ControlFlow:: Node cfn ;
25162550
2517- InstanceParameterAccessPostUpdateNode ( ) { this = TInstanceParameterAccessNode ( cfg , true ) }
2551+ InstanceParameterAccessPostUpdateNode ( ) { this = TInstanceParameterAccessNode ( cfn , true ) }
25182552
2519- override Node getPreUpdateNode ( ) { result = TInstanceParameterAccessNode ( cfg , false ) }
2553+ override Node getPreUpdateNode ( ) { result = TInstanceParameterAccessNode ( cfn , false ) }
25202554
25212555 override string toStringImpl ( ) { result = "[post] this" }
25222556 }
0 commit comments