@@ -131,16 +131,11 @@ class FormattingFunctionCall extends Expr {
131131 }
132132
133133 /**
134- * Gets the argument corresponding to the nth conversion specifier
134+ * Gets the argument corresponding to the nth conversion specifier.
135135 */
136136 Expr getConversionArgument ( int n ) {
137- exists ( FormatLiteral fl , int b , int o |
138- fl = this .getFormat ( ) and
139- b = sum ( int i , int toSum | i < n and toSum = fl .getNumArgNeeded ( i ) | toSum ) and
140- o = fl .getNumArgNeeded ( n ) and
141- o > 0 and
142- result = this .getFormatArgument ( b + o - 1 )
143- )
137+ result = this
138+ .getFormatArgument ( this .getFormat ( ) .( FormatLiteral ) .getFormatArgumentIndexFor ( n , 2 ) )
144139 }
145140
146141 /**
@@ -149,12 +144,8 @@ class FormattingFunctionCall extends Expr {
149144 * an explicit minimum field width).
150145 */
151146 Expr getMinFieldWidthArgument ( int n ) {
152- exists ( FormatLiteral fl , int b |
153- fl = this .getFormat ( ) and
154- b = sum ( int i , int toSum | i < n and toSum = fl .getNumArgNeeded ( i ) | toSum ) and
155- fl .hasImplicitMinFieldWidth ( n ) and
156- result = this .getFormatArgument ( b )
157- )
147+ result = this
148+ .getFormatArgument ( this .getFormat ( ) .( FormatLiteral ) .getFormatArgumentIndexFor ( n , 0 ) )
158149 }
159150
160151 /**
@@ -163,13 +154,8 @@ class FormattingFunctionCall extends Expr {
163154 * precision).
164155 */
165156 Expr getPrecisionArgument ( int n ) {
166- exists ( FormatLiteral fl , int b , int o |
167- fl = this .getFormat ( ) and
168- b = sum ( int i , int toSum | i < n and toSum = fl .getNumArgNeeded ( i ) | toSum ) and
169- ( if fl .hasImplicitMinFieldWidth ( n ) then o = 1 else o = 0 ) and
170- fl .hasImplicitPrecision ( n ) and
171- result = this .getFormatArgument ( b + o )
172- )
157+ result = this
158+ .getFormatArgument ( this .getFormat ( ) .( FormatLiteral ) .getFormatArgumentIndexFor ( n , 1 ) )
173159 }
174160
175161 /**
@@ -784,19 +770,53 @@ class FormatLiteral extends Literal {
784770 )
785771 }
786772
773+ /**
774+ * Holds if the nth conversion specifier of this format string (if `mode = 2`), it's
775+ * minimum field width (if `mode = 0`) or it's precision (if `mode = 1`) requires a
776+ * format argument.
777+ *
778+ * Most conversion specifiers require a format argument, whereas minimum field width
779+ * and precision only require a format argument if they are present and a `*` was
780+ * used for it's value in the format string.
781+ */
782+ private predicate hasFormatArgumentIndexFor ( int n , int mode ) {
783+ mode = 0 and
784+ this .hasImplicitMinFieldWidth ( n )
785+ or
786+ mode = 1 and
787+ this .hasImplicitPrecision ( n )
788+ or
789+ mode = 2 and
790+ exists ( this .getConvSpecOffset ( n ) ) and
791+ not this .getConversionChar ( n ) = "m"
792+ }
793+
794+ /**
795+ * Gets the format argument index for the nth conversion specifier of this format
796+ * string (if `mode = 2`), it's minimum field width (if `mode = 0`) or it's
797+ * precision (if `mode = 1`). Has no result if that element is not present. Does
798+ * not account for positional arguments (`$`).
799+ */
800+ int getFormatArgumentIndexFor ( int n , int mode ) {
801+ hasFormatArgumentIndexFor ( n , mode ) and
802+ result = count ( int n2 , int mode2 |
803+ hasFormatArgumentIndexFor ( n2 , mode2 ) and
804+ (
805+ n2 < n
806+ or
807+ n2 = n and
808+ mode2 < mode
809+ )
810+ )
811+ }
812+
787813 /**
788814 * Gets the number of arguments required by the nth conversion specifier
789815 * of this format string.
790816 */
791817 int getNumArgNeeded ( int n ) {
792818 exists ( this .getConvSpecOffset ( n ) ) and
793- not this .getConversionChar ( n ) = "%" and
794- exists ( int n1 , int n2 , int n3 |
795- ( if this .hasImplicitMinFieldWidth ( n ) then n1 = 1 else n1 = 0 ) and
796- ( if this .hasImplicitPrecision ( n ) then n2 = 1 else n2 = 0 ) and
797- ( if this .getConversionChar ( n ) = "m" then n3 = 0 else n3 = 1 ) and
798- result = n1 + n2 + n3
799- )
819+ result = count ( int mode | hasFormatArgumentIndexFor ( n , mode ) )
800820 }
801821
802822 /**
0 commit comments