@@ -126,7 +126,6 @@ private module SourceVariableImpl {
126126 */
127127 predicate variableDefinition ( BasicBlock bb , int i , Ssa:: SourceVariable v , AssignableDefinition ad ) {
128128 ad = v .getADefinition ( ) and
129- ad .getExpr ( ) .getControlFlowNode ( ) = bb .getNode ( i ) and
130129 // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
131130 not exists ( TupleAssignmentDefinition first , TupleAssignmentDefinition second | first = ad |
132131 second .getAssignment ( ) = first .getAssignment ( ) and
@@ -136,7 +135,13 @@ private module SourceVariableImpl {
136135 // In cases like `M(out x, out x)`, there is no inherent evaluation order, so we
137136 // collapse the two definitions of `x`, using the first access as the representative,
138137 // and expose both definitions in `ExplicitDefinition.getADefinition()`
139- not ad = getASameOutRefDefAfter ( v , _)
138+ not ad = getASameOutRefDefAfter ( v , _) and
139+ (
140+ ad .getExpr ( ) .getControlFlowNode ( ) = bb .getNode ( i )
141+ or
142+ ad .( AssignableDefinitions:: ImplicitParameterDefinition ) .getParameter ( ) .getControlFlowNode ( ) =
143+ bb .getNode ( i )
144+ )
140145 }
141146
142147 /**
@@ -754,9 +759,6 @@ private module Cached {
754759 cached
755760 predicate implicitEntryDefinition ( BasicBlock bb , Ssa:: SourceVariable v ) {
756761 exists ( Callable c |
757- // In case `c` has multiple bodies, we want each body to get its own implicit
758- // entry definition, so we use the basic block containing the body instead of
759- // the entry block.
760762 bb = c .getBody ( ) .getBasicBlock ( ) and
761763 c = v .getEnclosingCallable ( )
762764 |
@@ -770,6 +772,10 @@ private module Cached {
770772 // Each tracked field and property has an implicit entry definition
771773 v instanceof PlainFieldOrPropSourceVariable
772774 or
775+ // In case `c` has multiple bodies, we want each body to get its own implicit
776+ // entry definition, so we use the basic block containing the body instead of
777+ // the entry block.
778+ strictcount ( c .getBody ( ) ) > 1 and
773779 v .getAssignable ( ) instanceof Parameter
774780 )
775781 }
@@ -961,7 +967,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
961967 predicate ssaDefHasSource ( WriteDefinition def ) {
962968 // exclude flow directly from RHS to SSA definition, as we instead want to
963969 // go from RHS to matching assignable definition, and from there to SSA definition
964- def instanceof Ssa:: ImplicitParameterDefinition
970+ def instanceof Ssa:: ParameterDefinition
965971 }
966972
967973 /**
@@ -993,3 +999,64 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
993999}
9941000
9951001private module DataFlowIntegrationImpl = Impl:: DataFlowIntegration< DataFlowIntegrationInput > ;
1002+
1003+ private import semmle.code.csharp.internal.Location
1004+ private import semmle.code.csharp.dataflow.SSA
1005+
1006+ private module NearestLocationInput implements NearestLocationInputSig {
1007+ class C = MultiBodyParameterDefinition ;
1008+
1009+ predicate relevantLocations ( MultiBodyParameterDefinition def , Location l1 , Location l2 ) {
1010+ l1 = def .getParameter ( ) .getALocation ( ) and
1011+ l2 = def .getBasicBlock ( ) .getLocation ( )
1012+ }
1013+ }
1014+
1015+ pragma [ nomagic]
1016+ private predicate implicitEntryDef (
1017+ Ssa:: ImplicitEntryDefinition def , Ssa:: SourceVariable v , Callable c
1018+ ) {
1019+ v = def .getSourceVariable ( ) and
1020+ c = def .getCallable ( )
1021+ }
1022+
1023+ pragma [ nomagic]
1024+ predicate localScopeSourceVariable (
1025+ Ssa:: SourceVariables:: LocalScopeSourceVariable sv , LocalScopeVariable v , Callable c1 , Callable c2
1026+ ) {
1027+ sv .getAssignable ( ) = v and
1028+ sv .getEnclosingCallable ( ) = c1 and
1029+ v .getCallable ( ) = c2
1030+ }
1031+
1032+ /**
1033+ * An SSA definition representing the implicit initialization of a parameter
1034+ * at the beginning of a callable.
1035+ */
1036+ abstract class ParameterDefinitionImpl extends Ssa:: Definition {
1037+ /** Gets the parameter that this definition represents. */
1038+ abstract Parameter getParameter ( ) ;
1039+
1040+ override string toString ( ) {
1041+ result = "SSA param(" + pragma [ only_bind_out ] ( this .getParameter ( ) ) + ")"
1042+ }
1043+ }
1044+
1045+ class MultiBodyParameterDefinition extends ParameterDefinitionImpl , Ssa:: ImplicitEntryDefinition {
1046+ private Parameter p ;
1047+
1048+ MultiBodyParameterDefinition ( ) {
1049+ exists ( Ssa:: SourceVariable sv , Callable c |
1050+ implicitEntryDef ( this , sv , c ) and
1051+ localScopeSourceVariable ( sv , p , _, c )
1052+ )
1053+ }
1054+
1055+ override Parameter getParameter ( ) { result = p }
1056+
1057+ override string toString ( ) { result = ParameterDefinitionImpl .super .toString ( ) }
1058+
1059+ override Location getLocation ( ) {
1060+ NearestLocation< NearestLocationInput > :: nearestLocation ( this , result , _)
1061+ }
1062+ }
0 commit comments