@@ -480,3 +480,51 @@ private class SummarizedCallableWithCallback extends Public::SummarizedCallable
480480 model = "heuristic-callback"
481481 }
482482}
483+
484+ /**
485+ * A class of summaries for compiler generated Deconstruct methods.
486+ *
487+ * For record types, the compiler generates a `Deconstruct` method that allows deconstructing the record into its components.
488+ * ```csharp
489+ * public record R(int X, int Y);
490+ *
491+ * var r = new R(1, 2);
492+ * var (x, y) = r;
493+ * ```
494+ * In this case the compiler generates a `Deconstruct` method which is implicitly invoked on line 4 in the example above.
495+ *
496+ * The compiler generated `Deconstruct` method looks like:
497+ * ```csharp
498+ * public void Deconstruct(out int X, out int Y) {
499+ * X = this.X;
500+ * Y = this.Y;
501+ * }
502+ * ```
503+ * That is, we need to create summaries for compiler generated `Deconstruct` methods that reflect the flow from the record's properties
504+ * to the corresponding out parameters.
505+ */
506+ private class SummarizedDeconstruct extends Public:: SummarizedCallable {
507+ SummarizedDeconstruct ( ) {
508+ this .isCompilerGenerated ( ) and
509+ this .getDeclaringType ( ) instanceof RecordType and
510+ this .getName ( ) = "Deconstruct"
511+ }
512+
513+ override predicate propagatesFlow (
514+ string input , string output , boolean preservesValue , Public:: Provenance provenance ,
515+ boolean isExact , string model
516+ ) {
517+ exists ( Parameter p , int i , Property prop , string qualifier , string name |
518+ p = this .getParameter ( i ) and
519+ prop = this .getDeclaringType ( ) .getProperty ( p .getName ( ) )
520+ |
521+ prop .hasFullyQualifiedName ( qualifier , name ) and
522+ input = "Argument[this].Property[" + getQualifiedName ( qualifier , name ) + "]" and
523+ output = "Argument[" + i + "]" and
524+ preservesValue = true and
525+ provenance = "manual" and
526+ isExact = true and
527+ model = "deconstruct"
528+ )
529+ }
530+ }
0 commit comments