Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -723,12 +723,22 @@ namespace { -struct MacroNameAndInfo { +using ExpArgTokens = llvm::SmallVector; + +/// Maps unexpanded macro arguments to expanded arguments. A macro argument may +/// need to expanded further when it is nested inside another macro. +class MacroArgMap : public std::map { +public: + void expandFromPrevMacro(const MacroArgMap &Super); +}; + +struct MacroNameAndArgs { std::string Name; const MacroInfo *MI = nullptr; + MacroArgMap Args; - MacroNameAndInfo(std::string N, const MacroInfo *MI) - : Name(std::move(N)), MI(MI) {} + MacroNameAndArgs(std::string N, const MacroInfo *MI, MacroArgMap M) + : Name(std::move(N)), MI(MI), Args(std::move(M)) {} }; /// Helper class for printing tokens. @@ -753,10 +763,32 @@ 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, + MacroArgMap *PrevArgs); + +/// Retrieves the name of the macro and what it's arguments expand into +/// at \p ExpanLoc. +/// +/// For example, for the following macro expansion: +/// +/// #define SET_TO_NULL(x) x = 0 +/// #define NOT_SUSPICIOUS(a) \ +/// { \ +/// int b = 0; \ +/// } \ +/// SET_TO_NULL(a) +/// +/// int *ptr = new int(4); +/// NOT_SUSPICIOUS(&ptr); +/// *ptr = 5; +/// +/// When \p ExpanLoc references the last line, the macro name "NOT_SUSPICIOUS" +/// and the MacroArgMap map { (a, &ptr) } will be returned. +/// +/// 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 MacroNameAndArgs getMacroNameAndArgs(SourceLocation ExpanLoc, const Preprocessor &PP); /// Retrieves the ')' token that matches '(' \p It points to. @@ -781,18 +813,28 @@ llvm::SmallString<200> ExpansionBuf; llvm::raw_svector_ostream OS(ExpansionBuf); TokenPrinter Printer(OS, PP); - std::string MacroName = getMacroNameAndPrintExpansion(Printer, MacroLoc, PP); + std::string MacroName = getMacroNameAndPrintExpansion(Printer, MacroLoc, PP, + /* PrevArgs */ nullptr); return { MacroName, OS.str() }; } static std::string getMacroNameAndPrintExpansion(TokenPrinter &Printer, - SourceLocation MacroLoc, - const Preprocessor &PP) { + SourceLocation MacroLoc, + const Preprocessor &PP, + MacroArgMap *PrevArgs) { const SourceManager &SM = PP.getSourceManager(); - MacroNameAndInfo Info = getMacroNameAndInfo(SM.getExpansionLoc(MacroLoc), PP); + MacroNameAndArgs Info = getMacroNameAndArgs(SM.getExpansionLoc(MacroLoc), PP); + const MacroInfo *MI = Info.MI; + MacroArgMap &Args = Info.Args; + + // If this macro is nested inside another one, let's manually expand its + // arguments from the previous macro. + if (PrevArgs) + Args.expandFromPrevMacro(*PrevArgs); + PrevArgs = &Args; // Iterate over the macro's tokens and stringify them. for (auto It = MI->tokens_begin(), E = MI->tokens_end(); It != E; ++It) { @@ -812,7 +854,7 @@ // macro. if (const MacroInfo *MI = getMacroInfoForLocation(PP, SM, II, T.getLocation())) { - getMacroNameAndPrintExpansion(Printer, T.getLocation(), PP); + getMacroNameAndPrintExpansion(Printer, T.getLocation(), PP, PrevArgs); // If this is a function-like macro, skip its arguments, as // getExpandedMacro() already printed them. If this is the case, let's @@ -822,15 +864,25 @@ continue; } - // If control reached here, then this token isn't a macro identifier, print - // it. + // If this token is the current macro's argument, we should expand it. + if (Args.count(II)) { + for (const Token &ExpandedArgT : Args.at(II)) { + Printer.printToken(ExpandedArgT); + } + continue; + } + + // TODO: Handle tok::hash and tok::hashhash. + + // If control reached here, then this token isn't a macro identifier, nor an + // unexpanded macro argument that we need to handle, print it. Printer.printToken(T); } return Info.Name; } -static MacroNameAndInfo getMacroNameAndInfo(SourceLocation ExpanLoc, +static MacroNameAndArgs getMacroNameAndArgs(SourceLocation ExpanLoc, const Preprocessor &PP) { const SourceManager &SM = PP.getSourceManager(); @@ -857,7 +909,66 @@ const MacroInfo *MI = getMacroInfoForLocation(PP, SM, II, ExpanLoc); assert(MI && "The macro must've been defined at it's expansion location!"); - return { MacroName, MI }; + // Acquire the macro's arguments. + // + // The rough idea here is to lex from the first left parentheses to the last + // right parentheses, and map the macro's unexpanded arguments to what they + // will be expanded to. An expanded macro argument may contain several tokens + // (like '3 + 4'), so we'll lex until we find a tok::comma or tok::r_paren, at + // which point we start lexing the next argument or finish. + ArrayRef MacroArgs = MI->params(); + if (MacroArgs.empty()) + return { MacroName, MI, {} }; + + RawLexer.LexFromRawLexer(TheTok); + assert(TheTok.is(tok::l_paren) && + "The token after the macro's identifier token should be '('!"); + + MacroArgMap Args; + + // When the macro's argument is a function call, like + // CALL_FN(someFunctionName(param1, param2)) + // we will find tok::l_paren, tok::r_paren, and tok::comma that do not divide + // actual macro arguments, or do not represent the macro argument's closing + // parentheses, so we'll count how many parentheses aren't closed yet. + int ParenthesesDepth = 1; + + for (const IdentifierInfo *UnexpArgII : MacroArgs) { + MacroArgMap::mapped_type ExpandedArgTokens; + + // Lex the first token of the next macro parameter. + RawLexer.LexFromRawLexer(TheTok); + + while (TheTok.isNot(tok::comma) || ParenthesesDepth != 1) { + assert(TheTok.isNot(tok::eof) && + "EOF encountered while looking for expanded macro args!"); + + if (TheTok.is(tok::l_paren)) + ++ParenthesesDepth; + + if (TheTok.is(tok::r_paren)) + --ParenthesesDepth; + + if (ParenthesesDepth == 0) + break; + + if (TheTok.is(tok::raw_identifier)) + PP.LookUpIdentifierInfo(TheTok); + + ExpandedArgTokens.push_back(TheTok); + RawLexer.LexFromRawLexer(TheTok); + } + + Args.emplace(UnexpArgII, std::move(ExpandedArgTokens)); + } + + // TODO: The condition really should be TheTok.is(tok::r_paren), but variadic + // macro arguments are not handled yet. + assert(TheTok.isOneOf(tok::r_paren, tok::comma) && + "Expanded macro argument acquisition failed! After the end of the loop" + " this token should be ')'!"); + + return { MacroName, MI, Args }; } static MacroInfo::tokens_iterator getMatchingRParen( @@ -867,8 +978,8 @@ assert(It->is(tok::l_paren) && "This token should be '('!"); // Skip until we find the closing ')'. - int ParanthesesDepth = 1; - while (ParanthesesDepth != 0) { + int ParenthesesDepth = 1; + while (ParenthesesDepth != 0) { ++It; assert(It->isNot(tok::eof) && @@ -877,10 +988,10 @@ "End of the macro definition reached before finding ')'!"); if (It->is(tok::l_paren)) - ++ParanthesesDepth; + ++ParenthesesDepth; if (It->is(tok::r_paren)) - --ParanthesesDepth; + --ParenthesesDepth; } return It; } @@ -897,6 +1008,38 @@ return MD->findDirectiveAtLoc(Loc, SM).getMacroInfo(); } +void MacroArgMap::expandFromPrevMacro(const MacroArgMap &Super) { + + for (value_type &Pair : *this) { + ExpArgTokens &CurrExpArgTokens = Pair.second; + + // For each token in the expanded macro argument. + auto It = CurrExpArgTokens.begin(); + while (It != CurrExpArgTokens.end()) { + if (It->isNot(tok::identifier)) { + ++It; + continue; + } + + const auto *II = It->getIdentifierInfo(); + assert(II); + + // Is this an argument that "Super" expands further? + if (!Super.count(II)) { + ++It; + continue; + } + + const ExpArgTokens &SuperExpArgTokens = Super.at(II); + + It = CurrExpArgTokens.insert( + It, SuperExpArgTokens.begin(), SuperExpArgTokens.end()); + std::advance(It, SuperExpArgTokens.size()); + It = CurrExpArgTokens.erase(It); + } + } +} + 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. 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 @@ -588,7 +588,7 @@ file0 nameTO_NULL - expansionsetToNull(x) + expansionsetToNull(&ptr) descriptionDereference of null pointer (loaded from variable 'ptr') @@ -630,12 +630,12 @@ start - line79 + line78 col3 file0 - line79 + line78 col5 file0 @@ -643,12 +643,12 @@ end - line80 + line79 col3 file0 - line80 + line79 col9 file0 @@ -660,7 +660,7 @@ kindevent location - line80 + line79 col3 file0 @@ -668,12 +668,12 @@ - line80 + line79 col3 file0 - line80 + line79 col13 file0 @@ -766,7 +766,7 @@ kindevent location - line80 + line79 col3 file0 @@ -774,12 +774,12 @@ - line80 + line79 col3 file0 - line80 + line79 col13 file0 @@ -795,7 +795,7 @@ kindevent location - line81 + line80 col12 file0 @@ -803,12 +803,12 @@ - line81 + line80 col3 file0 - line81 + line80 col10 file0 @@ -826,22 +826,22 @@ location - line80 + line79 col3 file0 nameTO_NULL - expansionsetToNull(x) + expansionsetToNull(&a) location - line81 + line80 col3 file0 nameDEREF - expansion{ int b; b = 5; } print(x); *x + expansion{ int b; b = 5; } print(a); *a descriptionDereference of null pointer (loaded from variable 'a') @@ -855,7 +855,7 @@ issue_hash_function_offset3 location - line81 + line80 col12 file0 @@ -865,10 +865,10 @@ 50 51 + 77 78 79 80 - 81 @@ -883,12 +883,12 @@ start - line100 + line97 col3 file0 - line100 + line97 col5 file0 @@ -896,12 +896,12 @@ end - line101 + line98 col3 file0 - line101 + line98 col28 file0 @@ -913,7 +913,7 @@ kindevent location - line101 + line98 col3 file0 @@ -921,12 +921,12 @@ - line101 + line98 col3 file0 - line101 + line98 col33 file0 @@ -946,12 +946,12 @@ start - line102 + line99 col3 file0 - line102 + line99 col3 file0 @@ -959,12 +959,12 @@ end - line102 + line99 col8 file0 - line102 + line99 col8 file0 @@ -976,7 +976,7 @@ kindevent location - line102 + line99 col8 file0 @@ -984,12 +984,12 @@ - line102 + line99 col4 file0 - line102 + line99 col6 file0 @@ -1007,7 +1007,7 @@ location - line101 + line98 col3 file0 @@ -1026,7 +1026,7 @@ issue_hash_function_offset3 location - line102 + line99 col8 file0 @@ -1034,10 +1034,10 @@ 0 + 96 + 97 + 98 99 - 100 - 101 - 102 @@ -1052,12 +1052,12 @@ start - line118 + line114 col3 file0 - line118 + line114 col5 file0 @@ -1065,12 +1065,12 @@ end - line119 + line115 col3 file0 - line119 + line115 col42 file0 @@ -1082,7 +1082,7 @@ kindevent location - line119 + line115 col3 file0 @@ -1090,12 +1090,12 @@ - line119 + line115 col3 file0 - line119 + line115 col47 file0 @@ -1115,12 +1115,12 @@ start - line120 + line116 col3 file0 - line120 + line116 col3 file0 @@ -1128,12 +1128,12 @@ end - line120 + line116 col8 file0 - line120 + line116 col8 file0 @@ -1145,7 +1145,7 @@ kindevent location - line120 + line116 col8 file0 @@ -1153,12 +1153,12 @@ - line120 + line116 col4 file0 - line120 + line116 col6 file0 @@ -1176,7 +1176,7 @@ location - line119 + line115 col3 file0 @@ -1195,7 +1195,7 @@ issue_hash_function_offset3 location - line120 + line116 col8 file0 @@ -1203,10 +1203,10 @@ 0 - 117 - 118 - 119 - 120 + 113 + 114 + 115 + 116 @@ -1221,12 +1221,12 @@ start - line139 + line134 col3 file0 - line139 + line134 col5 file0 @@ -1234,12 +1234,12 @@ end - line140 + line135 col3 file0 - line140 + line135 col39 file0 @@ -1251,7 +1251,7 @@ kindevent location - line140 + line135 col3 file0 @@ -1259,12 +1259,12 @@ - line140 + line135 col3 file0 - line140 + line135 col44 file0 @@ -1284,12 +1284,12 @@ start - line141 + line136 col3 file0 - line141 + line136 col3 file0 @@ -1297,12 +1297,12 @@ end - line141 + line136 col8 file0 - line141 + line136 col8 file0 @@ -1314,7 +1314,7 @@ kindevent location - line141 + line136 col8 file0 @@ -1322,12 +1322,12 @@ - line141 + line136 col4 file0 - line141 + line136 col6 file0 @@ -1345,7 +1345,7 @@ location - line140 + line135 col3 file0 @@ -1364,7 +1364,3212 @@ issue_hash_function_offset3 location - line141 + line136 + col8 + file0 + + ExecutedLines + + 0 + + 133 + 134 + 135 + 136 + + + + + path + + + kindcontrol + edges + + + start + + + line161 + col3 + file0 + + + line161 + col5 + file0 + + + end + + + line162 + col3 + file0 + + + line162 + col19 + file0 + + + + + + + kindevent + location + + line162 + col3 + file0 + + ranges + + + + line162 + col3 + file0 + + + line162 + col52 + file0 + + + + depth0 + extended_message + Null pointer value stored to 'a' + message + Null pointer value stored to 'a' + + + kindcontrol + edges + + + start + + + line163 + col3 + file0 + + + line163 + col3 + file0 + + + end + + + line163 + col6 + file0 + + + line163 + col6 + file0 + + + + + + + kindevent + location + + line163 + col6 + file0 + + ranges + + + + line163 + col4 + file0 + + + line163 + col4 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'a') + message + Dereference of null pointer (loaded from variable 'a') + + + macro_expansions + + + location + + line162 + col3 + file0 + + nameTO_NULL_AND_PRINT + expansiona = 0; print( "Will this , cause a crash?") + + + descriptionDereference of null pointer (loaded from variable 'a') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context7a7344244350405a514682fe228e304e + issue_context_kindfunction + issue_contextmacroArgContainsCommaInStringTest + issue_hash_function_offset3 + location + + line163 + col6 + file0 + + ExecutedLines + + 0 + + 160 + 161 + 162 + 163 + + + + + path + + + kindcontrol + edges + + + start + + + line170 + col3 + file0 + + + line170 + col5 + file0 + + + end + + + line171 + col3 + file0 + + + line171 + col19 + file0 + + + + + + + kindevent + location + + line171 + col3 + file0 + + ranges + + + + line171 + col3 + file0 + + + line171 + col52 + file0 + + + + depth0 + extended_message + Null pointer value stored to 'a' + message + Null pointer value stored to 'a' + + + kindcontrol + edges + + + start + + + line172 + col3 + file0 + + + line172 + col3 + file0 + + + end + + + line172 + col6 + file0 + + + line172 + col6 + file0 + + + + + + + kindevent + location + + line172 + col6 + file0 + + ranges + + + + line172 + col4 + file0 + + + line172 + col4 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'a') + message + Dereference of null pointer (loaded from variable 'a') + + + macro_expansions + + + location + + line171 + col3 + file0 + + nameTO_NULL_AND_PRINT + expansiona = 0; print( "Will this ( cause a crash?") + + + descriptionDereference of null pointer (loaded from variable 'a') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context1d6d14e3f566cec02bd1f3542e3c8044 + issue_context_kindfunction + issue_contextmacroArgContainsLParenInStringTest + issue_hash_function_offset3 + location + + line172 + col6 + file0 + + ExecutedLines + + 0 + + 169 + 170 + 171 + 172 + + + + + path + + + kindcontrol + edges + + + start + + + line179 + col3 + file0 + + + line179 + col5 + file0 + + + end + + + line180 + col3 + file0 + + + line180 + col19 + file0 + + + + + + + kindevent + location + + line180 + col3 + file0 + + ranges + + + + line180 + col3 + file0 + + + line180 + col52 + file0 + + + + depth0 + extended_message + Null pointer value stored to 'a' + message + Null pointer value stored to 'a' + + + kindcontrol + edges + + + start + + + line181 + col3 + file0 + + + line181 + col3 + file0 + + + end + + + line181 + col6 + file0 + + + line181 + col6 + file0 + + + + + + + kindevent + location + + line181 + col6 + file0 + + ranges + + + + line181 + col4 + file0 + + + line181 + col4 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'a') + message + Dereference of null pointer (loaded from variable 'a') + + + macro_expansions + + + location + + line180 + col3 + file0 + + nameTO_NULL_AND_PRINT + expansiona = 0; print( "Will this ) cause a crash?") + + + descriptionDereference of null pointer (loaded from variable 'a') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context7354d762d71f0d0a3ffc9d6d827fe580 + issue_context_kindfunction + issue_contextmacroArgContainsRParenInStringTest + issue_hash_function_offset3 + location + + line181 + col6 + file0 + + ExecutedLines + + 0 + + 178 + 179 + 180 + 181 + + + + + path + + + kindcontrol + edges + + + start + + + line193 + col3 + file0 + + + line193 + col5 + file0 + + + end + + + line194 + col3 + file0 + + + line194 + col15 + file0 + + + + + + + kindevent + location + + line194 + col3 + file0 + + ranges + + + + line194 + col3 + file0 + + + line194 + col30 + file0 + + + + depth0 + extended_message + Calling 'setToNull' + message + Calling 'setToNull' + + + kindevent + location + + line50 + col1 + file0 + + depth1 + extended_message + Entered call from 'macroArgContainsLParenRParenTest' + message + Entered call from 'macroArgContainsLParenRParenTest' + + + kindcontrol + edges + + + start + + + line50 + col1 + file0 + + + line50 + col4 + file0 + + + end + + + line51 + col3 + file0 + + + line51 + col3 + file0 + + + + + + + kindevent + location + + line51 + col3 + file0 + + ranges + + + + line51 + col3 + file0 + + + line51 + col17 + file0 + + + + depth1 + extended_message + Null pointer value stored to 'a' + message + Null pointer value stored to 'a' + + + kindevent + location + + line194 + col3 + file0 + + ranges + + + + line194 + col3 + file0 + + + line194 + col30 + file0 + + + + depth0 + extended_message + Returning from 'setToNull' + message + Returning from 'setToNull' + + + kindcontrol + edges + + + start + + + line195 + col3 + file0 + + + line195 + col3 + file0 + + + end + + + line195 + col6 + file0 + + + line195 + col6 + file0 + + + + + + + kindevent + location + + line195 + col6 + file0 + + ranges + + + + line195 + col4 + file0 + + + line195 + col4 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'a') + message + Dereference of null pointer (loaded from variable 'a') + + + macro_expansions + + + location + + line194 + col3 + file0 + + nameCALL_FUNCTION + expansionsetToNull(&a) + + + descriptionDereference of null pointer (loaded from variable 'a') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_contextf00b6f77288a374e864a58609e9a42ea + issue_context_kindfunction + issue_contextmacroArgContainsLParenRParenTest + issue_hash_function_offset3 + location + + line195 + col6 + file0 + + ExecutedLines + + 0 + + 50 + 51 + 192 + 193 + 194 + 195 + + + + + path + + + kindcontrol + edges + + + start + + + line207 + col3 + file0 + + + line207 + col5 + file0 + + + end + + + line208 + col3 + file0 + + + line208 + col15 + file0 + + + + + + + kindevent + location + + line208 + col3 + file0 + + ranges + + + + line208 + col3 + file0 + + + line208 + col48 + file0 + + + + depth0 + extended_message + Calling 'setToNullAndPrint' + message + Calling 'setToNullAndPrint' + + + kindevent + location + + line201 + col1 + file0 + + depth1 + extended_message + Entered call from 'macroArgContainsCommaLParenRParenTest' + message + Entered call from 'macroArgContainsCommaLParenRParenTest' + + + kindcontrol + edges + + + start + + + line201 + col1 + file0 + + + line201 + col4 + file0 + + + end + + + line202 + col3 + file0 + + + line202 + col11 + file0 + + + + + + + kindevent + location + + line202 + col3 + file0 + + ranges + + + + line202 + col3 + file0 + + + line202 + col17 + file0 + + + + depth1 + extended_message + Calling 'setToNull' + message + Calling 'setToNull' + + + kindevent + location + + line50 + col1 + file0 + + depth2 + extended_message + Entered call from 'setToNullAndPrint' + message + Entered call from 'setToNullAndPrint' + + + kindcontrol + edges + + + start + + + line50 + col1 + file0 + + + line50 + col4 + file0 + + + end + + + line51 + col3 + file0 + + + line51 + col3 + file0 + + + + + + + kindevent + location + + line51 + col3 + file0 + + ranges + + + + line51 + col3 + file0 + + + line51 + col17 + file0 + + + + depth2 + extended_message + Null pointer value stored to 'a' + message + Null pointer value stored to 'a' + + + kindevent + location + + line202 + col3 + file0 + + ranges + + + + line202 + col3 + file0 + + + line202 + col17 + file0 + + + + depth1 + extended_message + Returning from 'setToNull' + message + Returning from 'setToNull' + + + kindcontrol + edges + + + start + + + line202 + col3 + file0 + + + line202 + col11 + file0 + + + end + + + line203 + col3 + file0 + + + line203 + col7 + file0 + + + + + + + kindevent + location + + line208 + col3 + file0 + + ranges + + + + line208 + col3 + file0 + + + line208 + col48 + file0 + + + + depth0 + extended_message + Returning from 'setToNullAndPrint' + message + Returning from 'setToNullAndPrint' + + + kindcontrol + edges + + + start + + + line209 + col3 + file0 + + + line209 + col3 + file0 + + + end + + + line209 + col6 + file0 + + + line209 + col6 + file0 + + + + + + + kindevent + location + + line209 + col6 + file0 + + ranges + + + + line209 + col4 + file0 + + + line209 + col4 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'a') + message + Dereference of null pointer (loaded from variable 'a') + + + macro_expansions + + + location + + line208 + col3 + file0 + + nameCALL_FUNCTION + expansionsetToNullAndPrint(&a, "Hello!") + + + descriptionDereference of null pointer (loaded from variable 'a') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_contextc5805abeb71bb4edb41b49ab317439b9 + issue_context_kindfunction + issue_contextmacroArgContainsCommaLParenRParenTest + issue_hash_function_offset3 + location + + line209 + col6 + file0 + + ExecutedLines + + 0 + + 50 + 51 + 201 + 202 + 203 + 206 + 207 + 208 + 209 + + + + + path + + + kindcontrol + edges + + + start + + + line219 + col3 + file0 + + + line219 + col5 + file0 + + + end + + + line220 + col3 + file0 + + + line220 + col31 + file0 + + + + + + + kindevent + location + + line220 + col3 + file0 + + ranges + + + + line220 + col3 + file0 + + + line220 + col64 + file0 + + + + depth0 + extended_message + Calling 'setToNullAndPrint' + message + Calling 'setToNullAndPrint' + + + kindevent + location + + line201 + col1 + file0 + + depth1 + extended_message + Entered call from 'macroArgContainsCommaLParenRParenTest2' + message + Entered call from 'macroArgContainsCommaLParenRParenTest2' + + + kindcontrol + edges + + + start + + + line201 + col1 + file0 + + + line201 + col4 + file0 + + + end + + + line202 + col3 + file0 + + + line202 + col11 + file0 + + + + + + + kindevent + location + + line202 + col3 + file0 + + ranges + + + + line202 + col3 + file0 + + + line202 + col17 + file0 + + + + depth1 + extended_message + Calling 'setToNull' + message + Calling 'setToNull' + + + kindevent + location + + line50 + col1 + file0 + + depth2 + extended_message + Entered call from 'setToNullAndPrint' + message + Entered call from 'setToNullAndPrint' + + + kindcontrol + edges + + + start + + + line50 + col1 + file0 + + + line50 + col4 + file0 + + + end + + + line51 + col3 + file0 + + + line51 + col3 + file0 + + + + + + + kindevent + location + + line51 + col3 + file0 + + ranges + + + + line51 + col3 + file0 + + + line51 + col17 + file0 + + + + depth2 + extended_message + Null pointer value stored to 'a' + message + Null pointer value stored to 'a' + + + kindevent + location + + line202 + col3 + file0 + + ranges + + + + line202 + col3 + file0 + + + line202 + col17 + file0 + + + + depth1 + extended_message + Returning from 'setToNull' + message + Returning from 'setToNull' + + + kindcontrol + edges + + + start + + + line202 + col3 + file0 + + + line202 + col11 + file0 + + + end + + + line203 + col3 + file0 + + + line203 + col7 + file0 + + + + + + + kindevent + location + + line220 + col3 + file0 + + ranges + + + + line220 + col3 + file0 + + + line220 + col64 + file0 + + + + depth0 + extended_message + Returning from 'setToNullAndPrint' + message + Returning from 'setToNullAndPrint' + + + kindcontrol + edges + + + start + + + line221 + col3 + file0 + + + line221 + col3 + file0 + + + end + + + line221 + col6 + file0 + + + line221 + col6 + file0 + + + + + + + kindevent + location + + line221 + col6 + file0 + + ranges + + + + line221 + col4 + file0 + + + line221 + col4 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'a') + message + Dereference of null pointer (loaded from variable 'a') + + + macro_expansions + + + location + + line220 + col3 + file0 + + nameCALL_FUNCTION_WITH_TWO_PARAMS + expansionsetToNullAndPrint( &a, "Hello!") + + + descriptionDereference of null pointer (loaded from variable 'a') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context4014a22ef054933e6ce9be43623ea85e + issue_context_kindfunction + issue_contextmacroArgContainsCommaLParenRParenTest2 + issue_hash_function_offset3 + location + + line221 + col6 + file0 + + ExecutedLines + + 0 + + 50 + 51 + 201 + 202 + 203 + 218 + 219 + 220 + 221 + + + + + path + + + kindcontrol + edges + + + start + + + line231 + col3 + file0 + + + line231 + col5 + file0 + + + end + + + line235 + col3 + file0 + + + line235 + col13 + file0 + + + + + + + kindevent + location + + line235 + col3 + file0 + + ranges + + + + line235 + col3 + file0 + + + line235 + col58 + file0 + + + + depth0 + extended_message + Calling 'operator()' + message + Calling 'operator()' + + + kindevent + location + + line235 + col3 + file0 + + depth1 + extended_message + Entered call from 'commaInBracketsTest' + message + Entered call from 'commaInBracketsTest' + + + kindevent + location + + line235 + col3 + file0 + + ranges + + + + line235 + col3 + file0 + + + line235 + col58 + file0 + + + + depth1 + extended_message + Calling 'setToNull' + message + Calling 'setToNull' + + + kindevent + location + + line50 + col1 + file0 + + depth2 + extended_message + Entered call from 'operator()' + message + Entered call from 'operator()' + + + kindcontrol + edges + + + start + + + line50 + col1 + file0 + + + line50 + col4 + file0 + + + end + + + line51 + col3 + file0 + + + line51 + col3 + file0 + + + + + + + kindevent + location + + line51 + col3 + file0 + + ranges + + + + line51 + col3 + file0 + + + line51 + col17 + file0 + + + + depth2 + extended_message + Null pointer value stored to 'ptr' + message + Null pointer value stored to 'ptr' + + + kindevent + location + + line235 + col3 + file0 + + ranges + + + + line235 + col3 + file0 + + + line235 + col58 + file0 + + + + depth1 + extended_message + Returning from 'setToNull' + message + Returning from 'setToNull' + + + kindevent + location + + line235 + col3 + file0 + + ranges + + + + line235 + col3 + file0 + + + line235 + col58 + file0 + + + + depth0 + extended_message + Returning from 'operator()' + message + Returning from 'operator()' + + + kindcontrol + edges + + + start + + + line236 + col3 + file0 + + + line236 + col3 + file0 + + + end + + + line236 + col8 + file0 + + + line236 + col8 + file0 + + + + + + + kindevent + location + + line236 + col8 + file0 + + ranges + + + + line236 + col4 + file0 + + + line236 + col6 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + macro_expansions + + + location + + line235 + col3 + file0 + + nameCALL_LAMBDA + expansion([&ptr, str] () mutable { TO_NULL(&ptr); })() + + + location + + line235 + col3 + file0 + + nameCALL_LAMBDA + expansion([&ptr, str] () mutable { TO_NULL(&ptr); })() + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_contexta8918c38ddfa6a991701e7d19c9cd6bb + issue_context_kindfunction + issue_contextcommaInBracketsTest + issue_hash_function_offset6 + location + + line236 + col8 + file0 + + ExecutedLines + + 0 + + 50 + 51 + 230 + 231 + 232 + 235 + 236 + + + + + path + + + kindevent + location + + line246 + col3 + file0 + + ranges + + + + line246 + col3 + file0 + + + line254 + col4 + file0 + + + + depth0 + extended_message + 'ptr' initialized to a null pointer value + message + 'ptr' initialized to a null pointer value + + + kindevent + location + + line246 + col3 + file0 + + ranges + + + + line246 + col3 + file0 + + + line254 + col4 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + macro_expansions + + + location + + line246 + col3 + file0 + + namePASTE_CODE + expansion{ int *ptr = nullptr; *ptr = 5; } + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context63042e03ae0d2f3832b141a63b1d4d49 + issue_context_kindfunction + issue_contextcommaInBracesTest + issue_hash_function_offset1 + location + + line246 + col3 + file0 + + ExecutedLines + + 0 + + 245 + 246 + + + + + path + + + kindcontrol + edges + + + start + + + line268 + col3 + file0 + + + line268 + col5 + file0 + + + end + + + line270 + col3 + file0 + + + line270 + col25 + file0 + + + + + + + kindevent + location + + line270 + col3 + file0 + + ranges + + + + line270 + col3 + file0 + + + line270 + col31 + file0 + + + + depth0 + extended_message + Null pointer value stored to 'ptr' + message + Null pointer value stored to 'ptr' + + + kindcontrol + edges + + + start + + + line271 + col3 + file0 + + + line271 + col3 + file0 + + + end + + + line271 + col8 + file0 + + + line271 + col8 + file0 + + + + + + + kindevent + location + + line271 + col8 + file0 + + ranges + + + + line271 + col4 + file0 + + + line271 + col6 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + macro_expansions + + + location + + line270 + col3 + file0 + + namePOTENTIALLY_EMPTY_PARAM + expansion;ptr = nullptr + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_contextcd980e278fbcd8f77bbeac79285084e2 + issue_context_kindfunction + issue_contextemptyParamTest + issue_hash_function_offset4 + location + + line271 + col8 + file0 + + ExecutedLines + + 0 + + 267 + 268 + 270 + 271 + + + + + path + + + kindcontrol + edges + + + start + + + line282 + col3 + file0 + + + line282 + col5 + file0 + + + end + + + line284 + col3 + file0 + + + line284 + col20 + file0 + + + + + + + kindevent + location + + line284 + col3 + file0 + + ranges + + + + line284 + col3 + file0 + + + line284 + col27 + file0 + + + + depth0 + extended_message + Null pointer value stored to 'ptr' + message + Null pointer value stored to 'ptr' + + + kindcontrol + edges + + + start + + + line285 + col3 + file0 + + + line285 + col3 + file0 + + + end + + + line285 + col8 + file0 + + + line285 + col8 + file0 + + + + + + + kindevent + location + + line285 + col8 + file0 + + ranges + + + + line285 + col4 + file0 + + + line285 + col6 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + macro_expansions + + + location + + line284 + col3 + file0 + + nameNESTED_EMPTY_PARAM + expansion; ptr = nullptr; + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_contextf6a5f6c93b6e3734842ddabd3d5a7341 + issue_context_kindfunction + issue_contextnestedEmptyParamTest + issue_hash_function_offset4 + location + + line285 + col8 + file0 + + ExecutedLines + + 0 + + 281 + 282 + 284 + 285 + + + + + path + + + kindcontrol + edges + + + start + + + line295 + col3 + file0 + + + line295 + col5 + file0 + + + end + + + line296 + col3 + file0 + + + line296 + col44 + file0 + + + + + + + kindevent + location + + line296 + col3 + file0 + + ranges + + + + line296 + col3 + file0 + + + line296 + col61 + file0 + + + + depth0 + extended_message + Calling 'setToNull' + message + Calling 'setToNull' + + + kindevent + location + + line50 + col1 + file0 + + depth1 + extended_message + Entered call from 'lParenRParenInNestedMacro' + message + Entered call from 'lParenRParenInNestedMacro' + + + kindcontrol + edges + + + start + + + line50 + col1 + file0 + + + line50 + col4 + file0 + + + end + + + line51 + col3 + file0 + + + line51 + col3 + file0 + + + + + + + kindevent + location + + line51 + col3 + file0 + + ranges + + + + line51 + col3 + file0 + + + line51 + col17 + file0 + + + + depth1 + extended_message + Null pointer value stored to 'ptr' + message + Null pointer value stored to 'ptr' + + + kindevent + location + + line296 + col3 + file0 + + ranges + + + + line296 + col3 + file0 + + + line296 + col61 + file0 + + + + depth0 + extended_message + Returning from 'setToNull' + message + Returning from 'setToNull' + + + kindcontrol + edges + + + start + + + line297 + col3 + file0 + + + line297 + col3 + file0 + + + end + + + line297 + col8 + file0 + + + line297 + col8 + file0 + + + + + + + kindevent + location + + line297 + col8 + file0 + + ranges + + + + line297 + col4 + file0 + + + line297 + col6 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + macro_expansions + + + location + + line296 + col3 + file0 + + nameCALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO + expansionsetToNull( &ptr) + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_contextff00c8344e685317303e814970082d5f + issue_context_kindfunction + issue_contextlParenRParenInNestedMacro + issue_hash_function_offset3 + location + + line297 + col8 + file0 + + ExecutedLines + + 0 + + 50 + 51 + 294 + 295 + 296 + 297 + + + + + path + + + kindcontrol + edges + + + start + + + line315 + col3 + file0 + + + line315 + col5 + file0 + + + end + + + line316 + col3 + file0 + + + line316 + col22 + file0 + + + + + + + kindevent + location + + line316 + col3 + file0 + + ranges + + + + line316 + col3 + file0 + + + line316 + col42 + file0 + + + + depth0 + extended_message + Null pointer value stored to 'ptr' + message + Null pointer value stored to 'ptr' + + + kindcontrol + edges + + + start + + + line317 + col3 + file0 + + + line317 + col3 + file0 + + + end + + + line317 + col8 + file0 + + + line317 + col8 + file0 + + + + + + + kindevent + location + + line317 + col8 + file0 + + ranges + + + + line317 + col4 + file0 + + + line317 + col6 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + macro_expansions + + + location + + line316 + col3 + file0 + + nameVARIADIC_SET_TO_NULL + expansionptr = nullptr; variadicFunc( 1) + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context1b0880549df23e9ce0edb60955ad5ac1 + issue_context_kindfunction + issue_contextvariadicMacroArgumentTest + issue_hash_function_offset3 + location + + line317 + col8 + file0 + + ExecutedLines + + 0 + + 314 + 315 + 316 + 317 + + + + + path + + + kindcontrol + edges + + + start + + + line333 + col3 + file0 + + + line333 + col5 + file0 + + + end + + + line334 + col3 + file0 + + + line334 + col30 + file0 + + + + + + + kindevent + location + + line334 + col3 + file0 + + ranges + + + + line334 + col3 + file0 + + + line334 + col45 + file0 + + + + depth0 + extended_message + Null pointer value stored to 'ptr' + message + Null pointer value stored to 'ptr' + + + kindcontrol + edges + + + start + + + line335 + col3 + file0 + + + line335 + col3 + file0 + + + end + + + line335 + col8 + file0 + + + line335 + col8 + file0 + + + + + + + kindevent + location + + line335 + col8 + file0 + + ranges + + + + line335 + col4 + file0 + + + line335 + col6 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + macro_expansions + + + location + + line334 + col3 + file0 + + nameDECLARE_FUNC_AND_SET_TO_NULL + expansionvoid generated_##whatever(); ptr = nullptr; + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context453ed8096f5394e74e16f965886e5623 + issue_context_kindfunction + issue_contexthashHashOperatorTest + issue_hash_function_offset3 + location + + line335 + col8 + file0 + + ExecutedLines + + 0 + + 332 + 333 + 334 + 335 + + + + + path + + + kindcontrol + edges + + + start + + + line347 + col3 + file0 + + + line347 + col5 + file0 + + + end + + + line348 + col3 + file0 + + + line348 + col11 + file0 + + + + + + + kindevent + location + + line348 + col3 + file0 + + ranges + + + + line348 + col3 + file0 + + + line348 + col23 + file0 + + + + depth0 + extended_message + Null pointer value stored to 'ptr' + message + Null pointer value stored to 'ptr' + + + kindcontrol + edges + + + start + + + line349 + col3 + file0 + + + line349 + col3 + file0 + + + end + + + line349 + col8 + file0 + + + line349 + col8 + file0 + + + + + + + kindevent + location + + line349 + col8 + file0 + + ranges + + + + line349 + col4 + file0 + + + line349 + col6 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + macro_expansions + + + location + + line348 + col3 + file0 + + namePRINT_STR + expansionprint(#Hello); ptr = nullptr + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_contexte6947ee72df70243a3b4c9e9eaed0888 + issue_context_kindfunction + issue_contexthashOperatorTest + issue_hash_function_offset3 + location + + line349 col8 file0 @@ -1372,10 +4577,10 @@ 0 - 138 - 139 - 140 - 141 + 346 + 347 + 348 + 349 Index: test/Analysis/plist-macros-with-expansion.cpp =================================================================== --- test/Analysis/plist-macros-with-expansion.cpp +++ test/Analysis/plist-macros-with-expansion.cpp @@ -60,9 +60,8 @@ *ptr = 5; // expected-warning{{Dereference of null pointer}} } -// TODO: Expand arguments. // CHECK: nameTO_NULL -// CHECK: expansionsetToNull(x) +// CHECK-NEXT: expansionsetToNull(&ptr) #define DOES_NOTHING(x) \ { \ @@ -81,13 +80,11 @@ DEREF(a) = 5; // expected-warning{{Dereference of null pointer}} } -// TODO: Expand arguments. // CHECK: nameTO_NULL -// CHECK-NEXT: expansionsetToNull(x) +// CHECK-NEXT: expansionsetToNull(&a) -// TODO: Expand arguments. // CHECK: nameDEREF -// CHECK-NEXT: expansion{ int b; b = 5; } print(x); *x +// CHECK-NEXT: expansion{ int b; b = 5; } print(a); *a //===----------------------------------------------------------------------===// // Tests for undefining and/or redifining macros. @@ -104,7 +101,6 @@ #undef WILL_UNDEF_SET_NULL_TO_PTR -// TODO: Expand arguments. // CHECK: nameWILL_UNDEF_SET_NULL_TO_PTR // CHECK-NEXT: expansionptr = nullptr; @@ -125,7 +121,6 @@ print("This string shouldn't be in the plist file at all. Or anywhere, " \ "but here."); -// TODO: Expand arguments. // CHECK: nameWILL_REDIFINE_MULTIPLE_TIMES_SET_TO_NULL // CHECK-NEXT: expansionptr = nullptr; @@ -146,3 +141,214 @@ // CHECK-NEXT: expansionptr = nullptr; #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: nameTO_NULL_AND_PRINT +// CHECK-NEXT: expansiona = 0; print( "Will this , cause a crash?") + +void macroArgContainsLParenInStringTest() { + int *a; + TO_NULL_AND_PRINT(a, "Will this ( cause a crash?"); + *a = 5; // expected-warning{{Dereference of null pointer}} +} + +// CHECK: nameTO_NULL_AND_PRINT +// CHECK-NEXT: expansiona = 0; print( "Will this ( cause a crash?") + +void macroArgContainsRParenInStringTest() { + int *a; + TO_NULL_AND_PRINT(a, "Will this ) cause a crash?"); + *a = 5; // expected-warning{{Dereference of null pointer}} +} + +// CHECK: nameTO_NULL_AND_PRINT +// CHECK-NEXT: expansiona = 0; print( "Will this ) cause a crash?") + +#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: nameCALL_FUNCTION +// CHECK-NEXT: expansionsetToNull(&a) + +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: nameCALL_FUNCTION +// CHECK-NEXT: expansionsetToNullAndPrint(&a, "Hello!") + +#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: nameCALL_FUNCTION_WITH_TWO_PARAMS +// CHECK-NEXT: expansionsetToNullAndPrint( &a, "Hello!") + +#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}} +} + +// CHECK: nameCALL_LAMBDA +// CHECK-NEXT: expansion([&ptr, str] () mutable { TO_NULL(&ptr); })() + +#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: namePASTE_CODE +// CHECK-NEXT: expansion{ int *ptr = nullptr; *ptr = 5; } + +// 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: namePOTENTIALLY_EMPTY_PARAM +// CHECK-NEXT: expansion;ptr = nullptr + +#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: nameNESTED_EMPTY_PARAM +// CHECK-NEXT: expansion; ptr = nullptr; + +#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: nameCALL_FUNCTION_WITH_ONE_PARAM_THROUGH_MACRO +// CHECK-NEXT: expansionsetToNull( &ptr) + +//===----------------------------------------------------------------------===// +// Tests for variadic macro arguments. +//===----------------------------------------------------------------------===// + +template +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}} +} + +// TODO: Should correctly display the rest of the parameters. +// CHECK: nameVARIADIC_SET_TO_NULL +// CHECK-NEXT: expansionptr = nullptr; variadicFunc( 1) + +//===----------------------------------------------------------------------===// +// 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}} +} + +// TODO: Should expand correctly. +// CHECK: nameDECLARE_FUNC_AND_SET_TO_NULL +// CHECK-NEXT: expansionvoid generated_##whatever(); ptr = nullptr; + +#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}} +} + +// TODO: Should expand correctly. +// CHECK: namePRINT_STR +// CHECK-NEXT: expansionprint(#Hello); ptr = nullptr