Szelethus updated this revision to Diff 172459. Szelethus marked an inline comment as done. Szelethus added a comment.
- Fixes according to @xazax.hun's observations Thanks! I'll commit when I have time watch buildbots. https://reviews.llvm.org/D52794 Files: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist test/Analysis/plist-macros-with-expansion.cpp
Index: test/Analysis/plist-macros-with-expansion.cpp =================================================================== --- test/Analysis/plist-macros-with-expansion.cpp +++ test/Analysis/plist-macros-with-expansion.cpp @@ -27,8 +27,8 @@ *ptr = 5; // expected-warning{{Dereference of null pointer}} } -// CHECK: <key>name</key><string></string> -// CHECK-NEXT: <key>expansion</key><string></string> +// CHECK: <key>name</key><string>SET_PTR_VAR_TO_NULL</string> +// CHECK-NEXT: <key>expansion</key><string>ptr = 0</string> #define NULL 0 #define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \ @@ -40,5 +40,109 @@ *ptr = 5; // expected-warning{{Dereference of null pointer}} } -// CHECK: <key>name</key><string></string> -// CHECK-NEXT: <key>expansion</key><string></string> +// CHECK: <key>name</key><string>SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO</string> +// CHECK-NEXT: <key>expansion</key><string>ptr =0</string> + +//===----------------------------------------------------------------------===// +// Tests for function-like macro expansions. +//===----------------------------------------------------------------------===// + +void setToNull(int **vptr) { + *vptr = nullptr; +} + +#define TO_NULL(x) \ + setToNull(x) + +void functionLikeMacroTest() { + int *ptr; + TO_NULL(&ptr); + *ptr = 5; // expected-warning{{Dereference of null pointer}} +} + +// TODO: Expand arguments. +// CHECK: <key>name</key><string>TO_NULL</string> +// CHECK: <key>expansion</key><string>setToNull(x)</string> + +#define DOES_NOTHING(x) \ + { \ + int b; \ + b = 5; \ + } \ + print(x) + +#define DEREF(x) \ + DOES_NOTHING(x); \ + *x + +void functionLikeNestedMacroTest() { + int *a; + TO_NULL(&a); + DEREF(a) = 5; // expected-warning{{Dereference of null pointer}} +} + +// TODO: Expand arguments. +// CHECK: <key>name</key><string>TO_NULL</string> +// CHECK-NEXT: <key>expansion</key><string>setToNull(x)</string> + +// TODO: Expand arguments. +// CHECK: <key>name</key><string>DEREF</string> +// CHECK-NEXT: <key>expansion</key><string>{ int b; b = 5; } print(x); *x</string> + +//===----------------------------------------------------------------------===// +// Tests for undefining and/or redifining macros. +//===----------------------------------------------------------------------===// + +#define WILL_UNDEF_SET_NULL_TO_PTR(ptr) \ + ptr = nullptr; + +void undefinedMacroByTheEndOfParsingTest() { + int *ptr; + WILL_UNDEF_SET_NULL_TO_PTR(ptr); + *ptr = 5; // expected-warning{{Dereference of null pointer}} +} + +#undef WILL_UNDEF_SET_NULL_TO_PTR + +// TODO: Expand arguments. +// CHECK: <key>name</key><string>WILL_UNDEF_SET_NULL_TO_PTR</string> +// CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string> + +#define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \ + /* Nothing */ +#undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL +#define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \ + ptr = nullptr; + +void macroRedefinedMultipleTimesTest() { + int *ptr; + WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) + *ptr = 5; // expected-warning{{Dereference of null pointer}} +} + +#undef WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL +#define WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr) \ + print("This string shouldn't be in the plist file at all. Or anywhere, " \ + "but here."); + +// TODO: Expand arguments. +// CHECK: <key>name</key><string>WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL</string> +// CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string> + +#define WILL_UNDEF_SET_NULL_TO_PTR_2(ptr) \ + ptr = nullptr; + +#define PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr) \ + WILL_UNDEF_SET_NULL_TO_PTR_2(ptr) + +void undefinedMacroInsideAnotherMacroTest() { + int *ptr; + PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr); + *ptr = 5; // expected-warning{{Dereference of null pointer}} +} + +// TODO: Expand arguments. +// CHECK: <key>name</key><string>PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD</string> +// CHECK-NEXT: <key>expansion</key><string>ptr = nullptr;</string> + +#undef WILL_UNDEF_SET_NULL_TO_PTR_2 Index: test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist =================================================================== --- test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist +++ test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist @@ -143,8 +143,8 @@ <key>col</key><integer>3</integer> <key>file</key><integer>0</integer> </dict> - <key>name</key><string></string> - <key>expansion</key><string></string> + <key>name</key><string>SET_PTR_VAR_TO_NULL</string> + <key>expansion</key><string>ptr = 0</string> </dict> </array> <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> @@ -312,8 +312,8 @@ <key>col</key><integer>3</integer> <key>file</key><integer>0</integer> </dict> - <key>name</key><string></string> - <key>expansion</key><string></string> + <key>name</key><string>SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO</string> + <key>expansion</key><string>ptr =0</string> </dict> </array> <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> @@ -342,10 +342,1047 @@ </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>58</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>58</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>59</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>59</integer> + <key>col</key><integer>9</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>59</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>59</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>59</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>Calling 'setToNull'</string> + <key>message</key> + <string>Calling 'setToNull'</string> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>50</integer> + <key>col</key><integer>1</integer> + <key>file</key><integer>0</integer> + </dict> + <key>depth</key><integer>1</integer> + <key>extended_message</key> + <string>Entered call from 'functionLikeMacroTest'</string> + <key>message</key> + <string>Entered call from 'functionLikeMacroTest'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>50</integer> + <key>col</key><integer>1</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>50</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>51</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>51</integer> + <key>col</key><integer>3</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>51</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>51</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>51</integer> + <key>col</key><integer>17</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>1</integer> + <key>extended_message</key> + <string>Null pointer value stored to 'ptr'</string> + <key>message</key> + <string>Null pointer value stored to 'ptr'</string> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>59</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>59</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>59</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>Returning from 'setToNull'</string> + <key>message</key> + <string>Returning from 'setToNull'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>60</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>60</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>60</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>60</integer> + <key>col</key><integer>8</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>60</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>60</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>60</integer> + <key>col</key><integer>6</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + </dict> + </array> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>59</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string>TO_NULL</string> + <key>expansion</key><string>setToNull(x)</string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>370a457744311752aac789447b4ef16c</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>functionLikeMacroTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>60</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>50</integer> + <integer>51</integer> + <integer>57</integer> + <integer>58</integer> + <integer>59</integer> + <integer>60</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>79</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>79</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>80</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>80</integer> + <key>col</key><integer>9</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>80</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>80</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>80</integer> + <key>col</key><integer>13</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Calling 'setToNull'</string> + <key>message</key> + <string>Calling 'setToNull'</string> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>50</integer> + <key>col</key><integer>1</integer> + <key>file</key><integer>0</integer> + </dict> + <key>depth</key><integer>1</integer> + <key>extended_message</key> + <string>Entered call from 'functionLikeNestedMacroTest'</string> + <key>message</key> + <string>Entered call from 'functionLikeNestedMacroTest'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>50</integer> + <key>col</key><integer>1</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>50</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>51</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>51</integer> + <key>col</key><integer>3</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>51</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>51</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>51</integer> + <key>col</key><integer>17</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>1</integer> + <key>extended_message</key> + <string>Null pointer value stored to 'a'</string> + <key>message</key> + <string>Null pointer value stored to 'a'</string> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>80</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>80</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>80</integer> + <key>col</key><integer>13</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Returning from 'setToNull'</string> + <key>message</key> + <string>Returning from 'setToNull'</string> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>81</integer> + <key>col</key><integer>12</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>81</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>81</integer> + <key>col</key><integer>10</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'a')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'a')</string> + </dict> + </array> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>80</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string>TO_NULL</string> + <key>expansion</key><string>setToNull(x)</string> + </dict> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>81</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string>DEREF</string> + <key>expansion</key><string>{ int b; b = 5; } print(x); *x</string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'a')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>873802674657bba4565f64c7bbf0ded9</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>functionLikeNestedMacroTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>81</integer> + <key>col</key><integer>12</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>50</integer> + <integer>51</integer> + <integer>78</integer> + <integer>79</integer> + <integer>80</integer> + <integer>81</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>100</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>100</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>101</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>101</integer> + <key>col</key><integer>28</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>101</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>101</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>101</integer> + <key>col</key><integer>33</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Null pointer value stored to 'ptr'</string> + <key>message</key> + <string>Null pointer value stored to 'ptr'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>102</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>102</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>102</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>102</integer> + <key>col</key><integer>8</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>102</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>102</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>102</integer> + <key>col</key><integer>6</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + </dict> + </array> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>101</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string>WILL_UNDEF_SET_NULL_TO_PTR</string> + <key>expansion</key><string>ptr = nullptr;</string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>79ce7ac344a15505929edba2fdf178b6</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>undefinedMacroByTheEndOfParsingTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>102</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>99</integer> + <integer>100</integer> + <integer>101</integer> + <integer>102</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>118</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>118</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>119</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>119</integer> + <key>col</key><integer>42</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>119</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>119</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>119</integer> + <key>col</key><integer>47</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Null pointer value stored to 'ptr'</string> + <key>message</key> + <string>Null pointer value stored to 'ptr'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>120</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>120</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>120</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>120</integer> + <key>col</key><integer>8</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>120</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>120</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>120</integer> + <key>col</key><integer>6</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + </dict> + </array> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>119</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string>WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL</string> + <key>expansion</key><string>ptr = nullptr;</string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>cbbecfb64198aebb884f3729dff84896</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>macroRedefinedMultipleTimesTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>120</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>117</integer> + <integer>118</integer> + <integer>119</integer> + <integer>120</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>139</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>139</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>140</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>140</integer> + <key>col</key><integer>39</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>140</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>140</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>140</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>Null pointer value stored to 'ptr'</string> + <key>message</key> + <string>Null pointer value stored to 'ptr'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>141</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>141</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>141</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>141</integer> + <key>col</key><integer>8</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>141</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>141</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>141</integer> + <key>col</key><integer>6</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + </dict> + </array> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>140</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string>PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD</string> + <key>expansion</key><string>ptr = nullptr;</string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>01684c77381713fd6c7be31ebc9b647a</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>undefinedMacroInsideAnotherMacroTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>141</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>138</integer> + <integer>139</integer> + <integer>140</integer> + <integer>141</integer> + </array> + </dict> + </dict> </array> <key>files</key> <array> - <string>/home/eumakri/Documents/2codechecker_dev_env/llvm/tools/clang/test/Analysis/plist-macros-with-expansion.cpp</string> + <string>/home/szelethus/Documents/macro_expansion/clang/test/Analysis/plist-macros-with-expansion.cpp</string> </array> </dict> </plist> Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/TokenConcatenation.h" #include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" @@ -400,12 +401,6 @@ // Static function definitions. //===----------------------------------------------------------------------===// -static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, - const Preprocessor &PP) { - // TODO: Implement macro expansion. - return { "", "" }; -} - /// Print coverage information to output stream {@code o}. /// May modify the used list of files {@code Fids} by inserting new ones. static void printCoverage(const PathDiagnostic *D, @@ -721,3 +716,196 @@ // Finish. o << "</dict>\n</plist>"; } + +//===----------------------------------------------------------------------===// +// Declarations of helper functions and data structures for expanding macros. +//===----------------------------------------------------------------------===// + +namespace { + +struct MacroNameAndInfo { + std::string Name; + const MacroInfo *MI = nullptr; + + MacroNameAndInfo(std::string N, const MacroInfo *MI) + : Name(std::move(N)), MI(MI) {} +}; + +/// Helper class for printing tokens. +class TokenPrinter { + llvm::raw_ostream &OS; + const Preprocessor &PP; + + Token PrevTok, PrevPrevTok; + TokenConcatenation ConcatInfo; + +public: + TokenPrinter(llvm::raw_ostream &OS, const Preprocessor &PP) + : OS(OS), PP(PP), ConcatInfo(PP) { + PrevTok.setKind(tok::unknown); + PrevPrevTok.setKind(tok::unknown); + } + + void printToken(const Token &Tok); +}; + +} // end of anonymous namespace + +static std::string getMacroNameAndPrintExpansion(TokenPrinter &Printer, + SourceLocation MacroLoc, + const Preprocessor &PP); + +/// Retrieves the name of the macro and its MacroInfo. +static MacroNameAndInfo getMacroNameAndInfo(SourceLocation ExpanLoc, + const Preprocessor &PP); + +/// Retrieves the ')' token that matches '(' \p It points to. +static MacroInfo::tokens_iterator getMatchingRParen( + MacroInfo::tokens_iterator It, + MacroInfo::tokens_iterator End); + +/// Retrieves the macro info for \p II refers to at \p Loc. This is important +/// because macros can be redefined or undefined. +static const MacroInfo *getMacroInfoForLocation(const Preprocessor &PP, + const SourceManager &SM, + const IdentifierInfo *II, + SourceLocation Loc); + +//===----------------------------------------------------------------------===// +// Definitions of helper functions and methods for expanding macros. +//===----------------------------------------------------------------------===// + +static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, + const Preprocessor &PP) { + + llvm::SmallString<200> ExpansionBuf; + llvm::raw_svector_ostream OS(ExpansionBuf); + TokenPrinter Printer(OS, PP); + return { getMacroNameAndPrintExpansion(Printer, MacroLoc, PP), OS.str() }; +} + +static std::string getMacroNameAndPrintExpansion(TokenPrinter &Printer, + SourceLocation MacroLoc, + const Preprocessor &PP) { + + const SourceManager &SM = PP.getSourceManager(); + + MacroNameAndInfo Info = getMacroNameAndInfo(SM.getExpansionLoc(MacroLoc), PP); + const MacroInfo *MI = Info.MI; + + // Iterate over the macro's tokens and stringify them. + for (auto It = MI->tokens_begin(), E = MI->tokens_end(); It != E; ++It) { + Token T = *It; + + // If this token is not an identifier, we only need to print it. + if (T.isNot(tok::identifier)) { + Printer.printToken(T); + continue; + } + + const auto *II = T.getIdentifierInfo(); + assert(II && + "This token is an identifier but has no IdentifierInfo!"); + + // If this token is a macro that should be expanded inside the currect + // macro. + if (const MacroInfo *MI = + getMacroInfoForLocation(PP, SM, II, T.getLocation())) { + getMacroNameAndPrintExpansion(Printer, T.getLocation(), PP); + + // If this is a function-like macro, skip its arguments, as + // getExpandedMacro() already printed them. If this is the case, let's + // first jumo to the '(' token. + if (MI->getNumParams() != 0) + It = getMatchingRParen(++It, E); + continue; + } + + // If control reached here, then this token isn't a macro identifier, print + // it. + Printer.printToken(T); + } + + return Info.Name; +} + +static MacroNameAndInfo getMacroNameAndInfo(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()); + + // Acquire the macro's name. + Token TheTok; + RawLexer.LexFromRawLexer(TheTok); + + std::string MacroName = PP.getSpelling(TheTok); + + const auto *II = PP.getIdentifierInfo(MacroName); + assert(II && "Failed to acquire the IndetifierInfo for the macro!"); + + const MacroInfo *MI = getMacroInfoForLocation(PP, SM, II, ExpanLoc); + assert(MI && "The macro must've been defined at it's expansion location!"); + + return { MacroName, MI }; +} + +static MacroInfo::tokens_iterator getMatchingRParen( + MacroInfo::tokens_iterator It, + MacroInfo::tokens_iterator End) { + + assert(It->is(tok::l_paren) && "This token should be '('!"); + + // Skip until we find the closing ')'. + int ParanthesesDepth = 1; + while (ParanthesesDepth != 0) { + ++It; + + assert(It->isNot(tok::eof) && + "Encountered EOF while attempting to skip macro arguments!"); + assert(It != End && + "End of the macro definition reached before finding ')'!"); + + if (It->is(tok::l_paren)) + ++ParanthesesDepth; + + if (It->is(tok::r_paren)) + --ParanthesesDepth; + } + return It; +} + +static const MacroInfo *getMacroInfoForLocation(const Preprocessor &PP, + const SourceManager &SM, + const IdentifierInfo *II, + SourceLocation Loc) { + + const MacroDirective *MD = PP.getLocalMacroDirectiveHistory(II); + if (!MD) + return nullptr; + + return MD->findDirectiveAtLoc(Loc, SM).getMacroInfo(); +} + +void TokenPrinter::printToken(const Token &Tok) { + // If the tokens were already space separated, or if they must be to avoid + // them being implicitly pasted, add a space between them. + // If this is the first token to be printed, don't print space. + if (PrevTok.isNot(tok::unknown) && (Tok.hasLeadingSpace() || + ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok))) + OS << ' '; + + OS << PP.getSpelling(Tok); + + PrevPrevTok = PrevTok; + PrevTok = Tok; +}
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits