Repository: github/codeql
Pull request #19148: C#: Improve `cs/invalid-string-formatting` and add to the Code Quality suite.
Author: login: michaelnebel
Labels: name: C#
name: documentation
Created: 2025-03-28T14:11:33Z | Merged: 2025-04-24T08:03:06Z

In this PR we
- Add the `cs/invalid-string-formatting` to the code quality suite.
- Re-write tests to use inline expectations tests; In this process a couple of faulty testcases were discovered and these were corrected (for instance - we only check that format strings are valid in case there are insertions).

Improve the `cs/invalid-string-formatting` query by
- Adding *invalid* string format results for `string.Format` where no additional arguments are provided (for instance `string.Format("{")`). Also start taking `CompositeFormat` versions of `Format` methods into account and consider `System.Text.CompositeFormat.Parse` a method that parses format strings and might throw exceptions and cause a runtime crash.
- Add support for more format methods like generic versions of `string.Format` and `StringBuilder.AppendFormat` and also add support for `MemoryExtensions.TryWrite`.
- Remove false positives related to `Console.WriteLine(string)` and friends (methods that itsn't format methods).
- Remove false positives related to `Console.WriteLine(string, ReadOnlySpan<object>) (methods that use params collection type overloads).

Review commit by commit is encouraged.

@hvitved : The data flow configurations are quite similar. Is it a better approach to use flow state to track calls to `CompositeFormat.Parse`? (instead of merging two similar graphs).


Diff:
diff --git a/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll b/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll
index 7a881981c1c1..b33c0f73d60d 100644
--- a/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll
+++ b/csharp/ql/lib/semmle/code/csharp/commons/Collections.qll
@@ -97,7 +97,8 @@ private class ParamsConstructedCollectionTypes extends ParamsCollectionTypeImpl
       unboundbase instanceof SystemCollectionsGenericIReadOnlyListTInterface or
       unboundbase instanceof SystemSpanStruct or
       unboundbase instanceof SystemReadOnlySpanStruct
-    )
+    ) and
+    not this instanceof SystemStringClass
   }
 
   override Type getElementType() { result = base.getTypeArgument(0) }
diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll
index f54476b9e4fc..cf61a5d75aab 100644
--- a/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll
+++ b/csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll
@@ -8,67 +8,120 @@ private import semmle.code.csharp.frameworks.System
 private import semmle.code.csharp.frameworks.system.Text
 
 /** A method that formats a string, for example `string.Format()`. */
-class FormatMethod extends Method {
-  FormatMethod() {
-    exists(Class declType | declType = this.getDeclaringType() |
+abstract private class FormatMethodImpl extends Method {
+  /**
+   * Gets the argument containing the format string. For example, the argument of
+   * `string.Format(IFormatProvider, String, Object)` is `1`.
+   */
+  abstract int getFormatArgument();
+
+  /**
+   * Gets the argument number of the first supplied insert.
+   */
+  int getFirstArgument() { result = this.getFormatArgument() + 1 }
+}
+
+final class FormatMethod = FormatMethodImpl;
+
+/** A class of types used for formatting. */
+private class FormatType extends Type {
+  FormatType() {
+    this instanceof StringType or
+    this instanceof SystemTextCompositeFormatClass
+  }
+}
+
+private class StringAndStringBuilderFormatMethods extends FormatMethodImpl {
+  StringAndStringBuilderFormatMethods() {
+    (
       this.getParameter(0).getType() instanceof SystemIFormatProviderInterface and
-      this.getParameter(1).getType() instanceof StringType and
+      this.getParameter(1).getType() instanceof FormatType
+      or
+      this.getParameter(0).getType() instanceof StringType
+    ) and
+    (
+      this = any(SystemStringClass c).getFormatMethod()
+      or
+      this = any(SystemTextStringBuilderClass c).getAppendFormatMethod()
+    )
+  }
+
+  override int getFormatArgument() {
+    if this.getParameter(0).getType() instanceof SystemIFormatProviderInterface
+    then result = 1
+    else result = 0
+  }
+}
+
+private class SystemMemoryExtensionsFormatMethods extends FormatMethodImpl {
+  SystemMemoryExtensionsFormatMethods() {
+    this = any(SystemMemoryExtensionsClass c).getTryWriteMethod() and
+    this.getParameter(1).getType() instanceof SystemIFormatProviderInterface and
+    this.getParameter(2).getType() instanceof SystemTextCompositeFormatClass
+  }
+
+  override int getFormatArgument() { result = 2 }
+
+  override int getFirstArgument() { result = this.getFormatArgument() + 2 }
+}
+
+private class SystemConsoleAndSystemIoTextWriterFormatMethods extends FormatMethodImpl {
+  SystemConsoleAndSystemIoTextWriterFormatMethods() {
+    this.getParameter(0).getType() instanceof StringType and
+    this.getNumberOfParameters() > 1 and
+    exists(Class declType | declType = this.getDeclaringType() |
+      this.hasName(["Write", "WriteLine"]) and
       (
-        this = any(SystemStringClass c).getFormatMethod()
+        declType.hasFullyQualifiedName("System", "Console")
         or
-        this = any(SystemTextStringBuilderClass c).getAppendFormatMethod()
+        declType.hasFullyQualifiedName("System.IO", "TextWriter")
       )
-      or
-      this.getParameter(0).getType() instanceof StringType and
+    )
+  }
+
+  override int getFormatArgument() { result = 0 }
+}
+
+private class SystemDiagnosticsDebugAssert extends FormatMethodImpl {
+  SystemDiagnosticsDebugAssert() {
+    this.hasName("Assert") and
+    this.getDeclaringType().hasFullyQualifiedName("System.Diagnostics", "Debug") and
+    this.getNumberOfParameters() = 4
+  }
+
+  override int getFormatArgument() { result = 2 }
+}
+
+private class SystemDiagnosticsFormatMethods extends FormatMethodImpl {
+  SystemDiagnosticsFormatMethods() {
+    this.getParameter(0).getType() instanceof StringType and
+    this.getNumberOfParameters() > 1 and
+    exists(Class declType |
+      declType = this.getDeclaringType() and
+      declType.getNamespace().getFullName() = "System.Diagnostics"
+    |
+      declType.hasName("Trace") and
       (
-        this = any(SystemStringClass c).getFormatMethod()
-        or
-        this = any(SystemTextStringBuilderClass c).getAppendFormatMethod()
-        or
-        (this.hasName("Write") or this.hasName("WriteLine")) and
-        (
-          declType.hasFullyQualifiedName("System", "Console")
-          or
-          declType.hasFullyQualifiedName("System.IO", "TextWriter")
-          or
-          declType.hasFullyQualifiedName("System.Diagnostics", "Debug") and
-          this.getParameter(1).getType() instanceof ArrayType
-        )
+        this.hasName("TraceError")
         or
-        declType.hasFullyQualifiedName("System.Diagnostics", "Trace") and
-        (
-          this.hasName("TraceError") or
-          this.hasName("TraceInformation") or
-          this.hasName("TraceWarning")
-        )
+        this.hasName("TraceInformation")
         or
-        this.hasName("TraceInformation") and
-        declType.hasFullyQualifiedName("System.Diagnostics", "TraceSource")
-        or
-        this.hasName("Print") and
-        declType.hasFullyQualifiedName("System.Diagnostics", "Debug")
+        this.hasName("TraceWarning")
       )
       or
-      this.hasName("Assert") and
-      declType.hasFullyQualifiedName("System.Diagnostics", "Debug") and
-      this.getNumberOfParameters() = 4
+      declType.hasName("TraceSource") and this.hasName("TraceInformation")
+      or
+      declType.hasName("Debug") and
+      (
+        this.hasName("Print")
+        or
+        this.hasName(["Write", "WriteLine"]) and
+        this.getParameter(1).getType() instanceof ArrayType
+      )
     )
   }
 
-  /**
-   * Gets the argument containing the format string. For example, the argument of
-   * `string.Format(IFormatProvider, String, Object)` is `1`.
-   */
-  int getFormatArgument() {
-    if this.getParameter(0).getType() instanceof SystemIFormatProviderInterface
-    then result = 1
-    else
-      if
-        this.hasName("Assert") and
-        this.getDeclaringType().hasFullyQualifiedName("System.Diagnostics", "Debug")
-      then result = 2
-      else result = 0
-  }
+  override int getFormatArgument() { result = 0 }
 }
 
 pragma[nomagic]
@@ -194,24 +247,36 @@ class FormatCall extends MethodCall {
   int getFormatArgument() { result = this.getTarget().(FormatMethod).getFormatArgument() }
 
   /** Gets the argument number of the first supplied insert. */
-  int getFirstArgument() { result = this.getFormatArgument() + 1 }
+  int getFirstArgument() { result = this.getTarget().(FormatMethod).getFirstArgument() }
 
   /** Holds if this call has one or more insertions. */
   predicate hasInsertions() { exists(this.getArgument(this.getFirstArgument())) }
 
-  /** Holds if the arguments are supplied in an array, not individually. */
-  predicate hasArrayExpr() {
+  /**
+   * DEPRECATED: use `hasCollectionExpr` instead.
+   *
+   * Holds if the arguments are supplied in an array, not individually.
+   */
+  deprecated predicate hasArrayExpr() {
     this.getNumberOfArguments() = this.getFirstArgument() + 1 and
     this.getArgument(this.getFirstArgument()).getType() instanceof ArrayType
   }
 
+  /**
+   * Holds if the arguments are supplied in a collection, not individually.
+   */
+  predicate hasCollectionExpr() {
+    this.getNumberOfArguments() = this.getFirstArgument() + 1 and
+    this.getArgument(this.getFirstArgument()).getType() instanceof ParamsCollectionType
+  }
+
   /**
    * Gets the number of supplied arguments (excluding the format string and format
    * provider). Does not return a value if the arguments are supplied in an array,
    * in which case we generally can't assess the size of the array.
    */
   int getSuppliedArguments() {
-    not this.hasArrayExpr() and
+    not this.hasCollectionExpr() and
     result = this.getNumberOfArguments() - this.getFirstArgument()
   }
 
diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll
index 678563589e8a..2681b9437b69 100644
--- a/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll
+++ b/csharp/ql/lib/semmle/code/csharp/frameworks/System.qll
@@ -365,7 +365,7 @@ class SystemStringClass extends StringType {
   /** Gets a `Format(...)` method. */
   Method getFormatMethod() {
     result.getDeclaringType() = this and
-    result.hasName("Format") and
+    result.getName().regexpMatch("Format(<.*>)?") and
     result.getNumberOfParameters() in [2 .. 5] and
     result.getReturnType() instanceof StringType
   }
@@ -751,6 +751,18 @@ class SystemNotImplementedExceptionClass extends SystemClass {
   SystemNotImplementedExceptionClass() { this.hasName("NotImplementedException") }
 }
 
+/** The `System.MemoryExtensions` class. */
+class SystemMemoryExtensionsClass extends SystemClass {
+  SystemMemoryExtensionsClass() { this.hasName("MemoryExtensions") }
+
+  /** Gets a `TryWrite` method. */
+  Method getTryWriteMethod() {
+    result.getDeclaringType() = this and
+    result.getName().regexpMatch("TryWrite(<.*>)?") and
+    result.getParameter(0).getType().getUnboundDeclaration() instanceof SystemSpanStruct
+  }
+}
+
 /** The `System.DateTime` struct. */
 class SystemDateTimeStruct extends SystemStruct {
   SystemDateTimeStruct() { this.hasName("DateTime") }
diff --git a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Text.qll b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Text.qll
index fb4c37489af6..c5d44c7c9add 100644
--- a/csharp/ql/lib/semmle/code/csharp/frameworks/system/Text.qll
+++ b/csharp/ql/lib/semmle/code/csharp/frameworks/system/Text.qll
@@ -22,7 +22,12 @@ class SystemTextStringBuilderClass extends SystemTextClass {
   SystemTextStringBuilderClass() { this.hasName("StringBuilder") }
 
   /** Gets the `AppendFormat` method. */
-  Method getAppendFormatMethod() { result = this.getAMethod("AppendFormat") }
+  Method getAppendFormatMethod() {
+    exists(string name |
+      name.regexpMatch("AppendFormat(<.*>)?") and
+      result = this.getAMethod(name)
+    )
+  }
 }
 
 /** The `System.Text.Encoding` class. */
@@ -38,3 +43,11 @@ class SystemTextEncodingClass extends SystemTextClass {
   /** Gets the `GetChars` method. */
   Method getGetCharsMethod() { result = this.getAMethod("GetChars") }
 }
+
+/** The `System.Text.CompositeFormat` class */
+class SystemTextCompositeFormatClass extends SystemTextClass {
+  SystemTextCompositeFormatClass() { this.hasName("CompositeFormat") }
+
+  /** Gets the `Parse` method. */
+  Method getParseMethod() { result = this.getAMethod("Parse") }
+}
diff --git a/csharp/ql/src/API Abuse/FormatInvalid.ql b/csharp/ql/src/API Abuse/FormatInvalid.ql
index 235daa1ecc25..a2b8ef5e2220 100644
--- a/csharp/ql/src/API Abuse/FormatInvalid.ql	
+++ b/csharp/ql/src/API Abuse/FormatInvalid.ql	
@@ -11,37 +11,75 @@
  */
 
 import csharp
+import semmle.code.csharp.frameworks.system.Text
 import semmle.code.csharp.frameworks.Format
-import FormatInvalid::PathGraph
+import FormatFlow::PathGraph
+
+abstract class FormatStringParseCall extends MethodCall {
+  abstract Expr getFormatExpr();
+}
+
+class OrdinaryFormatCall extends FormatStringParseCall instanceof FormatCall {
+  override Expr getFormatExpr() { result = FormatCall.super.getFormatExpr() }
+}
+
+class ParseFormatStringCall extends FormatStringParseCall {
+  ParseFormatStringCall() {
+    this.getTarget() = any(SystemTextCompositeFormatClass x).getParseMethod()
+  }
+
+  override Expr getFormatExpr() { result = this.getArgument(0) }
+}
 
 module FormatInvalidConfig implements DataFlow::ConfigSig {
   predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
 
-  predicate isSink(DataFlow::Node n) { exists(FormatCall c | n.asExpr() = c.getFormatExpr()) }
+  predicate isSink(DataFlow::Node n) {
+    exists(FormatStringParseCall c | n.asExpr() = c.getFormatExpr())
+  }
 }
 
 module FormatInvalid = DataFlow::Global<FormatInvalidConfig>;
 
+module FormatLiteralConfig implements DataFlow::ConfigSig {
+  predicate isSource(DataFlow::Node n) { n.asExpr() instanceof StringLiteral }
+
+  predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
+    // Add flow via `System.Text.CompositeFormat.Parse`.
+    exists(ParseFormatStringCall call |
+      pred.asExpr() = call.getFormatExpr() and
+      succ.asExpr() = call
+    )
+  }
+
+  predicate isSink(DataFlow::Node n) { exists(FormatCall c | n.asExpr() = c.getFormatExpr()) }
+}
+
+module FormatLiteral = DataFlow::Global<FormatLiteralConfig>;
+
+module FormatFlow =
+  DataFlow::MergePathGraph<FormatInvalid::PathNode, FormatLiteral::PathNode,
+    FormatInvalid::PathGraph, FormatLiteral::PathGraph>;
+
 private predicate invalidFormatString(
   InvalidFormatString src, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
-  FormatCall call, string callString
+  FormatStringParseCall call, string callString
 ) {
   source.getNode().asExpr() = src and
   sink.getNode().asExpr() = call.getFormatExpr() and
   FormatInvalid::flowPath(source, sink) and
-  call.hasInsertions() and
   msg = "Invalid format string used in $@ formatting call." and
   callString = "this"
 }
 
 private predicate unusedArgument(
-  FormatCall call, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
+  FormatCall call, FormatLiteral::PathNode source, FormatLiteral::PathNode sink, string msg,
   ValidFormatString src, string srcString, Expr unusedExpr, string unusedString
 ) {
   exists(int unused |
     source.getNode().asExpr() = src and
     sink.getNode().asExpr() = call.getFormatExpr() and
-    FormatInvalid::flowPath(source, sink) and
+    FormatLiteral::flowPath(source, sink) and
     unused = call.getASuppliedArgument() and
     not unused = src.getAnInsert() and
     not src.getValue() = "" and
@@ -53,13 +91,13 @@ private predicate unusedArgument(
 }
 
 private predicate missingArgument(
-  FormatCall call, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
+  FormatCall call, FormatLiteral::PathNode source, FormatLiteral::PathNode sink, string msg,
   ValidFormatString src, string srcString
 ) {
   exists(int used, int supplied |
     source.getNode().asExpr() = src and
     sink.getNode().asExpr() = call.getFormatExpr() and
-    FormatInvalid::flowPath(source, sink) and
+    FormatLiteral::flowPath(source, sink) and
     used = src.getAnInsert() and
     supplied = call.getSuppliedArguments() and
     used >= supplied and
@@ -69,16 +107,17 @@ private predicate missingArgument(
 }
 
 from
-  Element alert, FormatInvalid::PathNode source, FormatInvalid::PathNode sink, string msg,
-  Element extra1, string extra1String, Element extra2, string extra2String
+  Element alert, FormatFlow::PathNode source, FormatFlow::PathNode sink, string msg, Element extra1,
+  string extra1String, Element extra2, string extra2String
 where
-  invalidFormatString(alert, source, sink, msg, extra1, extra1String) and
+  invalidFormatString(alert, source.asPathNode1(), sink.asPathNode1(), msg, extra1, extra1String) and
   extra2 = extra1 and
   extra2String = extra1String
   or
-  unusedArgument(alert, source, sink, msg, extra1, extra1String, extra2, extra2String)
+  unusedArgument(alert, source.asPathNode2(), sink.asPathNode2(), msg, extra1, extra1String, extra2,
+    extra2String)
   or
-  missingArgument(alert, source, sink, msg, extra1, extra1String) and
+  missingArgument(alert, source.asPathNode2(), sink.asPathNode2(), msg, extra1, extra1String) and
   extra2 = extra1 and
   extra2String = extra1String
 select alert, source, sink, msg, extra1, extra1String, extra2, extra2String
diff --git a/csharp/ql/src/change-notes/2025-04-10-invalid-string-format.md b/csharp/ql/src/change-notes/2025-04-10-invalid-string-format.md
new file mode 100644
index 000000000000..1d1d424d985f
--- /dev/null
+++ b/csharp/ql/src/change-notes/2025-04-10-invalid-string-format.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* The precision of the query `cs/invalid-string-formatting` has been improved. More methods and more overloads of existing format like methods are taken into account by the query.
diff --git a/csharp/ql/src/codeql-suites/csharp-code-quality.qls b/csharp/ql/src/codeql-suites/csharp-code-quality.qls
index a7cfd44d7348..64a100acda22 100644
--- a/csharp/ql/src/codeql-suites/csharp-code-quality.qls
+++ b/csharp/ql/src/codeql-suites/csharp-code-quality.qls
@@ -13,3 +13,4 @@
       - cs/useless-gethashcode-call
       - cs/non-short-circuit
       - cs/useless-assignment-to-local
+      - cs/invalid-string-formatting
diff --git a/csharp/ql/test/library-tests/frameworks/format/StringFormatItemParameter.expected b/csharp/ql/test/library-tests/frameworks/format/StringFormatItemParameter.expected
index 692ec0529bb0..dc3017a5f6f2 100644
--- a/csharp/ql/test/library-tests/frameworks/format/StringFormatItemParameter.expected
+++ b/csharp/ql/test/library-tests/frameworks/format/StringFormatItemParameter.expected
@@ -17,6 +17,12 @@
 | Debug | Assert(bool, string, string, params Object[]) | args |
 | Debug | Print(string, params Object[]) | args |
 | Debug | WriteLine(string, params Object[]) | args |
+| MemoryExtensions | TryWrite(Span<char>, IFormatProvider, CompositeFormat, out int, params Object[]) | args |
+| MemoryExtensions | TryWrite(Span<char>, IFormatProvider, CompositeFormat, out int, params Object[]) | charsWritten |
+| MemoryExtensions | TryWrite(Span<char>, IFormatProvider, CompositeFormat, out int, params ReadOnlySpan<object>) | args |
+| MemoryExtensions | TryWrite(Span<char>, IFormatProvider, CompositeFormat, out int, params ReadOnlySpan<object>) | charsWritten |
+| StringBuilder | AppendFormat(IFormatProvider, CompositeFormat, params Object[]) | args |
+| StringBuilder | AppendFormat(IFormatProvider, CompositeFormat, params ReadOnlySpan<object>) | args |
 | StringBuilder | AppendFormat(IFormatProvider, string, object) | arg0 |
 | StringBuilder | AppendFormat(IFormatProvider, string, object, object) | arg0 |
 | StringBuilder | AppendFormat(IFormatProvider, string, object, object) | arg1 |
@@ -51,6 +57,8 @@
 | TextWriter | WriteLine(string, object, object, object) | arg2 |
 | TextWriter | WriteLine(string, params Object[]) | arg |
 | TextWriter | WriteLine(string, params ReadOnlySpan<object>) | arg |
+| string | Format(IFormatProvider, CompositeFormat, params Object[]) | args |
+| string | Format(IFormatProvider, CompositeFormat, params ReadOnlySpan<object>) | args |
 | string | Format(IFormatProvider, string, object) | arg0 |
 | string | Format(IFormatProvider, string, object, object) | arg0 |
 | string | Format(IFormatProvider, string, object, object) | arg1 |
diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs
index 4789da9cf6b5..75fc5e4ec236 100644
--- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs	
+++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs	
@@ -1,4 +1,5 @@
 using System;
+using System.Globalization;
 using System.Text;
 
 class FormatInvalid
@@ -24,38 +25,38 @@ void FormatStringTests()
         String.Format("{0, -10 :0.000}", 1);
 
         // BAD: Invalid format string
-        String.Format("{ 0}", 1);
+        String.Format("{ 0}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0,--1}", 1);
+        String.Format("{0,--1}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0:{}}", 1);
+        String.Format("{0:{}}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("%d", 1);
+        String.Format("%d", 1); // $ Alert
 
         // BAD: } { in the middle.
-        String.Format("{{0}-{1}}", 0, 1);
+        String.Format("{{0}-{1}}", 0, 1); // $ Alert
 
         // BAD: This is invalid
-        String.Format("{0}}", 0, 1);
+        String.Format("{0}}", 0, 1); // $ Alert
 
         // BAD: Invalid
-        string.Format("{foo{0}}", 0);
+        string.Format("{foo{0}}", 0); // $ Alert
 
         // GOOD: {{ is output as {
-        String.Format("{{sdc}}", 0);
+        String.Format("{{sdc}}{0}", 0);
 
         // BAD: Invalid: Stray }
-        String.Format("}", 0);
+        String.Format("}{0}", 0); // $ Alert
 
         // GOOD: {{ output as {
-        String.Format("new {0} ({1} => {{", 0);
+        String.Format("new {0} ({1} => {{", 0, 1);
 
         // GOOD: Literal {{ and }}
-        String.Format("{{", "");
-        String.Format("{{{{}}", "");
+        String.Format("{0}{{", 0);
+        String.Format("{0}{{{{}}", 0);
     }
 
     IFormatProvider fp;
@@ -72,51 +73,88 @@ void FormatMethodTests()
         Format("}", 0);
 
         // BAD: All of these are format methods with an invalid string.
-        String.Format("}", 0);
-        String.Format("}", ps);
-        String.Format(fp, "}", ps);
-        String.Format("}", 0, 1);
-        String.Format("}", 0, 1, 2);
-        String.Format("}", 0, 1, 2, 3);
-
-        sb.AppendFormat("}", 0);
-        sb.AppendFormat("}", ps);
-        sb.AppendFormat(fp, "}", ps);
-        sb.AppendFormat("}", 0, 1);
-        sb.AppendFormat("}", 0, 1, 2);
-        sb.AppendFormat("}", 0, 1, 2, 3);
-
-        Console.WriteLine("}", 0);
-        Console.WriteLine("}", ps);
-        Console.WriteLine("}", 0, 1);
-        Console.WriteLine("}", 0, 1, 2);
-        Console.WriteLine("}", 0, 1, 2, 3);
-
-        tw.WriteLine("}", 0);
-        tw.WriteLine("}", ps);
-        tw.WriteLine("}", 0, 1);
-        tw.WriteLine("}", 0, 1, 2);
-        tw.WriteLine("}", 0, 1, 2, 3);
-
-        System.Diagnostics.Debug.WriteLine("}", ps);
-        System.Diagnostics.Trace.TraceError("}", 0);
-        System.Diagnostics.Trace.TraceInformation("}", 0);
-        System.Diagnostics.Trace.TraceWarning("}", 0);
-        ts.TraceInformation("}", 0);
-
-        Console.Write("}", 0);
-        Console.Write("}", 0, 1);
-        Console.Write("}", 0, 1, 2);
-        Console.Write("}", 0, 1, 2, 3);
+        String.Format("}"); // $ Alert
+        String.Format("}", 0); // $ Alert
+        String.Format("}", ps); // $ Alert
+        String.Format(fp, "}", ps); // $ Alert
+        String.Format("}", 0, 1); // $ Alert
+        String.Format("}", 0, 1, 2); // $ Alert
+        String.Format("}", 0, 1, 2, 3); // $ Alert
+
+        sb.AppendFormat("}"); // $ Alert
+        sb.AppendFormat("}", 0); // $ Alert
+        sb.AppendFormat("}", ps); // $ Alert
+        sb.AppendFormat(fp, "}", ps); // $ Alert
+        sb.AppendFormat("}", 0, 1); // $ Alert
+        sb.AppendFormat("}", 0, 1, 2); // $ Alert
+        sb.AppendFormat("}", 0, 1, 2, 3); // $ Alert
+
+        Console.WriteLine("}", 0); // $ Alert
+        Console.WriteLine("}", ps); // $ Alert
+        Console.WriteLine("}", 0, 1); // $ Alert
+        Console.WriteLine("}", 0, 1, 2); // $ Alert
+        Console.WriteLine("}", 0, 1, 2, 3); // $ Alert
+
+        tw.WriteLine("}", 0); // $ Alert
+        tw.WriteLine("}", ps); // $ Alert
+        tw.WriteLine("}", 0, 1); // $ Alert
+        tw.WriteLine("}", 0, 1, 2); // $ Alert
+        tw.WriteLine("}", 0, 1, 2, 3); // $ Alert
+
+        System.Diagnostics.Debug.WriteLine("}", ps); // $ Alert
+        System.Diagnostics.Trace.TraceError("}", 0); // $ Alert
+        System.Diagnostics.Trace.TraceInformation("}", 0); // $ Alert
+        System.Diagnostics.Trace.TraceWarning("}", 0); // $ Alert
+        ts.TraceInformation("}", 0); // $ Alert
+
+        Console.Write("}", 0); // $ Alert
+        Console.Write("}", 0, 1); // $ Alert
+        Console.Write("}", 0, 1, 2); // $ Alert
+        Console.Write("}", 0, 1, 2, 3); // $ Alert
 
         System.Diagnostics.Debug.WriteLine("}", ""); // GOOD
         System.Diagnostics.Debug.Write("}", "");     // GOOD
 
-        System.Diagnostics.Debug.Assert(true, "Error", "}", ps);
-        sw.Write("}", 0);
-        System.Diagnostics.Debug.Print("}", ps);
+        System.Diagnostics.Debug.Assert(true, "Error", "}", ps); // $ Alert
+        sw.Write("}", 0); // $ Alert
+        System.Diagnostics.Debug.Print("}", ps); // $ Alert
 
         Console.WriteLine("}"); // GOOD
+
+        // The Following methods are not recognised as format methods.
+        Console.WriteLine("{0}"); // GOOD
+        Console.Write("{0}"); // GOOD
+        tw.WriteLine("{0}"); // GOOD
+        tw.Write("{0}"); // GOOD
+        System.Diagnostics.Debug.Print("{0}"); // GOOD
+        System.Diagnostics.Debug.WriteLine("{0}"); // GOOD
+        System.Diagnostics.Debug.Write("{0}");     // GOOD
+        System.Diagnostics.Trace.TraceError("{0}"); // GOOD
+        System.Diagnostics.Trace.TraceInformation("{0}"); // GOOD
+        System.Diagnostics.Trace.TraceWarning("{0}"); // GOOD
+        ts.TraceInformation("{0}"); // GOOD
+    }
+
+    void CompositeFormatMethods()
+    {
+        var format = CompositeFormat.Parse("}"); // $ Alert
+
+        // GOOD: Format is invalid and this flagged during parsing.
+        String.Format<string>(null, format, "");
+        String.Format<string, string>(null, format, "", "");
+        String.Format<string, string, string>(null, format, "", "", "");
+
+        sb.AppendFormat(null, format, "");
+        sb.AppendFormat<string>(null, format, "");
+        sb.AppendFormat<string, string>(null, format, "", "");
+        sb.AppendFormat<string, string, string>(null, format, "", "", "");
+
+
+        var span = new Span<char>();
+        span.TryWrite(null, format, out _);
+        span.TryWrite<object>(null, format, out _, new object());
+        span.TryWrite<object, object>(null, format, out _, new object(), new object());
+        span.TryWrite<object, object, object>(null, format, out _, "", "", "");
     }
 
     System.IO.StringWriter sw;
diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected
index a1c5e9254370..a33793ae461a 100644
--- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected	
+++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.expected	
@@ -1,160 +1,401 @@
+#select
+| FormatInvalid.cs:28:23:28:28 | "{ 0}" | FormatInvalid.cs:28:23:28:28 | "{ 0}" | FormatInvalid.cs:28:23:28:28 | "{ 0}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:28:9:28:32 | call to method Format | this | FormatInvalid.cs:28:9:28:32 | call to method Format | this |
+| FormatInvalid.cs:31:23:31:31 | "{0,--1}" | FormatInvalid.cs:31:23:31:31 | "{0,--1}" | FormatInvalid.cs:31:23:31:31 | "{0,--1}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:31:9:31:35 | call to method Format | this | FormatInvalid.cs:31:9:31:35 | call to method Format | this |
+| FormatInvalid.cs:34:23:34:30 | "{0:{}}" | FormatInvalid.cs:34:23:34:30 | "{0:{}}" | FormatInvalid.cs:34:23:34:30 | "{0:{}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:34:9:34:34 | call to method Format | this | FormatInvalid.cs:34:9:34:34 | call to method Format | this |
+| FormatInvalid.cs:37:9:37:30 | call to method Format | FormatInvalid.cs:37:23:37:26 | "%d" | FormatInvalid.cs:37:23:37:26 | "%d" | The $@ ignores $@. | FormatInvalid.cs:37:23:37:26 | "%d" | format string | FormatInvalid.cs:37:29:37:29 | (...) ... | this supplied value |
+| FormatInvalid.cs:40:23:40:33 | "{{0}-{1}}" | FormatInvalid.cs:40:23:40:33 | "{{0}-{1}}" | FormatInvalid.cs:40:23:40:33 | "{{0}-{1}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:40:9:40:40 | call to method Format | this | FormatInvalid.cs:40:9:40:40 | call to method Format | this |
+| FormatInvalid.cs:43:23:43:28 | "{0}}" | FormatInvalid.cs:43:23:43:28 | "{0}}" | FormatInvalid.cs:43:23:43:28 | "{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:43:9:43:35 | call to method Format | this | FormatInvalid.cs:43:9:43:35 | call to method Format | this |
+| FormatInvalid.cs:46:23:46:32 | "{foo{0}}" | FormatInvalid.cs:46:23:46:32 | "{foo{0}}" | FormatInvalid.cs:46:23:46:32 | "{foo{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:46:9:46:36 | call to method Format | this | FormatInvalid.cs:46:9:46:36 | call to method Format | this |
+| FormatInvalid.cs:52:23:52:28 | "}{0}" | FormatInvalid.cs:52:23:52:28 | "}{0}" | FormatInvalid.cs:52:23:52:28 | "}{0}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:52:9:52:32 | call to method Format | this | FormatInvalid.cs:52:9:52:32 | call to method Format | this |
+| FormatInvalid.cs:76:23:76:25 | "}" | FormatInvalid.cs:76:23:76:25 | "}" | FormatInvalid.cs:76:23:76:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:76:9:76:26 | call to method Format | this | FormatInvalid.cs:76:9:76:26 | call to method Format | this |
+| FormatInvalid.cs:77:23:77:25 | "}" | FormatInvalid.cs:77:23:77:25 | "}" | FormatInvalid.cs:77:23:77:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:77:9:77:29 | call to method Format | this | FormatInvalid.cs:77:9:77:29 | call to method Format | this |
+| FormatInvalid.cs:78:23:78:25 | "}" | FormatInvalid.cs:78:23:78:25 | "}" | FormatInvalid.cs:78:23:78:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:78:9:78:30 | call to method Format | this | FormatInvalid.cs:78:9:78:30 | call to method Format | this |
+| FormatInvalid.cs:79:27:79:29 | "}" | FormatInvalid.cs:79:27:79:29 | "}" | FormatInvalid.cs:79:27:79:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:79:9:79:34 | call to method Format | this | FormatInvalid.cs:79:9:79:34 | call to method Format | this |
+| FormatInvalid.cs:80:23:80:25 | "}" | FormatInvalid.cs:80:23:80:25 | "}" | FormatInvalid.cs:80:23:80:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:80:9:80:32 | call to method Format | this | FormatInvalid.cs:80:9:80:32 | call to method Format | this |
+| FormatInvalid.cs:81:23:81:25 | "}" | FormatInvalid.cs:81:23:81:25 | "}" | FormatInvalid.cs:81:23:81:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:81:9:81:35 | call to method Format | this | FormatInvalid.cs:81:9:81:35 | call to method Format | this |
+| FormatInvalid.cs:82:23:82:25 | "}" | FormatInvalid.cs:82:23:82:25 | "}" | FormatInvalid.cs:82:23:82:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:82:9:82:38 | call to method Format | this | FormatInvalid.cs:82:9:82:38 | call to method Format | this |
+| FormatInvalid.cs:84:25:84:27 | "}" | FormatInvalid.cs:84:25:84:27 | "}" | FormatInvalid.cs:84:25:84:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:84:9:84:28 | call to method AppendFormat | this | FormatInvalid.cs:84:9:84:28 | call to method AppendFormat | this |
+| FormatInvalid.cs:85:25:85:27 | "}" | FormatInvalid.cs:85:25:85:27 | "}" | FormatInvalid.cs:85:25:85:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:85:9:85:31 | call to method AppendFormat | this | FormatInvalid.cs:85:9:85:31 | call to method AppendFormat | this |
+| FormatInvalid.cs:86:25:86:27 | "}" | FormatInvalid.cs:86:25:86:27 | "}" | FormatInvalid.cs:86:25:86:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:86:9:86:32 | call to method AppendFormat | this | FormatInvalid.cs:86:9:86:32 | call to method AppendFormat | this |
+| FormatInvalid.cs:87:29:87:31 | "}" | FormatInvalid.cs:87:29:87:31 | "}" | FormatInvalid.cs:87:29:87:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:87:9:87:36 | call to method AppendFormat | this | FormatInvalid.cs:87:9:87:36 | call to method AppendFormat | this |
+| FormatInvalid.cs:88:25:88:27 | "}" | FormatInvalid.cs:88:25:88:27 | "}" | FormatInvalid.cs:88:25:88:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:88:9:88:34 | call to method AppendFormat | this | FormatInvalid.cs:88:9:88:34 | call to method AppendFormat | this |
+| FormatInvalid.cs:89:25:89:27 | "}" | FormatInvalid.cs:89:25:89:27 | "}" | FormatInvalid.cs:89:25:89:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:89:9:89:37 | call to method AppendFormat | this | FormatInvalid.cs:89:9:89:37 | call to method AppendFormat | this |
+| FormatInvalid.cs:90:25:90:27 | "}" | FormatInvalid.cs:90:25:90:27 | "}" | FormatInvalid.cs:90:25:90:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:90:9:90:40 | call to method AppendFormat | this | FormatInvalid.cs:90:9:90:40 | call to method AppendFormat | this |
+| FormatInvalid.cs:92:27:92:29 | "}" | FormatInvalid.cs:92:27:92:29 | "}" | FormatInvalid.cs:92:27:92:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:92:9:92:33 | call to method WriteLine | this | FormatInvalid.cs:92:9:92:33 | call to method WriteLine | this |
+| FormatInvalid.cs:93:27:93:29 | "}" | FormatInvalid.cs:93:27:93:29 | "}" | FormatInvalid.cs:93:27:93:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:93:9:93:34 | call to method WriteLine | this | FormatInvalid.cs:93:9:93:34 | call to method WriteLine | this |
+| FormatInvalid.cs:94:27:94:29 | "}" | FormatInvalid.cs:94:27:94:29 | "}" | FormatInvalid.cs:94:27:94:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:94:9:94:36 | call to method WriteLine | this | FormatInvalid.cs:94:9:94:36 | call to method WriteLine | this |
+| FormatInvalid.cs:95:27:95:29 | "}" | FormatInvalid.cs:95:27:95:29 | "}" | FormatInvalid.cs:95:27:95:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:95:9:95:39 | call to method WriteLine | this | FormatInvalid.cs:95:9:95:39 | call to method WriteLine | this |
+| FormatInvalid.cs:96:27:96:29 | "}" | FormatInvalid.cs:96:27:96:29 | "}" | FormatInvalid.cs:96:27:96:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:96:9:96:42 | call to method WriteLine | this | FormatInvalid.cs:96:9:96:42 | call to method WriteLine | this |
+| FormatInvalid.cs:98:22:98:24 | "}" | FormatInvalid.cs:98:22:98:24 | "}" | FormatInvalid.cs:98:22:98:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:98:9:98:28 | call to method WriteLine | this | FormatInvalid.cs:98:9:98:28 | call to method WriteLine | this |
+| FormatInvalid.cs:99:22:99:24 | "}" | FormatInvalid.cs:99:22:99:24 | "}" | FormatInvalid.cs:99:22:99:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:99:9:99:29 | call to method WriteLine | this | FormatInvalid.cs:99:9:99:29 | call to method WriteLine | this |
+| FormatInvalid.cs:100:22:100:24 | "}" | FormatInvalid.cs:100:22:100:24 | "}" | FormatInvalid.cs:100:22:100:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:100:9:100:31 | call to method WriteLine | this | FormatInvalid.cs:100:9:100:31 | call to method WriteLine | this |
+| FormatInvalid.cs:101:22:101:24 | "}" | FormatInvalid.cs:101:22:101:24 | "}" | FormatInvalid.cs:101:22:101:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:101:9:101:34 | call to method WriteLine | this | FormatInvalid.cs:101:9:101:34 | call to method WriteLine | this |
+| FormatInvalid.cs:102:22:102:24 | "}" | FormatInvalid.cs:102:22:102:24 | "}" | FormatInvalid.cs:102:22:102:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:102:9:102:37 | call to method WriteLine | this | FormatInvalid.cs:102:9:102:37 | call to method WriteLine | this |
+| FormatInvalid.cs:104:44:104:46 | "}" | FormatInvalid.cs:104:44:104:46 | "}" | FormatInvalid.cs:104:44:104:46 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:104:9:104:51 | call to method WriteLine | this | FormatInvalid.cs:104:9:104:51 | call to method WriteLine | this |
+| FormatInvalid.cs:105:45:105:47 | "}" | FormatInvalid.cs:105:45:105:47 | "}" | FormatInvalid.cs:105:45:105:47 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:105:9:105:51 | call to method TraceError | this | FormatInvalid.cs:105:9:105:51 | call to method TraceError | this |
+| FormatInvalid.cs:106:51:106:53 | "}" | FormatInvalid.cs:106:51:106:53 | "}" | FormatInvalid.cs:106:51:106:53 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:106:9:106:57 | call to method TraceInformation | this | FormatInvalid.cs:106:9:106:57 | call to method TraceInformation | this |
+| FormatInvalid.cs:107:47:107:49 | "}" | FormatInvalid.cs:107:47:107:49 | "}" | FormatInvalid.cs:107:47:107:49 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:107:9:107:53 | call to method TraceWarning | this | FormatInvalid.cs:107:9:107:53 | call to method TraceWarning | this |
+| FormatInvalid.cs:108:29:108:31 | "}" | FormatInvalid.cs:108:29:108:31 | "}" | FormatInvalid.cs:108:29:108:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:108:9:108:35 | call to method TraceInformation | this | FormatInvalid.cs:108:9:108:35 | call to method TraceInformation | this |
+| FormatInvalid.cs:110:23:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:110:9:110:29 | call to method Write | this | FormatInvalid.cs:110:9:110:29 | call to method Write | this |
+| FormatInvalid.cs:111:23:111:25 | "}" | FormatInvalid.cs:111:23:111:25 | "}" | FormatInvalid.cs:111:23:111:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:111:9:111:32 | call to method Write | this | FormatInvalid.cs:111:9:111:32 | call to method Write | this |
+| FormatInvalid.cs:112:23:112:25 | "}" | FormatInvalid.cs:112:23:112:25 | "}" | FormatInvalid.cs:112:23:112:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:112:9:112:35 | call to method Write | this | FormatInvalid.cs:112:9:112:35 | call to method Write | this |
+| FormatInvalid.cs:113:23:113:25 | "}" | FormatInvalid.cs:113:23:113:25 | "}" | FormatInvalid.cs:113:23:113:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:113:9:113:38 | call to method Write | this | FormatInvalid.cs:113:9:113:38 | call to method Write | this |
+| FormatInvalid.cs:118:56:118:58 | "}" | FormatInvalid.cs:118:56:118:58 | [assertion success] "}" | FormatInvalid.cs:118:56:118:58 | [assertion success] "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:118:9:118:63 | call to method Assert | this | FormatInvalid.cs:118:9:118:63 | call to method Assert | this |
+| FormatInvalid.cs:119:18:119:20 | "}" | FormatInvalid.cs:119:18:119:20 | "}" | FormatInvalid.cs:119:18:119:20 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:119:9:119:24 | call to method Write | this | FormatInvalid.cs:119:9:119:24 | call to method Write | this |
+| FormatInvalid.cs:120:40:120:42 | "}" | FormatInvalid.cs:120:40:120:42 | "}" | FormatInvalid.cs:120:40:120:42 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:120:9:120:47 | call to method Print | this | FormatInvalid.cs:120:9:120:47 | call to method Print | this |
+| FormatInvalid.cs:140:44:140:46 | "}" | FormatInvalid.cs:140:44:140:46 | "}" | FormatInvalid.cs:140:44:140:46 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:140:22:140:47 | call to method Parse | this | FormatInvalid.cs:140:22:140:47 | call to method Parse | this |
+| FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | Invalid format string used in $@ formatting call. | FormatInvalidBad.cs:7:16:7:50 | call to method Format | this | FormatInvalidBad.cs:7:16:7:50 | call to method Format | this |
+| FormatMissingArgument.cs:12:9:12:31 | call to method Format | FormatMissingArgument.cs:12:23:12:27 | "{1}" | FormatMissingArgument.cs:12:23:12:27 | "{1}" | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:12:23:12:27 | "{1}" | this | FormatMissingArgument.cs:12:23:12:27 | "{1}" | this |
+| FormatMissingArgument.cs:12:9:12:31 | call to method Format | FormatMissingArgument.cs:12:23:12:27 | "{1}" | FormatMissingArgument.cs:12:23:12:27 | "{1}" | The $@ ignores $@. | FormatMissingArgument.cs:12:23:12:27 | "{1}" | format string | FormatMissingArgument.cs:12:30:12:30 | (...) ... | this supplied value |
+| FormatMissingArgument.cs:15:9:15:38 | call to method Format | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | this | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | this |
+| FormatMissingArgument.cs:15:9:15:38 | call to method Format | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | this | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | this |
+| FormatMissingArgument.cs:15:9:15:38 | call to method Format | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | The $@ ignores $@. | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | format string | FormatMissingArgument.cs:15:34:15:34 | (...) ... | this supplied value |
+| FormatMissingArgument.cs:15:9:15:38 | call to method Format | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | The $@ ignores $@. | FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | format string | FormatMissingArgument.cs:15:37:15:37 | (...) ... | this supplied value |
+| FormatMissingArgument.cs:32:9:32:32 | call to method Format | FormatMissingArgument.cs:26:16:26:20 | "{1}" : String | FormatMissingArgument.cs:32:23:32:28 | access to parameter format | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:26:16:26:20 | "{1}" | this | FormatMissingArgument.cs:26:16:26:20 | "{1}" | this |
+| FormatMissingArgument.cs:32:9:32:32 | call to method Format | FormatMissingArgument.cs:26:16:26:20 | "{1}" : String | FormatMissingArgument.cs:32:23:32:28 | access to parameter format | The $@ ignores $@. | FormatMissingArgument.cs:26:16:26:20 | "{1}" | format string | FormatMissingArgument.cs:32:31:32:31 | (...) ... | this supplied value |
+| FormatMissingArgument.cs:46:9:46:48 | call to method Format<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:46:37:46:43 | access to local variable format1 | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this |
+| FormatMissingArgument.cs:46:9:46:48 | call to method Format<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:46:37:46:43 | access to local variable format1 | The $@ ignores $@. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | format string | FormatMissingArgument.cs:46:46:46:47 | "" | this supplied value |
+| FormatMissingArgument.cs:52:9:52:61 | call to method Format<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:52:45:52:52 | access to local variable format23 | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this |
+| FormatMissingArgument.cs:52:9:52:61 | call to method Format<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:52:45:52:52 | access to local variable format23 | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this |
+| FormatMissingArgument.cs:52:9:52:61 | call to method Format<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:52:45:52:52 | access to local variable format23 | The $@ ignores $@. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | format string | FormatMissingArgument.cs:52:55:52:56 | "" | this supplied value |
+| FormatMissingArgument.cs:52:9:52:61 | call to method Format<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:52:45:52:52 | access to local variable format23 | The $@ ignores $@. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | format string | FormatMissingArgument.cs:52:59:52:60 | "" | this supplied value |
+| FormatMissingArgument.cs:60:9:60:42 | call to method AppendFormat<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:60:31:60:37 | access to local variable format1 | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this |
+| FormatMissingArgument.cs:60:9:60:42 | call to method AppendFormat<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:60:31:60:37 | access to local variable format1 | The $@ ignores $@. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | format string | FormatMissingArgument.cs:60:40:60:41 | "" | this supplied value |
+| FormatMissingArgument.cs:61:9:61:50 | call to method AppendFormat<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:61:39:61:45 | access to local variable format1 | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this |
+| FormatMissingArgument.cs:61:9:61:50 | call to method AppendFormat<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:61:39:61:45 | access to local variable format1 | The $@ ignores $@. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | format string | FormatMissingArgument.cs:61:48:61:49 | "" | this supplied value |
+| FormatMissingArgument.cs:67:9:67:63 | call to method AppendFormat<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:67:47:67:54 | access to local variable format23 | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this |
+| FormatMissingArgument.cs:67:9:67:63 | call to method AppendFormat<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:67:47:67:54 | access to local variable format23 | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this |
+| FormatMissingArgument.cs:67:9:67:63 | call to method AppendFormat<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:67:47:67:54 | access to local variable format23 | The $@ ignores $@. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | format string | FormatMissingArgument.cs:67:57:67:58 | "" | this supplied value |
+| FormatMissingArgument.cs:67:9:67:63 | call to method AppendFormat<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:67:47:67:54 | access to local variable format23 | The $@ ignores $@. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | format string | FormatMissingArgument.cs:67:61:67:62 | "" | this supplied value |
+| FormatMissingArgument.cs:77:9:77:47 | call to method TryWrite<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:77:29:77:35 | access to local variable format1 | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this |
+| FormatMissingArgument.cs:77:9:77:47 | call to method TryWrite<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:77:29:77:35 | access to local variable format1 | The $@ ignores $@. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | format string | FormatMissingArgument.cs:77:45:77:46 | "" | this supplied value |
+| FormatMissingArgument.cs:78:9:78:55 | call to method TryWrite<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:78:37:78:43 | access to local variable format1 | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this | FormatMissingArgument.cs:38:45:38:49 | "{1}" | this |
+| FormatMissingArgument.cs:78:9:78:55 | call to method TryWrite<String> | FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:78:37:78:43 | access to local variable format1 | The $@ ignores $@. | FormatMissingArgument.cs:38:45:38:49 | "{1}" | format string | FormatMissingArgument.cs:78:53:78:54 | "" | this supplied value |
+| FormatMissingArgument.cs:84:9:84:68 | call to method TryWrite<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:84:45:84:52 | access to local variable format23 | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this |
+| FormatMissingArgument.cs:84:9:84:68 | call to method TryWrite<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:84:45:84:52 | access to local variable format23 | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | this |
+| FormatMissingArgument.cs:84:9:84:68 | call to method TryWrite<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:84:45:84:52 | access to local variable format23 | The $@ ignores $@. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | format string | FormatMissingArgument.cs:84:62:84:63 | "" | this supplied value |
+| FormatMissingArgument.cs:84:9:84:68 | call to method TryWrite<String,String> | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:84:45:84:52 | access to local variable format23 | The $@ ignores $@. | FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | format string | FormatMissingArgument.cs:84:66:84:67 | "" | this supplied value |
+| FormatMissingArgumentBad.cs:7:9:7:49 | call to method WriteLine | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | this | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | this |
+| FormatMissingArgumentBad.cs:8:9:8:55 | call to method WriteLine | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | this | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | this |
+| FormatMissingArgumentBad.cs:8:9:8:55 | call to method WriteLine | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | The $@ ignores $@. | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | format string | FormatMissingArgumentBad.cs:8:44:8:48 | access to parameter first | this supplied value |
+| FormatUnusedArgument.cs:12:9:12:29 | call to method Format | FormatUnusedArgument.cs:12:23:12:25 | "X" | FormatUnusedArgument.cs:12:23:12:25 | "X" | The $@ ignores $@. | FormatUnusedArgument.cs:12:23:12:25 | "X" | format string | FormatUnusedArgument.cs:12:28:12:28 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:15:9:15:34 | call to method Format | FormatUnusedArgument.cs:15:23:15:27 | "{0}" | FormatUnusedArgument.cs:15:23:15:27 | "{0}" | The $@ ignores $@. | FormatUnusedArgument.cs:15:23:15:27 | "{0}" | format string | FormatUnusedArgument.cs:15:33:15:33 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:18:9:18:38 | call to method Format | FormatUnusedArgument.cs:18:23:18:31 | "{0} {0}" | FormatUnusedArgument.cs:18:23:18:31 | "{0} {0}" | The $@ ignores $@. | FormatUnusedArgument.cs:18:23:18:31 | "{0} {0}" | format string | FormatUnusedArgument.cs:18:37:18:37 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:21:9:21:38 | call to method Format | FormatUnusedArgument.cs:21:23:21:31 | "{1} {1}" | FormatUnusedArgument.cs:21:23:21:31 | "{1} {1}" | The $@ ignores $@. | FormatUnusedArgument.cs:21:23:21:31 | "{1} {1}" | format string | FormatUnusedArgument.cs:21:34:21:34 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:24:9:24:41 | call to method Format | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | format string | FormatUnusedArgument.cs:24:34:24:34 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:24:9:24:41 | call to method Format | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | format string | FormatUnusedArgument.cs:24:37:24:37 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:24:9:24:41 | call to method Format | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | format string | FormatUnusedArgument.cs:24:40:24:40 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:27:9:27:35 | call to method Format | FormatUnusedArgument.cs:27:23:27:31 | "{{sdc}}" | FormatUnusedArgument.cs:27:23:27:31 | "{{sdc}}" | The $@ ignores $@. | FormatUnusedArgument.cs:27:23:27:31 | "{{sdc}}" | format string | FormatUnusedArgument.cs:27:34:27:34 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:39:9:39:33 | call to method Format | FormatUnusedArgument.cs:39:23:39:29 | "{{0}}" | FormatUnusedArgument.cs:39:23:39:29 | "{{0}}" | The $@ ignores $@. | FormatUnusedArgument.cs:39:23:39:29 | "{{0}}" | format string | FormatUnusedArgument.cs:39:32:39:32 | (...) ... | this supplied value |
+| FormatUnusedArgument.cs:53:9:53:47 | call to method Format<String> | FormatUnusedArgument.cs:48:44:48:46 | "X" : String | FormatUnusedArgument.cs:53:37:53:42 | access to local variable format | The $@ ignores $@. | FormatUnusedArgument.cs:48:44:48:46 | "X" | format string | FormatUnusedArgument.cs:53:45:53:46 | "" | this supplied value |
+| FormatUnusedArgument.cs:56:9:56:61 | call to method Format<String,String> | FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" : String | FormatUnusedArgument.cs:56:45:56:52 | access to local variable format00 | The $@ ignores $@. | FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" | format string | FormatUnusedArgument.cs:56:59:56:60 | "" | this supplied value |
+| FormatUnusedArgument.cs:59:9:59:61 | call to method Format<String,String> | FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" : String | FormatUnusedArgument.cs:59:45:59:52 | access to local variable format11 | The $@ ignores $@. | FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" | format string | FormatUnusedArgument.cs:59:55:59:56 | "" | this supplied value |
+| FormatUnusedArgument.cs:62:9:62:41 | call to method AppendFormat<String> | FormatUnusedArgument.cs:48:44:48:46 | "X" : String | FormatUnusedArgument.cs:62:31:62:36 | access to local variable format | The $@ ignores $@. | FormatUnusedArgument.cs:48:44:48:46 | "X" | format string | FormatUnusedArgument.cs:62:39:62:40 | "" | this supplied value |
+| FormatUnusedArgument.cs:63:9:63:49 | call to method AppendFormat<String> | FormatUnusedArgument.cs:48:44:48:46 | "X" : String | FormatUnusedArgument.cs:63:39:63:44 | access to local variable format | The $@ ignores $@. | FormatUnusedArgument.cs:48:44:48:46 | "X" | format string | FormatUnusedArgument.cs:63:47:63:48 | "" | this supplied value |
+| FormatUnusedArgument.cs:66:9:66:63 | call to method AppendFormat<String,String> | FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" : String | FormatUnusedArgument.cs:66:47:66:54 | access to local variable format00 | The $@ ignores $@. | FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" | format string | FormatUnusedArgument.cs:66:61:66:62 | "" | this supplied value |
+| FormatUnusedArgument.cs:69:9:69:63 | call to method AppendFormat<String,String> | FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" : String | FormatUnusedArgument.cs:69:47:69:54 | access to local variable format11 | The $@ ignores $@. | FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" | format string | FormatUnusedArgument.cs:69:57:69:58 | "" | this supplied value |
+| FormatUnusedArgument.cs:74:9:74:46 | call to method TryWrite<String> | FormatUnusedArgument.cs:48:44:48:46 | "X" : String | FormatUnusedArgument.cs:74:29:74:34 | access to local variable format | The $@ ignores $@. | FormatUnusedArgument.cs:48:44:48:46 | "X" | format string | FormatUnusedArgument.cs:74:44:74:45 | "" | this supplied value |
+| FormatUnusedArgument.cs:75:9:75:54 | call to method TryWrite<String> | FormatUnusedArgument.cs:48:44:48:46 | "X" : String | FormatUnusedArgument.cs:75:37:75:42 | access to local variable format | The $@ ignores $@. | FormatUnusedArgument.cs:48:44:48:46 | "X" | format string | FormatUnusedArgument.cs:75:52:75:53 | "" | this supplied value |
+| FormatUnusedArgument.cs:78:9:78:68 | call to method TryWrite<String,String> | FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" : String | FormatUnusedArgument.cs:78:45:78:52 | access to local variable format00 | The $@ ignores $@. | FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" | format string | FormatUnusedArgument.cs:78:66:78:67 | "" | this supplied value |
+| FormatUnusedArgument.cs:81:9:81:68 | call to method TryWrite<String,String> | FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" : String | FormatUnusedArgument.cs:81:45:81:52 | access to local variable format11 | The $@ ignores $@. | FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" | format string | FormatUnusedArgument.cs:81:62:81:63 | "" | this supplied value |
+| FormatUnusedArgumentBad.cs:7:9:7:71 | call to method WriteLine | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | format string | FormatUnusedArgumentBad.cs:7:61:7:70 | (...) ... | this supplied value |
+| FormatUnusedArgumentBad.cs:8:9:8:77 | call to method WriteLine | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | format string | FormatUnusedArgumentBad.cs:8:63:8:64 | access to parameter ex | this supplied value |
+| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:61:9:62 | access to parameter ex | this supplied value |
+| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:65:9:74 | (...) ... | this supplied value |
 edges
-| FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | FormatMissingArgument.cs:28:24:28:29 | format : String | provenance |  |
-| FormatMissingArgument.cs:28:24:28:29 | format : String | FormatMissingArgument.cs:31:23:31:28 | access to parameter format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:143:37:143:42 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:144:45:144:50 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:145:53:145:58 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:147:31:147:36 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:148:39:148:44 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:149:47:149:52 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:150:55:150:60 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:154:29:154:34 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:155:37:155:42 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:156:45:156:50 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | FormatInvalid.cs:157:53:157:58 | access to local variable format | provenance |  |
+| FormatInvalid.cs:140:22:140:47 | call to method Parse : CompositeFormat | FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | provenance |  |
+| FormatInvalid.cs:140:44:140:46 | "}" : String | FormatInvalid.cs:140:22:140:47 | call to method Parse : CompositeFormat | provenance | Config |
+| FormatMissingArgument.cs:26:16:26:20 | "{1}" : String | FormatMissingArgument.cs:29:24:29:29 | format : String | provenance |  |
+| FormatMissingArgument.cs:26:16:26:20 | "{1}" : String | FormatMissingArgument.cs:29:24:29:29 | format : String | provenance |  |
+| FormatMissingArgument.cs:29:24:29:29 | format : String | FormatMissingArgument.cs:32:23:32:28 | access to parameter format | provenance |  |
+| FormatMissingArgument.cs:29:24:29:29 | format : String | FormatMissingArgument.cs:32:23:32:28 | access to parameter format | provenance |  |
+| FormatMissingArgument.cs:37:13:37:19 | access to local variable format0 : CompositeFormat | FormatMissingArgument.cs:43:37:43:43 | access to local variable format0 | provenance |  |
+| FormatMissingArgument.cs:37:13:37:19 | access to local variable format0 : CompositeFormat | FormatMissingArgument.cs:56:31:56:37 | access to local variable format0 | provenance |  |
+| FormatMissingArgument.cs:37:13:37:19 | access to local variable format0 : CompositeFormat | FormatMissingArgument.cs:57:39:57:45 | access to local variable format0 | provenance |  |
+| FormatMissingArgument.cs:37:13:37:19 | access to local variable format0 : CompositeFormat | FormatMissingArgument.cs:73:29:73:35 | access to local variable format0 | provenance |  |
+| FormatMissingArgument.cs:37:13:37:19 | access to local variable format0 : CompositeFormat | FormatMissingArgument.cs:74:37:74:43 | access to local variable format0 | provenance |  |
+| FormatMissingArgument.cs:37:23:37:50 | call to method Parse : CompositeFormat | FormatMissingArgument.cs:37:13:37:19 | access to local variable format0 : CompositeFormat | provenance |  |
+| FormatMissingArgument.cs:37:45:37:49 | "{0}" : String | FormatMissingArgument.cs:37:23:37:50 | call to method Parse : CompositeFormat | provenance | Config |
+| FormatMissingArgument.cs:38:13:38:19 | access to local variable format1 : CompositeFormat | FormatMissingArgument.cs:46:37:46:43 | access to local variable format1 | provenance |  |
+| FormatMissingArgument.cs:38:13:38:19 | access to local variable format1 : CompositeFormat | FormatMissingArgument.cs:60:31:60:37 | access to local variable format1 | provenance |  |
+| FormatMissingArgument.cs:38:13:38:19 | access to local variable format1 : CompositeFormat | FormatMissingArgument.cs:61:39:61:45 | access to local variable format1 | provenance |  |
+| FormatMissingArgument.cs:38:13:38:19 | access to local variable format1 : CompositeFormat | FormatMissingArgument.cs:77:29:77:35 | access to local variable format1 | provenance |  |
+| FormatMissingArgument.cs:38:13:38:19 | access to local variable format1 : CompositeFormat | FormatMissingArgument.cs:78:37:78:43 | access to local variable format1 | provenance |  |
+| FormatMissingArgument.cs:38:23:38:50 | call to method Parse : CompositeFormat | FormatMissingArgument.cs:38:13:38:19 | access to local variable format1 : CompositeFormat | provenance |  |
+| FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | FormatMissingArgument.cs:38:23:38:50 | call to method Parse : CompositeFormat | provenance | Config |
+| FormatMissingArgument.cs:39:13:39:20 | access to local variable format01 : CompositeFormat | FormatMissingArgument.cs:49:45:49:52 | access to local variable format01 | provenance |  |
+| FormatMissingArgument.cs:39:13:39:20 | access to local variable format01 : CompositeFormat | FormatMissingArgument.cs:64:47:64:54 | access to local variable format01 | provenance |  |
+| FormatMissingArgument.cs:39:13:39:20 | access to local variable format01 : CompositeFormat | FormatMissingArgument.cs:81:45:81:52 | access to local variable format01 | provenance |  |
+| FormatMissingArgument.cs:39:24:39:54 | call to method Parse : CompositeFormat | FormatMissingArgument.cs:39:13:39:20 | access to local variable format01 : CompositeFormat | provenance |  |
+| FormatMissingArgument.cs:39:46:39:53 | "{0}{1}" : String | FormatMissingArgument.cs:39:24:39:54 | call to method Parse : CompositeFormat | provenance | Config |
+| FormatMissingArgument.cs:40:13:40:20 | access to local variable format23 : CompositeFormat | FormatMissingArgument.cs:52:45:52:52 | access to local variable format23 | provenance |  |
+| FormatMissingArgument.cs:40:13:40:20 | access to local variable format23 : CompositeFormat | FormatMissingArgument.cs:67:47:67:54 | access to local variable format23 | provenance |  |
+| FormatMissingArgument.cs:40:13:40:20 | access to local variable format23 : CompositeFormat | FormatMissingArgument.cs:84:45:84:52 | access to local variable format23 | provenance |  |
+| FormatMissingArgument.cs:40:24:40:54 | call to method Parse : CompositeFormat | FormatMissingArgument.cs:40:13:40:20 | access to local variable format23 : CompositeFormat | provenance |  |
+| FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | FormatMissingArgument.cs:40:24:40:54 | call to method Parse : CompositeFormat | provenance | Config |
+| FormatUnusedArgument.cs:48:13:48:18 | access to local variable format : CompositeFormat | FormatUnusedArgument.cs:53:37:53:42 | access to local variable format | provenance |  |
+| FormatUnusedArgument.cs:48:13:48:18 | access to local variable format : CompositeFormat | FormatUnusedArgument.cs:62:31:62:36 | access to local variable format | provenance |  |
+| FormatUnusedArgument.cs:48:13:48:18 | access to local variable format : CompositeFormat | FormatUnusedArgument.cs:63:39:63:44 | access to local variable format | provenance |  |
+| FormatUnusedArgument.cs:48:13:48:18 | access to local variable format : CompositeFormat | FormatUnusedArgument.cs:74:29:74:34 | access to local variable format | provenance |  |
+| FormatUnusedArgument.cs:48:13:48:18 | access to local variable format : CompositeFormat | FormatUnusedArgument.cs:75:37:75:42 | access to local variable format | provenance |  |
+| FormatUnusedArgument.cs:48:22:48:47 | call to method Parse : CompositeFormat | FormatUnusedArgument.cs:48:13:48:18 | access to local variable format : CompositeFormat | provenance |  |
+| FormatUnusedArgument.cs:48:44:48:46 | "X" : String | FormatUnusedArgument.cs:48:22:48:47 | call to method Parse : CompositeFormat | provenance | Config |
+| FormatUnusedArgument.cs:49:13:49:20 | access to local variable format00 : CompositeFormat | FormatUnusedArgument.cs:56:45:56:52 | access to local variable format00 | provenance |  |
+| FormatUnusedArgument.cs:49:13:49:20 | access to local variable format00 : CompositeFormat | FormatUnusedArgument.cs:66:47:66:54 | access to local variable format00 | provenance |  |
+| FormatUnusedArgument.cs:49:13:49:20 | access to local variable format00 : CompositeFormat | FormatUnusedArgument.cs:78:45:78:52 | access to local variable format00 | provenance |  |
+| FormatUnusedArgument.cs:49:24:49:54 | call to method Parse : CompositeFormat | FormatUnusedArgument.cs:49:13:49:20 | access to local variable format00 : CompositeFormat | provenance |  |
+| FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" : String | FormatUnusedArgument.cs:49:24:49:54 | call to method Parse : CompositeFormat | provenance | Config |
+| FormatUnusedArgument.cs:50:13:50:20 | access to local variable format11 : CompositeFormat | FormatUnusedArgument.cs:59:45:59:52 | access to local variable format11 | provenance |  |
+| FormatUnusedArgument.cs:50:13:50:20 | access to local variable format11 : CompositeFormat | FormatUnusedArgument.cs:69:47:69:54 | access to local variable format11 | provenance |  |
+| FormatUnusedArgument.cs:50:13:50:20 | access to local variable format11 : CompositeFormat | FormatUnusedArgument.cs:81:45:81:52 | access to local variable format11 | provenance |  |
+| FormatUnusedArgument.cs:50:24:50:54 | call to method Parse : CompositeFormat | FormatUnusedArgument.cs:50:13:50:20 | access to local variable format11 : CompositeFormat | provenance |  |
+| FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" : String | FormatUnusedArgument.cs:50:24:50:54 | call to method Parse : CompositeFormat | provenance | Config |
 nodes
-| FormatInvalid.cs:9:23:9:27 | "{0}" | semmle.label | "{0}" |
-| FormatInvalid.cs:12:23:12:29 | "{0,1}" | semmle.label | "{0,1}" |
-| FormatInvalid.cs:15:23:15:31 | "{0,  1}" | semmle.label | "{0,  1}" |
-| FormatInvalid.cs:18:23:18:30 | "{0,-1}" | semmle.label | "{0,-1}" |
-| FormatInvalid.cs:21:23:21:33 | "{0:0.000}" | semmle.label | "{0:0.000}" |
-| FormatInvalid.cs:24:23:24:39 | "{0, -10 :0.000}" | semmle.label | "{0, -10 :0.000}" |
-| FormatInvalid.cs:27:23:27:28 | "{ 0}" | semmle.label | "{ 0}" |
-| FormatInvalid.cs:30:23:30:31 | "{0,--1}" | semmle.label | "{0,--1}" |
-| FormatInvalid.cs:33:23:33:30 | "{0:{}}" | semmle.label | "{0:{}}" |
-| FormatInvalid.cs:36:23:36:26 | "%d" | semmle.label | "%d" |
-| FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | semmle.label | "{{0}-{1}}" |
-| FormatInvalid.cs:42:23:42:28 | "{0}}" | semmle.label | "{0}}" |
-| FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | semmle.label | "{foo{0}}" |
-| FormatInvalid.cs:48:23:48:31 | "{{sdc}}" | semmle.label | "{{sdc}}" |
-| FormatInvalid.cs:51:23:51:25 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:54:23:54:42 | "new {0} ({1} => {{" | semmle.label | "new {0} ({1} => {{" |
-| FormatInvalid.cs:57:23:57:26 | "{{" | semmle.label | "{{" |
-| FormatInvalid.cs:58:23:58:30 | "{{{{}}" | semmle.label | "{{{{}}" |
-| FormatInvalid.cs:75:23:75:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:10:23:10:27 | "{0}" | semmle.label | "{0}" |
+| FormatInvalid.cs:10:23:10:27 | "{0}" | semmle.label | "{0}" |
+| FormatInvalid.cs:13:23:13:29 | "{0,1}" | semmle.label | "{0,1}" |
+| FormatInvalid.cs:13:23:13:29 | "{0,1}" | semmle.label | "{0,1}" |
+| FormatInvalid.cs:16:23:16:31 | "{0,  1}" | semmle.label | "{0,  1}" |
+| FormatInvalid.cs:16:23:16:31 | "{0,  1}" | semmle.label | "{0,  1}" |
+| FormatInvalid.cs:19:23:19:30 | "{0,-1}" | semmle.label | "{0,-1}" |
+| FormatInvalid.cs:19:23:19:30 | "{0,-1}" | semmle.label | "{0,-1}" |
+| FormatInvalid.cs:22:23:22:33 | "{0:0.000}" | semmle.label | "{0:0.000}" |
+| FormatInvalid.cs:22:23:22:33 | "{0:0.000}" | semmle.label | "{0:0.000}" |
+| FormatInvalid.cs:25:23:25:39 | "{0, -10 :0.000}" | semmle.label | "{0, -10 :0.000}" |
+| FormatInvalid.cs:25:23:25:39 | "{0, -10 :0.000}" | semmle.label | "{0, -10 :0.000}" |
+| FormatInvalid.cs:28:23:28:28 | "{ 0}" | semmle.label | "{ 0}" |
+| FormatInvalid.cs:28:23:28:28 | "{ 0}" | semmle.label | "{ 0}" |
+| FormatInvalid.cs:31:23:31:31 | "{0,--1}" | semmle.label | "{0,--1}" |
+| FormatInvalid.cs:31:23:31:31 | "{0,--1}" | semmle.label | "{0,--1}" |
+| FormatInvalid.cs:34:23:34:30 | "{0:{}}" | semmle.label | "{0:{}}" |
+| FormatInvalid.cs:34:23:34:30 | "{0:{}}" | semmle.label | "{0:{}}" |
+| FormatInvalid.cs:37:23:37:26 | "%d" | semmle.label | "%d" |
+| FormatInvalid.cs:37:23:37:26 | "%d" | semmle.label | "%d" |
+| FormatInvalid.cs:40:23:40:33 | "{{0}-{1}}" | semmle.label | "{{0}-{1}}" |
+| FormatInvalid.cs:40:23:40:33 | "{{0}-{1}}" | semmle.label | "{{0}-{1}}" |
+| FormatInvalid.cs:43:23:43:28 | "{0}}" | semmle.label | "{0}}" |
+| FormatInvalid.cs:43:23:43:28 | "{0}}" | semmle.label | "{0}}" |
+| FormatInvalid.cs:46:23:46:32 | "{foo{0}}" | semmle.label | "{foo{0}}" |
+| FormatInvalid.cs:46:23:46:32 | "{foo{0}}" | semmle.label | "{foo{0}}" |
+| FormatInvalid.cs:49:23:49:34 | "{{sdc}}{0}" | semmle.label | "{{sdc}}{0}" |
+| FormatInvalid.cs:49:23:49:34 | "{{sdc}}{0}" | semmle.label | "{{sdc}}{0}" |
+| FormatInvalid.cs:52:23:52:28 | "}{0}" | semmle.label | "}{0}" |
+| FormatInvalid.cs:52:23:52:28 | "}{0}" | semmle.label | "}{0}" |
+| FormatInvalid.cs:55:23:55:42 | "new {0} ({1} => {{" | semmle.label | "new {0} ({1} => {{" |
+| FormatInvalid.cs:55:23:55:42 | "new {0} ({1} => {{" | semmle.label | "new {0} ({1} => {{" |
+| FormatInvalid.cs:58:23:58:29 | "{0}{{" | semmle.label | "{0}{{" |
+| FormatInvalid.cs:58:23:58:29 | "{0}{{" | semmle.label | "{0}{{" |
+| FormatInvalid.cs:59:23:59:33 | "{0}{{{{}}" | semmle.label | "{0}{{{{}}" |
+| FormatInvalid.cs:59:23:59:33 | "{0}{{{{}}" | semmle.label | "{0}{{{{}}" |
 | FormatInvalid.cs:76:23:76:25 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:77:27:77:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:76:23:76:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:77:23:77:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:77:23:77:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:78:23:78:25 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:78:23:78:25 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:79:23:79:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:79:27:79:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:79:27:79:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:80:23:80:25 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:80:23:80:25 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:82:25:82:27 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:83:25:83:27 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:84:29:84:31 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:81:23:81:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:81:23:81:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:82:23:82:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:82:23:82:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:84:25:84:27 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:84:25:84:27 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:85:25:85:27 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:85:25:85:27 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:86:25:86:27 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:86:25:86:27 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:87:25:87:27 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:89:27:89:29 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:90:27:90:29 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:91:27:91:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:87:29:87:31 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:87:29:87:31 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:88:25:88:27 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:88:25:88:27 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:89:25:89:27 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:89:25:89:27 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:90:25:90:27 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:90:25:90:27 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:92:27:92:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:92:27:92:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:93:27:93:29 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:93:27:93:29 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:95:22:95:24 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:96:22:96:24 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:97:22:97:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:94:27:94:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:94:27:94:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:95:27:95:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:95:27:95:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:96:27:96:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:96:27:96:29 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:98:22:98:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:98:22:98:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:99:22:99:24 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:99:22:99:24 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:101:44:101:46 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:102:45:102:47 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:103:51:103:53 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:104:47:104:49 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:105:29:105:31 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:107:23:107:25 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:108:23:108:25 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:109:23:109:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:100:22:100:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:100:22:100:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:101:22:101:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:101:22:101:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:102:22:102:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:102:22:102:24 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:104:44:104:46 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:104:44:104:46 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:105:45:105:47 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:105:45:105:47 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:106:51:106:53 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:106:51:106:53 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:107:47:107:49 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:107:47:107:49 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:108:29:108:31 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:108:29:108:31 | "}" | semmle.label | "}" |
 | FormatInvalid.cs:110:23:110:25 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:115:56:115:58 | [assertion success] "}" | semmle.label | [assertion success] "}" |
-| FormatInvalid.cs:116:18:116:20 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:117:40:117:42 | "}" | semmle.label | "}" |
-| FormatInvalid.cs:119:27:119:29 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:110:23:110:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:111:23:111:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:111:23:111:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:112:23:112:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:112:23:112:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:113:23:113:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:113:23:113:25 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:118:56:118:58 | [assertion success] "}" | semmle.label | [assertion success] "}" |
+| FormatInvalid.cs:118:56:118:58 | [assertion success] "}" | semmle.label | [assertion success] "}" |
+| FormatInvalid.cs:119:18:119:20 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:119:18:119:20 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:120:40:120:42 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:120:40:120:42 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:140:13:140:18 | access to local variable format : CompositeFormat | semmle.label | access to local variable format : CompositeFormat |
+| FormatInvalid.cs:140:22:140:47 | call to method Parse : CompositeFormat | semmle.label | call to method Parse : CompositeFormat |
+| FormatInvalid.cs:140:44:140:46 | "}" | semmle.label | "}" |
+| FormatInvalid.cs:140:44:140:46 | "}" : String | semmle.label | "}" : String |
+| FormatInvalid.cs:143:37:143:42 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:144:45:144:50 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:145:53:145:58 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:147:31:147:36 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:148:39:148:44 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:149:47:149:52 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:150:55:150:60 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:154:29:154:34 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:155:37:155:42 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:156:45:156:50 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalid.cs:157:53:157:58 | access to local variable format | semmle.label | access to local variable format |
+| FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | semmle.label | "class {0} { }" |
 | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | semmle.label | "class {0} { }" |
 | FormatInvalidGood.cs:7:30:7:46 | "class {0} {{ }}" | semmle.label | "class {0} {{ }}" |
-| FormatMissingArgument.cs:8:23:8:27 | "{0}" | semmle.label | "{0}" |
-| FormatMissingArgument.cs:11:23:11:27 | "{1}" | semmle.label | "{1}" |
-| FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | semmle.label | "{2} {3}" |
-| FormatMissingArgument.cs:17:23:17:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
-| FormatMissingArgument.cs:20:23:20:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" |
-| FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | semmle.label | "{1}" : String |
-| FormatMissingArgument.cs:25:27:25:31 | "{0}" | semmle.label | "{0}" |
-| FormatMissingArgument.cs:28:24:28:29 | format : String | semmle.label | format : String |
-| FormatMissingArgument.cs:31:23:31:28 | access to parameter format | semmle.label | access to parameter format |
+| FormatInvalidGood.cs:7:30:7:46 | "class {0} {{ }}" | semmle.label | "class {0} {{ }}" |
+| FormatMissingArgument.cs:9:23:9:27 | "{0}" | semmle.label | "{0}" |
+| FormatMissingArgument.cs:9:23:9:27 | "{0}" | semmle.label | "{0}" |
+| FormatMissingArgument.cs:12:23:12:27 | "{1}" | semmle.label | "{1}" |
+| FormatMissingArgument.cs:12:23:12:27 | "{1}" | semmle.label | "{1}" |
+| FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | semmle.label | "{2} {3}" |
+| FormatMissingArgument.cs:15:23:15:31 | "{2} {3}" | semmle.label | "{2} {3}" |
+| FormatMissingArgument.cs:18:23:18:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
+| FormatMissingArgument.cs:18:23:18:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
+| FormatMissingArgument.cs:21:23:21:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
+| FormatMissingArgument.cs:21:23:21:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
+| FormatMissingArgument.cs:24:23:24:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" |
+| FormatMissingArgument.cs:24:23:24:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" |
+| FormatMissingArgument.cs:26:16:26:20 | "{1}" : String | semmle.label | "{1}" : String |
+| FormatMissingArgument.cs:26:16:26:20 | "{1}" : String | semmle.label | "{1}" : String |
+| FormatMissingArgument.cs:29:24:29:29 | format : String | semmle.label | format : String |
+| FormatMissingArgument.cs:29:24:29:29 | format : String | semmle.label | format : String |
+| FormatMissingArgument.cs:32:23:32:28 | access to parameter format | semmle.label | access to parameter format |
+| FormatMissingArgument.cs:32:23:32:28 | access to parameter format | semmle.label | access to parameter format |
+| FormatMissingArgument.cs:37:13:37:19 | access to local variable format0 : CompositeFormat | semmle.label | access to local variable format0 : CompositeFormat |
+| FormatMissingArgument.cs:37:23:37:50 | call to method Parse : CompositeFormat | semmle.label | call to method Parse : CompositeFormat |
+| FormatMissingArgument.cs:37:45:37:49 | "{0}" | semmle.label | "{0}" |
+| FormatMissingArgument.cs:37:45:37:49 | "{0}" : String | semmle.label | "{0}" : String |
+| FormatMissingArgument.cs:38:13:38:19 | access to local variable format1 : CompositeFormat | semmle.label | access to local variable format1 : CompositeFormat |
+| FormatMissingArgument.cs:38:23:38:50 | call to method Parse : CompositeFormat | semmle.label | call to method Parse : CompositeFormat |
+| FormatMissingArgument.cs:38:45:38:49 | "{1}" | semmle.label | "{1}" |
+| FormatMissingArgument.cs:38:45:38:49 | "{1}" : String | semmle.label | "{1}" : String |
+| FormatMissingArgument.cs:39:13:39:20 | access to local variable format01 : CompositeFormat | semmle.label | access to local variable format01 : CompositeFormat |
+| FormatMissingArgument.cs:39:24:39:54 | call to method Parse : CompositeFormat | semmle.label | call to method Parse : CompositeFormat |
+| FormatMissingArgument.cs:39:46:39:53 | "{0}{1}" | semmle.label | "{0}{1}" |
+| FormatMissingArgument.cs:39:46:39:53 | "{0}{1}" : String | semmle.label | "{0}{1}" : String |
+| FormatMissingArgument.cs:40:13:40:20 | access to local variable format23 : CompositeFormat | semmle.label | access to local variable format23 : CompositeFormat |
+| FormatMissingArgument.cs:40:24:40:54 | call to method Parse : CompositeFormat | semmle.label | call to method Parse : CompositeFormat |
+| FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" | semmle.label | "{2}{3}" |
+| FormatMissingArgument.cs:40:46:40:53 | "{2}{3}" : String | semmle.label | "{2}{3}" : String |
+| FormatMissingArgument.cs:43:37:43:43 | access to local variable format0 | semmle.label | access to local variable format0 |
+| FormatMissingArgument.cs:46:37:46:43 | access to local variable format1 | semmle.label | access to local variable format1 |
+| FormatMissingArgument.cs:49:45:49:52 | access to local variable format01 | semmle.label | access to local variable format01 |
+| FormatMissingArgument.cs:52:45:52:52 | access to local variable format23 | semmle.label | access to local variable format23 |
+| FormatMissingArgument.cs:56:31:56:37 | access to local variable format0 | semmle.label | access to local variable format0 |
+| FormatMissingArgument.cs:57:39:57:45 | access to local variable format0 | semmle.label | access to local variable format0 |
+| FormatMissingArgument.cs:60:31:60:37 | access to local variable format1 | semmle.label | access to local variable format1 |
+| FormatMissingArgument.cs:61:39:61:45 | access to local variable format1 | semmle.label | access to local variable format1 |
+| FormatMissingArgument.cs:64:47:64:54 | access to local variable format01 | semmle.label | access to local variable format01 |
+| FormatMissingArgument.cs:67:47:67:54 | access to local variable format23 | semmle.label | access to local variable format23 |
+| FormatMissingArgument.cs:73:29:73:35 | access to local variable format0 | semmle.label | access to local variable format0 |
+| FormatMissingArgument.cs:74:37:74:43 | access to local variable format0 | semmle.label | access to local variable format0 |
+| FormatMissingArgument.cs:77:29:77:35 | access to local variable format1 | semmle.label | access to local variable format1 |
+| FormatMissingArgument.cs:78:37:78:43 | access to local variable format1 | semmle.label | access to local variable format1 |
+| FormatMissingArgument.cs:81:45:81:52 | access to local variable format01 | semmle.label | access to local variable format01 |
+| FormatMissingArgument.cs:84:45:84:52 | access to local variable format23 | semmle.label | access to local variable format23 |
 | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | semmle.label | "Hello {0} {1}" |
+| FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | semmle.label | "Hello {0} {1}" |
+| FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | semmle.label | "Hello {1} {2}" |
 | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | semmle.label | "Hello {1} {2}" |
 | FormatMissingArgumentGood.cs:7:27:7:41 | "Hello {0} {1}" | semmle.label | "Hello {0} {1}" |
-| FormatUnusedArgument.cs:8:23:8:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
-| FormatUnusedArgument.cs:11:23:11:25 | "X" | semmle.label | "X" |
-| FormatUnusedArgument.cs:14:23:14:27 | "{0}" | semmle.label | "{0}" |
-| FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | semmle.label | "{0} {0}" |
-| FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | semmle.label | "{1} {1}" |
-| FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | semmle.label | "abcdefg" |
-| FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | semmle.label | "{{sdc}}" |
-| FormatUnusedArgument.cs:29:23:29:33 | "{{{0:D}}}" | semmle.label | "{{{0:D}}}" |
-| FormatUnusedArgument.cs:32:23:32:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" |
-| FormatUnusedArgument.cs:35:23:35:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
-| FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | semmle.label | "{{0}}" |
-| FormatUnusedArgument.cs:42:23:42:24 | "" | semmle.label | "" |
+| FormatMissingArgumentGood.cs:7:27:7:41 | "Hello {0} {1}" | semmle.label | "Hello {0} {1}" |
+| FormatUnusedArgument.cs:9:23:9:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
+| FormatUnusedArgument.cs:9:23:9:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
+| FormatUnusedArgument.cs:12:23:12:25 | "X" | semmle.label | "X" |
+| FormatUnusedArgument.cs:12:23:12:25 | "X" | semmle.label | "X" |
+| FormatUnusedArgument.cs:15:23:15:27 | "{0}" | semmle.label | "{0}" |
+| FormatUnusedArgument.cs:15:23:15:27 | "{0}" | semmle.label | "{0}" |
+| FormatUnusedArgument.cs:18:23:18:31 | "{0} {0}" | semmle.label | "{0} {0}" |
+| FormatUnusedArgument.cs:18:23:18:31 | "{0} {0}" | semmle.label | "{0} {0}" |
+| FormatUnusedArgument.cs:21:23:21:31 | "{1} {1}" | semmle.label | "{1} {1}" |
+| FormatUnusedArgument.cs:21:23:21:31 | "{1} {1}" | semmle.label | "{1} {1}" |
+| FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | semmle.label | "abcdefg" |
+| FormatUnusedArgument.cs:24:23:24:31 | "abcdefg" | semmle.label | "abcdefg" |
+| FormatUnusedArgument.cs:27:23:27:31 | "{{sdc}}" | semmle.label | "{{sdc}}" |
+| FormatUnusedArgument.cs:27:23:27:31 | "{{sdc}}" | semmle.label | "{{sdc}}" |
+| FormatUnusedArgument.cs:30:23:30:33 | "{{{0:D}}}" | semmle.label | "{{{0:D}}}" |
+| FormatUnusedArgument.cs:30:23:30:33 | "{{{0:D}}}" | semmle.label | "{{{0:D}}}" |
+| FormatUnusedArgument.cs:33:23:33:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" |
+| FormatUnusedArgument.cs:33:23:33:39 | "{0} {1} {2} {3}" | semmle.label | "{0} {1} {2} {3}" |
+| FormatUnusedArgument.cs:36:23:36:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
+| FormatUnusedArgument.cs:36:23:36:35 | "{0} {1} {2}" | semmle.label | "{0} {1} {2}" |
+| FormatUnusedArgument.cs:39:23:39:29 | "{{0}}" | semmle.label | "{{0}}" |
+| FormatUnusedArgument.cs:39:23:39:29 | "{{0}}" | semmle.label | "{{0}}" |
+| FormatUnusedArgument.cs:43:23:43:24 | "" | semmle.label | "" |
+| FormatUnusedArgument.cs:43:23:43:24 | "" | semmle.label | "" |
+| FormatUnusedArgument.cs:48:13:48:18 | access to local variable format : CompositeFormat | semmle.label | access to local variable format : CompositeFormat |
+| FormatUnusedArgument.cs:48:22:48:47 | call to method Parse : CompositeFormat | semmle.label | call to method Parse : CompositeFormat |
+| FormatUnusedArgument.cs:48:44:48:46 | "X" | semmle.label | "X" |
+| FormatUnusedArgument.cs:48:44:48:46 | "X" : String | semmle.label | "X" : String |
+| FormatUnusedArgument.cs:49:13:49:20 | access to local variable format00 : CompositeFormat | semmle.label | access to local variable format00 : CompositeFormat |
+| FormatUnusedArgument.cs:49:24:49:54 | call to method Parse : CompositeFormat | semmle.label | call to method Parse : CompositeFormat |
+| FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" | semmle.label | "{0}{0}" |
+| FormatUnusedArgument.cs:49:46:49:53 | "{0}{0}" : String | semmle.label | "{0}{0}" : String |
+| FormatUnusedArgument.cs:50:13:50:20 | access to local variable format11 : CompositeFormat | semmle.label | access to local variable format11 : CompositeFormat |
+| FormatUnusedArgument.cs:50:24:50:54 | call to method Parse : CompositeFormat | semmle.label | call to method Parse : CompositeFormat |
+| FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" | semmle.label | "{1}{1}" |
+| FormatUnusedArgument.cs:50:46:50:53 | "{1}{1}" : String | semmle.label | "{1}{1}" : String |
+| FormatUnusedArgument.cs:53:37:53:42 | access to local variable format | semmle.label | access to local variable format |
+| FormatUnusedArgument.cs:56:45:56:52 | access to local variable format00 | semmle.label | access to local variable format00 |
+| FormatUnusedArgument.cs:59:45:59:52 | access to local variable format11 | semmle.label | access to local variable format11 |
+| FormatUnusedArgument.cs:62:31:62:36 | access to local variable format | semmle.label | access to local variable format |
+| FormatUnusedArgument.cs:63:39:63:44 | access to local variable format | semmle.label | access to local variable format |
+| FormatUnusedArgument.cs:66:47:66:54 | access to local variable format00 | semmle.label | access to local variable format00 |
+| FormatUnusedArgument.cs:69:47:69:54 | access to local variable format11 | semmle.label | access to local variable format11 |
+| FormatUnusedArgument.cs:74:29:74:34 | access to local variable format | semmle.label | access to local variable format |
+| FormatUnusedArgument.cs:75:37:75:42 | access to local variable format | semmle.label | access to local variable format |
+| FormatUnusedArgument.cs:78:45:78:52 | access to local variable format00 | semmle.label | access to local variable format00 |
+| FormatUnusedArgument.cs:81:45:81:52 | access to local variable format11 | semmle.label | access to local variable format11 |
+| FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | semmle.label | "Error processing file: {0}" |
 | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | semmle.label | "Error processing file: {0}" |
 | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | semmle.label | "Error processing file: {1} ({1})" |
+| FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | semmle.label | "Error processing file: {1} ({1})" |
+| FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | semmle.label | "Error processing file: %s (%d)" |
 | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | semmle.label | "Error processing file: %s (%d)" |
 subpaths
-#select
-| FormatInvalid.cs:27:23:27:28 | "{ 0}" | FormatInvalid.cs:27:23:27:28 | "{ 0}" | FormatInvalid.cs:27:23:27:28 | "{ 0}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:27:9:27:32 | call to method Format | this | FormatInvalid.cs:27:9:27:32 | call to method Format | this |
-| FormatInvalid.cs:30:23:30:31 | "{0,--1}" | FormatInvalid.cs:30:23:30:31 | "{0,--1}" | FormatInvalid.cs:30:23:30:31 | "{0,--1}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:30:9:30:35 | call to method Format | this | FormatInvalid.cs:30:9:30:35 | call to method Format | this |
-| FormatInvalid.cs:33:23:33:30 | "{0:{}}" | FormatInvalid.cs:33:23:33:30 | "{0:{}}" | FormatInvalid.cs:33:23:33:30 | "{0:{}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:33:9:33:34 | call to method Format | this | FormatInvalid.cs:33:9:33:34 | call to method Format | this |
-| FormatInvalid.cs:36:9:36:30 | call to method Format | FormatInvalid.cs:36:23:36:26 | "%d" | FormatInvalid.cs:36:23:36:26 | "%d" | The $@ ignores $@. | FormatInvalid.cs:36:23:36:26 | "%d" | format string | FormatInvalid.cs:36:29:36:29 | (...) ... | this supplied value |
-| FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | FormatInvalid.cs:39:23:39:33 | "{{0}-{1}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:39:9:39:40 | call to method Format | this | FormatInvalid.cs:39:9:39:40 | call to method Format | this |
-| FormatInvalid.cs:42:23:42:28 | "{0}}" | FormatInvalid.cs:42:23:42:28 | "{0}}" | FormatInvalid.cs:42:23:42:28 | "{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:42:9:42:35 | call to method Format | this | FormatInvalid.cs:42:9:42:35 | call to method Format | this |
-| FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | FormatInvalid.cs:45:23:45:32 | "{foo{0}}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:45:9:45:36 | call to method Format | this | FormatInvalid.cs:45:9:45:36 | call to method Format | this |
-| FormatInvalid.cs:48:9:48:35 | call to method Format | FormatInvalid.cs:48:23:48:31 | "{{sdc}}" | FormatInvalid.cs:48:23:48:31 | "{{sdc}}" | The $@ ignores $@. | FormatInvalid.cs:48:23:48:31 | "{{sdc}}" | format string | FormatInvalid.cs:48:34:48:34 | (...) ... | this supplied value |
-| FormatInvalid.cs:51:23:51:25 | "}" | FormatInvalid.cs:51:23:51:25 | "}" | FormatInvalid.cs:51:23:51:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:51:9:51:29 | call to method Format | this | FormatInvalid.cs:51:9:51:29 | call to method Format | this |
-| FormatInvalid.cs:54:9:54:46 | call to method Format | FormatInvalid.cs:54:23:54:42 | "new {0} ({1} => {{" | FormatInvalid.cs:54:23:54:42 | "new {0} ({1} => {{" | Argument '{1}' has not been supplied to $@ format string. | FormatInvalid.cs:54:23:54:42 | "new {0} ({1} => {{" | this | FormatInvalid.cs:54:23:54:42 | "new {0} ({1} => {{" | this |
-| FormatInvalid.cs:57:9:57:31 | call to method Format | FormatInvalid.cs:57:23:57:26 | "{{" | FormatInvalid.cs:57:23:57:26 | "{{" | The $@ ignores $@. | FormatInvalid.cs:57:23:57:26 | "{{" | format string | FormatInvalid.cs:57:29:57:30 | "" | this supplied value |
-| FormatInvalid.cs:58:9:58:35 | call to method Format | FormatInvalid.cs:58:23:58:30 | "{{{{}}" | FormatInvalid.cs:58:23:58:30 | "{{{{}}" | The $@ ignores $@. | FormatInvalid.cs:58:23:58:30 | "{{{{}}" | format string | FormatInvalid.cs:58:33:58:34 | "" | this supplied value |
-| FormatInvalid.cs:75:23:75:25 | "}" | FormatInvalid.cs:75:23:75:25 | "}" | FormatInvalid.cs:75:23:75:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:75:9:75:29 | call to method Format | this | FormatInvalid.cs:75:9:75:29 | call to method Format | this |
-| FormatInvalid.cs:76:23:76:25 | "}" | FormatInvalid.cs:76:23:76:25 | "}" | FormatInvalid.cs:76:23:76:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:76:9:76:30 | call to method Format | this | FormatInvalid.cs:76:9:76:30 | call to method Format | this |
-| FormatInvalid.cs:77:27:77:29 | "}" | FormatInvalid.cs:77:27:77:29 | "}" | FormatInvalid.cs:77:27:77:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:77:9:77:34 | call to method Format | this | FormatInvalid.cs:77:9:77:34 | call to method Format | this |
-| FormatInvalid.cs:78:23:78:25 | "}" | FormatInvalid.cs:78:23:78:25 | "}" | FormatInvalid.cs:78:23:78:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:78:9:78:32 | call to method Format | this | FormatInvalid.cs:78:9:78:32 | call to method Format | this |
-| FormatInvalid.cs:79:23:79:25 | "}" | FormatInvalid.cs:79:23:79:25 | "}" | FormatInvalid.cs:79:23:79:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:79:9:79:35 | call to method Format | this | FormatInvalid.cs:79:9:79:35 | call to method Format | this |
-| FormatInvalid.cs:80:23:80:25 | "}" | FormatInvalid.cs:80:23:80:25 | "}" | FormatInvalid.cs:80:23:80:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:80:9:80:38 | call to method Format | this | FormatInvalid.cs:80:9:80:38 | call to method Format | this |
-| FormatInvalid.cs:82:25:82:27 | "}" | FormatInvalid.cs:82:25:82:27 | "}" | FormatInvalid.cs:82:25:82:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:82:9:82:31 | call to method AppendFormat | this | FormatInvalid.cs:82:9:82:31 | call to method AppendFormat | this |
-| FormatInvalid.cs:83:25:83:27 | "}" | FormatInvalid.cs:83:25:83:27 | "}" | FormatInvalid.cs:83:25:83:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:83:9:83:32 | call to method AppendFormat | this | FormatInvalid.cs:83:9:83:32 | call to method AppendFormat | this |
-| FormatInvalid.cs:84:29:84:31 | "}" | FormatInvalid.cs:84:29:84:31 | "}" | FormatInvalid.cs:84:29:84:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:84:9:84:36 | call to method AppendFormat | this | FormatInvalid.cs:84:9:84:36 | call to method AppendFormat | this |
-| FormatInvalid.cs:85:25:85:27 | "}" | FormatInvalid.cs:85:25:85:27 | "}" | FormatInvalid.cs:85:25:85:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:85:9:85:34 | call to method AppendFormat | this | FormatInvalid.cs:85:9:85:34 | call to method AppendFormat | this |
-| FormatInvalid.cs:86:25:86:27 | "}" | FormatInvalid.cs:86:25:86:27 | "}" | FormatInvalid.cs:86:25:86:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:86:9:86:37 | call to method AppendFormat | this | FormatInvalid.cs:86:9:86:37 | call to method AppendFormat | this |
-| FormatInvalid.cs:87:25:87:27 | "}" | FormatInvalid.cs:87:25:87:27 | "}" | FormatInvalid.cs:87:25:87:27 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:87:9:87:40 | call to method AppendFormat | this | FormatInvalid.cs:87:9:87:40 | call to method AppendFormat | this |
-| FormatInvalid.cs:89:27:89:29 | "}" | FormatInvalid.cs:89:27:89:29 | "}" | FormatInvalid.cs:89:27:89:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:89:9:89:33 | call to method WriteLine | this | FormatInvalid.cs:89:9:89:33 | call to method WriteLine | this |
-| FormatInvalid.cs:90:27:90:29 | "}" | FormatInvalid.cs:90:27:90:29 | "}" | FormatInvalid.cs:90:27:90:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:90:9:90:34 | call to method WriteLine | this | FormatInvalid.cs:90:9:90:34 | call to method WriteLine | this |
-| FormatInvalid.cs:91:27:91:29 | "}" | FormatInvalid.cs:91:27:91:29 | "}" | FormatInvalid.cs:91:27:91:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:91:9:91:36 | call to method WriteLine | this | FormatInvalid.cs:91:9:91:36 | call to method WriteLine | this |
-| FormatInvalid.cs:92:27:92:29 | "}" | FormatInvalid.cs:92:27:92:29 | "}" | FormatInvalid.cs:92:27:92:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:92:9:92:39 | call to method WriteLine | this | FormatInvalid.cs:92:9:92:39 | call to method WriteLine | this |
-| FormatInvalid.cs:93:27:93:29 | "}" | FormatInvalid.cs:93:27:93:29 | "}" | FormatInvalid.cs:93:27:93:29 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:93:9:93:42 | call to method WriteLine | this | FormatInvalid.cs:93:9:93:42 | call to method WriteLine | this |
-| FormatInvalid.cs:95:22:95:24 | "}" | FormatInvalid.cs:95:22:95:24 | "}" | FormatInvalid.cs:95:22:95:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:95:9:95:28 | call to method WriteLine | this | FormatInvalid.cs:95:9:95:28 | call to method WriteLine | this |
-| FormatInvalid.cs:96:22:96:24 | "}" | FormatInvalid.cs:96:22:96:24 | "}" | FormatInvalid.cs:96:22:96:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:96:9:96:29 | call to method WriteLine | this | FormatInvalid.cs:96:9:96:29 | call to method WriteLine | this |
-| FormatInvalid.cs:97:22:97:24 | "}" | FormatInvalid.cs:97:22:97:24 | "}" | FormatInvalid.cs:97:22:97:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:97:9:97:31 | call to method WriteLine | this | FormatInvalid.cs:97:9:97:31 | call to method WriteLine | this |
-| FormatInvalid.cs:98:22:98:24 | "}" | FormatInvalid.cs:98:22:98:24 | "}" | FormatInvalid.cs:98:22:98:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:98:9:98:34 | call to method WriteLine | this | FormatInvalid.cs:98:9:98:34 | call to method WriteLine | this |
-| FormatInvalid.cs:99:22:99:24 | "}" | FormatInvalid.cs:99:22:99:24 | "}" | FormatInvalid.cs:99:22:99:24 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:99:9:99:37 | call to method WriteLine | this | FormatInvalid.cs:99:9:99:37 | call to method WriteLine | this |
-| FormatInvalid.cs:101:44:101:46 | "}" | FormatInvalid.cs:101:44:101:46 | "}" | FormatInvalid.cs:101:44:101:46 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:101:9:101:51 | call to method WriteLine | this | FormatInvalid.cs:101:9:101:51 | call to method WriteLine | this |
-| FormatInvalid.cs:102:45:102:47 | "}" | FormatInvalid.cs:102:45:102:47 | "}" | FormatInvalid.cs:102:45:102:47 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:102:9:102:51 | call to method TraceError | this | FormatInvalid.cs:102:9:102:51 | call to method TraceError | this |
-| FormatInvalid.cs:103:51:103:53 | "}" | FormatInvalid.cs:103:51:103:53 | "}" | FormatInvalid.cs:103:51:103:53 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:103:9:103:57 | call to method TraceInformation | this | FormatInvalid.cs:103:9:103:57 | call to method TraceInformation | this |
-| FormatInvalid.cs:104:47:104:49 | "}" | FormatInvalid.cs:104:47:104:49 | "}" | FormatInvalid.cs:104:47:104:49 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:104:9:104:53 | call to method TraceWarning | this | FormatInvalid.cs:104:9:104:53 | call to method TraceWarning | this |
-| FormatInvalid.cs:105:29:105:31 | "}" | FormatInvalid.cs:105:29:105:31 | "}" | FormatInvalid.cs:105:29:105:31 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:105:9:105:35 | call to method TraceInformation | this | FormatInvalid.cs:105:9:105:35 | call to method TraceInformation | this |
-| FormatInvalid.cs:107:23:107:25 | "}" | FormatInvalid.cs:107:23:107:25 | "}" | FormatInvalid.cs:107:23:107:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:107:9:107:29 | call to method Write | this | FormatInvalid.cs:107:9:107:29 | call to method Write | this |
-| FormatInvalid.cs:108:23:108:25 | "}" | FormatInvalid.cs:108:23:108:25 | "}" | FormatInvalid.cs:108:23:108:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:108:9:108:32 | call to method Write | this | FormatInvalid.cs:108:9:108:32 | call to method Write | this |
-| FormatInvalid.cs:109:23:109:25 | "}" | FormatInvalid.cs:109:23:109:25 | "}" | FormatInvalid.cs:109:23:109:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:109:9:109:35 | call to method Write | this | FormatInvalid.cs:109:9:109:35 | call to method Write | this |
-| FormatInvalid.cs:110:23:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | FormatInvalid.cs:110:23:110:25 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:110:9:110:38 | call to method Write | this | FormatInvalid.cs:110:9:110:38 | call to method Write | this |
-| FormatInvalid.cs:115:56:115:58 | "}" | FormatInvalid.cs:115:56:115:58 | [assertion success] "}" | FormatInvalid.cs:115:56:115:58 | [assertion success] "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:115:9:115:63 | call to method Assert | this | FormatInvalid.cs:115:9:115:63 | call to method Assert | this |
-| FormatInvalid.cs:116:18:116:20 | "}" | FormatInvalid.cs:116:18:116:20 | "}" | FormatInvalid.cs:116:18:116:20 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:116:9:116:24 | call to method Write | this | FormatInvalid.cs:116:9:116:24 | call to method Write | this |
-| FormatInvalid.cs:117:40:117:42 | "}" | FormatInvalid.cs:117:40:117:42 | "}" | FormatInvalid.cs:117:40:117:42 | "}" | Invalid format string used in $@ formatting call. | FormatInvalid.cs:117:9:117:47 | call to method Print | this | FormatInvalid.cs:117:9:117:47 | call to method Print | this |
-| FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | FormatInvalidBad.cs:7:30:7:44 | "class {0} { }" | Invalid format string used in $@ formatting call. | FormatInvalidBad.cs:7:16:7:50 | call to method Format | this | FormatInvalidBad.cs:7:16:7:50 | call to method Format | this |
-| FormatMissingArgument.cs:11:9:11:31 | call to method Format | FormatMissingArgument.cs:11:23:11:27 | "{1}" | FormatMissingArgument.cs:11:23:11:27 | "{1}" | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:11:23:11:27 | "{1}" | this | FormatMissingArgument.cs:11:23:11:27 | "{1}" | this |
-| FormatMissingArgument.cs:11:9:11:31 | call to method Format | FormatMissingArgument.cs:11:23:11:27 | "{1}" | FormatMissingArgument.cs:11:23:11:27 | "{1}" | The $@ ignores $@. | FormatMissingArgument.cs:11:23:11:27 | "{1}" | format string | FormatMissingArgument.cs:11:30:11:30 | (...) ... | this supplied value |
-| FormatMissingArgument.cs:14:9:14:38 | call to method Format | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this |
-| FormatMissingArgument.cs:14:9:14:38 | call to method Format | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | Argument '{3}' has not been supplied to $@ format string. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | this |
-| FormatMissingArgument.cs:14:9:14:38 | call to method Format | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | The $@ ignores $@. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | format string | FormatMissingArgument.cs:14:34:14:34 | (...) ... | this supplied value |
-| FormatMissingArgument.cs:14:9:14:38 | call to method Format | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | The $@ ignores $@. | FormatMissingArgument.cs:14:23:14:31 | "{2} {3}" | format string | FormatMissingArgument.cs:14:37:14:37 | (...) ... | this supplied value |
-| FormatMissingArgument.cs:25:9:25:32 | call to method WriteLine | FormatMissingArgument.cs:25:27:25:31 | "{0}" | FormatMissingArgument.cs:25:27:25:31 | "{0}" | Argument '{0}' has not been supplied to $@ format string. | FormatMissingArgument.cs:25:27:25:31 | "{0}" | this | FormatMissingArgument.cs:25:27:25:31 | "{0}" | this |
-| FormatMissingArgument.cs:31:9:31:32 | call to method Format | FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | FormatMissingArgument.cs:31:23:31:28 | access to parameter format | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgument.cs:22:16:22:20 | "{1}" | this | FormatMissingArgument.cs:22:16:22:20 | "{1}" | this |
-| FormatMissingArgument.cs:31:9:31:32 | call to method Format | FormatMissingArgument.cs:22:16:22:20 | "{1}" : String | FormatMissingArgument.cs:31:23:31:28 | access to parameter format | The $@ ignores $@. | FormatMissingArgument.cs:22:16:22:20 | "{1}" | format string | FormatMissingArgument.cs:31:31:31:31 | (...) ... | this supplied value |
-| FormatMissingArgumentBad.cs:7:9:7:49 | call to method WriteLine | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | Argument '{1}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | this | FormatMissingArgumentBad.cs:7:27:7:41 | "Hello {0} {1}" | this |
-| FormatMissingArgumentBad.cs:8:9:8:55 | call to method WriteLine | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | Argument '{2}' has not been supplied to $@ format string. | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | this | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | this |
-| FormatMissingArgumentBad.cs:8:9:8:55 | call to method WriteLine | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | The $@ ignores $@. | FormatMissingArgumentBad.cs:8:27:8:41 | "Hello {1} {2}" | format string | FormatMissingArgumentBad.cs:8:44:8:48 | access to parameter first | this supplied value |
-| FormatUnusedArgument.cs:11:9:11:29 | call to method Format | FormatUnusedArgument.cs:11:23:11:25 | "X" | FormatUnusedArgument.cs:11:23:11:25 | "X" | The $@ ignores $@. | FormatUnusedArgument.cs:11:23:11:25 | "X" | format string | FormatUnusedArgument.cs:11:28:11:28 | (...) ... | this supplied value |
-| FormatUnusedArgument.cs:14:9:14:34 | call to method Format | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | The $@ ignores $@. | FormatUnusedArgument.cs:14:23:14:27 | "{0}" | format string | FormatUnusedArgument.cs:14:33:14:33 | (...) ... | this supplied value |
-| FormatUnusedArgument.cs:17:9:17:38 | call to method Format | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | The $@ ignores $@. | FormatUnusedArgument.cs:17:23:17:31 | "{0} {0}" | format string | FormatUnusedArgument.cs:17:37:17:37 | (...) ... | this supplied value |
-| FormatUnusedArgument.cs:20:9:20:38 | call to method Format | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | The $@ ignores $@. | FormatUnusedArgument.cs:20:23:20:31 | "{1} {1}" | format string | FormatUnusedArgument.cs:20:34:20:34 | (...) ... | this supplied value |
-| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:34:23:34 | (...) ... | this supplied value |
-| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:37:23:37 | (...) ... | this supplied value |
-| FormatUnusedArgument.cs:23:9:23:41 | call to method Format | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | The $@ ignores $@. | FormatUnusedArgument.cs:23:23:23:31 | "abcdefg" | format string | FormatUnusedArgument.cs:23:40:23:40 | (...) ... | this supplied value |
-| FormatUnusedArgument.cs:26:9:26:35 | call to method Format | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | The $@ ignores $@. | FormatUnusedArgument.cs:26:23:26:31 | "{{sdc}}" | format string | FormatUnusedArgument.cs:26:34:26:34 | (...) ... | this supplied value |
-| FormatUnusedArgument.cs:38:9:38:33 | call to method Format | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | The $@ ignores $@. | FormatUnusedArgument.cs:38:23:38:29 | "{{0}}" | format string | FormatUnusedArgument.cs:38:32:38:32 | (...) ... | this supplied value |
-| FormatUnusedArgumentBad.cs:7:9:7:71 | call to method WriteLine | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:7:27:7:54 | "Error processing file: {0}" | format string | FormatUnusedArgumentBad.cs:7:61:7:70 | (...) ... | this supplied value |
-| FormatUnusedArgumentBad.cs:8:9:8:77 | call to method WriteLine | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:8:27:8:60 | "Error processing file: {1} ({1})" | format string | FormatUnusedArgumentBad.cs:8:63:8:64 | access to parameter ex | this supplied value |
-| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:61:9:62 | access to parameter ex | this supplied value |
-| FormatUnusedArgumentBad.cs:9:9:9:75 | call to method WriteLine | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | The $@ ignores $@. | FormatUnusedArgumentBad.cs:9:27:9:58 | "Error processing file: %s (%d)" | format string | FormatUnusedArgumentBad.cs:9:65:9:74 | (...) ... | this supplied value |
diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.qlref b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.qlref
index 75f1d04fe147..9c660b69de53 100644
--- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.qlref	
+++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.qlref	
@@ -1 +1,2 @@
-API Abuse/FormatInvalid.ql
\ No newline at end of file
+query: API Abuse/FormatInvalid.ql
+postprocess: utils/test/InlineExpectationsTestQuery.ql
diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalidBad.cs b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalidBad.cs
index ec3df72655de..424781b80bc7 100644
--- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalidBad.cs	
+++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalidBad.cs	
@@ -4,6 +4,6 @@ class Bad1
 {
     string GenerateEmptyClass(string c)
     {
-        return string.Format("class {0} { }", "C");
+        return string.Format("class {0} { }", "C"); // $ Alert
     }
 }
diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgument.cs b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgument.cs
index 94201c0ddf8e..b5ff280d86df 100644
--- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgument.cs	
+++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgument.cs	
@@ -1,4 +1,5 @@
 using System;
+using System.Text;
 
 class Class1
 {
@@ -8,28 +9,82 @@ void TestFormatMissingArgument()
         String.Format("{0}", 0);
 
         // BAD: Missing {1}
-        String.Format("{1}", 0);
+        String.Format("{1}", 0); // $ Alert
 
         // BAD: Missing {2} and {3}
-        String.Format("{2} {3}", 0, 1);
+        String.Format("{2} {3}", 0, 1); // $ Alert
 
         // GOOD: An array has been supplied.
         String.Format("{0} {1} {2}", args);
 
+        // GOOD: A collection has been supplied.
+        String.Format("{0} {1} {2}", [0, 1, 2]);
+
         // GOOD: All arguments supplied to params
         String.Format("{0} {1} {2} {3}", 0, 1, 2, 3);
 
-        helper("{1}");
-
-        // BAD: Missing {0}
-        Console.WriteLine("{0}");
+        helper("{1}"); // $ Source=source1
     }
 
     void helper(string format)
     {
         // BAD: Missing {1}
-        String.Format(format, 0);
+        String.Format(format, 0); // $ Alert=source1
+    }
+
+    void TestCompositeFormatMissingArgument()
+    {
+        var format0 = CompositeFormat.Parse("{0}");
+        var format1 = CompositeFormat.Parse("{1}"); // $ Source=source2
+        var format01 = CompositeFormat.Parse("{0}{1}");
+        var format23 = CompositeFormat.Parse("{2}{3}"); // $ Source=source3
+
+        // GOOD: All args supplied
+        String.Format<string>(null, format0, "");
+
+        // BAD: Missing {1}
+        String.Format<string>(null, format1, ""); // $ Alert=source2
+
+        // GOOD: All args supplied
+        String.Format<string, string>(null, format01, "", "");
+
+        // BAD: Missing {2} and {3}
+        String.Format<string, string>(null, format23, "", ""); // $ Alert=source3
+
+
+        // GOOD: All arguments supplied
+        sb.AppendFormat(null, format0, "");
+        sb.AppendFormat<string>(null, format0, "");
+
+        // BAD: Missing {1}
+        sb.AppendFormat(null, format1, ""); // $ Alert=source2
+        sb.AppendFormat<string>(null, format1, ""); // $ Alert=source2
+
+        // GOOD: All args supplied
+        sb.AppendFormat<string, string>(null, format01, "", "");
+
+        // BAD: Missing {2} and {3}
+        sb.AppendFormat<string, string>(null, format23, "", ""); // $ Alert=source3
+
+
+        var span = new Span<char>();
+
+        // GOOD: All args supplied
+        span.TryWrite(null, format0, out _, "");
+        span.TryWrite<string>(null, format0, out _, "");
+
+        // BAD: Missing {1}
+        span.TryWrite(null, format1, out _, ""); // $ Alert=source2
+        span.TryWrite<string>(null, format1, out _, ""); // $ Alert=source2
+
+        // GOOD: All args supplied
+        span.TryWrite<string, string>(null, format01, out _, "", "");
+
+        // BAD: Missing {2} and {3}
+        span.TryWrite<string, string>(null, format23, out _, "", ""); // $ Alert=source3
     }
 
     object[] args;
+
+    StringBuilder sb;
 }
diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgumentBad.cs b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgumentBad.cs
index a66eea4cf323..74c2ffd627a0 100644
--- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgumentBad.cs	
+++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgumentBad.cs	
@@ -4,7 +4,7 @@ class Bad3
 {
     void Hello(string first, string last)
     {
-        Console.WriteLine("Hello {0} {1}", first);
-        Console.WriteLine("Hello {1} {2}", first, last);
+        Console.WriteLine("Hello {0} {1}", first); // $ Alert
+        Console.WriteLine("Hello {1} {2}", first, last); // $ Alert
     }
 }
diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatUnusedArgument.cs b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatUnusedArgument.cs
index 81842d1e19de..c064025ed686 100644
--- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatUnusedArgument.cs	
+++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatUnusedArgument.cs	
@@ -1,4 +1,5 @@
 using System;
+using System.Text;
 
 class C
 {
@@ -8,22 +9,22 @@ void FormatTests()
         String.Format("{0} {1} {2}", 0, 1, 2);
 
         // BAD: Missing arg {0}
-        String.Format("X", 1);
+        String.Format("X", 1); // $ Alert
 
         // BAD: Missing {1}
-        String.Format("{0}", 1, 2);
+        String.Format("{0}", 1, 2); // $ Alert
 
         // BAD: Missing {1}
-        String.Format("{0} {0}", 1, 2);
+        String.Format("{0} {0}", 1, 2); // $ Alert
 
         // BAD: Missing {0}
-        String.Format("{1} {1}", 1, 2);
+        String.Format("{1} {1}", 1, 2); // $ Alert
 
         // BAD: Missing {0}, {1} and {2}
-        String.Format("abcdefg", 0, 1, 2);
+        String.Format("abcdefg", 0, 1, 2); // $ Alert
 
         // BAD: {0} is unused
-        String.Format("{{sdc}}", 0);
+        String.Format("{{sdc}}", 0); // $ Alert
 
         // GOOD: {0} is used
         String.Format("{{{0:D}}}", 0);
@@ -35,12 +36,52 @@ void FormatTests()
         String.Format("{0} {1} {2}", ps);
 
         // BAD: Would display "{0}"
-        String.Format("{{0}}", 1);
+        String.Format("{{0}}", 1); // $ Alert
 
         // GOOD: Ignore the empty string as it's often used as the default value
         // of GetResource().
         String.Format("", 1);
     }
 
+    void CompositeFormatTests()
+    {
+        var format = CompositeFormat.Parse("X"); // $ Source=source4
+        var format00 = CompositeFormat.Parse("{0}{0}"); // $ Source=source5
+        var format11 = CompositeFormat.Parse("{1}{1}"); // $ Source=source6
+
+        // BAD: Unused arg {0}
+        String.Format<string>(null, format, ""); // $ Alert=source4
+
+        // BAD: Unused arg {1}
+        String.Format<string, string>(null, format00, "", ""); // $ Alert=source5
+
+        // BAD: Unused arg {0}
+        String.Format<string, string>(null, format11, "", ""); // $ Alert=source6
+
+        // BAD: Unused arg {0}
+        sb.AppendFormat(null, format, ""); // $ Alert=source4
+        sb.AppendFormat<string>(null, format, ""); // $ Alert=source4
+
+        // BAD: Unused arg {1}
+        sb.AppendFormat<string, string>(null, format00, "", ""); // $ Alert=source5
+
+        // BAD: Unused arg {0}
+        sb.AppendFormat<string, string>(null, format11, "", ""); // $ Alert=source6
+
+        var span = new Span<char>();
+
+        // BAD: Unused arg {0}
+        span.TryWrite(null, format, out _, ""); // $ Alert=source4
+        span.TryWrite<string>(null, format, out _, ""); // $ Alert=source4
+
+        // BAD: Unused arg {1}
+        span.TryWrite<string, string>(null, format00, out _, "", ""); // $ Alert=source5
+
+        // BAD: Unused arg {0}
+        span.TryWrite<string, string>(null, format11, out _, "", ""); // $ Alert=source6
+    }
+
     object[] ps;
+
+    StringBuilder sb;
 }
diff --git a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatUnusedArgumentBad.cs b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatUnusedArgumentBad.cs
index 25bce1a742e9..969c2b86e9f6 100644
--- a/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatUnusedArgumentBad.cs	
+++ b/csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatUnusedArgumentBad.cs	
@@ -4,8 +4,8 @@ class Bad2
 {
     void M(Exception ex)
     {
-        Console.WriteLine("Error processing file: {0}", ex, ex.HResult);
-        Console.WriteLine("Error processing file: {1} ({1})", ex, ex.HResult);
-        Console.WriteLine("Error processing file: %s (%d)", ex, ex.HResult);
+        Console.WriteLine("Error processing file: {0}", ex, ex.HResult); // $ Alert
+        Console.WriteLine("Error processing file: {1} ({1})", ex, ex.HResult); // $ Alert
+        Console.WriteLine("Error processing file: %s (%d)", ex, ex.HResult); // $ Alert
     }
 }


Reviews:
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-08T14:51:35Z
user: login: hvitved
body: Great work, thanks for breaking up into individual commits, that made reviewing a lot easier.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T07:56:41Z
user: login: michaelnebel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T09:32:07Z
user: login: hvitved
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T09:49:04Z
user: login: michaelnebel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T10:38:23Z
user: login: hvitved
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T10:56:00Z
user: login: michaelnebel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T11:02:19Z
user: login: hvitved
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-24T07:00:30Z

Review comments:
diff_hunk: @@ -8,67 +8,117 @@
 private import semmle.code.csharp.frameworks.system.Text
 
 /** A method that formats a string, for example `string.Format()`. */
-class FormatMethod extends Method {
-  FormatMethod() {
-    exists(Class declType | declType = this.getDeclaringType() |
+abstract class FormatMethod extends Method {
+  /**
+   * Gets the argument containing the format string. For example, the argument of
+   * `string.Format(IFormatProvider, String, Object)` is `1`.
+   */
+  abstract int getFormatArgument();
+}
+
+/** A class of types used for formatting. */
+private class FormatType extends Type {
+  FormatType() {
+    this instanceof StringType or
+    this instanceof SystemTextCompositeFormatClass
+  }
+}
+
+private class StringAndStringBuilderFormatMethods extends FormatMethod {
+  StringAndStringBuilderFormatMethods() {
+    (
       this.getParameter(0).getType() instanceof SystemIFormatProviderInterface and
-      this.getParameter(1).getType() instanceof StringType and
+      this.getParameter(1).getType() instanceof FormatType
+      or
+      this.getParameter(0).getType() instanceof StringType
+    ) and
+    (
+      this = any(SystemStringClass c).getFormatMethod()
+      or
+      this = any(SystemTextStringBuilderClass c).getAppendFormatMethod()
+    )
+  }
+
+  override int getFormatArgument() {
+    if this.getParameter(0).getType() instanceof SystemIFormatProviderInterface
+    then result = 1
+    else result = 0
+  }
+}
+
+private class SystemMemoryExtensionsFormatMethods extends FormatMethod {
+  SystemMemoryExtensionsFormatMethods() {
+    this = any(SystemMemoryExtensionsClass c).getTryWriteMethod() and
+    this.getParameter(1).getType() instanceof SystemIFormatProviderInterface and
+    this.getParameter(2).getType() instanceof SystemTextCompositeFormatClass
+  }
+
+  override int getFormatArgument() { result = 2 }
+}
+
+private predicate myTest(Callable c, Parameter p) {
path: csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll
user: login: github-advanced-security[bot]
body: ## Dead code

This code is never used, and it's not publicly exported.

[Show more details](https://github.com/github/codeql/security/code-scanning/94975)
created_at: 2025-04-08T14:51:35Z
author_association: NONE
diff_hunk: @@ -8,27 +8,27 @@ void TestFormatMissingArgument()
         String.Format("{0}", 0);
 
         // BAD: Missing {1}
-        String.Format("{1}", 0);
+        String.Format("{1}", 0); // $ Alert Sink
 
         // BAD: Missing {2} and {3}
-        String.Format("{2} {3}", 0, 1);
+        String.Format("{2} {3}", 0, 1); // $ Alert Sink
 
         // GOOD: An array has been supplied.
         String.Format("{0} {1} {2}", args);
 
         // GOOD: All arguments supplied to params
         String.Format("{0} {1} {2} {3}", 0, 1, 2, 3);
 
-        helper("{1}");
+        helper("{1}"); // $ Source
path: csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgument.cs
user: login: hvitved
body: I think this should be e.g. `Source=source1` and then `$ Alert=source1` further down.
created_at: 2025-04-23T07:22:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,38 +24,38 @@ void FormatStringTests()
         String.Format("{0, -10 :0.000}", 1);
 
         // BAD: Invalid format string
-        String.Format("{ 0}", 1);
+        String.Format("{ 0}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0,--1}", 1);
+        String.Format("{0,--1}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0:{}}", 1);
+        String.Format("{0:{}}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("%d", 1);
+        String.Format("%d", 1); // $ Alert Sink
path: csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs
user: login: hvitved
body: I don't think the `Sink` part is needed when it is on the same line as the alert.
created_at: 2025-04-23T07:25:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,67 +8,91 @@ private import semmle.code.csharp.frameworks.System
 private import semmle.code.csharp.frameworks.system.Text
 
 /** A method that formats a string, for example `string.Format()`. */
-class FormatMethod extends Method {
-  FormatMethod() {
-    exists(Class declType | declType = this.getDeclaringType() |
+abstract class FormatMethod extends Method {
path: csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll
user: login: hvitved
body: Now we are exposing an abstract method, which is not backwards-compatible (and also not best practice). So Instead replace the current abstract `FormatMethod` class with a private `FormatMethodImpl` class, and add `final class FormatMethod = FormatMethodImpl;`.
created_at: 2025-04-23T07:27:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -28,5 +29,59 @@ void helper(string format)
         String.Format(format, 0); // $ Alert Sink
     }
 
+    void TestCompositeFormatMissingArgument()
+    {
+        var format0 = CompositeFormat.Parse("{0}");
+        var format1 = CompositeFormat.Parse("{1}"); // $ Source
path: csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatMissingArgument.cs
user: login: hvitved
body: Again, it is better to uniquely identify the sources so we can match them up against the alerts.
created_at: 2025-04-23T07:30:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,67 +8,91 @@ private import semmle.code.csharp.frameworks.System
 private import semmle.code.csharp.frameworks.system.Text
 
 /** A method that formats a string, for example `string.Format()`. */
-class FormatMethod extends Method {
-  FormatMethod() {
-    exists(Class declType | declType = this.getDeclaringType() |
+abstract class FormatMethod extends Method {
path: csharp/ql/lib/semmle/code/csharp/frameworks/Format.qll
user: login: hvitved
body: Never mind, I see that you did exactly this in a subsequent commit.
created_at: 2025-04-23T07:36:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,38 +24,38 @@ void FormatStringTests()
         String.Format("{0, -10 :0.000}", 1);
 
         // BAD: Invalid format string
-        String.Format("{ 0}", 1);
+        String.Format("{ 0}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0,--1}", 1);
+        String.Format("{0,--1}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0:{}}", 1);
+        String.Format("{0:{}}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("%d", 1);
+        String.Format("%d", 1); // $ Alert Sink
path: csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs
user: login: michaelnebel
body: The Sink and Alert doesn't have the exact same location (only the same line numbers), so the test fails, if we don't add both tags.
created_at: 2025-04-23T09:32:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,38 +24,38 @@ void FormatStringTests()
         String.Format("{0, -10 :0.000}", 1);
 
         // BAD: Invalid format string
-        String.Format("{ 0}", 1);
+        String.Format("{ 0}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0,--1}", 1);
+        String.Format("{0,--1}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0:{}}", 1);
+        String.Format("{0:{}}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("%d", 1);
+        String.Format("%d", 1); // $ Alert Sink
path: csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs
user: login: hvitved
body: Oh, right. Looks like we need to do the same as https://github.com/github/codeql/pull/18653 for sinks then (cc @asgerf ).
created_at: 2025-04-23T09:49:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,38 +24,38 @@ void FormatStringTests()
         String.Format("{0, -10 :0.000}", 1);
 
         // BAD: Invalid format string
-        String.Format("{ 0}", 1);
+        String.Format("{ 0}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0,--1}", 1);
+        String.Format("{0,--1}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0:{}}", 1);
+        String.Format("{0:{}}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("%d", 1);
+        String.Format("%d", 1); // $ Alert Sink
path: csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs
user: login: michaelnebel
body: https://github.com/github/codeql/pull/19354/files
created_at: 2025-04-23T10:38:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,38 +24,38 @@ void FormatStringTests()
         String.Format("{0, -10 :0.000}", 1);
 
         // BAD: Invalid format string
-        String.Format("{ 0}", 1);
+        String.Format("{ 0}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0,--1}", 1);
+        String.Format("{0,--1}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0:{}}", 1);
+        String.Format("{0:{}}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("%d", 1);
+        String.Format("%d", 1); // $ Alert Sink
path: csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs
user: login: hvitved
body: Nice!
created_at: 2025-04-23T10:56:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,38 +24,38 @@ void FormatStringTests()
         String.Format("{0, -10 :0.000}", 1);
 
         // BAD: Invalid format string
-        String.Format("{ 0}", 1);
+        String.Format("{ 0}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0,--1}", 1);
+        String.Format("{0,--1}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("{0:{}}", 1);
+        String.Format("{0:{}}", 1); // $ Alert
 
         // BAD: Invalid format string
-        String.Format("%d", 1);
+        String.Format("%d", 1); // $ Alert Sink
path: csharp/ql/test/query-tests/API Abuse/FormatInvalid/FormatInvalid.cs
user: login: michaelnebel
body: CoPilot managed to do it 😸 
created_at: 2025-04-23T11:02:19Z
author_association: CONTRIBUTOR

PR comments:
user: login: michaelnebel
created_at: 2025-04-10T06:43:53Z
body: DCA
- There doesn't appear to be any changes to performance or results for our DCA suite.
- The level produced on our DCA suite for this query looks acceptable (query is not unreasonable noisy).
author_association: CONTRIBUTOR
user: login: hvitved
created_at: 2025-04-23T07:57:21Z
body: > * @hvitved : The data flow configurations are quite similar. Is it a better approach to use flow state to track calls to `CompositeFormat.Parse`? (instead of merging two similar graphs).

I think it is fine to keep as-is.
author_association: CONTRIBUTOR