@@ -67,7 +67,7 @@ module StringOps {
6767 }
6868
6969 /**
70- * An expression of form `strings.HasPrefix(A, B)`.
70+ * An expression of the form `strings.HasPrefix(A, B)`.
7171 */
7272 private class StringsHasPrefix extends Range , DataFlow:: CallNode {
7373 StringsHasPrefix ( ) { getTarget ( ) .hasQualifiedName ( "strings" , "HasPrefix" ) }
@@ -78,15 +78,25 @@ module StringOps {
7878 }
7979
8080 /**
81- * An expression of form `strings.Index(A, B) === 0`.
81+ * Holds if `eq` is of the form `nd == 0` or `nd != 0`.
82+ */
83+ pragma [ noinline]
84+ private predicate comparesToZero ( DataFlow:: EqualityTestNode eq , DataFlow:: Node nd ) {
85+ exists ( DataFlow:: Node zero |
86+ eq .hasOperands ( globalValueNumber ( nd ) .getANode ( ) , zero ) and
87+ zero .getIntValue ( ) = 0
88+ )
89+ }
90+
91+ /**
92+ * An expression of the form `strings.Index(A, B) == 0`.
8293 */
8394 private class HasPrefix_IndexOfEquals extends Range , DataFlow:: EqualityTestNode {
8495 DataFlow:: CallNode indexOf ;
8596
8697 HasPrefix_IndexOfEquals ( ) {
87- indexOf .getTarget ( ) .hasQualifiedName ( "strings" , "Index" ) and
88- getAnOperand ( ) = globalValueNumber ( indexOf ) .getANode ( ) and
89- getAnOperand ( ) .getIntValue ( ) = 0
98+ comparesToZero ( this , indexOf ) and
99+ indexOf .getTarget ( ) .hasQualifiedName ( "strings" , "Index" )
90100 }
91101
92102 override DataFlow:: Node getBaseString ( ) { result = indexOf .getArgument ( 0 ) }
@@ -97,27 +107,38 @@ module StringOps {
97107 }
98108
99109 /**
100- * A comparison of form `x[0] === 'k'` for some rune literal `k`.
110+ * Holds if `eq` is of the form `str[0] == rhs` or `str[0] != rhs`.
111+ */
112+ pragma [ noinline]
113+ private predicate comparesFirstCharacter (
114+ DataFlow:: EqualityTestNode eq , DataFlow:: Node str , DataFlow:: Node rhs
115+ ) {
116+ exists ( DataFlow:: ElementReadNode read |
117+ eq .hasOperands ( globalValueNumber ( read ) .getANode ( ) , rhs ) and
118+ str = read .getBase ( ) and
119+ str .getType ( ) .getUnderlyingType ( ) instanceof StringType and
120+ read .getIndex ( ) .getIntValue ( ) = 0
121+ )
122+ }
123+
124+ /**
125+ * A comparison of the form `x[0] == 'k'` for some rune literal `k`.
101126 */
102127 private class HasPrefix_FirstCharacter extends Range , DataFlow:: EqualityTestNode {
103- DataFlow:: ElementReadNode read ;
128+ DataFlow:: Node base ;
104129 DataFlow:: Node runeLiteral ;
105130
106- HasPrefix_FirstCharacter ( ) {
107- read .getBase ( ) .getType ( ) .getUnderlyingType ( ) instanceof StringType and
108- read .getIndex ( ) .getIntValue ( ) = 0 and
109- eq ( _, globalValueNumber ( read ) .getANode ( ) , runeLiteral )
110- }
131+ HasPrefix_FirstCharacter ( ) { comparesFirstCharacter ( this , base , runeLiteral ) }
111132
112- override DataFlow:: Node getBaseString ( ) { result = read . getBase ( ) }
133+ override DataFlow:: Node getBaseString ( ) { result = base }
113134
114135 override DataFlow:: Node getSubstring ( ) { result = runeLiteral }
115136
116137 override boolean getPolarity ( ) { result = expr .getPolarity ( ) }
117138 }
118139
119140 /**
120- * A comparison of form `x[:len(y)] = == y`.
141+ * A comparison of the form `x[:len(y)] == y`.
121142 */
122143 private class HasPrefix_Substring extends Range , DataFlow:: EqualityTestNode {
123144 DataFlow:: SliceNode slice ;
0 commit comments