PlistDiagnostics.cpp revision 68fbb3ee8ae374b6505885e907af92b30eef707f
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- C++ -*-===// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The LLVM Compiler Infrastructure 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// License. See LICENSE.TXT for details. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file defines the PlistDiagnostics object. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Basic/SourceManager.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Basic/FileManager.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Lex/Preprocessor.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/raw_ostream.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/Casting.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/DenseMap.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/SmallVector.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang; 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace ento; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef llvm::DenseMap<FileID, unsigned> FIDMap; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class PlistDiagnostics : public PathDiagnosticConsumer { 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string OutputFile; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LangOptions &LangOpts; 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OwningPtr<PathDiagnosticConsumer> SubPD; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool flushed; 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PathDiagnosticConsumer *subPD); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~PlistDiagnostics() {} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SmallVectorImpl<std::string> *FilesMade); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual StringRef getName() const { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "PlistDiagnostics"; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PathGenerationScheme getGenerationScheme() const; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool supportsLogicalOpControlFlow() const { return true; } 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool supportsAllBlockEdges() const { return true; } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual bool useVerboseDescription() const { return false; } 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // end anonymous namespace 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PlistDiagnostics::PlistDiagnostics(const std::string& output, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LangOptions &LO, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PathDiagnosticConsumer *subPD) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {} 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PathDiagnosticConsumer* 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ento::createPlistDiagnosticConsumer(const std::string& s, const Preprocessor &PP, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PathDiagnosticConsumer *subPD) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new PlistDiagnostics(s, PP.getLangOptions(), subPD); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PathDiagnosticConsumer::PathGenerationScheme 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PlistDiagnostics::getGenerationScheme() const { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (const PathDiagnosticConsumer *PD = SubPD.get()) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return PD->getGenerationScheme(); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Extensive; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V, 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SourceManager* SM, SourceLocation L) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileID FID = SM->getFileID(SM->getExpansionLoc(L)); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FIDMap::iterator I = FIDs.find(FID); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (I != FIDs.end()) return; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FIDs[FID] = V.size(); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) V.push_back(FID); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM, 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SourceLocation L) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FileID FID = SM.getFileID(SM.getExpansionLoc(L)); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FIDMap::const_iterator I = FIDs.find(FID); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert(I != FIDs.end()); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return I->second; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static raw_ostream &Indent(raw_ostream &o, const unsigned indent) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (unsigned i = 0; i < indent; ++i) o << ' '; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return o; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EmitLocation(raw_ostream &o, const SourceManager &SM, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LangOptions &LangOpts, 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SourceLocation L, const FIDMap &FM, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned indent, bool extend = false) { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FullSourceLoc Loc(SM.getExpansionLoc(L), const_cast<SourceManager&>(SM)); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Add in the length of the token, so that we cover multi-char tokens. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned offset = 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<dict>\n"; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << " <key>line</key><integer>" 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << Loc.getExpansionLineNumber() << "</integer>\n"; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << " <key>col</key><integer>" 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << Loc.getExpansionColumnNumber() + offset << "</integer>\n"; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << " <key>file</key><integer>" 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << GetFID(FM, SM, Loc) << "</integer>\n"; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "</dict>\n"; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EmitLocation(raw_ostream &o, const SourceManager &SM, 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LangOptions &LangOpts, 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PathDiagnosticLocation &L, const FIDMap& FM, 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned indent, bool extend = false) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void EmitRange(raw_ostream &o, const SourceManager &SM, 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LangOptions &LangOpts, 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PathDiagnosticRange R, const FIDMap &FM, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned indent) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<array>\n"; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, !R.isPoint); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "</array>\n"; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static raw_ostream &EmitString(raw_ostream &o, 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& s) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) o << "<string>"; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char c = *I; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (c) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: o << c; break; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case '&': o << "&"; break; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case '<': o << "<"; break; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case '>': o << ">"; break; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case '\'': o << "'"; break; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case '\"': o << """; break; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) o << "</string>"; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return o; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ReportControlFlow(raw_ostream &o, 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PathDiagnosticControlFlowPiece& P, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FIDMap& FM, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SourceManager &SM, 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LangOptions &LangOpts, 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unsigned indent) { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<dict>\n"; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++indent; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<key>kind</key><string>control</string>\n"; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Emit edges. 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<key>edges</key>\n"; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++indent; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<array>\n"; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++indent; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end(); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) I!=E; ++I) { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<dict>\n"; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++indent; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<key>start</key>\n"; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EmitRange(o, SM, LangOpts, I->getStart().asRange(), FM, indent+1); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<key>end</key>\n"; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EmitRange(o, SM, LangOpts, I->getEnd().asRange(), FM, indent+1); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --indent; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "</dict>\n"; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --indent; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "</array>\n"; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --indent; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Output any helper text. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& s = P.getString(); 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!s.empty()) { 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "<key>alternate</key>"; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EmitString(o, s) << '\n'; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --indent; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Indent(o, indent) << "</dict>\n"; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, 197 const FIDMap& FM, 198 const SourceManager &SM, 199 const LangOptions &LangOpts, 200 unsigned indent) { 201 202 Indent(o, indent) << "<dict>\n"; 203 ++indent; 204 205 Indent(o, indent) << "<key>kind</key><string>event</string>\n"; 206 207 // Output the location. 208 FullSourceLoc L = P.getLocation().asLocation(); 209 210 Indent(o, indent) << "<key>location</key>\n"; 211 EmitLocation(o, SM, LangOpts, L, FM, indent); 212 213 // Output the ranges (if any). 214 PathDiagnosticPiece::range_iterator RI = P.ranges_begin(), 215 RE = P.ranges_end(); 216 217 if (RI != RE) { 218 Indent(o, indent) << "<key>ranges</key>\n"; 219 Indent(o, indent) << "<array>\n"; 220 ++indent; 221 for (; RI != RE; ++RI) 222 EmitRange(o, SM, LangOpts, *RI, FM, indent+1); 223 --indent; 224 Indent(o, indent) << "</array>\n"; 225 } 226 227 // Output the text. 228 assert(!P.getString().empty()); 229 Indent(o, indent) << "<key>extended_message</key>\n"; 230 Indent(o, indent); 231 EmitString(o, P.getString()) << '\n'; 232 233 // Output the short text. 234 // FIXME: Really use a short string. 235 Indent(o, indent) << "<key>message</key>\n"; 236 EmitString(o, P.getString()) << '\n'; 237 238 // Finish up. 239 --indent; 240 Indent(o, indent); o << "</dict>\n"; 241} 242 243static void ReportMacro(raw_ostream &o, 244 const PathDiagnosticMacroPiece& P, 245 const FIDMap& FM, const SourceManager &SM, 246 const LangOptions &LangOpts, 247 unsigned indent) { 248 249 for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end(); 250 I!=E; ++I) { 251 252 switch ((*I)->getKind()) { 253 default: 254 break; 255 case PathDiagnosticPiece::Event: 256 ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts, 257 indent); 258 break; 259 case PathDiagnosticPiece::Macro: 260 ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts, 261 indent); 262 break; 263 } 264 } 265} 266 267static void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P, 268 const FIDMap& FM, const SourceManager &SM, 269 const LangOptions &LangOpts) { 270 271 unsigned indent = 4; 272 273 switch (P.getKind()) { 274 case PathDiagnosticPiece::ControlFlow: 275 ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM, 276 LangOpts, indent); 277 break; 278 case PathDiagnosticPiece::CallEnter: 279 case PathDiagnosticPiece::CallExit: 280 case PathDiagnosticPiece::Event: 281 ReportEvent(o, cast<PathDiagnosticSpotPiece>(P), FM, SM, LangOpts, 282 indent); 283 break; 284 case PathDiagnosticPiece::Macro: 285 ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts, 286 indent); 287 break; 288 } 289} 290 291void PlistDiagnostics::FlushDiagnosticsImpl( 292 std::vector<const PathDiagnostic *> &Diags, 293 SmallVectorImpl<std::string> *FilesMade) { 294 // Build up a set of FIDs that we use by scanning the locations and 295 // ranges of the diagnostics. 296 FIDMap FM; 297 SmallVector<FileID, 10> Fids; 298 const SourceManager* SM = 0; 299 300 if (!Diags.empty()) 301 SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager(); 302 303 for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(), 304 DE = Diags.end(); DI != DE; ++DI) { 305 306 const PathDiagnostic *D = *DI; 307 308 for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end(); 309 I!=E; ++I) { 310 AddFID(FM, Fids, SM, (*I)->getLocation().asLocation()); 311 312 for (PathDiagnosticPiece::range_iterator RI = (*I)->ranges_begin(), 313 RE= (*I)->ranges_end(); RI != RE; ++RI) { 314 AddFID(FM, Fids, SM, RI->getBegin()); 315 AddFID(FM, Fids, SM, RI->getEnd()); 316 } 317 } 318 } 319 320 // Open the file. 321 std::string ErrMsg; 322 llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg); 323 if (!ErrMsg.empty()) { 324 llvm::errs() << "warning: could not create file: " << OutputFile << '\n'; 325 return; 326 } 327 328 // Write the plist header. 329 o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 330 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " 331 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 332 "<plist version=\"1.0\">\n"; 333 334 // Write the root object: a <dict> containing... 335 // - "files", an <array> mapping from FIDs to file names 336 // - "diagnostics", an <array> containing the path diagnostics 337 o << "<dict>\n" 338 " <key>files</key>\n" 339 " <array>\n"; 340 341 for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); 342 I!=E; ++I) { 343 o << " "; 344 EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n'; 345 } 346 347 o << " </array>\n" 348 " <key>diagnostics</key>\n" 349 " <array>\n"; 350 351 for (std::vector<const PathDiagnostic*>::iterator DI=Diags.begin(), 352 DE = Diags.end(); DI!=DE; ++DI) { 353 354 o << " <dict>\n" 355 " <key>path</key>\n"; 356 357 const PathDiagnostic *D = *DI; 358 359 o << " <array>\n"; 360 361 for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end(); 362 I != E; ++I) 363 ReportDiag(o, **I, FM, *SM, LangOpts); 364 365 o << " </array>\n"; 366 367 // Output the bug type and bug category. 368 o << " <key>description</key>"; 369 EmitString(o, D->getDescription()) << '\n'; 370 o << " <key>category</key>"; 371 EmitString(o, D->getCategory()) << '\n'; 372 o << " <key>type</key>"; 373 EmitString(o, D->getBugType()) << '\n'; 374 375 // Output the location of the bug. 376 o << " <key>location</key>\n"; 377 EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2); 378 379 // Output the diagnostic to the sub-diagnostic client, if any. 380 if (SubPD) { 381 std::vector<const PathDiagnostic *> SubDiags; 382 SubDiags.push_back(D); 383 SmallVector<std::string, 1> SubFilesMade; 384 SubPD->FlushDiagnosticsImpl(SubDiags, &SubFilesMade); 385 386 if (!SubFilesMade.empty()) { 387 o << " <key>" << SubPD->getName() << "_files</key>\n"; 388 o << " <array>\n"; 389 for (size_t i = 0, n = SubFilesMade.size(); i < n ; ++i) 390 o << " <string>" << SubFilesMade[i] << "</string>\n"; 391 o << " </array>\n"; 392 } 393 } 394 395 // Close up the entry. 396 o << " </dict>\n"; 397 } 398 399 o << " </array>\n"; 400 401 // Finish. 402 o << "</dict>\n</plist>"; 403 404 if (FilesMade) 405 FilesMade->push_back(OutputFile); 406} 407