Mercurial > hg > CbC > CbC_llvm
view clang/test/Analysis/plist-macros-with-expansion.cpp @ 236:c4bab56944e8 llvm-original
LLVM 16
author | kono |
---|---|
date | Wed, 09 Nov 2022 17:45:10 +0900 |
parents | 79ff65ed7e25 |
children |
line wrap: on
line source
// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core %s \ // RUN: -analyzer-output=plist -o %t.plist \ // RUN: -analyzer-config expand-macros=true -verify // // RUN: FileCheck --input-file=%t.plist %s void print(const void*); //===----------------------------------------------------------------------===// // Tests for non-function-like macro expansions. //===----------------------------------------------------------------------===// #define SET_PTR_VAR_TO_NULL \ ptr = 0 void nonFunctionLikeMacroTest() { int *ptr; SET_PTR_VAR_TO_NULL; *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>18</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>SET_PTR_VAR_TO_NULL</string> // CHECK-NEXT: <key>expansion</key><string>ptr =0</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define NULL 0 #define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \ ptr = NULL void nonFunctionLikeNestedMacroTest() { int *ptr; SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO; *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>42</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO</string> // CHECK-NEXT: <key>expansion</key><string>ptr =0</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> //===----------------------------------------------------------------------===// // 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}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>73</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>TO_NULL(&ptr)</string> // CHECK-NEXT: <key>expansion</key><string>setToNull (&ptr )</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #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}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>104</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>TO_NULL(&a)</string> // CHECK-NEXT: <key>expansion</key><string>setToNull (&a )</string> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>105</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>DEREF(a)</string> // CHECK-NEXT: <key>expansion</key><string>{int b ;b =5;}print (a );*a </string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> //===----------------------------------------------------------------------===// // 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 // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>141</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>WILL_UNDEF_SET_NULL_TO_PTR(ptr)</string> // CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #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."); // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>169</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>WILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL(ptr)</string> // CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #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}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>200</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>PASS_PTR_TO_MACRO_THAT_WILL_BE_UNDEFD(ptr)</string> // CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #undef WILL_UNDEF_SET_NULL_TO_PTR_2 //===----------------------------------------------------------------------===// // Tests for macro arguments containing commas and parantheses. // // As of writing these tests, the algorithm expands macro arguments by lexing // the macro's expansion location, and relies on finding tok::comma and // tok::l_paren/tok::r_paren. //===----------------------------------------------------------------------===// // Note that this commas, parantheses in strings aren't parsed as tok::comma or // tok::l_paren/tok::r_paren, but why not test them. #define TO_NULL_AND_PRINT(x, str) \ x = 0; \ print(str) void macroArgContainsCommaInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this , cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>237</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this , cause a crash?")</string> // CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this , cause a crash?")</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> void macroArgContainsLParenInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this ( cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>257</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this ( cause a crash?")</string> // CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this ( cause a crash?")</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> void macroArgContainsRParenInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this ) cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>277</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this ) cause a crash?")</string> // CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this ) cause a crash?")</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define CALL_FUNCTION(funcCall) \ funcCall // Function calls do contain both tok::comma and tok::l_paren/tok::r_paren. void macroArgContainsLParenRParenTest() { int *a; CALL_FUNCTION(setToNull(&a)); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>302</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>CALL_FUNCTION(setToNull(&a))</string> // CHECK-NEXT: <key>expansion</key><string>setToNull (&a )</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> void setToNullAndPrint(int **vptr, const char *str) { setToNull(vptr); print(str); } void macroArgContainsCommaLParenRParenTest() { int *a; CALL_FUNCTION(setToNullAndPrint(&a, "Hello!")); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>327</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>CALL_FUNCTION(setToNullAndPrint(&a, "Hello!"))</string> // CHECK-NEXT: <key>expansion</key><string>setToNullAndPrint (&a ,"Hello!")</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define CALL_FUNCTION_WITH_TWO_PARAMS(funcCall, param1, param2) \ funcCall(param1, param2) void macroArgContainsCommaLParenRParenTest2() { int *a; CALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &a, "Hello!"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>350</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>CALL_FUNCTION_WITH_TWO_PARAMS(setToNullAndPrint, &a, "Hello!")</string> // CHECK-NEXT: <key>expansion</key><string>setToNullAndPrint (&a ,"Hello!")</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define CALL_LAMBDA(l) \ l() void commaInBracketsTest() { int *ptr; const char str[] = "Hello!"; // You need to add parantheses around a lambda expression to compile this, // else the comma in the capture will be parsed as divider of macro args. CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); })); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // FIXME: Why does the expansion appear twice? // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>376</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); }))</string> // CHECK-NEXT: <key>expansion</key><string>([&ptr ,str ]()mutable {setToNull (&ptr );})()</string> // CHECK-NEXT: </dict> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>376</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>CALL_LAMBDA(([&ptr, str] () mutable { TO_NULL(&ptr); }))</string> // CHECK-NEXT: <key>expansion</key><string>([&ptr ,str ]()mutable {setToNull (&ptr );})()</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define PASTE_CODE(code) \ code void commaInBracesTest() { PASTE_CODE({ // expected-warning{{Dereference of null pointer}} // NOTE: If we were to add a new variable here after a comma, we'd get a // compilation error, so this test is mainly here to show that this was also // investigated. // // int *ptr = nullptr, a; int *ptr = nullptr; *ptr = 5; }) } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>408</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>PASTE_CODE({ // expected- // CHECK-NEXT: // NOTE: If we were to add a new variable here after a comma, we'd get a // CHECK-NEXT: // compilation error, so this test is mainly here to show that this was also // CHECK-NEXT: // investigated. // CHECK-NEXT: // // CHECK-NEXT: // int *ptr = nullptr, a; // CHECK-NEXT: int *ptr = nullptr; // CHECK-NEXT: *ptr = 5; // CHECK-NEXT: })</string> // CHECK-NEXT: <key>expansion</key><string>{int *ptr =nullptr ;*ptr =5;}</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> // Example taken from // https://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html#Macro-Arguments. #define POTENTIALLY_EMPTY_PARAM(x, y) \ x; \ y = nullptr void emptyParamTest() { int *ptr; POTENTIALLY_EMPTY_PARAM(,ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>451</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>POTENTIALLY_EMPTY_PARAM(,ptr)</string> // CHECK-NEXT: <key>expansion</key><string>;ptr =nullptr </string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define NESTED_EMPTY_PARAM(a, b) \ POTENTIALLY_EMPTY_PARAM(a, b); void nestedEmptyParamTest() { int *ptr; NESTED_EMPTY_PARAM(, ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>476</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>NESTED_EMPTY_PARAM(, ptr)</string> // CHECK-NEXT: <key>expansion</key><string>;ptr =nullptr ;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(func, param) \ CALL_FUNCTION(func(param)) void lParenRParenInNestedMacro() { int *ptr; CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>499</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>CALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO(setToNull, &ptr)</string> // CHECK-NEXT: <key>expansion</key><string>setToNull (&ptr )</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> //===----------------------------------------------------------------------===// // Tests for variadic macro arguments. //===----------------------------------------------------------------------===// template <typename ...Args> void variadicFunc(Args ...args); #define VARIADIC_SET_TO_NULL(ptr, ...) \ ptr = nullptr; \ variadicFunc(__VA_ARGS__) void variadicMacroArgumentTest() { int *ptr; VARIADIC_SET_TO_NULL(ptr, 1, 5, "haha!"); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>530</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>VARIADIC_SET_TO_NULL(ptr, 1, 5, "haha!")</string> // CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;variadicFunc (1,5,"haha!")</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> void variadicMacroArgumentWithoutAnyArgumentTest() { int *ptr; // Not adding a single parameter to ... is silly (and also causes a // preprocessor warning), but is not an excuse to crash on it. VARIADIC_SET_TO_NULL(ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>552</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>VARIADIC_SET_TO_NULL(ptr)</string> // CHECK-NEXT: <key>expansion</key><string>ptr =nullptr ;variadicFunc ()</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> //===----------------------------------------------------------------------===// // Tests for # and ##. //===----------------------------------------------------------------------===// #define DECLARE_FUNC_AND_SET_TO_NULL(funcName, ptr) \ void generated_##funcName(); \ ptr = nullptr; void hashHashOperatorTest() { int *ptr; DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>580</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>DECLARE_FUNC_AND_SET_TO_NULL(whatever, ptr)</string> // CHECK-NEXT: <key>expansion</key><string>void generated_whatever ();ptr =nullptr ;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> void macroArgContainsHashHashInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this ## cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>600</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this ## cause a crash?")</string> // CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this ## cause a crash?")</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define PRINT_STR(str, ptr) \ print(#str); \ ptr = nullptr void hashOperatorTest() { int *ptr; PRINT_STR(Hello, ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>624</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>PRINT_STR(Hello, ptr)</string> // CHECK-NEXT: <key>expansion</key><string>print ("Hello");ptr =nullptr </string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> void macroArgContainsHashInStringTest() { int *a; TO_NULL_AND_PRINT(a, "Will this # cause a crash?"); *a = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>644</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>TO_NULL_AND_PRINT(a, "Will this # cause a crash?")</string> // CHECK-NEXT: <key>expansion</key><string>a =0;print ("Will this # cause a crash?")</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> //===----------------------------------------------------------------------===// // Tests for more complex macro expansions. // // We won't cover anything that wasn't covered up to this point, but rather // show more complex, macros with deeper nesting, more arguments (some unused) // and so on. //===----------------------------------------------------------------------===// #define IF(Condition) \ if ( Condition ) #define L_BRACE { #define R_BRACE } #define LESS < #define GREATER > #define EQUALS = #define SEMICOLON ; #define NEGATIVE - #define RETURN return #define ZERO 0 #define EUCLIDEAN_ALGORITHM(A, B) \ IF(A LESS ZERO) L_BRACE \ A EQUALS NEGATIVE A SEMICOLON \ R_BRACE \ IF(B LESS ZERO) L_BRACE \ B EQUALS NEGATIVE B SEMICOLON \ R_BRACE \ \ /* This is where a while loop would be, but that seems to be too complex */ \ /* for the analyzer just yet. Let's just pretend that this algorithm */ \ /* works. */ \ \ RETURN B / (B - B) SEMICOLON int getLowestCommonDenominator(int A, int B) { EUCLIDEAN_ALGORITHM(A, B) // expected-warning{{Division by zero}} } void testVeryComplexAlgorithm() { int tmp = 8 / (getLowestCommonDenominator(5, 7) - 1); print(&tmp); } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>698</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>EUCLIDEAN_ALGORITHM(A, B)</string> // CHECK-NEXT: <key>expansion</key><string>if (A <0){A =-A ;}if (B <0){B =-B ;}return B /(B -B );</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define YET_ANOTHER_SET_TO_NULL(x, y, z) \ print((void *) x); \ print((void *) y); \ z = nullptr; #define DO_NOTHING(str) str #define DO_NOTHING2(str2) DO_NOTHING(str2) void test() { int *ptr; YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr); *ptr = 5; // expected-warning{{Dereference of null pointer}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>730</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>YET_ANOTHER_SET_TO_NULL(5, DO_NOTHING2("Remember the Vasa"), ptr)</string> // CHECK-NEXT: <key>expansion</key><string>print ((void *)5);print ((void *)"Remember the Vasa");ptr =nullptr ;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> int garbage_value; #define REC_MACRO_FUNC(REC_MACRO_PARAM) garbage_##REC_MACRO_PARAM #define value REC_MACRO_FUNC(value) void recursiveMacroUser() { if (value == 0) 1 / value; // expected-warning{{Division by zero}} // expected-warning@-1{{expression result unused}} } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>754</integer> // CHECK-NEXT: <key>col</key><integer>7</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>value</string> // CHECK-NEXT: <key>expansion</key><string>garbage_value </string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define FOO(x) int foo() { return x; } #define APPLY_ZERO1(function) function(0) APPLY_ZERO1(FOO) void useZeroApplier1() { (void)(1 / foo()); } // expected-warning{{Division by zero}} // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>776</integer> // CHECK-NEXT: <key>col</key><integer>1</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>APPLY_ZERO1(FOO)</string> // CHECK-NEXT: <key>expansion</key><string>int foo (){return 0;}</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #define BAR(x) int bar() { return x; } #define APPLY_ZERO2 BAR(0) APPLY_ZERO2 void useZeroApplier2() { (void)(1 / bar()); } // expected-warning{{Division by zero}} // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>796</integer> // CHECK-NEXT: <key>col</key><integer>1</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>APPLY_ZERO2</string> // CHECK-NEXT: <key>expansion</key><string>int bar (){return 0;}</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> 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>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>821</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>DISPATCH(x, "LF1M healer")</string> // CHECK-NEXT: <key>expansion</key><string>foo (x ,"LF1M healer");x =0;;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> 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>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>846</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>CONCAT_VA_ARGS(x, "You need to construct additional pylons.", 'c', 9)</string> // CHECK-NEXT: <key>expansion</key><string>variadicCFunction (x ,"You need to construct additional pylons.",'c',9);x =0;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> 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>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>866</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>CONCAT_VA_ARGS(x, "You need to construct")</string> // CHECK-NEXT: <key>expansion</key><string>variadicCFunction (x ,"You need to construct");x =0;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> #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>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>889</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>STRINGIFIED_VA_ARGS(x, "Additional supply depots required.", 'a', 10)</string> // CHECK-NEXT: <key>expansion</key><string>variadicCFunction (x ,"Additional supply depots required.","'a', 10");x =0;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> 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>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>909</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>STRINGIFIED_VA_ARGS(x, "Additional supply depots required.")</string> // CHECK-NEXT: <key>expansion</key><string>variadicCFunction (x ,"Additional supply depots required.","");x =0;</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array> // bz44493: Support GNU-style named variadic arguments in plister #define BZ44493_GNUVA(i, args...) --(i); int bz44493(void) { int a = 2; BZ44493_GNUVA(a); BZ44493_GNUVA(a, "arg2"); (void)(10 / a); // expected-warning{{Division by zero}} return 0; } // CHECK: <key>macro_expansions</key> // CHECK-NEXT: <array> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>location</key> // CHECK-NEXT: <dict> // CHECK-NEXT: <key>line</key><integer>933</integer> // CHECK-NEXT: <key>col</key><integer>3</integer> // CHECK-NEXT: <key>file</key><integer>0</integer> // CHECK-NEXT: </dict> // CHECK-NEXT: <key>name</key><string>BZ44493_GNUVA(a, "arg2")</string> // CHECK-NEXT: <key>expansion</key><string>--(a );</string> // CHECK-NEXT: </dict> // CHECK-NEXT: </array>