@@ -15,6 +15,7 @@ private import codeql.rust.dataflow.Ssa
1515private import codeql.rust.dataflow.FlowSummary
1616private import FlowSummaryImpl as FlowSummaryImpl
1717private import codeql.rust.elements.internal.PathResolution as PathResolution
18+ private import codeql.rust.elements.internal.TypeInference as TypeInference
1819
1920/**
2021 * A return kind. A return kind describes how a value can be returned from a
@@ -738,10 +739,6 @@ abstract class Content extends TContent {
738739 */
739740abstract class VariantContent extends Content { }
740741
741- private TupleField getVariantTupleField ( Variant v , int i ) {
742- result = v .getFieldList ( ) .( TupleFieldList ) .getField ( i )
743- }
744-
745742/** A tuple variant. */
746743private class VariantTupleFieldContent extends VariantContent , TVariantTupleFieldContent {
747744 private Variant v ;
@@ -755,16 +752,11 @@ private class VariantTupleFieldContent extends VariantContent, TVariantTupleFiel
755752 exists ( string name |
756753 name = v .getName ( ) .getText ( ) and
757754 // only print indices when the arity is > 1
758- if exists ( getVariantTupleField ( v , 1 ) ) then result = name + "(" + pos_ + ")" else result = name
755+ if exists ( v . getTupleField ( 1 ) ) then result = name + "(" + pos_ + ")" else result = name
759756 )
760757 }
761758
762- final override Location getLocation ( ) { result = getVariantTupleField ( v , pos_ ) .getLocation ( ) }
763- }
764-
765- private RecordField getVariantRecordField ( Variant v , string field ) {
766- result = v .getFieldList ( ) .( RecordFieldList ) .getAField ( ) and
767- field = result .getName ( ) .getText ( )
759+ final override Location getLocation ( ) { result = v .getTupleField ( pos_ ) .getLocation ( ) }
768760}
769761
770762/** A record variant. */
@@ -780,34 +772,56 @@ private class VariantRecordFieldContent extends VariantContent, TVariantRecordFi
780772 exists ( string name |
781773 name = v .getName ( ) .getText ( ) and
782774 // only print field when the arity is > 1
783- if strictcount ( string f | exists ( getVariantRecordField ( v , f ) ) ) > 1
775+ if strictcount ( v . getRecordField ( _ ) ) > 1
784776 then result = name + "{" + field_ + "}"
785777 else result = name
786778 )
787779 }
788780
789781 final override Location getLocation ( ) {
790- result = getVariantRecordField ( v , field_ ) .getName ( ) .getLocation ( )
782+ result = v .getRecordField ( field_ ) .getName ( ) .getLocation ( )
783+ }
784+ }
785+
786+ abstract private class FieldContent extends Content {
787+ pragma [ nomagic]
788+ abstract FieldExprCfgNode getAnAccess ( ) ;
789+ }
790+
791+ /** Content stored in a tuple field on a struct. */
792+ private class StructTupleFieldContent extends FieldContent , TStructTupleFieldContent {
793+ private Struct s ;
794+ private int pos_ ;
795+
796+ StructTupleFieldContent ( ) { this = TStructTupleFieldContent ( s , pos_ ) }
797+
798+ Struct getStruct ( int pos ) { result = s and pos = pos_ }
799+
800+ override FieldExprCfgNode getAnAccess ( ) {
801+ s .getTupleField ( pos_ ) = TypeInference:: resolveTupleFieldExpr ( result .getFieldExpr ( ) )
791802 }
803+
804+ override string toString ( ) { result = s .getName ( ) .getText ( ) + "." + pos_ .toString ( ) }
805+
806+ override Location getLocation ( ) { result = s .getTupleField ( pos_ ) .getLocation ( ) }
792807}
793808
794- /** Content stored in a field on a struct. */
795- private class StructFieldContent extends Content , TStructFieldContent {
809+ /** Content stored in a record field on a struct. */
810+ private class StructRecordFieldContent extends FieldContent , TStructRecordFieldContent {
796811 private Struct s ;
797812 private string field_ ;
798813
799- StructFieldContent ( ) { this = TStructFieldContent ( s , field_ ) }
814+ StructRecordFieldContent ( ) { this = TStructRecordFieldContent ( s , field_ ) }
800815
801816 Struct getStruct ( string field ) { result = s and field = field_ }
802817
818+ override FieldExprCfgNode getAnAccess ( ) {
819+ s .getRecordField ( field_ ) = TypeInference:: resolveRecordFieldExpr ( result .getFieldExpr ( ) )
820+ }
821+
803822 override string toString ( ) { result = s .getName ( ) .getText ( ) + "." + field_ .toString ( ) }
804823
805- override Location getLocation ( ) {
806- exists ( Name f | f = s .getFieldList ( ) .( RecordFieldList ) .getAField ( ) .getName ( ) |
807- f .getText ( ) = field_ and
808- result = f .getLocation ( )
809- )
810- }
824+ override Location getLocation ( ) { result = s .getRecordField ( field_ ) .getName ( ) .getLocation ( ) }
811825}
812826
813827/** A captured variable. */
@@ -851,23 +865,23 @@ final class ElementContent extends Content, TElementContent {
851865 * NOTE: Unlike `struct`s and `enum`s tuples are structural and not nominal,
852866 * hence we don't store a canonical path for them.
853867 */
854- final class TuplePositionContent extends Content , TTuplePositionContent {
868+ final class TuplePositionContent extends FieldContent , TTuplePositionContent {
855869 private int pos ;
856870
857871 TuplePositionContent ( ) { this = TTuplePositionContent ( pos ) }
858872
859873 int getPosition ( ) { result = pos }
860874
875+ override FieldExprCfgNode getAnAccess ( ) {
876+ // todo: limit to tuple types
877+ result .getNameRef ( ) .getText ( ) .toInt ( ) = pos
878+ }
879+
861880 override string toString ( ) { result = "tuple." + pos .toString ( ) }
862881
863882 override Location getLocation ( ) { result instanceof EmptyLocation }
864883}
865884
866- /** Holds if `access` indexes a tuple at an index corresponding to `c`. */
867- private predicate fieldTuplePositionContent ( FieldExprCfgNode access , TuplePositionContent c ) {
868- access .getNameRef ( ) .getText ( ) .toInt ( ) = c .getPosition ( )
869- }
870-
871885/** A value that represents a set of `Content`s. */
872886abstract class ContentSet extends TContentSet {
873887 /** Gets a textual representation of this element. */
@@ -1103,6 +1117,10 @@ module RustDataFlow implements InputSig<Location> {
11031117 pathResolveToVariant ( p , v )
11041118 }
11051119
1120+ /** Holds if `p` destructs an struct `s`. */
1121+ pragma [ nomagic]
1122+ private predicate tupleStructDestruction ( TupleStructPat p , Struct s ) { pathResolveToStruct ( p , s ) }
1123+
11061124 /** Holds if `p` destructs an enum variant `v`. */
11071125 pragma [ nomagic]
11081126 private predicate recordVariantDestruction ( RecordPat p , Variant v ) { pathResolveToVariant ( p , v ) }
@@ -1124,6 +1142,8 @@ module RustDataFlow implements InputSig<Location> {
11241142 |
11251143 tupleVariantDestruction ( pat .getPat ( ) , c .( VariantTupleFieldContent ) .getVariant ( pos ) )
11261144 or
1145+ tupleStructDestruction ( pat .getPat ( ) , c .( StructTupleFieldContent ) .getStruct ( pos ) )
1146+ or
11271147 VariantLib:: tupleVariantCanonicalDestruction ( pat .getPat ( ) , c , pos )
11281148 )
11291149 or
@@ -1140,7 +1160,7 @@ module RustDataFlow implements InputSig<Location> {
11401160 recordVariantDestruction ( pat .getPat ( ) , c .( VariantRecordFieldContent ) .getVariant ( field ) )
11411161 or
11421162 // Pattern destructs a struct.
1143- structDestruction ( pat .getPat ( ) , c .( StructFieldContent ) .getStruct ( field ) )
1163+ structDestruction ( pat .getPat ( ) , c .( StructRecordFieldContent ) .getStruct ( field ) )
11441164 ) and
11451165 node2 .asPat ( ) = pat .getFieldPat ( field )
11461166 )
@@ -1149,11 +1169,9 @@ module RustDataFlow implements InputSig<Location> {
11491169 node1 .asPat ( ) .( RefPatCfgNode ) .getPat ( ) = node2 .asPat ( )
11501170 or
11511171 exists ( FieldExprCfgNode access |
1152- // Read of a tuple entry
1153- fieldTuplePositionContent ( access , c ) and
1154- // TODO: Handle read of a struct field.
11551172 node1 .asExpr ( ) = access .getExpr ( ) and
1156- node2 .asExpr ( ) = access
1173+ node2 .asExpr ( ) = access and
1174+ access = c .( FieldContent ) .getAnAccess ( )
11571175 )
11581176 or
11591177 exists ( IndexExprCfgNode arr |
@@ -1211,12 +1229,13 @@ module RustDataFlow implements InputSig<Location> {
12111229 pragma [ nomagic]
12121230 private predicate structConstruction ( RecordExpr re , Struct s ) { pathResolveToStruct ( re , s ) }
12131231
1214- private predicate tupleAssignment ( Node node1 , Node node2 , TuplePositionContent c ) {
1232+ pragma [ nomagic]
1233+ private predicate fieldAssignment ( Node node1 , Node node2 , FieldContent c ) {
12151234 exists ( AssignmentExprCfgNode assignment , FieldExprCfgNode access |
12161235 assignment .getLhs ( ) = access and
1217- fieldTuplePositionContent ( access , c ) and
12181236 node1 .asExpr ( ) = assignment .getRhs ( ) and
1219- node2 .asExpr ( ) = access .getExpr ( )
1237+ node2 .asExpr ( ) = access .getExpr ( ) and
1238+ access = c .getAnAccess ( )
12201239 )
12211240 }
12221241
@@ -1238,7 +1257,7 @@ module RustDataFlow implements InputSig<Location> {
12381257 c .( VariantRecordFieldContent ) .getVariant ( field ) )
12391258 or
12401259 // Expression is for a struct.
1241- structConstruction ( re .getRecordExpr ( ) , c .( StructFieldContent ) .getStruct ( field ) )
1260+ structConstruction ( re .getRecordExpr ( ) , c .( StructRecordFieldContent ) .getStruct ( field ) )
12421261 ) and
12431262 node1 .asExpr ( ) = re .getFieldExpr ( field ) and
12441263 node2 .asExpr ( ) = re
@@ -1256,7 +1275,7 @@ module RustDataFlow implements InputSig<Location> {
12561275 node2 .asExpr ( ) .( ArrayListExprCfgNode ) .getAnExpr ( )
12571276 ]
12581277 or
1259- tupleAssignment ( node1 , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
1278+ fieldAssignment ( node1 , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) , c )
12601279 or
12611280 exists ( AssignmentExprCfgNode assignment , IndexExprCfgNode index |
12621281 c instanceof ElementContent and
@@ -1292,7 +1311,7 @@ module RustDataFlow implements InputSig<Location> {
12921311 * in `x.f = newValue`.
12931312 */
12941313 predicate clearsContent ( Node n , ContentSet cs ) {
1295- tupleAssignment ( _, n , cs .( SingletonContentSet ) .getContent ( ) )
1314+ fieldAssignment ( _, n , cs .( SingletonContentSet ) .getContent ( ) )
12961315 or
12971316 FlowSummaryImpl:: Private:: Steps:: summaryClearsContent ( n .( Node:: FlowSummaryNode ) .getSummaryNode ( ) ,
12981317 cs )
@@ -1598,12 +1617,12 @@ private module Cached {
15981617
15991618 cached
16001619 newtype TContent =
1601- TVariantTupleFieldContent ( Variant v , int pos ) { exists ( getVariantTupleField ( v , pos ) ) } or
1620+ TVariantTupleFieldContent ( Variant v , int pos ) { exists ( v . getTupleField ( pos ) ) } or
16021621 // TODO: Remove once library types are extracted
16031622 TVariantLibTupleFieldContent ( VariantLib:: VariantLib v , int pos ) {
16041623 VariantLib:: variantLibPos ( v , pos )
16051624 } or
1606- TVariantRecordFieldContent ( Variant v , string field ) { exists ( getVariantRecordField ( v , field ) ) } or
1625+ TVariantRecordFieldContent ( Variant v , string field ) { exists ( v . getRecordField ( field ) ) } or
16071626 TElementContent ( ) or
16081627 TTuplePositionContent ( int pos ) {
16091628 pos in [ 0 .. max ( [
@@ -1612,9 +1631,8 @@ private module Cached {
16121631 ]
16131632 ) ]
16141633 } or
1615- TStructFieldContent ( Struct s , string field ) {
1616- field = s .getFieldList ( ) .( RecordFieldList ) .getAField ( ) .getName ( ) .getText ( )
1617- } or
1634+ TStructTupleFieldContent ( Struct s , int pos ) { exists ( s .getTupleField ( pos ) ) } or
1635+ TStructRecordFieldContent ( Struct s , string field ) { exists ( s .getRecordField ( field ) ) } or
16181636 TCapturedVariableContent ( VariableCapture:: CapturedVariable v ) or
16191637 TReferenceContent ( )
16201638
0 commit comments