diff options
Diffstat (limited to 'lib/Frontend/PlistDiagnostics.cpp')
-rw-r--r-- | lib/Frontend/PlistDiagnostics.cpp | 471 |
1 files changed, 0 insertions, 471 deletions
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp deleted file mode 100644 index 5706a07..0000000 --- a/lib/Frontend/PlistDiagnostics.cpp +++ /dev/null @@ -1,471 +0,0 @@ -//===--- PlistDiagnostics.cpp - Plist Diagnostics for Paths -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the PlistDiagnostics object. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/PathDiagnosticClients.h" -#include "clang/Checker/BugReporter/PathDiagnostic.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/FileManager.h" -#include "clang/Lex/Preprocessor.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Casting.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallVector.h" -using namespace clang; -using llvm::cast; - -typedef llvm::DenseMap<FileID, unsigned> FIDMap; - -namespace clang { - class Preprocessor; -} - -namespace { -struct CompareDiagnostics { - // Compare if 'X' is "<" than 'Y'. - bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { - // First compare by location - const FullSourceLoc &XLoc = X->getLocation().asLocation(); - const FullSourceLoc &YLoc = Y->getLocation().asLocation(); - if (XLoc < YLoc) - return true; - if (XLoc != YLoc) - return false; - - // Next, compare by bug type. - llvm::StringRef XBugType = X->getBugType(); - llvm::StringRef YBugType = Y->getBugType(); - if (XBugType < YBugType) - return true; - if (XBugType != YBugType) - return false; - - // Next, compare by bug description. - llvm::StringRef XDesc = X->getDescription(); - llvm::StringRef YDesc = Y->getDescription(); - if (XDesc < YDesc) - return true; - if (XDesc != YDesc) - return false; - - // FIXME: Further refine by comparing PathDiagnosticPieces? - return false; - } -}; -} - -namespace { - class PlistDiagnostics : public PathDiagnosticClient { - std::vector<const PathDiagnostic*> BatchedDiags; - const std::string OutputFile; - const LangOptions &LangOpts; - llvm::OwningPtr<PathDiagnosticClient> SubPD; - bool flushed; - public: - PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts, - PathDiagnosticClient *subPD); - - ~PlistDiagnostics() { FlushDiagnostics(NULL); } - - void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade); - - void HandlePathDiagnostic(const PathDiagnostic* D); - - virtual llvm::StringRef getName() const { - return "PlistDiagnostics"; - } - - 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, - PathDiagnosticClient *subPD) - : OutputFile(output), LangOpts(LO), SubPD(subPD), flushed(false) {} - -PathDiagnosticClient* -clang::CreatePlistDiagnosticClient(const std::string& s, const Preprocessor &PP, - PathDiagnosticClient *subPD) { - return new PlistDiagnostics(s, PP.getLangOptions(), subPD); -} - -PathDiagnosticClient::PathGenerationScheme -PlistDiagnostics::getGenerationScheme() const { - if (const PathDiagnosticClient *PD = SubPD.get()) - return PD->getGenerationScheme(); - - return Extensive; -} - -static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V, - const SourceManager* SM, SourceLocation L) { - - FileID FID = SM->getFileID(SM->getInstantiationLoc(L)); - FIDMap::iterator I = FIDs.find(FID); - if (I != FIDs.end()) return; - FIDs[FID] = V.size(); - V.push_back(FID); -} - -static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM, - SourceLocation L) { - FileID FID = SM.getFileID(SM.getInstantiationLoc(L)); - FIDMap::const_iterator I = FIDs.find(FID); - assert(I != FIDs.end()); - return I->second; -} - -static llvm::raw_ostream& Indent(llvm::raw_ostream& o, const unsigned indent) { - for (unsigned i = 0; i < indent; ++i) o << ' '; - return o; -} - -static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM, - const LangOptions &LangOpts, - SourceLocation L, const FIDMap &FM, - unsigned indent, bool extend = false) { - - FullSourceLoc Loc(SM.getInstantiationLoc(L), const_cast<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"; - Indent(o, indent) << " <key>col</key><integer>" - << Loc.getInstantiationColumnNumber() + offset << "</integer>\n"; - Indent(o, indent) << " <key>file</key><integer>" - << GetFID(FM, SM, Loc) << "</integer>\n"; - Indent(o, indent) << "</dict>\n"; -} - -static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM, - const LangOptions &LangOpts, - const PathDiagnosticLocation &L, const FIDMap& FM, - unsigned indent, bool extend = false) { - EmitLocation(o, SM, LangOpts, L.asLocation(), FM, indent, extend); -} - -static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM, - const LangOptions &LangOpts, - 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.getEnd(), FM, indent+1, !R.isPoint); - Indent(o, indent) << "</array>\n"; -} - -static llvm::raw_ostream& EmitString(llvm::raw_ostream& o, - const std::string& s) { - o << "<string>"; - for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) { - char c = *I; - switch (c) { - default: o << c; break; - case '&': o << "&"; break; - case '<': o << "<"; break; - case '>': o << ">"; break; - case '\'': o << "'"; break; - case '\"': o << """; break; - } - } - o << "</string>"; - return o; -} - -static void ReportControlFlow(llvm::raw_ostream& o, - const PathDiagnosticControlFlowPiece& 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>control</string>\n"; - - // Emit edges. - Indent(o, indent) << "<key>edges</key>\n"; - ++indent; - Indent(o, indent) << "<array>\n"; - ++indent; - for (PathDiagnosticControlFlowPiece::const_iterator I=P.begin(), E=P.end(); - I!=E; ++I) { - Indent(o, indent) << "<dict>\n"; - ++indent; - Indent(o, indent) << "<key>start</key>\n"; - EmitRange(o, SM, LangOpts, I->getStart().asRange(), FM, indent+1); - Indent(o, indent) << "<key>end</key>\n"; - EmitRange(o, SM, LangOpts, I->getEnd().asRange(), FM, indent+1); - --indent; - Indent(o, indent) << "</dict>\n"; - } - --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"; -} - -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"; - ++indent; - for (; RI != RE; ++RI) - EmitRange(o, SM, LangOpts, *RI, FM, indent+1); - --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"; - EmitString(o, P.getString()) << '\n'; - - // Finish up. - --indent; - Indent(o, indent); o << "</dict>\n"; -} - -static void ReportMacro(llvm::raw_ostream& o, - const PathDiagnosticMacroPiece& P, - 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; - case PathDiagnosticPiece::Event: - ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts, - indent); - break; - case PathDiagnosticPiece::Macro: - ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts, - indent); - break; - } - } -} - -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, - LangOpts, indent); - break; - case PathDiagnosticPiece::Event: - ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts, - indent); - break; - case PathDiagnosticPiece::Macro: - ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts, - indent); - break; - } -} - -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(); - BatchedDiags.push_back(D); -} - -void PlistDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> - *FilesMade) { - - if (flushed) - return; - - flushed = true; - - // Sort the diagnostics so that they are always emitted in a deterministic - // order. - if (!BatchedDiags.empty()) - std::sort(BatchedDiags.begin(), BatchedDiags.end(), CompareDiagnostics()); - - // 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()) - 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()); - AddFID(FM, Fids, SM, RI->getEnd()); - } - } - } - - // Open the file. - std::string 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" - "<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 - 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. - 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 (SubPD) { - SubPD->HandlePathDiagnostic(OwnedD.take()); - llvm::SmallVector<std::string, 1> SubFilesMade; - SubPD->FlushDiagnostics(SubFilesMade); - - if (!SubFilesMade.empty()) { - o << " <key>" << SubPD->getName() << "_files</key>\n"; - o << " <array>\n"; - for (size_t i = 0, n = SubFilesMade.size(); i < n ; ++i) - o << " <string>" << SubFilesMade[i] << "</string>\n"; - o << " </array>\n"; - } - } - - // Close up the entry. - o << " </dict>\n"; - } - - o << " </array>\n"; - - // Finish. - o << "</dict>\n</plist>"; - - if (FilesMade) - FilesMade->push_back(OutputFile); - - BatchedDiags.clear(); -} |