@@ -8,67 +8,120 @@ private import semmle.code.csharp.frameworks.System
88private import semmle.code.csharp.frameworks.system.Text
99
1010/** A method that formats a string, for example `string.Format()`. */
11- class FormatMethod extends Method {
12- FormatMethod ( ) {
13- exists ( Class declType | declType = this .getDeclaringType ( ) |
11+ abstract private class FormatMethodImpl extends Method {
12+ /**
13+ * Gets the argument containing the format string. For example, the argument of
14+ * `string.Format(IFormatProvider, String, Object)` is `1`.
15+ */
16+ abstract int getFormatArgument ( ) ;
17+
18+ /**
19+ * Gets the argument number of the first supplied insert.
20+ */
21+ int getFirstArgument ( ) { result = this .getFormatArgument ( ) + 1 }
22+ }
23+
24+ final class FormatMethod = FormatMethodImpl ;
25+
26+ /** A class of types used for formatting. */
27+ private class FormatType extends Type {
28+ FormatType ( ) {
29+ this instanceof StringType or
30+ this instanceof SystemTextCompositeFormatClass
31+ }
32+ }
33+
34+ private class StringAndStringBuilderFormatMethods extends FormatMethodImpl {
35+ StringAndStringBuilderFormatMethods ( ) {
36+ (
1437 this .getParameter ( 0 ) .getType ( ) instanceof SystemIFormatProviderInterface and
15- this .getParameter ( 1 ) .getType ( ) instanceof StringType and
38+ this .getParameter ( 1 ) .getType ( ) instanceof FormatType
39+ or
40+ this .getParameter ( 0 ) .getType ( ) instanceof StringType
41+ ) and
42+ (
43+ this = any ( SystemStringClass c ) .getFormatMethod ( )
44+ or
45+ this = any ( SystemTextStringBuilderClass c ) .getAppendFormatMethod ( )
46+ )
47+ }
48+
49+ override int getFormatArgument ( ) {
50+ if this .getParameter ( 0 ) .getType ( ) instanceof SystemIFormatProviderInterface
51+ then result = 1
52+ else result = 0
53+ }
54+ }
55+
56+ private class SystemMemoryExtensionsFormatMethods extends FormatMethodImpl {
57+ SystemMemoryExtensionsFormatMethods ( ) {
58+ this = any ( SystemMemoryExtensionsClass c ) .getTryWriteMethod ( ) and
59+ this .getParameter ( 1 ) .getType ( ) instanceof SystemIFormatProviderInterface and
60+ this .getParameter ( 2 ) .getType ( ) instanceof SystemTextCompositeFormatClass
61+ }
62+
63+ override int getFormatArgument ( ) { result = 2 }
64+
65+ override int getFirstArgument ( ) { result = this .getFormatArgument ( ) + 2 }
66+ }
67+
68+ private class SystemConsoleAndSystemIoTextWriterFormatMethods extends FormatMethodImpl {
69+ SystemConsoleAndSystemIoTextWriterFormatMethods ( ) {
70+ this .getParameter ( 0 ) .getType ( ) instanceof StringType and
71+ this .getNumberOfParameters ( ) > 1 and
72+ exists ( Class declType | declType = this .getDeclaringType ( ) |
73+ this .hasName ( [ "Write" , "WriteLine" ] ) and
1674 (
17- this = any ( SystemStringClass c ) . getFormatMethod ( )
75+ declType . hasFullyQualifiedName ( "System" , "Console" )
1876 or
19- this = any ( SystemTextStringBuilderClass c ) . getAppendFormatMethod ( )
77+ declType . hasFullyQualifiedName ( "System.IO" , "TextWriter" )
2078 )
21- or
22- this .getParameter ( 0 ) .getType ( ) instanceof StringType and
79+ )
80+ }
81+
82+ override int getFormatArgument ( ) { result = 0 }
83+ }
84+
85+ private class SystemDiagnosticsDebugAssert extends FormatMethodImpl {
86+ SystemDiagnosticsDebugAssert ( ) {
87+ this .hasName ( "Assert" ) and
88+ this .getDeclaringType ( ) .hasFullyQualifiedName ( "System.Diagnostics" , "Debug" ) and
89+ this .getNumberOfParameters ( ) = 4
90+ }
91+
92+ override int getFormatArgument ( ) { result = 2 }
93+ }
94+
95+ private class SystemDiagnosticsFormatMethods extends FormatMethodImpl {
96+ SystemDiagnosticsFormatMethods ( ) {
97+ this .getParameter ( 0 ) .getType ( ) instanceof StringType and
98+ this .getNumberOfParameters ( ) > 1 and
99+ exists ( Class declType |
100+ declType = this .getDeclaringType ( ) and
101+ declType .getNamespace ( ) .getFullName ( ) = "System.Diagnostics"
102+ |
103+ declType .hasName ( "Trace" ) and
23104 (
24- this = any ( SystemStringClass c ) .getFormatMethod ( )
25- or
26- this = any ( SystemTextStringBuilderClass c ) .getAppendFormatMethod ( )
27- or
28- ( this .hasName ( "Write" ) or this .hasName ( "WriteLine" ) ) and
29- (
30- declType .hasFullyQualifiedName ( "System" , "Console" )
31- or
32- declType .hasFullyQualifiedName ( "System.IO" , "TextWriter" )
33- or
34- declType .hasFullyQualifiedName ( "System.Diagnostics" , "Debug" ) and
35- this .getParameter ( 1 ) .getType ( ) instanceof ArrayType
36- )
105+ this .hasName ( "TraceError" )
37106 or
38- declType .hasFullyQualifiedName ( "System.Diagnostics" , "Trace" ) and
39- (
40- this .hasName ( "TraceError" ) or
41- this .hasName ( "TraceInformation" ) or
42- this .hasName ( "TraceWarning" )
43- )
107+ this .hasName ( "TraceInformation" )
44108 or
45- this .hasName ( "TraceInformation" ) and
46- declType .hasFullyQualifiedName ( "System.Diagnostics" , "TraceSource" )
47- or
48- this .hasName ( "Print" ) and
49- declType .hasFullyQualifiedName ( "System.Diagnostics" , "Debug" )
109+ this .hasName ( "TraceWarning" )
50110 )
51111 or
52- this .hasName ( "Assert" ) and
53- declType .hasFullyQualifiedName ( "System.Diagnostics" , "Debug" ) and
54- this .getNumberOfParameters ( ) = 4
112+ declType .hasName ( "TraceSource" ) and this .hasName ( "TraceInformation" )
113+ or
114+ declType .hasName ( "Debug" ) and
115+ (
116+ this .hasName ( "Print" )
117+ or
118+ this .hasName ( [ "Write" , "WriteLine" ] ) and
119+ this .getParameter ( 1 ) .getType ( ) instanceof ArrayType
120+ )
55121 )
56122 }
57123
58- /**
59- * Gets the argument containing the format string. For example, the argument of
60- * `string.Format(IFormatProvider, String, Object)` is `1`.
61- */
62- int getFormatArgument ( ) {
63- if this .getParameter ( 0 ) .getType ( ) instanceof SystemIFormatProviderInterface
64- then result = 1
65- else
66- if
67- this .hasName ( "Assert" ) and
68- this .getDeclaringType ( ) .hasFullyQualifiedName ( "System.Diagnostics" , "Debug" )
69- then result = 2
70- else result = 0
71- }
124+ override int getFormatArgument ( ) { result = 0 }
72125}
73126
74127pragma [ nomagic]
@@ -194,24 +247,36 @@ class FormatCall extends MethodCall {
194247 int getFormatArgument ( ) { result = this .getTarget ( ) .( FormatMethod ) .getFormatArgument ( ) }
195248
196249 /** Gets the argument number of the first supplied insert. */
197- int getFirstArgument ( ) { result = this .getFormatArgument ( ) + 1 }
250+ int getFirstArgument ( ) { result = this .getTarget ( ) . ( FormatMethod ) . getFirstArgument ( ) }
198251
199252 /** Holds if this call has one or more insertions. */
200253 predicate hasInsertions ( ) { exists ( this .getArgument ( this .getFirstArgument ( ) ) ) }
201254
202- /** Holds if the arguments are supplied in an array, not individually. */
203- predicate hasArrayExpr ( ) {
255+ /**
256+ * DEPRECATED: use `hasCollectionExpr` instead.
257+ *
258+ * Holds if the arguments are supplied in an array, not individually.
259+ */
260+ deprecated predicate hasArrayExpr ( ) {
204261 this .getNumberOfArguments ( ) = this .getFirstArgument ( ) + 1 and
205262 this .getArgument ( this .getFirstArgument ( ) ) .getType ( ) instanceof ArrayType
206263 }
207264
265+ /**
266+ * Holds if the arguments are supplied in a collection, not individually.
267+ */
268+ predicate hasCollectionExpr ( ) {
269+ this .getNumberOfArguments ( ) = this .getFirstArgument ( ) + 1 and
270+ this .getArgument ( this .getFirstArgument ( ) ) .getType ( ) instanceof ParamsCollectionType
271+ }
272+
208273 /**
209274 * Gets the number of supplied arguments (excluding the format string and format
210275 * provider). Does not return a value if the arguments are supplied in an array,
211276 * in which case we generally can't assess the size of the array.
212277 */
213278 int getSuppliedArguments ( ) {
214- not this .hasArrayExpr ( ) and
279+ not this .hasCollectionExpr ( ) and
215280 result = this .getNumberOfArguments ( ) - this .getFirstArgument ( )
216281 }
217282
0 commit comments