Szelethus created this revision. Szelethus added reviewers: xazax.hun, rnkovacs, george.karpenkov, NoQ. Herald added subscribers: cfe-commits, dkrupp, donat.nagy, mikhail.ramalho, a.sidorin, szepet, whisperity.
This has been a long time coming. Note the usage of `AnalyzerOptions`: I'll need it for https://reviews.llvm.org/D52742, and added it in https://reviews.llvm.org/rC343620. Repository: rC Clang https://reviews.llvm.org/D53810 Files: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -24,10 +24,16 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" + using namespace clang; using namespace ento; using namespace markup; +//===----------------------------------------------------------------------===// +// Declarations of helper classes and functions for emitting bug reports in +// plist format. +//===----------------------------------------------------------------------===// + namespace { class PlistDiagnostics : public PathDiagnosticConsumer { const std::string OutputFile; @@ -59,34 +65,86 @@ }; } // end anonymous namespace -PlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts, - const std::string& output, - const Preprocessor &PP, - bool supportsMultipleFiles) - : OutputFile(output), PP(PP), AnOpts(AnalyzerOpts), - SupportsCrossFileDiagnostics(supportsMultipleFiles) {} +namespace { -void ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, - PathDiagnosticConsumers &C, - const std::string& s, - const Preprocessor &PP) { - C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, - /*supportsMultipleFiles*/ false)); -} +/// A helper class for emitting a single report. +class PlistPrinter { + const FIDMap& FM; + AnalyzerOptions &AnOpts; + const Preprocessor &PP; -void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, - PathDiagnosticConsumers &C, - const std::string &s, - const Preprocessor &PP) { - C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, - /*supportsMultipleFiles*/ true)); -} +public: + PlistPrinter(const FIDMap& FM, AnalyzerOptions &AnOpts, + const Preprocessor &PP) + : FM(FM), AnOpts(AnOpts), PP(PP) { + } + + void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) { + ReportPiece(o, P, /*indent*/ 4, /*depth*/ 0, /*includeControlFlow*/ true); + + // Don't emit a warning about an unused private field. + (void)AnOpts; + } + +private: + void ReportPiece(raw_ostream &o, const PathDiagnosticPiece &P, + unsigned indent, unsigned depth, bool includeControlFlow, + bool isKeyEvent = false) { + switch (P.getKind()) { + case PathDiagnosticPiece::ControlFlow: + if (includeControlFlow) + ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), indent); + break; + case PathDiagnosticPiece::Call: + ReportCall(o, cast<PathDiagnosticCallPiece>(P), indent, + depth); + break; + case PathDiagnosticPiece::Event: + ReportEvent(o, cast<PathDiagnosticEventPiece>(P), indent, depth, + isKeyEvent); + break; + case PathDiagnosticPiece::Macro: + ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), indent, depth); + break; + case PathDiagnosticPiece::Note: + ReportNote(o, cast<PathDiagnosticNotePiece>(P), indent); + break; + } + } -static void EmitRanges(raw_ostream &o, - const ArrayRef<SourceRange> Ranges, - const FIDMap& FM, - const Preprocessor &PP, - unsigned indent) { + void EmitRanges(raw_ostream &o, const ArrayRef<SourceRange> Ranges, + unsigned indent); + void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent); + + void ReportControlFlow(raw_ostream &o, + const PathDiagnosticControlFlowPiece& P, + unsigned indent); + void ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece& P, + 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 ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, + unsigned indent); +}; + +} // end of anonymous namespace + +/// 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, + unsigned InputIndentLevel, + SmallVectorImpl<FileID> &Fids, + FIDMap &FM, + llvm::raw_fd_ostream &o); +//===----------------------------------------------------------------------===// +// Methods of PlistPrinter. +//===----------------------------------------------------------------------===// + +void PlistPrinter::EmitRanges(raw_ostream &o, + const ArrayRef<SourceRange> Ranges, + unsigned indent) { if (Ranges.empty()) return; @@ -106,7 +164,8 @@ Indent(o, indent) << "</array>\n"; } -static void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent) { +void PlistPrinter::EmitMessage(raw_ostream &o, StringRef Message, + unsigned indent) { // Output the text. assert(!Message.empty()); Indent(o, indent) << "<key>extended_message</key>\n"; @@ -120,11 +179,9 @@ EmitString(o, Message) << '\n'; } -static void ReportControlFlow(raw_ostream &o, - const PathDiagnosticControlFlowPiece& P, - const FIDMap& FM, - const Preprocessor &PP, - unsigned indent) { +void PlistPrinter::ReportControlFlow(raw_ostream &o, + const PathDiagnosticControlFlowPiece& P, + unsigned indent) { const SourceManager &SM = PP.getSourceManager(); const LangOptions &LangOpts = PP.getLangOpts(); @@ -176,13 +233,9 @@ Indent(o, indent) << "</dict>\n"; } -static void ReportEvent(raw_ostream &o, - const PathDiagnosticEventPiece& P, - const FIDMap& FM, - const Preprocessor &PP, - unsigned indent, - unsigned depth, - bool isKeyEvent = false) { +void PlistPrinter::ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece& P, + unsigned indent, unsigned depth, + bool isKeyEvent) { const SourceManager &SM = PP.getSourceManager(); @@ -203,7 +256,7 @@ // Output the ranges (if any). ArrayRef<SourceRange> Ranges = P.getRanges(); - EmitRanges(o, Ranges, FM, PP, indent); + EmitRanges(o, Ranges, indent); // Output the call depth. Indent(o, indent) << "<key>depth</key>"; @@ -217,65 +270,42 @@ Indent(o, indent); o << "</dict>\n"; } -static void ReportPiece(raw_ostream &o, - const PathDiagnosticPiece &P, - const FIDMap& FM, - const Preprocessor &PP, - AnalyzerOptions &AnOpts, - unsigned indent, - unsigned depth, - bool includeControlFlow, - bool isKeyEvent = false); - -static void ReportCall(raw_ostream &o, - const PathDiagnosticCallPiece &P, - const FIDMap& FM, - const Preprocessor &PP, - AnalyzerOptions &AnOpts, - unsigned indent, - unsigned depth) { +void PlistPrinter::ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P, + unsigned indent, + unsigned depth) { if (auto callEnter = P.getCallEnterEvent()) - ReportPiece(o, *callEnter, FM, PP, AnOpts, indent, depth, - /*includeControlFlow*/ true, P.isLastInMainSourceFile()); + ReportPiece(o, *callEnter, indent, depth, /*includeControlFlow*/ true, + P.isLastInMainSourceFile()); ++depth; if (auto callEnterWithinCaller = P.getCallEnterWithinCallerEvent()) - ReportPiece(o, *callEnterWithinCaller, FM, PP, AnOpts, indent, depth, + ReportPiece(o, *callEnterWithinCaller, indent, depth, /*includeControlFlow*/ true); for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I) - ReportPiece(o, **I, FM, PP, AnOpts, indent, depth, - /*includeControlFlow*/ true); + ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ true); --depth; if (auto callExit = P.getCallExitEvent()) - ReportPiece(o, *callExit, FM, PP, AnOpts, indent, depth, - /*includeControlFlow*/ true); + ReportPiece(o, *callExit, indent, depth, /*includeControlFlow*/ true); } -static void ReportMacro(raw_ostream &o, - const PathDiagnosticMacroPiece& P, - const FIDMap& FM, - const Preprocessor &PP, - AnalyzerOptions &AnOpts, - unsigned indent, - unsigned depth) { +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) { - ReportPiece(o, **I, FM, PP, AnOpts, indent, depth, - /*includeControlFlow*/ false); + ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ false); } } -static void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, - const FIDMap& FM, - const Preprocessor &PP, - unsigned indent) { +void PlistPrinter::ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, + unsigned indent) { const SourceManager &SM = PP.getSourceManager(); @@ -290,7 +320,7 @@ // Output the ranges (if any). ArrayRef<SourceRange> Ranges = P.getRanges(); - EmitRanges(o, Ranges, FM, PP, indent); + EmitRanges(o, Ranges, indent); // Output the text. EmitMessage(o, P.getString(), indent); @@ -300,47 +330,9 @@ Indent(o, indent); o << "</dict>\n"; } -static void ReportDiag(raw_ostream &o, - const PathDiagnosticPiece& P, - const FIDMap& FM, - const Preprocessor &PP, - AnalyzerOptions &AnOpts) { - ReportPiece(o, P, FM, PP, AnOpts, /*indent*/ 4, /*depth*/ 0, - /*includeControlFlow*/ true); -} - -static void ReportPiece(raw_ostream &o, - const PathDiagnosticPiece &P, - const FIDMap& FM, - const Preprocessor &PP, - AnalyzerOptions &AnOpts, - unsigned indent, - unsigned depth, - bool includeControlFlow, - bool isKeyEvent) { - switch (P.getKind()) { - case PathDiagnosticPiece::ControlFlow: - if (includeControlFlow) - ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, PP, - indent); - break; - case PathDiagnosticPiece::Call: - ReportCall(o, cast<PathDiagnosticCallPiece>(P), FM, PP, AnOpts, indent, - depth); - break; - case PathDiagnosticPiece::Event: - ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, PP, indent, depth, - isKeyEvent); - break; - case PathDiagnosticPiece::Macro: - ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, PP, AnOpts, indent, - depth); - break; - case PathDiagnosticPiece::Note: - ReportNote(o, cast<PathDiagnosticNotePiece>(P), FM, PP, indent); - break; - } -} +//===----------------------------------------------------------------------===// +// Static function definitions. +//===----------------------------------------------------------------------===// /// Print coverage information to output stream {@code o}. /// May modify the used list of files {@code Fids} by inserting new ones. @@ -375,6 +367,32 @@ assert(IndentLevel == InputIndentLevel); } +//===----------------------------------------------------------------------===// +// Methods of PlistDiagnostics. +//===----------------------------------------------------------------------===// + +PlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts, + const std::string& output, + const Preprocessor &PP, + bool supportsMultipleFiles) + : OutputFile(output), PP(PP), AnOpts(AnalyzerOpts), + SupportsCrossFileDiagnostics(supportsMultipleFiles) {} + +void ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, + PathDiagnosticConsumers &C, + const std::string& s, + const Preprocessor &PP) { + C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, + /*supportsMultipleFiles*/ false)); +} + +void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, + PathDiagnosticConsumers &C, + const std::string &s, + const Preprocessor &PP) { + C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, + /*supportsMultipleFiles*/ true)); +} void PlistDiagnostics::FlushDiagnosticsImpl( std::vector<const PathDiagnostic *> &Diags, FilesMade *filesMade) { @@ -443,6 +461,8 @@ o << " <key>diagnostics</key>\n" " <array>\n"; + PlistPrinter Printer(FM, AnOpts, PP); + for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(), DE = Diags.end(); DI!=DE; ++DI) { @@ -469,7 +489,7 @@ " <array>\n"; for (; I != FirstNonNote; ++I) - ReportDiag(o, **I, FM, PP, AnOpts); + Printer.ReportDiag(o, **I); o << " </array>\n"; } @@ -479,7 +499,7 @@ o << " <array>\n"; for (PathPieces::const_iterator E = Path.end(); I != E; ++I) - ReportDiag(o, **I, FM, PP, AnOpts); + Printer.ReportDiag(o, **I); o << " </array>\n";
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits