Szelethus created this revision.
Szelethus added reviewers: NoQ, vsavchenko, xazax.hun, martong, balazske,
baloghadamsoftware, gamesh411.
Szelethus added a project: clang.
Herald added subscribers: cfe-commits, ASDenysPetrov, steakhal, Charusso,
dkrupp, donat.nagy, mikhail.ramalho, a.sidorin, rnkovacs, szepet, whisperity.
Szelethus requested review of this revision.
In short, macro expansions handled the case where a variadic //parameter//
mapped to multiple //arguments//, but not the other way around. An internal
ticket was submitted that demonstrated that we fail an assertion. Macro
expansion so far worked by lexing the source code token-by-token and using the
`Preprocessor` to turn these tokens into identifiers or just get their proper
spelling, but what this counter intuitively doesn't do, is actually expand
these macros, so we have to do the heavy lifting -- in this case, figure out
what `__VA_ARGS__` expands into. Since this case can only occur in a nested
macro, the information we gathered from the containing macro does contain this
information. If a parameter resolves to `__VA_ARGS__`, we need to temporarily
stop getting our tokens from the lexer, and get the tokens from what
`__VA_ARGS__` maps to.
I also found a few more deficiencies I'll have to handle sooner rather then
later. I also have 3 commits about to land this is based on, some miscellaneous
renames, clarification in the documentation, prettifying some tests.
An educational rant:
For those that didn't have the displeasure of following my macro expansion
project, here's why this is so annoying: We really, really suck at
understanding macros. D74473 <https://reviews.llvm.org/D74473> is a recent
example where we attempt to get the definition of the `EOF` macro, but give up
rather fast if it isn't something trivial. D54349#1294765
<https://reviews.llvm.org/D54349#1294765> is also memorable for me. Indeed,
whenever we hit a macro, we are in deep trouble.
Since CodeChecker isn't an IDE, what we really wanted to achieve is when the
bug path goes through a macro, show what it would expand into.
The fundamental problem is, we simply can't ask `Preprocessor` what a macro
expands into without hacking really hard. The HTML output commits about every
sin under the sun; hiding under `clang/lib/Rewrite/HTMLRewrite.cpp`, it
`const_cast`s a `Preprocessor` object, stores most of its inner state (you
can't guarantee you got them all) such as the `DiagnosticsEngine`, some of the
user configurations in temporary variables, replaces them with new ones,
practically reruns the entire lexing and preprocessing stage of the compiler,
and at the end, puts the original inner state back in. This enables it to not
have to literally reimplement the preprocessor, but creates a large
preprocessed version of the source code, which it is almost impossible to
reliably link the two together (answering the question that what a specific
macro usage expands into).
Pp-trace, a Clang tool, would be great, but unfortunately it still isn't able
to do macro expansions in a single go, just step by step (think about nested
macros and variadic arguments).
So, I chose to practically reimplement the entire preprocessor with the goal of
taking a single source location of a macro usage, and spitting the entire
expansion out. This has a few advantages, namely that it leaves the
Preprocessor const, and provides a rather deep understanding of the process of
the macro expansion. The problem is, its a nightmare due to the extreme
primitiveness of the available tools, and will have to be updated as time goes
on.
You can learn a bit more from these patches and discussions:
D52742 <https://reviews.llvm.org/D52742> (check the patch stack)
http://lists.llvm.org/pipermail/cfe-dev/2018-September/059226.html
http://lists.llvm.org/pipermail/cfe-dev/2017-August/055077.html
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D86135
Files:
clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
clang/test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist
clang/test/Analysis/plist-macros-with-expansion.cpp
Index: clang/test/Analysis/plist-macros-with-expansion.cpp
===================================================================
--- clang/test/Analysis/plist-macros-with-expansion.cpp
+++ clang/test/Analysis/plist-macros-with-expansion.cpp
@@ -472,3 +472,62 @@
// CHECK: <key>name</key><string>APPLY_ZERO2</string>
// CHECK-NEXT: <key>expansion</key><string>int bar() { return 0; }</string>
+
+void foo(int &x, const char *str);
+
+#define PARAMS_RESOLVE_TO_VA_ARGS(i, fmt) \
+ foo(i, fmt); \
+ i = 0;
+#define DISPATCH(...) PARAMS_RESOLVE_TO_VA_ARGS(__VA_ARGS__);
+
+void mulitpleParamsResolveToVA_ARGS(void) {
+ int x = 1;
+ DISPATCH(x, "LF1M healer");
+ (void)(10 / x); // expected-warning{{Division by zero}}
+}
+// CHECK: <key>name</key><string>DISPATCH</string>
+// CHECK-NEXT: <key>expansion</key><string>foo(x, "LF1M healer");x = 0;;</string>
+
+void variadicCFunction(int &x, const char *str, ...);
+
+#define CONCAT_VA_ARGS(i, fmt, ...) \
+ variadicCFunction(i, fmt, ##__VA_ARGS__); \
+ i = 0;
+
+void concatVA_ARGS(void) {
+ int x = 1;
+ CONCAT_VA_ARGS(x, "You need to construct additional pylons.", 'c', 9);
+ (void)(10 / x); // expected-warning{{Division by zero}}
+}
+// CHECK: <key>name</key><string>CONCAT_VA_ARGS</string>
+// CHECK-NEXT: <key>expansion</key><string>variadicCFunction(x, "You need to construct additional pylons.",'c', 9);x = 0;</string>
+
+void concatVA_ARGSEmpty(void) {
+ int x = 1;
+ CONCAT_VA_ARGS(x, "You need to construct");
+ (void)(10 / x); // expected-warning{{Division by zero}}
+}
+// CHECK: <key>name</key><string>CONCAT_VA_ARGS</string>
+// CHECK-NEXT: <key>expansion</key><string>variadicCFunction(x, "You need to construct",);x = 0;</string>
+
+#define STRINGIFIED_VA_ARGS(i, fmt, ...) \
+ variadicCFunction(i, fmt, #__VA_ARGS__); \
+ i = 0;
+
+void stringifyVA_ARGS(void) {
+ int x = 1;
+ STRINGIFIED_VA_ARGS(x, "Additional supply depots required.", 'a', 10);
+ (void)(10 / x); // expected-warning{{Division by zero}}
+}
+
+// CHECK: <key>name</key><string>STRINGIFIED_VA_ARGS</string>
+// CHECK-NEXT: <key>expansion</key><string>variadicCFunction(x, "Additional supply depots required.", "'a'", 10);x = 0;</string>
+
+void stringifyVA_ARGSEmpty(void) {
+ int x = 1;
+ STRINGIFIED_VA_ARGS(x, "Additional supply depots required.");
+ (void)(10 / x); // expected-warning{{Division by zero}}
+}
+
+// CHECK: <key>name</key><string>STRINGIFIED_VA_ARGS</string>
+// CHECK-NEXT: <key>expansion</key><string>variadicCFunction(x, "Additional supply depots required.", ")";x = 0;</string>
Index: clang/test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist
+++ clang/test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist
@@ -6112,6 +6112,681 @@
</array>
</dict>
</dict>
+ <dict>
+ <key>path</key>
+ <array>
+ <dict>
+ <key>kind</key><string>control</string>
+ <key>edges</key>
+ <array>
+ <dict>
+ <key>start</key>
+ <array>
+ <dict>
+ <key>line</key><integer>483</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>483</integer>
+ <key>col</key><integer>5</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ <key>end</key>
+ <array>
+ <dict>
+ <key>line</key><integer>484</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>484</integer>
+ <key>col</key><integer>10</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>484</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>484</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>484</integer>
+ <key>col</key><integer>28</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ <key>message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>485</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>485</integer>
+ <key>col</key><integer>10</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>485</integer>
+ <key>col</key><integer>15</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>Division by zero</string>
+ <key>message</key>
+ <string>Division by zero</string>
+ </dict>
+ </array>
+ <key>macro_expansions</key>
+ <array>
+ <dict>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>484</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>name</key><string>DISPATCH</string>
+ <key>expansion</key><string>foo(x, "LF1M healer");x = 0;;</string>
+ </dict>
+ </array>
+ <key>description</key><string>Division by zero</string>
+ <key>category</key><string>Logic error</string>
+ <key>type</key><string>Division by zero</string>
+ <key>check_name</key><string>core.DivideZero</string>
+ <!-- This hash is experimental and going to change! -->
+ <key>issue_hash_content_of_line_in_context</key><string>0911a97774745d4fa0ac03cd9680dfe1</string>
+ <key>issue_context_kind</key><string>function</string>
+ <key>issue_context</key><string>mulitpleParamsResolveToVA_ARGS</string>
+ <key>issue_hash_function_offset</key><string>3</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>485</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ExecutedLines</key>
+ <dict>
+ <key>0</key>
+ <array>
+ <integer>482</integer>
+ <integer>483</integer>
+ <integer>484</integer>
+ <integer>485</integer>
+ </array>
+ </dict>
+ </dict>
+ <dict>
+ <key>path</key>
+ <array>
+ <dict>
+ <key>kind</key><string>control</string>
+ <key>edges</key>
+ <array>
+ <dict>
+ <key>start</key>
+ <array>
+ <dict>
+ <key>line</key><integer>496</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>496</integer>
+ <key>col</key><integer>5</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ <key>end</key>
+ <array>
+ <dict>
+ <key>line</key><integer>497</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>497</integer>
+ <key>col</key><integer>16</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>497</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>497</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>497</integer>
+ <key>col</key><integer>71</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ <key>message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>498</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>498</integer>
+ <key>col</key><integer>10</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>498</integer>
+ <key>col</key><integer>15</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>Division by zero</string>
+ <key>message</key>
+ <string>Division by zero</string>
+ </dict>
+ </array>
+ <key>macro_expansions</key>
+ <array>
+ <dict>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>497</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>name</key><string>CONCAT_VA_ARGS</string>
+ <key>expansion</key><string>variadicCFunction(x, "You need to construct additional pylons.",'c', 9);x = 0;</string>
+ </dict>
+ </array>
+ <key>description</key><string>Division by zero</string>
+ <key>category</key><string>Logic error</string>
+ <key>type</key><string>Division by zero</string>
+ <key>check_name</key><string>core.DivideZero</string>
+ <!-- This hash is experimental and going to change! -->
+ <key>issue_hash_content_of_line_in_context</key><string>ed592fb952ed786e7efdc81bbc538e94</string>
+ <key>issue_context_kind</key><string>function</string>
+ <key>issue_context</key><string>concatVA_ARGS</string>
+ <key>issue_hash_function_offset</key><string>3</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>498</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ExecutedLines</key>
+ <dict>
+ <key>0</key>
+ <array>
+ <integer>495</integer>
+ <integer>496</integer>
+ <integer>497</integer>
+ <integer>498</integer>
+ </array>
+ </dict>
+ </dict>
+ <dict>
+ <key>path</key>
+ <array>
+ <dict>
+ <key>kind</key><string>control</string>
+ <key>edges</key>
+ <array>
+ <dict>
+ <key>start</key>
+ <array>
+ <dict>
+ <key>line</key><integer>504</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>504</integer>
+ <key>col</key><integer>5</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ <key>end</key>
+ <array>
+ <dict>
+ <key>line</key><integer>505</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>505</integer>
+ <key>col</key><integer>16</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>505</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>505</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>505</integer>
+ <key>col</key><integer>44</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ <key>message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>506</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>506</integer>
+ <key>col</key><integer>10</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>506</integer>
+ <key>col</key><integer>15</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>Division by zero</string>
+ <key>message</key>
+ <string>Division by zero</string>
+ </dict>
+ </array>
+ <key>macro_expansions</key>
+ <array>
+ <dict>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>505</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>name</key><string>CONCAT_VA_ARGS</string>
+ <key>expansion</key><string>variadicCFunction(x, "You need to construct",);x = 0;</string>
+ </dict>
+ </array>
+ <key>description</key><string>Division by zero</string>
+ <key>category</key><string>Logic error</string>
+ <key>type</key><string>Division by zero</string>
+ <key>check_name</key><string>core.DivideZero</string>
+ <!-- This hash is experimental and going to change! -->
+ <key>issue_hash_content_of_line_in_context</key><string>4b0ab46d7a972d0a388b4bb59351480a</string>
+ <key>issue_context_kind</key><string>function</string>
+ <key>issue_context</key><string>concatVA_ARGSEmpty</string>
+ <key>issue_hash_function_offset</key><string>3</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>506</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ExecutedLines</key>
+ <dict>
+ <key>0</key>
+ <array>
+ <integer>503</integer>
+ <integer>504</integer>
+ <integer>505</integer>
+ <integer>506</integer>
+ </array>
+ </dict>
+ </dict>
+ <dict>
+ <key>path</key>
+ <array>
+ <dict>
+ <key>kind</key><string>control</string>
+ <key>edges</key>
+ <array>
+ <dict>
+ <key>start</key>
+ <array>
+ <dict>
+ <key>line</key><integer>516</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>516</integer>
+ <key>col</key><integer>5</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ <key>end</key>
+ <array>
+ <dict>
+ <key>line</key><integer>517</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>517</integer>
+ <key>col</key><integer>21</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>517</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>517</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>517</integer>
+ <key>col</key><integer>71</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ <key>message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>518</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>518</integer>
+ <key>col</key><integer>10</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>518</integer>
+ <key>col</key><integer>15</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>Division by zero</string>
+ <key>message</key>
+ <string>Division by zero</string>
+ </dict>
+ </array>
+ <key>macro_expansions</key>
+ <array>
+ <dict>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>517</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>name</key><string>STRINGIFIED_VA_ARGS</string>
+ <key>expansion</key><string>variadicCFunction(x, "Additional supply depots required.", "'a'", 10);x = 0;</string>
+ </dict>
+ </array>
+ <key>description</key><string>Division by zero</string>
+ <key>category</key><string>Logic error</string>
+ <key>type</key><string>Division by zero</string>
+ <key>check_name</key><string>core.DivideZero</string>
+ <!-- This hash is experimental and going to change! -->
+ <key>issue_hash_content_of_line_in_context</key><string>6622e3f0651f97e6cbf4e075e6b07707</string>
+ <key>issue_context_kind</key><string>function</string>
+ <key>issue_context</key><string>stringifyVA_ARGS</string>
+ <key>issue_hash_function_offset</key><string>3</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>518</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ExecutedLines</key>
+ <dict>
+ <key>0</key>
+ <array>
+ <integer>515</integer>
+ <integer>516</integer>
+ <integer>517</integer>
+ <integer>518</integer>
+ </array>
+ </dict>
+ </dict>
+ <dict>
+ <key>path</key>
+ <array>
+ <dict>
+ <key>kind</key><string>control</string>
+ <key>edges</key>
+ <array>
+ <dict>
+ <key>start</key>
+ <array>
+ <dict>
+ <key>line</key><integer>525</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>525</integer>
+ <key>col</key><integer>5</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ <key>end</key>
+ <array>
+ <dict>
+ <key>line</key><integer>526</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>526</integer>
+ <key>col</key><integer>21</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>526</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>526</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>526</integer>
+ <key>col</key><integer>62</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ <key>message</key>
+ <string>The value 0 is assigned to 'x'</string>
+ </dict>
+ <dict>
+ <key>kind</key><string>event</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>527</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ranges</key>
+ <array>
+ <array>
+ <dict>
+ <key>line</key><integer>527</integer>
+ <key>col</key><integer>10</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <dict>
+ <key>line</key><integer>527</integer>
+ <key>col</key><integer>15</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ </array>
+ </array>
+ <key>depth</key><integer>0</integer>
+ <key>extended_message</key>
+ <string>Division by zero</string>
+ <key>message</key>
+ <string>Division by zero</string>
+ </dict>
+ </array>
+ <key>macro_expansions</key>
+ <array>
+ <dict>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>526</integer>
+ <key>col</key><integer>3</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>name</key><string>STRINGIFIED_VA_ARGS</string>
+ <key>expansion</key><string>variadicCFunction(x, "Additional supply depots required.", ")";x = 0;</string>
+ </dict>
+ </array>
+ <key>description</key><string>Division by zero</string>
+ <key>category</key><string>Logic error</string>
+ <key>type</key><string>Division by zero</string>
+ <key>check_name</key><string>core.DivideZero</string>
+ <!-- This hash is experimental and going to change! -->
+ <key>issue_hash_content_of_line_in_context</key><string>86c6e52c81f1129e6c9f51e6938d9ee7</string>
+ <key>issue_context_kind</key><string>function</string>
+ <key>issue_context</key><string>stringifyVA_ARGSEmpty</string>
+ <key>issue_hash_function_offset</key><string>3</string>
+ <key>location</key>
+ <dict>
+ <key>line</key><integer>527</integer>
+ <key>col</key><integer>13</integer>
+ <key>file</key><integer>0</integer>
+ </dict>
+ <key>ExecutedLines</key>
+ <dict>
+ <key>0</key>
+ <array>
+ <integer>524</integer>
+ <integer>525</integer>
+ <integer>526</integer>
+ <integer>527</integer>
+ </array>
+ </dict>
+ </dict>
</array>
<key>files</key>
<array>
Index: clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -27,6 +27,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
+#include <memory>
using namespace clang;
using namespace ento;
@@ -879,6 +880,44 @@
void printToken(const Token &Tok);
};
+/// Wrapper around a Lexer object that can lex tokens one-by-one. Optionally,
+/// one can "inject" a range of tokens into the stream, in which case the next
+/// token is retrieved from the next element of the range, until the end of the
+/// range is reached.
+class TokenStream {
+public:
+ TokenStream(SourceLocation ExpanLoc, const SourceManager &SM,
+ const LangOptions &LangOpts)
+ : ExpanLoc(ExpanLoc) {
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(ExpanLoc);
+ const llvm::MemoryBuffer *MB = SM.getBuffer(LocInfo.first);
+ const char *MacroNameTokenPos = MB->getBufferStart() + LocInfo.second;
+
+ RawLexer.reset(new Lexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts,
+ MB->getBufferStart(), MacroNameTokenPos,
+ MB->getBufferEnd()));
+ }
+
+ void next(Token &Result) {
+ if (CurrTokenIt == TokenRange.end()) {
+ RawLexer->LexFromRawLexer(Result);
+ return;
+ }
+ Result = *CurrTokenIt;
+ CurrTokenIt++;
+ }
+
+ void injextRange(const ArgTokensTy &Range) {
+ TokenRange = Range;
+ CurrTokenIt = TokenRange.begin();
+ }
+
+ std::unique_ptr<Lexer> RawLexer;
+ ArgTokensTy TokenRange;
+ ArgTokensTy::iterator CurrTokenIt = TokenRange.begin();
+ SourceLocation ExpanLoc;
+};
+
} // end of anonymous namespace
/// The implementation method of getMacroExpansion: It prints the expansion of
@@ -933,8 +972,9 @@
/// When \p ExpanLoc references "SET_TO_NULL(a)" within the definition of
/// "NOT_SUSPICOUS", the macro name "SET_TO_NULL" and the MacroArgMap map
/// { (x, a) } will be returned.
-static MacroExpansionInfo getMacroExpansionInfo(SourceLocation ExpanLoc,
- const Preprocessor &PP);
+static MacroExpansionInfo
+getMacroExpansionInfo(const MacroParamMap &PrevParamMap,
+ SourceLocation ExpanLoc, const Preprocessor &PP);
/// Retrieves the ')' token that matches '(' \p It points to.
static MacroInfo::tokens_iterator getMatchingRParen(
@@ -980,7 +1020,7 @@
const SourceManager &SM = PP.getSourceManager();
MacroExpansionInfo MExpInfo =
- getMacroExpansionInfo(SM.getExpansionLoc(MacroLoc), PP);
+ getMacroExpansionInfo(PrevParamMap, SM.getExpansionLoc(MacroLoc), PP);
IdentifierInfo *MacroNameII = PP.getIdentifierInfo(MExpInfo.Name);
// TODO: If the macro definition contains another symbol then this function is
@@ -1077,24 +1117,20 @@
return MExpInfo.Name;
}
-static MacroExpansionInfo getMacroExpansionInfo(SourceLocation ExpanLoc,
- const Preprocessor &PP) {
+static MacroExpansionInfo
+getMacroExpansionInfo(const MacroParamMap &PrevParamMap,
+ SourceLocation ExpanLoc, const Preprocessor &PP) {
const SourceManager &SM = PP.getSourceManager();
const LangOptions &LangOpts = PP.getLangOpts();
// First, we create a Lexer to lex *at the expansion location* the tokens
// referring to the macro's name and its arguments.
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(ExpanLoc);
- const llvm::MemoryBuffer *MB = SM.getBuffer(LocInfo.first);
- const char *MacroNameTokenPos = MB->getBufferStart() + LocInfo.second;
-
- Lexer RawLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts,
- MB->getBufferStart(), MacroNameTokenPos, MB->getBufferEnd());
+ TokenStream TStream(ExpanLoc, SM, LangOpts);
// Acquire the macro's name.
Token TheTok;
- RawLexer.LexFromRawLexer(TheTok);
+ TStream.next(TheTok);
std::string MacroName = PP.getSpelling(TheTok);
@@ -1122,7 +1158,7 @@
if (MacroParams.empty())
return { MacroName, MI, {} };
- RawLexer.LexFromRawLexer(TheTok);
+ TStream.next(TheTok);
// When this is a token which expands to another macro function then its
// parentheses are not at its expansion locaiton. For example:
//
@@ -1166,7 +1202,7 @@
if (ParenthesesDepth != 0) {
// Lex the first token of the next macro parameter.
- RawLexer.LexFromRawLexer(TheTok);
+ TStream.next(TheTok);
while (
!(ParenthesesDepth == 1 &&
@@ -1183,16 +1219,20 @@
if (ParenthesesDepth == 0)
break;
- if (TheTok.is(tok::raw_identifier))
+ if (TheTok.is(tok::raw_identifier)) {
PP.LookUpIdentifierInfo(TheTok);
+ if (TheTok.getIdentifierInfo() == __VA_ARGS__II) {
+ TStream.injextRange(
+ const_cast<MacroParamMap &>(PrevParamMap)[__VA_ARGS__II]);
+ TStream.next(TheTok);
+ continue;
+ }
+ }
ArgTokens.push_back(TheTok);
- RawLexer.LexFromRawLexer(TheTok);
+ TStream.next(TheTok);
}
} else {
- // FIXME: Handle when multiple parameters map to a single argument.
- // Currently, we only handle when multiple arguments map to the same
- // parameter.
assert(CurrParamII == __VA_ARGS__II &&
"No more macro arguments are found, but the current parameter "
"isn't __VA_ARGS__!");
@@ -1295,6 +1335,9 @@
}
void TokenPrinter::printToken(const Token &Tok) {
+ // TODO: Handle the case where hash and hashhash occurs right before
+ // __VA_ARGS__.
+
// If this is the first token to be printed, don't print space.
if (PrevTok.isNot(tok::unknown)) {
// If the tokens were already space separated, or if they must be to avoid
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits