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 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 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 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 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(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 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 @@ + + path + + + kindcontrol + edges + + + start + + + line483 + col3 + file0 + + + line483 + col5 + file0 + + + end + + + line484 + col3 + file0 + + + line484 + col10 + file0 + + + + + + + kindevent + location + + line484 + col3 + file0 + + ranges + + + + line484 + col3 + file0 + + + line484 + col28 + file0 + + + + depth0 + extended_message + The value 0 is assigned to 'x' + message + The value 0 is assigned to 'x' + + + kindevent + location + + line485 + col13 + file0 + + ranges + + + + line485 + col10 + file0 + + + line485 + col15 + file0 + + + + depth0 + extended_message + Division by zero + message + Division by zero + + + macro_expansions + + + location + + line484 + col3 + file0 + + nameDISPATCH + expansionfoo(x, "LF1M healer");x = 0;; + + + descriptionDivision by zero + categoryLogic error + typeDivision by zero + check_namecore.DivideZero + + issue_hash_content_of_line_in_context0911a97774745d4fa0ac03cd9680dfe1 + issue_context_kindfunction + issue_contextmulitpleParamsResolveToVA_ARGS + issue_hash_function_offset3 + location + + line485 + col13 + file0 + + ExecutedLines + + 0 + + 482 + 483 + 484 + 485 + + + + + path + + + kindcontrol + edges + + + start + + + line496 + col3 + file0 + + + line496 + col5 + file0 + + + end + + + line497 + col3 + file0 + + + line497 + col16 + file0 + + + + + + + kindevent + location + + line497 + col3 + file0 + + ranges + + + + line497 + col3 + file0 + + + line497 + col71 + file0 + + + + depth0 + extended_message + The value 0 is assigned to 'x' + message + The value 0 is assigned to 'x' + + + kindevent + location + + line498 + col13 + file0 + + ranges + + + + line498 + col10 + file0 + + + line498 + col15 + file0 + + + + depth0 + extended_message + Division by zero + message + Division by zero + + + macro_expansions + + + location + + line497 + col3 + file0 + + nameCONCAT_VA_ARGS + expansionvariadicCFunction(x, "You need to construct additional pylons.",'c', 9);x = 0; + + + descriptionDivision by zero + categoryLogic error + typeDivision by zero + check_namecore.DivideZero + + issue_hash_content_of_line_in_contexted592fb952ed786e7efdc81bbc538e94 + issue_context_kindfunction + issue_contextconcatVA_ARGS + issue_hash_function_offset3 + location + + line498 + col13 + file0 + + ExecutedLines + + 0 + + 495 + 496 + 497 + 498 + + + + + path + + + kindcontrol + edges + + + start + + + line504 + col3 + file0 + + + line504 + col5 + file0 + + + end + + + line505 + col3 + file0 + + + line505 + col16 + file0 + + + + + + + kindevent + location + + line505 + col3 + file0 + + ranges + + + + line505 + col3 + file0 + + + line505 + col44 + file0 + + + + depth0 + extended_message + The value 0 is assigned to 'x' + message + The value 0 is assigned to 'x' + + + kindevent + location + + line506 + col13 + file0 + + ranges + + + + line506 + col10 + file0 + + + line506 + col15 + file0 + + + + depth0 + extended_message + Division by zero + message + Division by zero + + + macro_expansions + + + location + + line505 + col3 + file0 + + nameCONCAT_VA_ARGS + expansionvariadicCFunction(x, "You need to construct",);x = 0; + + + descriptionDivision by zero + categoryLogic error + typeDivision by zero + check_namecore.DivideZero + + issue_hash_content_of_line_in_context4b0ab46d7a972d0a388b4bb59351480a + issue_context_kindfunction + issue_contextconcatVA_ARGSEmpty + issue_hash_function_offset3 + location + + line506 + col13 + file0 + + ExecutedLines + + 0 + + 503 + 504 + 505 + 506 + + + + + path + + + kindcontrol + edges + + + start + + + line516 + col3 + file0 + + + line516 + col5 + file0 + + + end + + + line517 + col3 + file0 + + + line517 + col21 + file0 + + + + + + + kindevent + location + + line517 + col3 + file0 + + ranges + + + + line517 + col3 + file0 + + + line517 + col71 + file0 + + + + depth0 + extended_message + The value 0 is assigned to 'x' + message + The value 0 is assigned to 'x' + + + kindevent + location + + line518 + col13 + file0 + + ranges + + + + line518 + col10 + file0 + + + line518 + col15 + file0 + + + + depth0 + extended_message + Division by zero + message + Division by zero + + + macro_expansions + + + location + + line517 + col3 + file0 + + nameSTRINGIFIED_VA_ARGS + expansionvariadicCFunction(x, "Additional supply depots required.", "'a'", 10);x = 0; + + + descriptionDivision by zero + categoryLogic error + typeDivision by zero + check_namecore.DivideZero + + issue_hash_content_of_line_in_context6622e3f0651f97e6cbf4e075e6b07707 + issue_context_kindfunction + issue_contextstringifyVA_ARGS + issue_hash_function_offset3 + location + + line518 + col13 + file0 + + ExecutedLines + + 0 + + 515 + 516 + 517 + 518 + + + + + path + + + kindcontrol + edges + + + start + + + line525 + col3 + file0 + + + line525 + col5 + file0 + + + end + + + line526 + col3 + file0 + + + line526 + col21 + file0 + + + + + + + kindevent + location + + line526 + col3 + file0 + + ranges + + + + line526 + col3 + file0 + + + line526 + col62 + file0 + + + + depth0 + extended_message + The value 0 is assigned to 'x' + message + The value 0 is assigned to 'x' + + + kindevent + location + + line527 + col13 + file0 + + ranges + + + + line527 + col10 + file0 + + + line527 + col15 + file0 + + + + depth0 + extended_message + Division by zero + message + Division by zero + + + macro_expansions + + + location + + line526 + col3 + file0 + + nameSTRINGIFIED_VA_ARGS + expansionvariadicCFunction(x, "Additional supply depots required.", ")";x = 0; + + + descriptionDivision by zero + categoryLogic error + typeDivision by zero + check_namecore.DivideZero + + issue_hash_content_of_line_in_context86c6e52c81f1129e6c9f51e6938d9ee7 + issue_context_kindfunction + issue_contextstringifyVA_ARGSEmpty + issue_hash_function_offset3 + location + + line527 + col13 + file0 + + ExecutedLines + + 0 + + 524 + 525 + 526 + 527 + + + files 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: nameAPPLY_ZERO2 // CHECK-NEXT: expansionint bar() { return 0; } + +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: nameDISPATCH +// CHECK-NEXT: expansionfoo(x, "LF1M healer");x = 0;; + +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: nameCONCAT_VA_ARGS +// CHECK-NEXT: expansionvariadicCFunction(x, "You need to construct additional pylons.",'c', 9);x = 0; + +void concatVA_ARGSEmpty(void) { + int x = 1; + CONCAT_VA_ARGS(x, "You need to construct"); + (void)(10 / x); // expected-warning{{Division by zero}} +} +// CHECK: nameCONCAT_VA_ARGS +// CHECK-NEXT: expansionvariadicCFunction(x, "You need to construct",);x = 0; + +#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: nameSTRINGIFIED_VA_ARGS +// CHECK-NEXT: expansionvariadicCFunction(x, "Additional supply depots required.", "'a'", 10);x = 0; + +void stringifyVA_ARGSEmpty(void) { + int x = 1; + STRINGIFIED_VA_ARGS(x, "Additional supply depots required."); + (void)(10 / x); // expected-warning{{Division by zero}} +} + +// CHECK: nameSTRINGIFIED_VA_ARGS +// CHECK-NEXT: expansionvariadicCFunction(x, "Additional supply depots required.", ")";x = 0;