This revision was automatically updated to reflect the committed changes. Closed by commit rL345724: [analyzer][PlistMacroExpansion] Part 1.: New expand-macros flag (authored by Szelethus, committed by ). Herald added a subscriber: llvm-commits.
Changed prior to commit: https://reviews.llvm.org/D52742?vs=171533&id=171921#toc Repository: rL LLVM https://reviews.llvm.org/D52742 Files: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp cfe/trunk/test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist cfe/trunk/test/Analysis/plist-macros-with-expansion.cpp
Index: cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -72,6 +72,7 @@ const FIDMap& FM; AnalyzerOptions &AnOpts; const Preprocessor &PP; + llvm::SmallVector<const PathDiagnosticMacroPiece *, 0> MacroPieces; public: PlistPrinter(const FIDMap& FM, AnalyzerOptions &AnOpts, @@ -86,6 +87,14 @@ (void)AnOpts; } + /// Print the expansions of the collected macro pieces. + /// + /// Each time ReportDiag is called on a PathDiagnosticMacroPiece (or, if one + /// is found through a call piece, etc), it's subpieces are reported, and the + /// piece itself is collected. Call this function after the entire bugpath + /// was reported. + void ReportMacroExpansions(raw_ostream &o, unsigned indent); + private: void ReportPiece(raw_ostream &o, const PathDiagnosticPiece &P, unsigned indent, unsigned depth, bool includeControlFlow, @@ -104,7 +113,8 @@ isKeyEvent); break; case PathDiagnosticPiece::Macro: - ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), indent, depth); + ReportMacroSubPieces(o, cast<PathDiagnosticMacroPiece>(P), indent, + depth); break; case PathDiagnosticPiece::Note: ReportNote(o, cast<PathDiagnosticNotePiece>(P), indent); @@ -123,14 +133,25 @@ unsigned indent, unsigned depth, bool isKeyEvent = false); void ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P, unsigned indent, unsigned depth); - void ReportMacro(raw_ostream &o, const PathDiagnosticMacroPiece& P, - unsigned indent, unsigned depth); + void ReportMacroSubPieces(raw_ostream &o, const PathDiagnosticMacroPiece& P, + unsigned indent, unsigned depth); void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, unsigned indent); }; } // end of anonymous namespace +namespace { + +struct ExpansionInfo { + std::string MacroName; + std::string Expansion; + ExpansionInfo(std::string N, std::string E) + : MacroName(std::move(N)), Expansion(std::move(E)) {} +}; + +} // end of anonymous namespace + static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM, AnalyzerOptions &AnOpts, const Preprocessor &PP, @@ -143,6 +164,10 @@ SmallVectorImpl<FileID> &Fids, FIDMap &FM, llvm::raw_fd_ostream &o); + +static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, + const Preprocessor &PP); + //===----------------------------------------------------------------------===// // Methods of PlistPrinter. //===----------------------------------------------------------------------===// @@ -299,16 +324,52 @@ ReportPiece(o, *callExit, indent, depth, /*includeControlFlow*/ true); } -void PlistPrinter::ReportMacro(raw_ostream &o, - const PathDiagnosticMacroPiece& P, - unsigned indent, unsigned depth) { - - for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end(); - I!=E; ++I) { +void PlistPrinter::ReportMacroSubPieces(raw_ostream &o, + const PathDiagnosticMacroPiece& P, + unsigned indent, unsigned depth) { + MacroPieces.push_back(&P); + + for (PathPieces::const_iterator I = P.subPieces.begin(), + E = P.subPieces.end(); + I != E; ++I) { ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ false); } } +void PlistPrinter::ReportMacroExpansions(raw_ostream &o, unsigned indent) { + + for (const PathDiagnosticMacroPiece *P : MacroPieces) { + const SourceManager &SM = PP.getSourceManager(); + ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP); + + Indent(o, indent) << "<dict>\n"; + ++indent; + + // Output the location. + FullSourceLoc L = P->getLocation().asLocation(); + + Indent(o, indent) << "<key>location</key>\n"; + EmitLocation(o, SM, L, FM, indent); + + // Output the ranges (if any). + ArrayRef<SourceRange> Ranges = P->getRanges(); + EmitRanges(o, Ranges, indent); + + // Output the macro name. + Indent(o, indent) << "<key>name</key>"; + EmitString(o, EI.MacroName) << '\n'; + + // Output what it expands into. + Indent(o, indent) << "<key>expansion</key>"; + EmitString(o, EI.Expansion) << '\n'; + + // Finish up. + --indent; + Indent(o, indent); + o << "</dict>\n"; + } +} + void PlistPrinter::ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, unsigned indent) { @@ -339,6 +400,12 @@ // Static function definitions. //===----------------------------------------------------------------------===// +static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc, + const Preprocessor &PP) { + // TODO: Implement macro expansion. + return { "", "" }; +} + /// Print coverage information to output stream {@code o}. /// May modify the used list of files {@code Fids} by inserting new ones. static void printCoverage(const PathDiagnostic *D, @@ -408,6 +475,14 @@ Printer.ReportDiag(o, **I); o << " </array>\n"; + + if (!AnOpts.shouldDisplayMacroExpansions()) + return; + + o << " <key>macro_expansions</key>\n" + " <array>\n"; + Printer.ReportMacroExpansions(o, /* indent */ 4); + o << " </array>\n"; } //===----------------------------------------------------------------------===// Index: cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -546,7 +546,8 @@ } } -static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM); +static void CompactMacroExpandedPieces(PathPieces &path, + const SourceManager& SM); std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForSwitchOP( @@ -1972,8 +1973,6 @@ PathDiagnosticLocation::createBegin(D, SM)); } - if (!AddPathEdges && GenerateDiagnostics) - CompactPathDiagnostic(PD->getMutablePieces(), SM); // Finally, prune the diagnostic path of uninteresting stuff. if (!PD->path.empty()) { @@ -2007,6 +2006,10 @@ removeRedundantMsgs(PD->getMutablePieces()); removeEdgesToDefaultInitializers(PD->getMutablePieces()); } + + if (GenerateDiagnostics && Opts.shouldDisplayMacroExpansions()) + CompactMacroExpandedPieces(PD->getMutablePieces(), SM); + return PD; } @@ -2436,9 +2439,10 @@ return true; } -/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object -/// and collapses PathDiagosticPieces that are expanded by macros. -static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) { +/// CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic +/// object and collapses PathDiagosticPieces that are expanded by macros. +static void CompactMacroExpandedPieces(PathPieces &path, + const SourceManager& SM) { using MacroStackTy = std::vector< std::pair<std::shared_ptr<PathDiagnosticMacroPiece>, SourceLocation>>; @@ -2454,7 +2458,7 @@ // Recursively compact calls. if (auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) { - CompactPathDiagnostic(call->path, SM); + CompactMacroExpandedPieces(call->path, SM); } // Get the location of the PathDiagnosticPiece. Index: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -464,6 +464,13 @@ return DisplayNotesAsEvents.getValue(); } +bool AnalyzerOptions::shouldDisplayMacroExpansions() { + if (!DisplayMacroExpansions.hasValue()) + DisplayMacroExpansions = + getBooleanOption("expand-macros", /*Default=*/false); + return DisplayMacroExpansions.getValue(); +} + bool AnalyzerOptions::shouldAggressivelySimplifyBinaryOperation() { if (!AggressiveBinaryOperationSimplification.hasValue()) AggressiveBinaryOperationSimplification = Index: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -307,6 +307,9 @@ /// \sa shouldDisplayNotesAsEvents Optional<bool> DisplayNotesAsEvents; + /// \sa shouldDisplayMacroExpansions + Optional<bool> DisplayMacroExpansions; + /// \sa shouldAggressivelySimplifyBinaryOperation Optional<bool> AggressiveBinaryOperationSimplification; @@ -693,6 +696,13 @@ /// to false when unset. bool shouldDisplayNotesAsEvents(); + /// Returns true if macros related to the bugpath should be expanded and + /// included in the plist output. + /// + /// This is controlled by the 'expand-macros' option, which defaults to false + /// when unset. + bool shouldDisplayMacroExpansions(); + /// Returns true if SValBuilder should rearrange comparisons and additive /// operations of symbolic expressions which consist of a sum of a symbol and /// a concrete integer into the format where symbols are on the left-hand Index: cfe/trunk/test/Analysis/plist-macros-with-expansion.cpp =================================================================== --- cfe/trunk/test/Analysis/plist-macros-with-expansion.cpp +++ cfe/trunk/test/Analysis/plist-macros-with-expansion.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s +// +// RUN: %clang_analyze_cc1 -analyzer-checker=core %s \ +// RUN: -analyzer-output=plist -o %t.plist \ +// RUN: -analyzer-config expand-macros=true +// +// Check the actual plist output. +// RUN: cat %t.plist | %diff_plist \ +// RUN: %S/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist +// +// Check the macro expansions from the plist output here, to make the test more +// understandable. +// 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>name</key><string></string> +// CHECK-NEXT: <key>expansion</key><string></string> + +#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>name</key><string></string> +// CHECK-NEXT: <key>expansion</key><string></string> Index: cfe/trunk/test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist =================================================================== --- cfe/trunk/test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist +++ cfe/trunk/test/Analysis/Inputs/expected-plists/plist-macros-with-expansion.cpp.plist @@ -0,0 +1,351 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>diagnostics</key> + <array> + <dict> + <key>path</key> + <array> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>25</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>25</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>21</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>21</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Null pointer value stored to 'ptr'</string> + <key>message</key> + <string>Null pointer value stored to 'ptr'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>6</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + </dict> + </array> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>26</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string></string> + <key>expansion</key><string></string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>f8fbc46cc5afbb056d92bd3d3d702781</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>nonFunctionLikeMacroTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>27</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>24</integer> + <integer>25</integer> + <integer>26</integer> + <integer>27</integer> + </array> + </dict> + </dict> + <dict> + <key>path</key> + <array> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>38</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>38</integer> + <key>col</key><integer>5</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>39</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>39</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Null pointer value stored to 'ptr'</string> + <key>message</key> + <string>Null pointer value stored to 'ptr'</string> + </dict> + <dict> + <key>kind</key><string>control</string> + <key>edges</key> + <array> + <dict> + <key>start</key> + <array> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + <key>end</key> + <array> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </dict> + </array> + </dict> + <dict> + <key>kind</key><string>event</string> + <key>location</key> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ranges</key> + <array> + <array> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>4</integer> + <key>file</key><integer>0</integer> + </dict> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>6</integer> + <key>file</key><integer>0</integer> + </dict> + </array> + </array> + <key>depth</key><integer>0</integer> + <key>extended_message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>message</key> + <string>Dereference of null pointer (loaded from variable 'ptr')</string> + </dict> + </array> + <key>macro_expansions</key> + <array> + <dict> + <key>location</key> + <dict> + <key>line</key><integer>39</integer> + <key>col</key><integer>3</integer> + <key>file</key><integer>0</integer> + </dict> + <key>name</key><string></string> + <key>expansion</key><string></string> + </dict> + </array> + <key>description</key><string>Dereference of null pointer (loaded from variable 'ptr')</string> + <key>category</key><string>Logic error</string> + <key>type</key><string>Dereference of null pointer</string> + <key>check_name</key><string>core.NullDereference</string> + <!-- This hash is experimental and going to change! --> + <key>issue_hash_content_of_line_in_context</key><string>d5eba61193b41c27fc7b2705cbd607ba</string> + <key>issue_context_kind</key><string>function</string> + <key>issue_context</key><string>nonFunctionLikeNestedMacroTest</string> + <key>issue_hash_function_offset</key><string>3</string> + <key>location</key> + <dict> + <key>line</key><integer>40</integer> + <key>col</key><integer>8</integer> + <key>file</key><integer>0</integer> + </dict> + <key>ExecutedLines</key> + <dict> + <key>0</key> + <array> + <integer>37</integer> + <integer>38</integer> + <integer>39</integer> + <integer>40</integer> + </array> + </dict> + </dict> + </array> + <key>files</key> + <array> + <string>/home/eumakri/Documents/2codechecker_dev_env/llvm/tools/clang/test/Analysis/plist-macros-with-expansion.cpp</string> + </array> +</dict> +</plist>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits