Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -269,10 +269,7 @@ } // end of anonymous namespace static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, - const Preprocessor &PP) { - // TODO: Implement macro expansion. - return { "", "" }; -} + const Preprocessor &PP); static void ReportMacro(raw_ostream &o, const PathDiagnosticMacroPiece& P, @@ -669,3 +666,121 @@ // Finish. o << "\n"; } + +//===----------------------------------------------------------------------===// +// 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) {} +}; + +} // end of anonymous namespace + +/// Retrieves the name of the macro and its MacroInfo. +static MacroNameAndInfo getMacroNameAndInfo(SourceLocation ExpanLoc, + const Preprocessor &PP); + +static ExpansionInfo getExpandedMacroImpl(SourceLocation MacroLoc, + const Preprocessor &PP) { + + const SourceManager &SM = PP.getSourceManager(); + + MacroNameAndInfo Info = getMacroNameAndInfo(SM.getExpansionLoc(MacroLoc), PP); + + std::string MacroName = std::move(Info.Name); + const MacroInfo *MI = Info.MI; + + // Iterate over the macro's tokens and stringify them. + llvm::SmallString<200> ExpansionBuf; + llvm::raw_svector_ostream ExpansionOS(ExpansionBuf); + + for (auto It = MI->tokens_begin(), E = MI->tokens_end(); It != E; ++It) { + Token T = *It; + + if (T.is(tok::identifier)) { + 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 = PP.getMacroInfo(II)) { + ExpansionOS << getExpandedMacroImpl(T.getLocation(), PP) + .Expansion; + + // If this is a function-like macro, skip its arguments, as + // getExpandedMacro() already printed them. + if (MI->getNumParams() != 0) { + ++It; + assert(It->is(tok::l_paren) && + "This token should be '(' if the previous was a function-like " + "macro!"); + + // 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 != E && + "End of the macro definition reached before finding ')'!"); + + if (It->is(tok::l_paren)) + ++ParanthesesDepth; + + if (It->is(tok::r_paren)) + --ParanthesesDepth; + } + } + continue; + } + } + + // If control reaches here, there's nothing left to do, print the token. + ExpansionOS << PP.getSpelling(T) + ' '; + } + + return {MacroName, ExpansionOS.str()}; +} + +static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, + const Preprocessor &PP) { + return getExpandedMacroImpl(MacroLoc, PP); +} + +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 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 = PP.getMacroInfo(II); + assert(MI && "This IdentifierInfo should refer to a macro!"); + + return { MacroName, MI }; +} 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 @@ -3,7 +3,7 @@ clang_version -clang version 8.0.0 (http://mainstream.inf.elte.hu/Szelethus/clang 85a6dda64587a5a18482f091cbcf020fbd3ec1dd) (https://github.com/llvm-mirror/llvm 1ffbf26a1a0a190d69327af875a3337b74a2ce82) +clang version 8.0.0 (http://mainstream.inf.elte.hu/Szelethus/clang 7bb09c0bd99537e54637926df8b2814fd9e02947) (https://github.com/llvm-mirror/llvm 1ffbf26a1a0a190d69327af875a3337b74a2ce82) diagnostics @@ -52,9 +52,9 @@ file0 extended_message - Expanding macro '' to '' + Expanding macro 'SET_PTR_VAR_TO_NULL' to 'ptr = 0 ' message - Expanding macro '' to '' + Expanding macro 'SET_PTR_VAR_TO_NULL' to 'ptr = 0 ' kindevent @@ -221,9 +221,9 @@ file0 extended_message - Expanding macro '' to '' + Expanding macro 'SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO' to 'ptr = 0 ' message - Expanding macro '' to '' + Expanding macro 'SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO' to 'ptr = 0 ' kindevent @@ -344,6 +344,539 @@ + + path + + + kindcontrol + edges + + + start + + + line56 + col3 + file0 + + + line56 + col5 + file0 + + + end + + + line57 + col3 + file0 + + + line57 + col9 + file0 + + + + + + + kindmacro_expansion + location + + line57 + col3 + file0 + + extended_message + Expanding macro 'TO_NULL' to 'setToNull ( x ) ' + message + Expanding macro 'TO_NULL' to 'setToNull ( x ) ' + + + kindevent + location + + line57 + col3 + file0 + + ranges + + + + line57 + col3 + file0 + + + line57 + col15 + file0 + + + + depth0 + extended_message + Calling 'setToNull' + message + Calling 'setToNull' + + + kindevent + location + + line48 + col1 + file0 + + depth1 + extended_message + Entered call from 'functionLikeMacroTest' + message + Entered call from 'functionLikeMacroTest' + + + kindcontrol + edges + + + start + + + line48 + col1 + file0 + + + line48 + col4 + file0 + + + end + + + line49 + col3 + file0 + + + line49 + col3 + file0 + + + + + + + kindevent + location + + line49 + col3 + file0 + + ranges + + + + line49 + col3 + file0 + + + line49 + col17 + file0 + + + + depth1 + extended_message + Null pointer value stored to 'ptr' + message + Null pointer value stored to 'ptr' + + + kindevent + location + + line57 + col3 + file0 + + ranges + + + + line57 + col3 + file0 + + + line57 + col15 + file0 + + + + depth0 + extended_message + Returning from 'setToNull' + message + Returning from 'setToNull' + + + kindcontrol + edges + + + start + + + line58 + col3 + file0 + + + line58 + col3 + file0 + + + end + + + line58 + col8 + file0 + + + line58 + col8 + file0 + + + + + + + kindevent + location + + line58 + col8 + file0 + + ranges + + + + line58 + col4 + file0 + + + line58 + col6 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'ptr') + message + Dereference of null pointer (loaded from variable 'ptr') + + + descriptionDereference of null pointer (loaded from variable 'ptr') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context370a457744311752aac789447b4ef16c + issue_context_kindfunction + issue_contextfunctionLikeMacroTest + issue_hash_function_offset3 + location + + line58 + col8 + file0 + + ExecutedLines + + 0 + + 48 + 49 + 55 + 56 + 57 + 58 + + + + + path + + + kindcontrol + edges + + + start + + + line76 + col3 + file0 + + + line76 + col5 + file0 + + + end + + + line77 + col3 + file0 + + + line77 + col9 + file0 + + + + + + + kindmacro_expansion + location + + line77 + col3 + file0 + + extended_message + Expanding macro 'TO_NULL' to 'setToNull ( x ) ' + message + Expanding macro 'TO_NULL' to 'setToNull ( x ) ' + + + kindevent + location + + line77 + col3 + file0 + + ranges + + + + line77 + col3 + file0 + + + line77 + col13 + file0 + + + + depth0 + extended_message + Calling 'setToNull' + message + Calling 'setToNull' + + + kindevent + location + + line48 + col1 + file0 + + depth1 + extended_message + Entered call from 'functionLikeNestedMacroTest' + message + Entered call from 'functionLikeNestedMacroTest' + + + kindcontrol + edges + + + start + + + line48 + col1 + file0 + + + line48 + col4 + file0 + + + end + + + line49 + col3 + file0 + + + line49 + col3 + file0 + + + + + + + kindevent + location + + line49 + col3 + file0 + + ranges + + + + line49 + col3 + file0 + + + line49 + col17 + file0 + + + + depth1 + extended_message + Null pointer value stored to 'a' + message + Null pointer value stored to 'a' + + + kindevent + location + + line77 + col3 + file0 + + ranges + + + + line77 + col3 + file0 + + + line77 + col13 + file0 + + + + depth0 + extended_message + Returning from 'setToNull' + message + Returning from 'setToNull' + + + kindmacro_expansion + location + + line78 + col3 + file0 + + extended_message + Expanding macro 'DEREF' to '{ int b ; b = 5 ; } print ( x ) ; * x ' + message + Expanding macro 'DEREF' to '{ int b ; b = 5 ; } print ( x ) ; * x ' + + + kindevent + location + + line78 + col12 + file0 + + ranges + + + + line78 + col3 + file0 + + + line78 + col10 + file0 + + + + depth0 + extended_message + Dereference of null pointer (loaded from variable 'a') + message + Dereference of null pointer (loaded from variable 'a') + + + descriptionDereference of null pointer (loaded from variable 'a') + categoryLogic error + typeDereference of null pointer + check_namecore.NullDereference + + issue_hash_content_of_line_in_context873802674657bba4565f64c7bbf0ded9 + issue_context_kindfunction + issue_contextfunctionLikeNestedMacroTest + issue_hash_function_offset3 + location + + line78 + col12 + file0 + + ExecutedLines + + 0 + + 48 + 49 + 75 + 76 + 77 + 78 + + + files Index: test/Analysis/plist-macros-with-expansion.cpp =================================================================== --- test/Analysis/plist-macros-with-expansion.cpp +++ test/Analysis/plist-macros-with-expansion.cpp @@ -27,7 +27,7 @@ *ptr = 5; // expected-warning{{Dereference of null pointer}} } -// CHECK: Expanding macro '' to '' +// CHECK: Expanding macro 'SET_PTR_VAR_TO_NULL' to 'ptr = 0 ' #define NULL 0 #define SET_PTR_VAR_TO_NULL_WITH_NESTED_MACRO \ @@ -39,4 +39,47 @@ *ptr = 5; // expected-warning{{Dereference of null pointer}} } -// CHECK: Expanding macro '' to '' +// CHECK: Expanding macro 'SET_PTR_VAR_TO_NULL' to 'ptr = 0 ' + +//===----------------------------------------------------------------------===// +// 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 macro arguments. +// CHECK: Expanding macro 'TO_NULL' to 'setToNull ( x ) ' + +#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 macro arguments. +// CHECK: Expanding macro 'TO_NULL' to 'setToNull ( x ) ' + +// TODO: Expand macro arguments. +// CHECK: Expanding macro 'DEREF' to '{ int b ; b = 5 ; } print ( x ) ; * x '