diff options
Diffstat (limited to 'lib/Frontend/PlistDiagnostics.cpp')
-rw-r--r-- | lib/Frontend/PlistDiagnostics.cpp | 148 |
1 files changed, 92 insertions, 56 deletions
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp index 387ed45a9c710..a83dca0a5ffa9 100644 --- a/lib/Frontend/PlistDiagnostics.cpp +++ b/lib/Frontend/PlistDiagnostics.cpp @@ -37,26 +37,44 @@ namespace { std::vector<const PathDiagnostic*> BatchedDiags; const std::string OutputFile; const LangOptions &LangOpts; + llvm::OwningPtr<PathDiagnosticClientFactory> PF; + llvm::OwningPtr<PathDiagnosticClient> SubPDC; + llvm::SmallVector<std::string, 1> FilesMade; public: - PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts); + PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, + PathDiagnosticClientFactory *pf); ~PlistDiagnostics(); void HandlePathDiagnostic(const PathDiagnostic* D); - - PathGenerationScheme getGenerationScheme() const { return Extensive; } + + PathGenerationScheme getGenerationScheme() const; bool supportsLogicalOpControlFlow() const { return true; } bool supportsAllBlockEdges() const { return true; } virtual bool useVerboseDescription() const { return false; } - }; + }; } // end anonymous namespace PlistDiagnostics::PlistDiagnostics(const std::string& output, - const LangOptions &LO) - : OutputFile(output), LangOpts(LO) {} + const LangOptions &LO, + PathDiagnosticClientFactory *pf) + : OutputFile(output), LangOpts(LO), PF(pf) { + + if (PF) + SubPDC.reset(PF->createPathDiagnosticClient(&FilesMade)); +} PathDiagnosticClient* clang::CreatePlistDiagnosticClient(const std::string& s, - Preprocessor *PP, PreprocessorFactory*) { - return new PlistDiagnostics(s, PP->getLangOptions()); + Preprocessor *PP, PreprocessorFactory*, + PathDiagnosticClientFactory *PF) { + return new PlistDiagnostics(s, PP->getLangOptions(), PF); +} + +PathDiagnosticClient::PathGenerationScheme +PlistDiagnostics::getGenerationScheme() const { + if (const PathDiagnosticClient *PD = SubPDC.get()) + return PD->getGenerationScheme(); + + return Extensive; } static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V, @@ -92,7 +110,7 @@ static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM, // Add in the length of the token, so that we cover multi-char tokens. unsigned offset = extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0; - + Indent(o, indent) << "<dict>\n"; Indent(o, indent) << " <key>line</key><integer>" << Loc.getInstantiationLineNumber() << "</integer>\n"; @@ -115,7 +133,7 @@ static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM, PathDiagnosticRange R, const FIDMap &FM, unsigned indent) { Indent(o, indent) << "<array>\n"; - EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); + EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1); EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, !R.isPoint); Indent(o, indent) << "</array>\n"; } @@ -144,12 +162,12 @@ static void ReportControlFlow(llvm::raw_ostream& o, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent) { - + Indent(o, indent) << "<dict>\n"; ++indent; - + Indent(o, indent) << "<key>kind</key><string>control</string>\n"; - + // Emit edges. Indent(o, indent) << "<key>edges</key>\n"; ++indent; @@ -169,39 +187,39 @@ static void ReportControlFlow(llvm::raw_ostream& o, --indent; Indent(o, indent) << "</array>\n"; --indent; - + // Output any helper text. const std::string& s = P.getString(); if (!s.empty()) { Indent(o, indent) << "<key>alternate</key>"; EmitString(o, s) << '\n'; } - + --indent; - Indent(o, indent) << "</dict>\n"; + Indent(o, indent) << "</dict>\n"; } -static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P, +static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent) { - + Indent(o, indent) << "<dict>\n"; ++indent; Indent(o, indent) << "<key>kind</key><string>event</string>\n"; - + // Output the location. FullSourceLoc L = P.getLocation().asLocation(); - + Indent(o, indent) << "<key>location</key>\n"; EmitLocation(o, SM, LangOpts, L, FM, indent); - + // Output the ranges (if any). PathDiagnosticPiece::range_iterator RI = P.ranges_begin(), RE = P.ranges_end(); - + if (RI != RE) { Indent(o, indent) << "<key>ranges</key>\n"; Indent(o, indent) << "<array>\n"; @@ -211,13 +229,13 @@ static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P, --indent; Indent(o, indent) << "</array>\n"; } - + // Output the text. assert(!P.getString().empty()); Indent(o, indent) << "<key>extended_message</key>\n"; Indent(o, indent); EmitString(o, P.getString()) << '\n'; - + // Output the short text. // FIXME: Really use a short string. Indent(o, indent) << "<key>message</key>\n"; @@ -233,10 +251,10 @@ static void ReportMacro(llvm::raw_ostream& o, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent) { - + for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end(); I!=E; ++I) { - + switch ((*I)->getKind()) { default: break; @@ -248,16 +266,16 @@ static void ReportMacro(llvm::raw_ostream& o, ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts, indent); break; - } - } + } + } } -static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P, +static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts) { unsigned indent = 4; - + switch (P.getKind()) { case PathDiagnosticPiece::ControlFlow: ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM, @@ -277,38 +295,38 @@ static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P, void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) { if (!D) return; - + if (D->empty()) { delete D; return; } - + // We need to flatten the locations (convert Stmt* to locations) because // the referenced statements may be freed by the time the diagnostics // are emitted. - const_cast<PathDiagnostic*>(D)->flattenLocations(); + const_cast<PathDiagnostic*>(D)->flattenLocations(); BatchedDiags.push_back(D); } -PlistDiagnostics::~PlistDiagnostics() { +PlistDiagnostics::~PlistDiagnostics() { // Build up a set of FIDs that we use by scanning the locations and // ranges of the diagnostics. FIDMap FM; llvm::SmallVector<FileID, 10> Fids; const SourceManager* SM = 0; - - if (!BatchedDiags.empty()) + + if (!BatchedDiags.empty()) SM = &(*BatchedDiags.begin())->begin()->getLocation().getManager(); for (std::vector<const PathDiagnostic*>::iterator DI = BatchedDiags.begin(), DE = BatchedDiags.end(); DI != DE; ++DI) { - + const PathDiagnostic *D = *DI; - + for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I!=E; ++I) { AddFID(FM, Fids, SM, I->getLocation().asLocation()); - + for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(), RE=I->ranges_end(); RI!=RE; ++RI) { AddFID(FM, Fids, SM, RI->getBegin()); @@ -319,71 +337,89 @@ PlistDiagnostics::~PlistDiagnostics() { // Open the file. std::string ErrMsg; - llvm::raw_fd_ostream o(OutputFile.c_str(), false, ErrMsg); + llvm::raw_fd_ostream o(OutputFile.c_str(), ErrMsg); if (!ErrMsg.empty()) { llvm::errs() << "warning: could not creat file: " << OutputFile << '\n'; return; } - + // Write the plist header. o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" " - "http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" "<plist version=\"1.0\">\n"; - + // Write the root object: a <dict> containing... // - "files", an <array> mapping from FIDs to file names - // - "diagnostics", an <array> containing the path diagnostics + // - "diagnostics", an <array> containing the path diagnostics o << "<dict>\n" " <key>files</key>\n" " <array>\n"; - + for (llvm::SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); I!=E; ++I) { o << " "; EmitString(o, SM->getFileEntryForID(*I)->getName()) << '\n'; } - + o << " </array>\n" " <key>diagnostics</key>\n" " <array>\n"; - + for (std::vector<const PathDiagnostic*>::iterator DI=BatchedDiags.begin(), DE = BatchedDiags.end(); DI!=DE; ++DI) { - + o << " <dict>\n" " <key>path</key>\n"; - + const PathDiagnostic *D = *DI; // Create an owning smart pointer for 'D' just so that we auto-free it // when we exit this method. llvm::OwningPtr<PathDiagnostic> OwnedD(const_cast<PathDiagnostic*>(D)); o << " <array>\n"; - + for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) ReportDiag(o, *I, FM, *SM, LangOpts); - + o << " </array>\n"; - - // Output the bug type and bug category. + + // Output the bug type and bug category. o << " <key>description</key>"; EmitString(o, D->getDescription()) << '\n'; o << " <key>category</key>"; EmitString(o, D->getCategory()) << '\n'; o << " <key>type</key>"; EmitString(o, D->getBugType()) << '\n'; - + // Output the location of the bug. o << " <key>location</key>\n"; EmitLocation(o, *SM, LangOpts, D->getLocation(), FM, 2); - + + // Output the diagnostic to the sub-diagnostic client, if any. + if (PF) { + if (!SubPDC.get()) + SubPDC.reset(PF->createPathDiagnosticClient(&FilesMade)); + + FilesMade.clear(); + SubPDC->HandlePathDiagnostic(OwnedD.take()); + SubPDC.reset(0); + + if (!FilesMade.empty()) { + o << " <key>" << PF->getName() << "_files</key>\n"; + o << " <array>\n"; + for (size_t i = 0, n = FilesMade.size(); i < n ; ++i) + o << " <string>" << FilesMade[i] << "</string>\n"; + o << " </array>\n"; + } + } + // Close up the entry. o << " </dict>\n"; } o << " </array>\n"; - + // Finish. o << "</dict>\n</plist>"; } |