19c4b2225SAlexander Belyaev //===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- C++ -*-===// 29c4b2225SAlexander Belyaev // 39c4b2225SAlexander Belyaev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 49c4b2225SAlexander Belyaev // See https://llvm.org/LICENSE.txt for license information. 59c4b2225SAlexander Belyaev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 69c4b2225SAlexander Belyaev // 79c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 89c4b2225SAlexander Belyaev // 99c4b2225SAlexander Belyaev // This file defines the PlistDiagnostics object. 109c4b2225SAlexander Belyaev // 119c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 129c4b2225SAlexander Belyaev 139c4b2225SAlexander Belyaev #include "clang/Analysis/IssueHash.h" 147c58fb6bSBalazs Benics #include "clang/Analysis/MacroExpansionContext.h" 159c4b2225SAlexander Belyaev #include "clang/Analysis/PathDiagnostic.h" 169c4b2225SAlexander Belyaev #include "clang/Basic/FileManager.h" 179c4b2225SAlexander Belyaev #include "clang/Basic/PlistSupport.h" 189c4b2225SAlexander Belyaev #include "clang/Basic/SourceManager.h" 199c4b2225SAlexander Belyaev #include "clang/Basic/Version.h" 209c4b2225SAlexander Belyaev #include "clang/CrossTU/CrossTranslationUnit.h" 219c4b2225SAlexander Belyaev #include "clang/Frontend/ASTUnit.h" 229c4b2225SAlexander Belyaev #include "clang/Lex/Preprocessor.h" 239c4b2225SAlexander Belyaev #include "clang/Lex/TokenConcatenation.h" 249c4b2225SAlexander Belyaev #include "clang/Rewrite/Core/HTMLRewrite.h" 259c4b2225SAlexander Belyaev #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" 269c4b2225SAlexander Belyaev #include "llvm/ADT/SmallPtrSet.h" 279c4b2225SAlexander Belyaev #include "llvm/ADT/SmallVector.h" 289c4b2225SAlexander Belyaev #include "llvm/ADT/Statistic.h" 299c4b2225SAlexander Belyaev #include "llvm/Support/Casting.h" 309c4b2225SAlexander Belyaev #include <memory> 31a1580d7bSKazu Hirata #include <optional> 329c4b2225SAlexander Belyaev 339c4b2225SAlexander Belyaev using namespace clang; 349c4b2225SAlexander Belyaev using namespace ento; 359c4b2225SAlexander Belyaev using namespace markup; 369c4b2225SAlexander Belyaev 379c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 389c4b2225SAlexander Belyaev // Declarations of helper classes and functions for emitting bug reports in 399c4b2225SAlexander Belyaev // plist format. 409c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 419c4b2225SAlexander Belyaev 429c4b2225SAlexander Belyaev namespace { 439c4b2225SAlexander Belyaev class PlistDiagnostics : public PathDiagnosticConsumer { 449c4b2225SAlexander Belyaev PathDiagnosticConsumerOptions DiagOpts; 459c4b2225SAlexander Belyaev const std::string OutputFile; 469c4b2225SAlexander Belyaev const Preprocessor &PP; 479c4b2225SAlexander Belyaev const cross_tu::CrossTranslationUnitContext &CTU; 487c58fb6bSBalazs Benics const MacroExpansionContext &MacroExpansions; 499c4b2225SAlexander Belyaev const bool SupportsCrossFileDiagnostics; 509c4b2225SAlexander Belyaev 519c4b2225SAlexander Belyaev void printBugPath(llvm::raw_ostream &o, const FIDMap &FM, 529c4b2225SAlexander Belyaev const PathPieces &Path); 539c4b2225SAlexander Belyaev 549c4b2225SAlexander Belyaev public: 559c4b2225SAlexander Belyaev PlistDiagnostics(PathDiagnosticConsumerOptions DiagOpts, 569c4b2225SAlexander Belyaev const std::string &OutputFile, const Preprocessor &PP, 579c4b2225SAlexander Belyaev const cross_tu::CrossTranslationUnitContext &CTU, 587c58fb6bSBalazs Benics const MacroExpansionContext &MacroExpansions, 599c4b2225SAlexander Belyaev bool supportsMultipleFiles); 609c4b2225SAlexander Belyaev 619c4b2225SAlexander Belyaev ~PlistDiagnostics() override {} 629c4b2225SAlexander Belyaev 639c4b2225SAlexander Belyaev void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, 649c4b2225SAlexander Belyaev FilesMade *filesMade) override; 659c4b2225SAlexander Belyaev 669c4b2225SAlexander Belyaev StringRef getName() const override { 679c4b2225SAlexander Belyaev return "PlistDiagnostics"; 689c4b2225SAlexander Belyaev } 699c4b2225SAlexander Belyaev 709c4b2225SAlexander Belyaev PathGenerationScheme getGenerationScheme() const override { 719c4b2225SAlexander Belyaev return Extensive; 729c4b2225SAlexander Belyaev } 739c4b2225SAlexander Belyaev bool supportsLogicalOpControlFlow() const override { return true; } 749c4b2225SAlexander Belyaev bool supportsCrossFileDiagnostics() const override { 759c4b2225SAlexander Belyaev return SupportsCrossFileDiagnostics; 769c4b2225SAlexander Belyaev } 779c4b2225SAlexander Belyaev }; 789c4b2225SAlexander Belyaev } // end anonymous namespace 799c4b2225SAlexander Belyaev 809c4b2225SAlexander Belyaev namespace { 819c4b2225SAlexander Belyaev 829c4b2225SAlexander Belyaev /// A helper class for emitting a single report. 839c4b2225SAlexander Belyaev class PlistPrinter { 849c4b2225SAlexander Belyaev const FIDMap& FM; 859c4b2225SAlexander Belyaev const Preprocessor &PP; 869c4b2225SAlexander Belyaev const cross_tu::CrossTranslationUnitContext &CTU; 877c58fb6bSBalazs Benics const MacroExpansionContext &MacroExpansions; 889c4b2225SAlexander Belyaev llvm::SmallVector<const PathDiagnosticMacroPiece *, 0> MacroPieces; 899c4b2225SAlexander Belyaev 909c4b2225SAlexander Belyaev public: 917c58fb6bSBalazs Benics PlistPrinter(const FIDMap &FM, const Preprocessor &PP, 927c58fb6bSBalazs Benics const cross_tu::CrossTranslationUnitContext &CTU, 937c58fb6bSBalazs Benics const MacroExpansionContext &MacroExpansions) 947c58fb6bSBalazs Benics : FM(FM), PP(PP), CTU(CTU), MacroExpansions(MacroExpansions) {} 959c4b2225SAlexander Belyaev 969c4b2225SAlexander Belyaev void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) { 979c4b2225SAlexander Belyaev ReportPiece(o, P, /*indent*/ 4, /*depth*/ 0, /*includeControlFlow*/ true); 989c4b2225SAlexander Belyaev } 999c4b2225SAlexander Belyaev 1009c4b2225SAlexander Belyaev /// Print the expansions of the collected macro pieces. 1019c4b2225SAlexander Belyaev /// 1029c4b2225SAlexander Belyaev /// Each time ReportDiag is called on a PathDiagnosticMacroPiece (or, if one 1039c4b2225SAlexander Belyaev /// is found through a call piece, etc), it's subpieces are reported, and the 1049c4b2225SAlexander Belyaev /// piece itself is collected. Call this function after the entire bugpath 1059c4b2225SAlexander Belyaev /// was reported. 1069c4b2225SAlexander Belyaev void ReportMacroExpansions(raw_ostream &o, unsigned indent); 1079c4b2225SAlexander Belyaev 1089c4b2225SAlexander Belyaev private: 1099c4b2225SAlexander Belyaev void ReportPiece(raw_ostream &o, const PathDiagnosticPiece &P, 1109c4b2225SAlexander Belyaev unsigned indent, unsigned depth, bool includeControlFlow, 1119c4b2225SAlexander Belyaev bool isKeyEvent = false) { 1129c4b2225SAlexander Belyaev switch (P.getKind()) { 1139c4b2225SAlexander Belyaev case PathDiagnosticPiece::ControlFlow: 1149c4b2225SAlexander Belyaev if (includeControlFlow) 1159c4b2225SAlexander Belyaev ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), indent); 1169c4b2225SAlexander Belyaev break; 1179c4b2225SAlexander Belyaev case PathDiagnosticPiece::Call: 1189c4b2225SAlexander Belyaev ReportCall(o, cast<PathDiagnosticCallPiece>(P), indent, 1199c4b2225SAlexander Belyaev depth); 1209c4b2225SAlexander Belyaev break; 1219c4b2225SAlexander Belyaev case PathDiagnosticPiece::Event: 1229c4b2225SAlexander Belyaev ReportEvent(o, cast<PathDiagnosticEventPiece>(P), indent, depth, 1239c4b2225SAlexander Belyaev isKeyEvent); 1249c4b2225SAlexander Belyaev break; 1259c4b2225SAlexander Belyaev case PathDiagnosticPiece::Macro: 1269c4b2225SAlexander Belyaev ReportMacroSubPieces(o, cast<PathDiagnosticMacroPiece>(P), indent, 1279c4b2225SAlexander Belyaev depth); 1289c4b2225SAlexander Belyaev break; 1299c4b2225SAlexander Belyaev case PathDiagnosticPiece::Note: 1309c4b2225SAlexander Belyaev ReportNote(o, cast<PathDiagnosticNotePiece>(P), indent); 1319c4b2225SAlexander Belyaev break; 1329c4b2225SAlexander Belyaev case PathDiagnosticPiece::PopUp: 1339c4b2225SAlexander Belyaev ReportPopUp(o, cast<PathDiagnosticPopUpPiece>(P), indent); 1349c4b2225SAlexander Belyaev break; 1359c4b2225SAlexander Belyaev } 1369c4b2225SAlexander Belyaev } 1379c4b2225SAlexander Belyaev 1389c4b2225SAlexander Belyaev void EmitRanges(raw_ostream &o, const ArrayRef<SourceRange> Ranges, 1399c4b2225SAlexander Belyaev unsigned indent); 1409c4b2225SAlexander Belyaev void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent); 1419c4b2225SAlexander Belyaev void EmitFixits(raw_ostream &o, ArrayRef<FixItHint> fixits, unsigned indent); 1429c4b2225SAlexander Belyaev 1439c4b2225SAlexander Belyaev void ReportControlFlow(raw_ostream &o, 1449c4b2225SAlexander Belyaev const PathDiagnosticControlFlowPiece& P, 1459c4b2225SAlexander Belyaev unsigned indent); 1469c4b2225SAlexander Belyaev void ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece& P, 1479c4b2225SAlexander Belyaev unsigned indent, unsigned depth, bool isKeyEvent = false); 1489c4b2225SAlexander Belyaev void ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P, 1499c4b2225SAlexander Belyaev unsigned indent, unsigned depth); 1509c4b2225SAlexander Belyaev void ReportMacroSubPieces(raw_ostream &o, const PathDiagnosticMacroPiece& P, 1519c4b2225SAlexander Belyaev unsigned indent, unsigned depth); 1529c4b2225SAlexander Belyaev void ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, 1539c4b2225SAlexander Belyaev unsigned indent); 1549c4b2225SAlexander Belyaev 1559c4b2225SAlexander Belyaev void ReportPopUp(raw_ostream &o, const PathDiagnosticPopUpPiece &P, 1569c4b2225SAlexander Belyaev unsigned indent); 1579c4b2225SAlexander Belyaev }; 1589c4b2225SAlexander Belyaev 1599c4b2225SAlexander Belyaev } // end of anonymous namespace 1609c4b2225SAlexander Belyaev 1611cb15b10SAaron Puchert /// Print coverage information to output stream @c o. 1621cb15b10SAaron Puchert /// May modify the used list of files @c Fids by inserting new ones. 1639c4b2225SAlexander Belyaev static void printCoverage(const PathDiagnostic *D, 1649c4b2225SAlexander Belyaev unsigned InputIndentLevel, 1659c4b2225SAlexander Belyaev SmallVectorImpl<FileID> &Fids, 1669c4b2225SAlexander Belyaev FIDMap &FM, 1679c4b2225SAlexander Belyaev llvm::raw_fd_ostream &o); 1689c4b2225SAlexander Belyaev 1696ad0788cSKazu Hirata static std::optional<StringRef> getExpandedMacro( 170170c67d5SBalazs Benics SourceLocation MacroLoc, const cross_tu::CrossTranslationUnitContext &CTU, 171170c67d5SBalazs Benics const MacroExpansionContext &MacroExpansions, const SourceManager &SM); 1729c4b2225SAlexander Belyaev 1739c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 1749c4b2225SAlexander Belyaev // Methods of PlistPrinter. 1759c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 1769c4b2225SAlexander Belyaev 1779c4b2225SAlexander Belyaev void PlistPrinter::EmitRanges(raw_ostream &o, 1789c4b2225SAlexander Belyaev const ArrayRef<SourceRange> Ranges, 1799c4b2225SAlexander Belyaev unsigned indent) { 1809c4b2225SAlexander Belyaev 1819c4b2225SAlexander Belyaev if (Ranges.empty()) 1829c4b2225SAlexander Belyaev return; 1839c4b2225SAlexander Belyaev 1849c4b2225SAlexander Belyaev Indent(o, indent) << "<key>ranges</key>\n"; 1859c4b2225SAlexander Belyaev Indent(o, indent) << "<array>\n"; 1869c4b2225SAlexander Belyaev ++indent; 1879c4b2225SAlexander Belyaev 1889c4b2225SAlexander Belyaev const SourceManager &SM = PP.getSourceManager(); 1899c4b2225SAlexander Belyaev const LangOptions &LangOpts = PP.getLangOpts(); 1909c4b2225SAlexander Belyaev 1919c4b2225SAlexander Belyaev for (auto &R : Ranges) 1929c4b2225SAlexander Belyaev EmitRange(o, SM, 1939c4b2225SAlexander Belyaev Lexer::getAsCharRange(SM.getExpansionRange(R), SM, LangOpts), 1949c4b2225SAlexander Belyaev FM, indent + 1); 1959c4b2225SAlexander Belyaev --indent; 1969c4b2225SAlexander Belyaev Indent(o, indent) << "</array>\n"; 1979c4b2225SAlexander Belyaev } 1989c4b2225SAlexander Belyaev 1999c4b2225SAlexander Belyaev void PlistPrinter::EmitMessage(raw_ostream &o, StringRef Message, 2009c4b2225SAlexander Belyaev unsigned indent) { 2019c4b2225SAlexander Belyaev // Output the text. 2029c4b2225SAlexander Belyaev assert(!Message.empty()); 2039c4b2225SAlexander Belyaev Indent(o, indent) << "<key>extended_message</key>\n"; 2049c4b2225SAlexander Belyaev Indent(o, indent); 2059c4b2225SAlexander Belyaev EmitString(o, Message) << '\n'; 2069c4b2225SAlexander Belyaev 2079c4b2225SAlexander Belyaev // Output the short text. 2089c4b2225SAlexander Belyaev // FIXME: Really use a short string. 2099c4b2225SAlexander Belyaev Indent(o, indent) << "<key>message</key>\n"; 2109c4b2225SAlexander Belyaev Indent(o, indent); 2119c4b2225SAlexander Belyaev EmitString(o, Message) << '\n'; 2129c4b2225SAlexander Belyaev } 2139c4b2225SAlexander Belyaev 2149c4b2225SAlexander Belyaev void PlistPrinter::EmitFixits(raw_ostream &o, ArrayRef<FixItHint> fixits, 2159c4b2225SAlexander Belyaev unsigned indent) { 2169c4b2225SAlexander Belyaev if (fixits.size() == 0) 2179c4b2225SAlexander Belyaev return; 2189c4b2225SAlexander Belyaev 2199c4b2225SAlexander Belyaev const SourceManager &SM = PP.getSourceManager(); 2209c4b2225SAlexander Belyaev const LangOptions &LangOpts = PP.getLangOpts(); 2219c4b2225SAlexander Belyaev 2229c4b2225SAlexander Belyaev Indent(o, indent) << "<key>fixits</key>\n"; 2239c4b2225SAlexander Belyaev Indent(o, indent) << "<array>\n"; 2249c4b2225SAlexander Belyaev for (const auto &fixit : fixits) { 2259c4b2225SAlexander Belyaev assert(!fixit.isNull()); 2269c4b2225SAlexander Belyaev // FIXME: Add support for InsertFromRange and BeforePreviousInsertion. 2279c4b2225SAlexander Belyaev assert(!fixit.InsertFromRange.isValid() && "Not implemented yet!"); 2289c4b2225SAlexander Belyaev assert(!fixit.BeforePreviousInsertions && "Not implemented yet!"); 2299c4b2225SAlexander Belyaev Indent(o, indent) << " <dict>\n"; 2309c4b2225SAlexander Belyaev Indent(o, indent) << " <key>remove_range</key>\n"; 2319c4b2225SAlexander Belyaev EmitRange(o, SM, Lexer::getAsCharRange(fixit.RemoveRange, SM, LangOpts), 2329c4b2225SAlexander Belyaev FM, indent + 2); 2339c4b2225SAlexander Belyaev Indent(o, indent) << " <key>insert_string</key>"; 2349c4b2225SAlexander Belyaev EmitString(o, fixit.CodeToInsert); 2359c4b2225SAlexander Belyaev o << "\n"; 2369c4b2225SAlexander Belyaev Indent(o, indent) << " </dict>\n"; 2379c4b2225SAlexander Belyaev } 2389c4b2225SAlexander Belyaev Indent(o, indent) << "</array>\n"; 2399c4b2225SAlexander Belyaev } 2409c4b2225SAlexander Belyaev 2419c4b2225SAlexander Belyaev void PlistPrinter::ReportControlFlow(raw_ostream &o, 2429c4b2225SAlexander Belyaev const PathDiagnosticControlFlowPiece& P, 2439c4b2225SAlexander Belyaev unsigned indent) { 2449c4b2225SAlexander Belyaev 2459c4b2225SAlexander Belyaev const SourceManager &SM = PP.getSourceManager(); 2469c4b2225SAlexander Belyaev const LangOptions &LangOpts = PP.getLangOpts(); 2479c4b2225SAlexander Belyaev 2489c4b2225SAlexander Belyaev Indent(o, indent) << "<dict>\n"; 2499c4b2225SAlexander Belyaev ++indent; 2509c4b2225SAlexander Belyaev 2519c4b2225SAlexander Belyaev Indent(o, indent) << "<key>kind</key><string>control</string>\n"; 2529c4b2225SAlexander Belyaev 2539c4b2225SAlexander Belyaev // Emit edges. 2549c4b2225SAlexander Belyaev Indent(o, indent) << "<key>edges</key>\n"; 2559c4b2225SAlexander Belyaev ++indent; 2569c4b2225SAlexander Belyaev Indent(o, indent) << "<array>\n"; 2579c4b2225SAlexander Belyaev ++indent; 2589c4b2225SAlexander Belyaev for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end(); 2599c4b2225SAlexander Belyaev I!=E; ++I) { 2609c4b2225SAlexander Belyaev Indent(o, indent) << "<dict>\n"; 2619c4b2225SAlexander Belyaev ++indent; 2629c4b2225SAlexander Belyaev 2639c4b2225SAlexander Belyaev // Make the ranges of the start and end point self-consistent with adjacent edges 2649c4b2225SAlexander Belyaev // by forcing to use only the beginning of the range. This simplifies the layout 2659c4b2225SAlexander Belyaev // logic for clients. 2669c4b2225SAlexander Belyaev Indent(o, indent) << "<key>start</key>\n"; 2679c4b2225SAlexander Belyaev SourceRange StartEdge( 2689c4b2225SAlexander Belyaev SM.getExpansionLoc(I->getStart().asRange().getBegin())); 2699c4b2225SAlexander Belyaev EmitRange(o, SM, Lexer::getAsCharRange(StartEdge, SM, LangOpts), FM, 2709c4b2225SAlexander Belyaev indent + 1); 2719c4b2225SAlexander Belyaev 2729c4b2225SAlexander Belyaev Indent(o, indent) << "<key>end</key>\n"; 2739c4b2225SAlexander Belyaev SourceRange EndEdge(SM.getExpansionLoc(I->getEnd().asRange().getBegin())); 2749c4b2225SAlexander Belyaev EmitRange(o, SM, Lexer::getAsCharRange(EndEdge, SM, LangOpts), FM, 2759c4b2225SAlexander Belyaev indent + 1); 2769c4b2225SAlexander Belyaev 2779c4b2225SAlexander Belyaev --indent; 2789c4b2225SAlexander Belyaev Indent(o, indent) << "</dict>\n"; 2799c4b2225SAlexander Belyaev } 2809c4b2225SAlexander Belyaev --indent; 2819c4b2225SAlexander Belyaev Indent(o, indent) << "</array>\n"; 2829c4b2225SAlexander Belyaev --indent; 2839c4b2225SAlexander Belyaev 2849c4b2225SAlexander Belyaev // Output any helper text. 2859c4b2225SAlexander Belyaev const auto &s = P.getString(); 2869c4b2225SAlexander Belyaev if (!s.empty()) { 2879c4b2225SAlexander Belyaev Indent(o, indent) << "<key>alternate</key>"; 2889c4b2225SAlexander Belyaev EmitString(o, s) << '\n'; 2899c4b2225SAlexander Belyaev } 2909c4b2225SAlexander Belyaev 2919c4b2225SAlexander Belyaev assert(P.getFixits().size() == 0 && 2929c4b2225SAlexander Belyaev "Fixits on constrol flow pieces are not implemented yet!"); 2939c4b2225SAlexander Belyaev 2949c4b2225SAlexander Belyaev --indent; 2959c4b2225SAlexander Belyaev Indent(o, indent) << "</dict>\n"; 2969c4b2225SAlexander Belyaev } 2979c4b2225SAlexander Belyaev 2989c4b2225SAlexander Belyaev void PlistPrinter::ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece& P, 2999c4b2225SAlexander Belyaev unsigned indent, unsigned depth, 3009c4b2225SAlexander Belyaev bool isKeyEvent) { 3019c4b2225SAlexander Belyaev 3029c4b2225SAlexander Belyaev const SourceManager &SM = PP.getSourceManager(); 3039c4b2225SAlexander Belyaev 3049c4b2225SAlexander Belyaev Indent(o, indent) << "<dict>\n"; 3059c4b2225SAlexander Belyaev ++indent; 3069c4b2225SAlexander Belyaev 3079c4b2225SAlexander Belyaev Indent(o, indent) << "<key>kind</key><string>event</string>\n"; 3089c4b2225SAlexander Belyaev 3099c4b2225SAlexander Belyaev if (isKeyEvent) { 3109c4b2225SAlexander Belyaev Indent(o, indent) << "<key>key_event</key><true/>\n"; 3119c4b2225SAlexander Belyaev } 3129c4b2225SAlexander Belyaev 3139c4b2225SAlexander Belyaev // Output the location. 3149c4b2225SAlexander Belyaev FullSourceLoc L = P.getLocation().asLocation(); 3159c4b2225SAlexander Belyaev 3169c4b2225SAlexander Belyaev Indent(o, indent) << "<key>location</key>\n"; 3179c4b2225SAlexander Belyaev EmitLocation(o, SM, L, FM, indent); 3189c4b2225SAlexander Belyaev 3199c4b2225SAlexander Belyaev // Output the ranges (if any). 3209c4b2225SAlexander Belyaev ArrayRef<SourceRange> Ranges = P.getRanges(); 3219c4b2225SAlexander Belyaev EmitRanges(o, Ranges, indent); 3229c4b2225SAlexander Belyaev 3239c4b2225SAlexander Belyaev // Output the call depth. 3249c4b2225SAlexander Belyaev Indent(o, indent) << "<key>depth</key>"; 3259c4b2225SAlexander Belyaev EmitInteger(o, depth) << '\n'; 3269c4b2225SAlexander Belyaev 3279c4b2225SAlexander Belyaev // Output the text. 3289c4b2225SAlexander Belyaev EmitMessage(o, P.getString(), indent); 3299c4b2225SAlexander Belyaev 3309c4b2225SAlexander Belyaev // Output the fixits. 3319c4b2225SAlexander Belyaev EmitFixits(o, P.getFixits(), indent); 3329c4b2225SAlexander Belyaev 3339c4b2225SAlexander Belyaev // Finish up. 3349c4b2225SAlexander Belyaev --indent; 3359c4b2225SAlexander Belyaev Indent(o, indent); o << "</dict>\n"; 3369c4b2225SAlexander Belyaev } 3379c4b2225SAlexander Belyaev 3389c4b2225SAlexander Belyaev void PlistPrinter::ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P, 3399c4b2225SAlexander Belyaev unsigned indent, 3409c4b2225SAlexander Belyaev unsigned depth) { 3419c4b2225SAlexander Belyaev 3429c4b2225SAlexander Belyaev if (auto callEnter = P.getCallEnterEvent()) 3439c4b2225SAlexander Belyaev ReportPiece(o, *callEnter, indent, depth, /*includeControlFlow*/ true, 3449c4b2225SAlexander Belyaev P.isLastInMainSourceFile()); 3459c4b2225SAlexander Belyaev 3469c4b2225SAlexander Belyaev 3479c4b2225SAlexander Belyaev ++depth; 3489c4b2225SAlexander Belyaev 3499c4b2225SAlexander Belyaev if (auto callEnterWithinCaller = P.getCallEnterWithinCallerEvent()) 3509c4b2225SAlexander Belyaev ReportPiece(o, *callEnterWithinCaller, indent, depth, 3519c4b2225SAlexander Belyaev /*includeControlFlow*/ true); 3529c4b2225SAlexander Belyaev 3539c4b2225SAlexander Belyaev for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I) 3549c4b2225SAlexander Belyaev ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ true); 3559c4b2225SAlexander Belyaev 3569c4b2225SAlexander Belyaev --depth; 3579c4b2225SAlexander Belyaev 3589c4b2225SAlexander Belyaev if (auto callExit = P.getCallExitEvent()) 3599c4b2225SAlexander Belyaev ReportPiece(o, *callExit, indent, depth, /*includeControlFlow*/ true); 3609c4b2225SAlexander Belyaev 3619c4b2225SAlexander Belyaev assert(P.getFixits().size() == 0 && 3629c4b2225SAlexander Belyaev "Fixits on call pieces are not implemented yet!"); 3639c4b2225SAlexander Belyaev } 3649c4b2225SAlexander Belyaev 3659c4b2225SAlexander Belyaev void PlistPrinter::ReportMacroSubPieces(raw_ostream &o, 3669c4b2225SAlexander Belyaev const PathDiagnosticMacroPiece& P, 3679c4b2225SAlexander Belyaev unsigned indent, unsigned depth) { 3689c4b2225SAlexander Belyaev MacroPieces.push_back(&P); 3699c4b2225SAlexander Belyaev 3705c23e27bSBalazs Benics for (const auto &SubPiece : P.subPieces) { 3715c23e27bSBalazs Benics ReportPiece(o, *SubPiece, indent, depth, /*includeControlFlow*/ false); 3729c4b2225SAlexander Belyaev } 3739c4b2225SAlexander Belyaev 3749c4b2225SAlexander Belyaev assert(P.getFixits().size() == 0 && 3759c4b2225SAlexander Belyaev "Fixits on constrol flow pieces are not implemented yet!"); 3769c4b2225SAlexander Belyaev } 3779c4b2225SAlexander Belyaev 3789c4b2225SAlexander Belyaev void PlistPrinter::ReportMacroExpansions(raw_ostream &o, unsigned indent) { 3799c4b2225SAlexander Belyaev 3809c4b2225SAlexander Belyaev for (const PathDiagnosticMacroPiece *P : MacroPieces) { 3819c4b2225SAlexander Belyaev const SourceManager &SM = PP.getSourceManager(); 382170c67d5SBalazs Benics 383170c67d5SBalazs Benics SourceLocation MacroExpansionLoc = 384170c67d5SBalazs Benics P->getLocation().asLocation().getExpansionLoc(); 385170c67d5SBalazs Benics 3866ad0788cSKazu Hirata const std::optional<StringRef> MacroName = 387170c67d5SBalazs Benics MacroExpansions.getOriginalText(MacroExpansionLoc); 3886ad0788cSKazu Hirata const std::optional<StringRef> ExpansionText = 389170c67d5SBalazs Benics getExpandedMacro(MacroExpansionLoc, CTU, MacroExpansions, SM); 390170c67d5SBalazs Benics 391452db157SKazu Hirata if (!MacroName || !ExpansionText) 392170c67d5SBalazs Benics continue; 3939c4b2225SAlexander Belyaev 3949c4b2225SAlexander Belyaev Indent(o, indent) << "<dict>\n"; 3959c4b2225SAlexander Belyaev ++indent; 3969c4b2225SAlexander Belyaev 3979c4b2225SAlexander Belyaev // Output the location. 3989c4b2225SAlexander Belyaev FullSourceLoc L = P->getLocation().asLocation(); 3999c4b2225SAlexander Belyaev 4009c4b2225SAlexander Belyaev Indent(o, indent) << "<key>location</key>\n"; 4019c4b2225SAlexander Belyaev EmitLocation(o, SM, L, FM, indent); 4029c4b2225SAlexander Belyaev 4039c4b2225SAlexander Belyaev // Output the ranges (if any). 4049c4b2225SAlexander Belyaev ArrayRef<SourceRange> Ranges = P->getRanges(); 4059c4b2225SAlexander Belyaev EmitRanges(o, Ranges, indent); 4069c4b2225SAlexander Belyaev 4079c4b2225SAlexander Belyaev // Output the macro name. 4089c4b2225SAlexander Belyaev Indent(o, indent) << "<key>name</key>"; 40953e5cd4dSFangrui Song EmitString(o, *MacroName) << '\n'; 4109c4b2225SAlexander Belyaev 4119c4b2225SAlexander Belyaev // Output what it expands into. 4129c4b2225SAlexander Belyaev Indent(o, indent) << "<key>expansion</key>"; 41353e5cd4dSFangrui Song EmitString(o, *ExpansionText) << '\n'; 4149c4b2225SAlexander Belyaev 4159c4b2225SAlexander Belyaev // Finish up. 4169c4b2225SAlexander Belyaev --indent; 4179c4b2225SAlexander Belyaev Indent(o, indent); 4189c4b2225SAlexander Belyaev o << "</dict>\n"; 4199c4b2225SAlexander Belyaev } 4209c4b2225SAlexander Belyaev } 4219c4b2225SAlexander Belyaev 4229c4b2225SAlexander Belyaev void PlistPrinter::ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P, 4239c4b2225SAlexander Belyaev unsigned indent) { 4249c4b2225SAlexander Belyaev 4259c4b2225SAlexander Belyaev const SourceManager &SM = PP.getSourceManager(); 4269c4b2225SAlexander Belyaev 4279c4b2225SAlexander Belyaev Indent(o, indent) << "<dict>\n"; 4289c4b2225SAlexander Belyaev ++indent; 4299c4b2225SAlexander Belyaev 4309c4b2225SAlexander Belyaev // Output the location. 4319c4b2225SAlexander Belyaev FullSourceLoc L = P.getLocation().asLocation(); 4329c4b2225SAlexander Belyaev 4339c4b2225SAlexander Belyaev Indent(o, indent) << "<key>location</key>\n"; 4349c4b2225SAlexander Belyaev EmitLocation(o, SM, L, FM, indent); 4359c4b2225SAlexander Belyaev 4369c4b2225SAlexander Belyaev // Output the ranges (if any). 4379c4b2225SAlexander Belyaev ArrayRef<SourceRange> Ranges = P.getRanges(); 4389c4b2225SAlexander Belyaev EmitRanges(o, Ranges, indent); 4399c4b2225SAlexander Belyaev 4409c4b2225SAlexander Belyaev // Output the text. 4419c4b2225SAlexander Belyaev EmitMessage(o, P.getString(), indent); 4429c4b2225SAlexander Belyaev 4439c4b2225SAlexander Belyaev // Output the fixits. 4449c4b2225SAlexander Belyaev EmitFixits(o, P.getFixits(), indent); 4459c4b2225SAlexander Belyaev 4469c4b2225SAlexander Belyaev // Finish up. 4479c4b2225SAlexander Belyaev --indent; 4489c4b2225SAlexander Belyaev Indent(o, indent); o << "</dict>\n"; 4499c4b2225SAlexander Belyaev } 4509c4b2225SAlexander Belyaev 4519c4b2225SAlexander Belyaev void PlistPrinter::ReportPopUp(raw_ostream &o, 4529c4b2225SAlexander Belyaev const PathDiagnosticPopUpPiece &P, 4539c4b2225SAlexander Belyaev unsigned indent) { 4549c4b2225SAlexander Belyaev const SourceManager &SM = PP.getSourceManager(); 4559c4b2225SAlexander Belyaev 4569c4b2225SAlexander Belyaev Indent(o, indent) << "<dict>\n"; 4579c4b2225SAlexander Belyaev ++indent; 4589c4b2225SAlexander Belyaev 4599c4b2225SAlexander Belyaev Indent(o, indent) << "<key>kind</key><string>pop-up</string>\n"; 4609c4b2225SAlexander Belyaev 4619c4b2225SAlexander Belyaev // Output the location. 4629c4b2225SAlexander Belyaev FullSourceLoc L = P.getLocation().asLocation(); 4639c4b2225SAlexander Belyaev 4649c4b2225SAlexander Belyaev Indent(o, indent) << "<key>location</key>\n"; 4659c4b2225SAlexander Belyaev EmitLocation(o, SM, L, FM, indent); 4669c4b2225SAlexander Belyaev 4679c4b2225SAlexander Belyaev // Output the ranges (if any). 4689c4b2225SAlexander Belyaev ArrayRef<SourceRange> Ranges = P.getRanges(); 4699c4b2225SAlexander Belyaev EmitRanges(o, Ranges, indent); 4709c4b2225SAlexander Belyaev 4719c4b2225SAlexander Belyaev // Output the text. 4729c4b2225SAlexander Belyaev EmitMessage(o, P.getString(), indent); 4739c4b2225SAlexander Belyaev 4749c4b2225SAlexander Belyaev assert(P.getFixits().size() == 0 && 4759c4b2225SAlexander Belyaev "Fixits on pop-up pieces are not implemented yet!"); 4769c4b2225SAlexander Belyaev 4779c4b2225SAlexander Belyaev // Finish up. 4789c4b2225SAlexander Belyaev --indent; 4799c4b2225SAlexander Belyaev Indent(o, indent) << "</dict>\n"; 4809c4b2225SAlexander Belyaev } 4819c4b2225SAlexander Belyaev 4829c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 4839c4b2225SAlexander Belyaev // Static function definitions. 4849c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 4859c4b2225SAlexander Belyaev 4861cb15b10SAaron Puchert /// Print coverage information to output stream @c o. 4871cb15b10SAaron Puchert /// May modify the used list of files @c Fids by inserting new ones. 4889c4b2225SAlexander Belyaev static void printCoverage(const PathDiagnostic *D, 4899c4b2225SAlexander Belyaev unsigned InputIndentLevel, 4909c4b2225SAlexander Belyaev SmallVectorImpl<FileID> &Fids, 4919c4b2225SAlexander Belyaev FIDMap &FM, 4929c4b2225SAlexander Belyaev llvm::raw_fd_ostream &o) { 4939c4b2225SAlexander Belyaev unsigned IndentLevel = InputIndentLevel; 4949c4b2225SAlexander Belyaev 4959c4b2225SAlexander Belyaev Indent(o, IndentLevel) << "<key>ExecutedLines</key>\n"; 4969c4b2225SAlexander Belyaev Indent(o, IndentLevel) << "<dict>\n"; 4979c4b2225SAlexander Belyaev IndentLevel++; 4989c4b2225SAlexander Belyaev 4999c4b2225SAlexander Belyaev // Mapping from file IDs to executed lines. 5009c4b2225SAlexander Belyaev const FilesToLineNumsMap &ExecutedLines = D->getExecutedLines(); 5015c23e27bSBalazs Benics for (const auto &[FID, Lines] : ExecutedLines) { 5025c23e27bSBalazs Benics unsigned FileKey = AddFID(FM, Fids, FID); 5039c4b2225SAlexander Belyaev Indent(o, IndentLevel) << "<key>" << FileKey << "</key>\n"; 5049c4b2225SAlexander Belyaev Indent(o, IndentLevel) << "<array>\n"; 5059c4b2225SAlexander Belyaev IndentLevel++; 5065c23e27bSBalazs Benics for (unsigned LineNo : Lines) { 5079c4b2225SAlexander Belyaev Indent(o, IndentLevel); 5089c4b2225SAlexander Belyaev EmitInteger(o, LineNo) << "\n"; 5099c4b2225SAlexander Belyaev } 5109c4b2225SAlexander Belyaev IndentLevel--; 5119c4b2225SAlexander Belyaev Indent(o, IndentLevel) << "</array>\n"; 5129c4b2225SAlexander Belyaev } 5139c4b2225SAlexander Belyaev IndentLevel--; 5149c4b2225SAlexander Belyaev Indent(o, IndentLevel) << "</dict>\n"; 5159c4b2225SAlexander Belyaev 5169c4b2225SAlexander Belyaev assert(IndentLevel == InputIndentLevel); 5179c4b2225SAlexander Belyaev } 5189c4b2225SAlexander Belyaev 5199c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 5209c4b2225SAlexander Belyaev // Methods of PlistDiagnostics. 5219c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 5229c4b2225SAlexander Belyaev 5239c4b2225SAlexander Belyaev PlistDiagnostics::PlistDiagnostics( 5249c4b2225SAlexander Belyaev PathDiagnosticConsumerOptions DiagOpts, const std::string &output, 5259c4b2225SAlexander Belyaev const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU, 5267c58fb6bSBalazs Benics const MacroExpansionContext &MacroExpansions, bool supportsMultipleFiles) 5279c4b2225SAlexander Belyaev : DiagOpts(std::move(DiagOpts)), OutputFile(output), PP(PP), CTU(CTU), 5287c58fb6bSBalazs Benics MacroExpansions(MacroExpansions), 5299c4b2225SAlexander Belyaev SupportsCrossFileDiagnostics(supportsMultipleFiles) { 5309c4b2225SAlexander Belyaev // FIXME: Will be used by a later planned change. 5319c4b2225SAlexander Belyaev (void)this->CTU; 5329c4b2225SAlexander Belyaev } 5339c4b2225SAlexander Belyaev 5349c4b2225SAlexander Belyaev void ento::createPlistDiagnosticConsumer( 5359c4b2225SAlexander Belyaev PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C, 5369c4b2225SAlexander Belyaev const std::string &OutputFile, const Preprocessor &PP, 5377c58fb6bSBalazs Benics const cross_tu::CrossTranslationUnitContext &CTU, 5387c58fb6bSBalazs Benics const MacroExpansionContext &MacroExpansions) { 5399c4b2225SAlexander Belyaev 5409c4b2225SAlexander Belyaev // TODO: Emit an error here. 5419c4b2225SAlexander Belyaev if (OutputFile.empty()) 5429c4b2225SAlexander Belyaev return; 5439c4b2225SAlexander Belyaev 5449c4b2225SAlexander Belyaev C.push_back(new PlistDiagnostics(DiagOpts, OutputFile, PP, CTU, 5457c58fb6bSBalazs Benics MacroExpansions, 5469c4b2225SAlexander Belyaev /*supportsMultipleFiles=*/false)); 5479c4b2225SAlexander Belyaev createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, OutputFile, 5487c58fb6bSBalazs Benics PP, CTU, MacroExpansions); 5499c4b2225SAlexander Belyaev } 5509c4b2225SAlexander Belyaev 5519c4b2225SAlexander Belyaev void ento::createPlistMultiFileDiagnosticConsumer( 5529c4b2225SAlexander Belyaev PathDiagnosticConsumerOptions DiagOpts, PathDiagnosticConsumers &C, 5539c4b2225SAlexander Belyaev const std::string &OutputFile, const Preprocessor &PP, 5547c58fb6bSBalazs Benics const cross_tu::CrossTranslationUnitContext &CTU, 5557c58fb6bSBalazs Benics const MacroExpansionContext &MacroExpansions) { 5569c4b2225SAlexander Belyaev 5579c4b2225SAlexander Belyaev // TODO: Emit an error here. 5589c4b2225SAlexander Belyaev if (OutputFile.empty()) 5599c4b2225SAlexander Belyaev return; 5609c4b2225SAlexander Belyaev 5619c4b2225SAlexander Belyaev C.push_back(new PlistDiagnostics(DiagOpts, OutputFile, PP, CTU, 5627c58fb6bSBalazs Benics MacroExpansions, 5639c4b2225SAlexander Belyaev /*supportsMultipleFiles=*/true)); 5649c4b2225SAlexander Belyaev createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts), C, OutputFile, 5657c58fb6bSBalazs Benics PP, CTU, MacroExpansions); 5669c4b2225SAlexander Belyaev } 5679c4b2225SAlexander Belyaev 5689c4b2225SAlexander Belyaev void PlistDiagnostics::printBugPath(llvm::raw_ostream &o, const FIDMap &FM, 5699c4b2225SAlexander Belyaev const PathPieces &Path) { 5707c58fb6bSBalazs Benics PlistPrinter Printer(FM, PP, CTU, MacroExpansions); 5719c4b2225SAlexander Belyaev assert(std::is_partitioned(Path.begin(), Path.end(), 5729c4b2225SAlexander Belyaev [](const PathDiagnosticPieceRef &E) { 5739c4b2225SAlexander Belyaev return E->getKind() == PathDiagnosticPiece::Note; 5749c4b2225SAlexander Belyaev }) && 5759c4b2225SAlexander Belyaev "PathDiagnostic is not partitioned so that notes precede the rest"); 5769c4b2225SAlexander Belyaev 5779c4b2225SAlexander Belyaev PathPieces::const_iterator FirstNonNote = std::partition_point( 5789c4b2225SAlexander Belyaev Path.begin(), Path.end(), [](const PathDiagnosticPieceRef &E) { 5799c4b2225SAlexander Belyaev return E->getKind() == PathDiagnosticPiece::Note; 5809c4b2225SAlexander Belyaev }); 5819c4b2225SAlexander Belyaev 5829c4b2225SAlexander Belyaev PathPieces::const_iterator I = Path.begin(); 5839c4b2225SAlexander Belyaev 5849c4b2225SAlexander Belyaev if (FirstNonNote != Path.begin()) { 5859c4b2225SAlexander Belyaev o << " <key>notes</key>\n" 5869c4b2225SAlexander Belyaev " <array>\n"; 5879c4b2225SAlexander Belyaev 5889c4b2225SAlexander Belyaev for (; I != FirstNonNote; ++I) 5899c4b2225SAlexander Belyaev Printer.ReportDiag(o, **I); 5909c4b2225SAlexander Belyaev 5919c4b2225SAlexander Belyaev o << " </array>\n"; 5929c4b2225SAlexander Belyaev } 5939c4b2225SAlexander Belyaev 5949c4b2225SAlexander Belyaev o << " <key>path</key>\n"; 5959c4b2225SAlexander Belyaev 5969c4b2225SAlexander Belyaev o << " <array>\n"; 5979c4b2225SAlexander Belyaev 5985c23e27bSBalazs Benics for (const auto &Piece : llvm::make_range(I, Path.end())) 5995c23e27bSBalazs Benics Printer.ReportDiag(o, *Piece); 6009c4b2225SAlexander Belyaev 6019c4b2225SAlexander Belyaev o << " </array>\n"; 6029c4b2225SAlexander Belyaev 6039c4b2225SAlexander Belyaev if (!DiagOpts.ShouldDisplayMacroExpansions) 6049c4b2225SAlexander Belyaev return; 6059c4b2225SAlexander Belyaev 6069c4b2225SAlexander Belyaev o << " <key>macro_expansions</key>\n" 6079c4b2225SAlexander Belyaev " <array>\n"; 6089c4b2225SAlexander Belyaev Printer.ReportMacroExpansions(o, /* indent */ 4); 6099c4b2225SAlexander Belyaev o << " </array>\n"; 6109c4b2225SAlexander Belyaev } 6119c4b2225SAlexander Belyaev 6129c4b2225SAlexander Belyaev void PlistDiagnostics::FlushDiagnosticsImpl( 6139c4b2225SAlexander Belyaev std::vector<const PathDiagnostic *> &Diags, 6149c4b2225SAlexander Belyaev FilesMade *filesMade) { 6159c4b2225SAlexander Belyaev // Build up a set of FIDs that we use by scanning the locations and 6169c4b2225SAlexander Belyaev // ranges of the diagnostics. 6179c4b2225SAlexander Belyaev FIDMap FM; 6189c4b2225SAlexander Belyaev SmallVector<FileID, 10> Fids; 6199c4b2225SAlexander Belyaev const SourceManager& SM = PP.getSourceManager(); 6209c4b2225SAlexander Belyaev const LangOptions &LangOpts = PP.getLangOpts(); 6219c4b2225SAlexander Belyaev 6229c4b2225SAlexander Belyaev auto AddPieceFID = [&FM, &Fids, &SM](const PathDiagnosticPiece &Piece) { 6239c4b2225SAlexander Belyaev AddFID(FM, Fids, SM, Piece.getLocation().asLocation()); 6249c4b2225SAlexander Belyaev ArrayRef<SourceRange> Ranges = Piece.getRanges(); 6259c4b2225SAlexander Belyaev for (const SourceRange &Range : Ranges) { 6269c4b2225SAlexander Belyaev AddFID(FM, Fids, SM, Range.getBegin()); 6279c4b2225SAlexander Belyaev AddFID(FM, Fids, SM, Range.getEnd()); 6289c4b2225SAlexander Belyaev } 6299c4b2225SAlexander Belyaev }; 6309c4b2225SAlexander Belyaev 6319c4b2225SAlexander Belyaev for (const PathDiagnostic *D : Diags) { 6329c4b2225SAlexander Belyaev 6339c4b2225SAlexander Belyaev SmallVector<const PathPieces *, 5> WorkList; 6349c4b2225SAlexander Belyaev WorkList.push_back(&D->path); 6359c4b2225SAlexander Belyaev 6369c4b2225SAlexander Belyaev while (!WorkList.empty()) { 6379c4b2225SAlexander Belyaev const PathPieces &Path = *WorkList.pop_back_val(); 6389c4b2225SAlexander Belyaev 6399c4b2225SAlexander Belyaev for (const auto &Iter : Path) { 6409c4b2225SAlexander Belyaev const PathDiagnosticPiece &Piece = *Iter; 6419c4b2225SAlexander Belyaev AddPieceFID(Piece); 6429c4b2225SAlexander Belyaev 6439c4b2225SAlexander Belyaev if (const PathDiagnosticCallPiece *Call = 6449c4b2225SAlexander Belyaev dyn_cast<PathDiagnosticCallPiece>(&Piece)) { 6459c4b2225SAlexander Belyaev if (auto CallEnterWithin = Call->getCallEnterWithinCallerEvent()) 6469c4b2225SAlexander Belyaev AddPieceFID(*CallEnterWithin); 6479c4b2225SAlexander Belyaev 6489c4b2225SAlexander Belyaev if (auto CallEnterEvent = Call->getCallEnterEvent()) 6499c4b2225SAlexander Belyaev AddPieceFID(*CallEnterEvent); 6509c4b2225SAlexander Belyaev 6519c4b2225SAlexander Belyaev WorkList.push_back(&Call->path); 6529c4b2225SAlexander Belyaev } else if (const PathDiagnosticMacroPiece *Macro = 6539c4b2225SAlexander Belyaev dyn_cast<PathDiagnosticMacroPiece>(&Piece)) { 6549c4b2225SAlexander Belyaev WorkList.push_back(&Macro->subPieces); 6559c4b2225SAlexander Belyaev } 6569c4b2225SAlexander Belyaev } 6579c4b2225SAlexander Belyaev } 6589c4b2225SAlexander Belyaev } 6599c4b2225SAlexander Belyaev 6609c4b2225SAlexander Belyaev // Open the file. 6619c4b2225SAlexander Belyaev std::error_code EC; 66282b3e28eSAbhina Sreeskantharajan llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::OF_TextWithCRLF); 6639c4b2225SAlexander Belyaev if (EC) { 6649c4b2225SAlexander Belyaev llvm::errs() << "warning: could not create file: " << EC.message() << '\n'; 6659c4b2225SAlexander Belyaev return; 6669c4b2225SAlexander Belyaev } 6679c4b2225SAlexander Belyaev 6689c4b2225SAlexander Belyaev EmitPlistHeader(o); 6699c4b2225SAlexander Belyaev 6709c4b2225SAlexander Belyaev // Write the root object: a <dict> containing... 6719c4b2225SAlexander Belyaev // - "clang_version", the string representation of clang version 6729c4b2225SAlexander Belyaev // - "files", an <array> mapping from FIDs to file names 6739c4b2225SAlexander Belyaev // - "diagnostics", an <array> containing the path diagnostics 6749c4b2225SAlexander Belyaev o << "<dict>\n" << 6759c4b2225SAlexander Belyaev " <key>clang_version</key>\n"; 6769c4b2225SAlexander Belyaev EmitString(o, getClangFullVersion()) << '\n'; 6779c4b2225SAlexander Belyaev o << " <key>diagnostics</key>\n" 6789c4b2225SAlexander Belyaev " <array>\n"; 6799c4b2225SAlexander Belyaev 6809c4b2225SAlexander Belyaev for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(), 6819c4b2225SAlexander Belyaev DE = Diags.end(); DI!=DE; ++DI) { 6829c4b2225SAlexander Belyaev 6839c4b2225SAlexander Belyaev o << " <dict>\n"; 6849c4b2225SAlexander Belyaev 6859c4b2225SAlexander Belyaev const PathDiagnostic *D = *DI; 6869c4b2225SAlexander Belyaev printBugPath(o, FM, D->path); 6879c4b2225SAlexander Belyaev 6889c4b2225SAlexander Belyaev // Output the bug type and bug category. 6899c4b2225SAlexander Belyaev o << " <key>description</key>"; 6909c4b2225SAlexander Belyaev EmitString(o, D->getShortDescription()) << '\n'; 6919c4b2225SAlexander Belyaev o << " <key>category</key>"; 6929c4b2225SAlexander Belyaev EmitString(o, D->getCategory()) << '\n'; 6939c4b2225SAlexander Belyaev o << " <key>type</key>"; 6949c4b2225SAlexander Belyaev EmitString(o, D->getBugType()) << '\n'; 6959c4b2225SAlexander Belyaev o << " <key>check_name</key>"; 6969c4b2225SAlexander Belyaev EmitString(o, D->getCheckerName()) << '\n'; 6979c4b2225SAlexander Belyaev 6989c4b2225SAlexander Belyaev o << " <!-- This hash is experimental and going to change! -->\n"; 6999c4b2225SAlexander Belyaev o << " <key>issue_hash_content_of_line_in_context</key>"; 7009c4b2225SAlexander Belyaev PathDiagnosticLocation UPDLoc = D->getUniqueingLoc(); 7019c4b2225SAlexander Belyaev FullSourceLoc L(SM.getExpansionLoc(UPDLoc.isValid() 7029c4b2225SAlexander Belyaev ? UPDLoc.asLocation() 7039c4b2225SAlexander Belyaev : D->getLocation().asLocation()), 7049c4b2225SAlexander Belyaev SM); 7059c4b2225SAlexander Belyaev const Decl *DeclWithIssue = D->getDeclWithIssue(); 7069c4b2225SAlexander Belyaev EmitString(o, getIssueHash(L, D->getCheckerName(), D->getBugType(), 7079c4b2225SAlexander Belyaev DeclWithIssue, LangOpts)) 7089c4b2225SAlexander Belyaev << '\n'; 7099c4b2225SAlexander Belyaev 7109c4b2225SAlexander Belyaev // Output information about the semantic context where 7119c4b2225SAlexander Belyaev // the issue occurred. 7129c4b2225SAlexander Belyaev if (const Decl *DeclWithIssue = D->getDeclWithIssue()) { 7139c4b2225SAlexander Belyaev // FIXME: handle blocks, which have no name. 7149c4b2225SAlexander Belyaev if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) { 7159c4b2225SAlexander Belyaev StringRef declKind; 7169c4b2225SAlexander Belyaev switch (ND->getKind()) { 7179c4b2225SAlexander Belyaev case Decl::CXXRecord: 7189c4b2225SAlexander Belyaev declKind = "C++ class"; 7199c4b2225SAlexander Belyaev break; 7209c4b2225SAlexander Belyaev case Decl::CXXMethod: 7219c4b2225SAlexander Belyaev declKind = "C++ method"; 7229c4b2225SAlexander Belyaev break; 7239c4b2225SAlexander Belyaev case Decl::ObjCMethod: 7249c4b2225SAlexander Belyaev declKind = "Objective-C method"; 7259c4b2225SAlexander Belyaev break; 7269c4b2225SAlexander Belyaev case Decl::Function: 7279c4b2225SAlexander Belyaev declKind = "function"; 7289c4b2225SAlexander Belyaev break; 7299c4b2225SAlexander Belyaev default: 7309c4b2225SAlexander Belyaev break; 7319c4b2225SAlexander Belyaev } 7329c4b2225SAlexander Belyaev if (!declKind.empty()) { 7339c4b2225SAlexander Belyaev const std::string &declName = ND->getDeclName().getAsString(); 7349c4b2225SAlexander Belyaev o << " <key>issue_context_kind</key>"; 7359c4b2225SAlexander Belyaev EmitString(o, declKind) << '\n'; 7369c4b2225SAlexander Belyaev o << " <key>issue_context</key>"; 7379c4b2225SAlexander Belyaev EmitString(o, declName) << '\n'; 7389c4b2225SAlexander Belyaev } 7399c4b2225SAlexander Belyaev 7409c4b2225SAlexander Belyaev // Output the bug hash for issue unique-ing. Currently, it's just an 7419c4b2225SAlexander Belyaev // offset from the beginning of the function. 7429c4b2225SAlexander Belyaev if (const Stmt *Body = DeclWithIssue->getBody()) { 7439c4b2225SAlexander Belyaev 7449c4b2225SAlexander Belyaev // If the bug uniqueing location exists, use it for the hash. 7459c4b2225SAlexander Belyaev // For example, this ensures that two leaks reported on the same line 7469c4b2225SAlexander Belyaev // will have different issue_hashes and that the hash will identify 7479c4b2225SAlexander Belyaev // the leak location even after code is added between the allocation 7489c4b2225SAlexander Belyaev // site and the end of scope (leak report location). 7499c4b2225SAlexander Belyaev if (UPDLoc.isValid()) { 7509c4b2225SAlexander Belyaev FullSourceLoc UFunL( 7519c4b2225SAlexander Belyaev SM.getExpansionLoc( 7529c4b2225SAlexander Belyaev D->getUniqueingDecl()->getBody()->getBeginLoc()), 7539c4b2225SAlexander Belyaev SM); 7549c4b2225SAlexander Belyaev o << " <key>issue_hash_function_offset</key><string>" 7559c4b2225SAlexander Belyaev << L.getExpansionLineNumber() - UFunL.getExpansionLineNumber() 7569c4b2225SAlexander Belyaev << "</string>\n"; 7579c4b2225SAlexander Belyaev 7589c4b2225SAlexander Belyaev // Otherwise, use the location on which the bug is reported. 7599c4b2225SAlexander Belyaev } else { 7609c4b2225SAlexander Belyaev FullSourceLoc FunL(SM.getExpansionLoc(Body->getBeginLoc()), SM); 7619c4b2225SAlexander Belyaev o << " <key>issue_hash_function_offset</key><string>" 7629c4b2225SAlexander Belyaev << L.getExpansionLineNumber() - FunL.getExpansionLineNumber() 7639c4b2225SAlexander Belyaev << "</string>\n"; 7649c4b2225SAlexander Belyaev } 7659c4b2225SAlexander Belyaev 7669c4b2225SAlexander Belyaev } 7679c4b2225SAlexander Belyaev } 7689c4b2225SAlexander Belyaev } 7699c4b2225SAlexander Belyaev 7709c4b2225SAlexander Belyaev // Output the location of the bug. 7719c4b2225SAlexander Belyaev o << " <key>location</key>\n"; 7729c4b2225SAlexander Belyaev EmitLocation(o, SM, D->getLocation().asLocation(), FM, 2); 7739c4b2225SAlexander Belyaev 7749c4b2225SAlexander Belyaev // Output the diagnostic to the sub-diagnostic client, if any. 7759c4b2225SAlexander Belyaev if (!filesMade->empty()) { 7769c4b2225SAlexander Belyaev StringRef lastName; 7779c4b2225SAlexander Belyaev PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D); 7789c4b2225SAlexander Belyaev if (files) { 7799c4b2225SAlexander Belyaev for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(), 7809c4b2225SAlexander Belyaev CE = files->end(); CI != CE; ++CI) { 7819c4b2225SAlexander Belyaev StringRef newName = CI->first; 7829c4b2225SAlexander Belyaev if (newName != lastName) { 7839c4b2225SAlexander Belyaev if (!lastName.empty()) { 7849c4b2225SAlexander Belyaev o << " </array>\n"; 7859c4b2225SAlexander Belyaev } 7869c4b2225SAlexander Belyaev lastName = newName; 7879c4b2225SAlexander Belyaev o << " <key>" << lastName << "_files</key>\n"; 7889c4b2225SAlexander Belyaev o << " <array>\n"; 7899c4b2225SAlexander Belyaev } 7909c4b2225SAlexander Belyaev o << " <string>" << CI->second << "</string>\n"; 7919c4b2225SAlexander Belyaev } 7929c4b2225SAlexander Belyaev o << " </array>\n"; 7939c4b2225SAlexander Belyaev } 7949c4b2225SAlexander Belyaev } 7959c4b2225SAlexander Belyaev 7969c4b2225SAlexander Belyaev printCoverage(D, /*IndentLevel=*/2, Fids, FM, o); 7979c4b2225SAlexander Belyaev 7989c4b2225SAlexander Belyaev // Close up the entry. 7999c4b2225SAlexander Belyaev o << " </dict>\n"; 8009c4b2225SAlexander Belyaev } 8019c4b2225SAlexander Belyaev 8029c4b2225SAlexander Belyaev o << " </array>\n"; 8039c4b2225SAlexander Belyaev 8049c4b2225SAlexander Belyaev o << " <key>files</key>\n" 8059c4b2225SAlexander Belyaev " <array>\n"; 8069c4b2225SAlexander Belyaev for (FileID FID : Fids) 807*523c4712SJan Svoboda EmitString(o << " ", SM.getFileEntryRefForID(FID)->getName()) << '\n'; 8089c4b2225SAlexander Belyaev o << " </array>\n"; 8099c4b2225SAlexander Belyaev 8109c4b2225SAlexander Belyaev if (llvm::AreStatisticsEnabled() && DiagOpts.ShouldSerializeStats) { 8119c4b2225SAlexander Belyaev o << " <key>statistics</key>\n"; 8129c4b2225SAlexander Belyaev std::string stats; 8139c4b2225SAlexander Belyaev llvm::raw_string_ostream os(stats); 8149c4b2225SAlexander Belyaev llvm::PrintStatisticsJSON(os); 8159c4b2225SAlexander Belyaev EmitString(o, html::EscapeText(stats)) << '\n'; 8169c4b2225SAlexander Belyaev } 8179c4b2225SAlexander Belyaev 8189c4b2225SAlexander Belyaev // Finish. 8199c4b2225SAlexander Belyaev o << "</dict>\n</plist>\n"; 8209c4b2225SAlexander Belyaev } 8219c4b2225SAlexander Belyaev 8229c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 8239c4b2225SAlexander Belyaev // Definitions of helper functions and methods for expanding macros. 8249c4b2225SAlexander Belyaev //===----------------------------------------------------------------------===// 8259c4b2225SAlexander Belyaev 8266ad0788cSKazu Hirata static std::optional<StringRef> 827170c67d5SBalazs Benics getExpandedMacro(SourceLocation MacroExpansionLoc, 828170c67d5SBalazs Benics const cross_tu::CrossTranslationUnitContext &CTU, 829170c67d5SBalazs Benics const MacroExpansionContext &MacroExpansions, 830170c67d5SBalazs Benics const SourceManager &SM) { 83138b18583SBalazs Benics if (auto CTUMacroExpCtx = 83238b18583SBalazs Benics CTU.getMacroExpansionContextForSourceLocation(MacroExpansionLoc)) { 83338b18583SBalazs Benics return CTUMacroExpCtx->getExpandedText(MacroExpansionLoc); 8349c4b2225SAlexander Belyaev } 835170c67d5SBalazs Benics return MacroExpansions.getExpandedText(MacroExpansionLoc); 8369c4b2225SAlexander Belyaev } 837