Skip to content

Commit c9ed986

Browse files
committed
C#: Prototype breaking pattern assignments into multiple steps.
1 parent 990ac0f commit c9ed986

File tree

4 files changed

+47
-26
lines changed

4 files changed

+47
-26
lines changed

csharp/ql/lib/semmle/code/csharp/Assignable.qll

+20-11
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,17 @@ module AssignableInternal {
273273
def = TPatternDefinition(result)
274274
}
275275

276-
/** A local variable declaration at the top-level of a pattern. */
277-
class TopLevelPatternDecl extends LocalVariableDeclExpr {
276+
/** A pattern containing a local variable declaration. */
277+
class LocalVariablePatternDecl extends LocalVariableDeclExpr {
278278
private PatternMatch pm;
279279

280-
TopLevelPatternDecl() { this = pm.getPattern().(BindingPatternExpr).getVariableDeclExpr() }
280+
LocalVariablePatternDecl() {
281+
exists(BindingPatternExpr bpe |
282+
this = bpe.getVariableDeclExpr() and pm = bpe.getPatternMatch()
283+
)
284+
}
285+
286+
predicate isTopLevel() { this = pm.getPattern().(BindingPatternExpr).getVariableDeclExpr() }
281287

282288
PatternMatch getMatch() { result = pm }
283289
}
@@ -297,7 +303,7 @@ module AssignableInternal {
297303
TLocalVariableDefinition(LocalVariableDeclExpr lvde) {
298304
not lvde.hasInitializer() and
299305
not exists(getTupleSource(TTupleAssignmentDefinition(_, lvde))) and
300-
not lvde instanceof TopLevelPatternDecl and
306+
not lvde instanceof LocalVariablePatternDecl and
301307
not lvde.isOutArgument()
302308
} or
303309
TImplicitParameterDefinition(Parameter p) {
@@ -309,7 +315,7 @@ module AssignableInternal {
309315
)
310316
} or
311317
TAddressOfDefinition(AddressOfExpr aoe) or
312-
TPatternDefinition(TopLevelPatternDecl tlpd)
318+
TPatternDefinition(LocalVariablePatternDecl lvpd)
313319

314320
/**
315321
* Gets the source expression assigned in tuple definition `def`, if any.
@@ -699,22 +705,25 @@ module AssignableDefinitions {
699705
}
700706

701707
/**
702-
* A local variable definition in a pattern, for example `x is int i`.
708+
* A local variable definition in a pattern, for example `int i` in `x is int i`.
703709
*/
704710
class PatternDefinition extends AssignableDefinition, TPatternDefinition {
705-
TopLevelPatternDecl tlpd;
711+
LocalVariablePatternDecl lvpd;
706712

707-
PatternDefinition() { this = TPatternDefinition(tlpd) }
713+
PatternDefinition() { this = TPatternDefinition(lvpd) }
708714

709715
/** Gets the element matches against this pattern. */
710-
PatternMatch getMatch() { result = tlpd.getMatch() }
716+
PatternMatch getMatch() { result = lvpd.getMatch() }
711717

712718
/** Gets the underlying local variable declaration. */
713-
LocalVariableDeclExpr getDeclaration() { result = tlpd }
719+
LocalVariableDeclExpr getDeclaration() { result = lvpd }
714720

715-
override Expr getSource() { result = this.getMatch().getExpr() }
721+
override Expr getSource() { this.isTopLevel() and result = this.getMatch().getExpr() }
716722

717723
override string toString() { result = this.getDeclaration().toString() }
724+
725+
/** Holds if the local variable definition is at the top level of the pattern. */
726+
predicate isTopLevel() { lvpd.isTopLevel() }
718727
}
719728

720729
/**

csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ private predicate nonNullDef(Ssa::ExplicitDefinition def) {
104104
def.getADefinition().getSource() instanceof NonNullExpr
105105
or
106106
exists(AssignableDefinition ad | ad = def.getADefinition() |
107-
ad instanceof AssignableDefinitions::PatternDefinition
107+
ad.(AssignableDefinitions::PatternDefinition).isTopLevel()
108108
or
109109
ad =
110110
any(AssignableDefinitions::LocalVariableDefinition d |

csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll

+19-14
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ module LocalFlow {
605605
isSuccessor = false
606606
or
607607
isSuccessor = true and
608-
exists(ControlFlowElement cfe | cfe = e2.(TupleExpr).(PatternExpr).getPatternMatch() |
608+
exists(ControlFlowElement cfe | cfe = e2.(TuplePatternExpr).getPatternMatch() |
609609
cfe.(IsExpr).getExpr() = e1 and scope = cfe
610610
or
611611
exists(Switch sw | sw.getACase() = cfe and sw.getExpr() = e1 and scope = sw)
@@ -624,25 +624,28 @@ module LocalFlow {
624624
scope = def.getExpr() and
625625
isSuccessor = true
626626
or
627-
scope = def.(AssignableDefinitions::PatternDefinition).getMatch().(IsExpr) and
628-
isSuccessor = false
629-
or
630-
exists(Switch s |
631-
s.getACase() = def.(AssignableDefinitions::PatternDefinition).getMatch() and
632-
isSuccessor = true
633-
|
634-
scope = s.getExpr()
627+
exists(AssignableDefinitions::PatternDefinition def0 | def = def0 and def0.isTopLevel() |
628+
scope = def0.getMatch().(IsExpr) and
629+
isSuccessor = false
635630
or
636-
scope = s.getACase()
631+
exists(Switch s |
632+
s.getACase() = def0.getMatch() and
633+
isSuccessor = true
634+
|
635+
scope = s.getExpr()
636+
or
637+
scope = s.getACase()
638+
)
637639
)
638640
)
639641
or
640642
// Needed for read steps for pattern matching involving properties.
641643
scope = def.getExpr() and
642644
e.(VariablePatternExpr).getVariableDeclExpr() =
643-
def.(AssignableDefinitions::LocalVariableDefinition).getExpr() and
645+
def.(AssignableDefinitions::PatternDefinition).getExpr() and
644646
exactScope = false and
645-
isSuccessor = false
647+
isSuccessor = false and
648+
not def.(AssignableDefinitions::PatternDefinition).isTopLevel()
646649
}
647650
}
648651

@@ -2955,8 +2958,10 @@ class CastNode extends Node {
29552958
CastNode() {
29562959
this.asExpr() instanceof Cast
29572960
or
2958-
this.(AssignableDefinitionNode).getDefinition() instanceof
2959-
AssignableDefinitions::PatternDefinition
2961+
this.(AssignableDefinitionNode)
2962+
.getDefinition()
2963+
.(AssignableDefinitions::PatternDefinition)
2964+
.isTopLevel()
29602965
}
29612966
}
29622967

csharp/ql/lib/semmle/code/csharp/exprs/Expr.qll

+7
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,13 @@ class LabeledPatternExpr extends PatternExpr {
531531
override string getAPrimaryQlClass() { result = "LabeledPatternExpr" }
532532
}
533533

534+
/**
535+
* A tuple pattern. For example, `var (x, y)`.
536+
*/
537+
class TuplePatternExpr extends TupleExpr, PatternExpr {
538+
override string getAPrimaryQlClass() { result = "TuplePatternExpr" }
539+
}
540+
534541
/** A positional pattern. For example, `(int x, int y)`. */
535542
class PositionalPatternExpr extends PatternExpr, @positional_pattern_expr {
536543
override string toString() { result = "( ... )" }

0 commit comments

Comments
 (0)