@@ -1682,15 +1682,51 @@ class LocalVariableDeclExpr extends Expr, @localvariabledeclexpr {
16821682 /** Holds if this is a declaration stemming from a pattern instanceof expression. */
16831683 predicate hasAssociatedInstanceOfExpr ( ) { exists ( this .getAssociatedInstanceOfExpr ( ) ) }
16841684
1685- /** Gets the initializer expression of this local variable declaration expression, if any. */
1685+ /**
1686+ * Gets the initializer expression of this local variable declaration expression, if any.
1687+ *
1688+ * Note this applies specifically to a syntactic initialization like `T varname = init`;
1689+ * to include also `e instanceof T varname` and `switch(e) ... case T varname`, which both
1690+ * have the effect of initializing `varname` to a known local expression without using
1691+ * that syntax, use `getInitOrPatternSource`.
1692+ */
16861693 Expr getInit ( ) { result .isNthChildOf ( this , 0 ) }
16871694
1695+ /**
1696+ * Gets the local expression that initializes this variable declaration, if any.
1697+ *
1698+ * Note this includes explicit `T varname = init;`, as well as `e instanceof T varname`
1699+ * and `switch(e) ... case T varname`. To get only explicit initializers, use `getInit`.
1700+ *
1701+ * Note that record pattern variables like `e instance of T Record(T varname)` do not have
1702+ * either an explicit initializer or a pattern source.
1703+ */
1704+ Expr getInitOrPatternSource ( ) {
1705+ result = this .getInit ( )
1706+ or
1707+ exists ( SwitchStmt switch |
1708+ result = switch .getExpr ( ) and
1709+ this = switch .getAPatternCase ( ) .getPattern ( ) .asBindingPattern ( )
1710+ )
1711+ or
1712+ exists ( SwitchExpr switch |
1713+ result = switch .getExpr ( ) and
1714+ this = switch .getAPatternCase ( ) .getPattern ( ) .asBindingPattern ( )
1715+ )
1716+ or
1717+ exists ( InstanceOfExpr ioe |
1718+ result = ioe .getExpr ( ) and
1719+ this = ioe .getPattern ( ) .asBindingPattern ( )
1720+ )
1721+ }
1722+
16881723 /** Holds if this variable declaration implicitly initializes the variable. */
16891724 predicate hasImplicitInit ( ) {
1690- exists ( CatchClause cc | cc .getVariable ( ) = this ) or
1691- exists ( EnhancedForStmt efs | efs .getVariable ( ) = this ) or
1692- this .hasAssociatedSwitch ( ) or
1693- this .hasAssociatedInstanceOfExpr ( )
1725+ exists ( CatchClause cc | cc .getVariable ( ) = this )
1726+ or
1727+ exists ( EnhancedForStmt efs | efs .getVariable ( ) = this )
1728+ or
1729+ this .getParent ( ) instanceof RecordPatternExpr
16941730 }
16951731
16961732 /** Gets a printable representation of this expression. */
@@ -1699,6 +1735,13 @@ class LocalVariableDeclExpr extends Expr, @localvariabledeclexpr {
16991735 override string getAPrimaryQlClass ( ) { result = "LocalVariableDeclExpr" }
17001736}
17011737
1738+ /** A local variable declaration that occurs within a record pattern. */
1739+ class RecordBindingVariableExpr extends LocalVariableDeclExpr {
1740+ RecordBindingVariableExpr ( ) {
1741+ this .getParent ( ) instanceof RecordPatternExpr
1742+ }
1743+ }
1744+
17021745/** An update of a variable or an initialization of the variable. */
17031746class VariableUpdate extends Expr {
17041747 VariableUpdate ( ) {
@@ -1727,12 +1770,12 @@ class VariableAssign extends VariableUpdate {
17271770 /**
17281771 * Gets the source (right-hand side) of this assignment, if any.
17291772 *
1730- * An initialization in a `CatchClause` or `EnhancedForStmt` is implicit and
1731- * does not have a source.
1773+ * An initialization in a `CatchClause`, `EnhancedForStmt` or `RecordPatternExpr`
1774+ * is implicit and does not have a source.
17321775 */
17331776 Expr getSource ( ) {
17341777 result = this .( AssignExpr ) .getSource ( ) or
1735- result = this .( LocalVariableDeclExpr ) .getInit ( )
1778+ result = this .( LocalVariableDeclExpr ) .getInitOrPatternSource ( )
17361779 }
17371780}
17381781
0 commit comments