[cfe-commits] r58647 - in /cfe/trunk: include/clang/Driver/PathDiagnosticClients.h lib/Driver/PlistDiagnostics.cpp
Ted Kremenek
kremenek at apple.com
Mon Nov 3 14:33:58 PST 2008
Author: kremenek
Date: Mon Nov 3 16:33:57 2008
New Revision: 58647
URL: http://llvm.org/viewvc/llvm-project?rev=58647&view=rev
Log:
Add path diagnostics client for emitting path reports using Plists.
Added:
cfe/trunk/lib/Driver/PlistDiagnostics.cpp
Modified:
cfe/trunk/include/clang/Driver/PathDiagnosticClients.h
Modified: cfe/trunk/include/clang/Driver/PathDiagnosticClients.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/PathDiagnosticClients.h?rev=58647&r1=58646&r2=58647&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/PathDiagnosticClients.h (original)
+++ cfe/trunk/include/clang/Driver/PathDiagnosticClients.h Mon Nov 3 16:33:57 2008
@@ -1,4 +1,4 @@
-//===--- HTMLPathDiagnostic.h - HTML Diagnostics for Paths ------*- C++ -*-===//
+//===--- PathDiagnosticClients.h - Path Diagnostic Clients ------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,12 +7,12 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines the interface to create a HTMLPathDiagnostic object.
+// This file defines the interface to create different path diagostic clients.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_PATH_HTML_DIAGNOSTIC_H
-#define LLVM_CLANG_PATH_HTML_DIAGNOSTIC_H
+#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_CLIENTS_H
+#define LLVM_CLANG_PATH_DIAGNOSTIC_CLiENTS_H
#include <string>
@@ -22,10 +22,11 @@
class Preprocessor;
class PreprocessorFactory;
-
PathDiagnosticClient* CreateHTMLDiagnosticClient(const std::string& prefix,
Preprocessor* PP,
PreprocessorFactory* PPF);
+
+PathDiagnosticClient* CreatePlistDiagnosticClient(const std::string& prefix);
}
#endif
Added: cfe/trunk/lib/Driver/PlistDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/PlistDiagnostics.cpp?rev=58647&view=auto
==============================================================================
--- cfe/trunk/lib/Driver/PlistDiagnostics.cpp (added)
+++ cfe/trunk/lib/Driver/PlistDiagnostics.cpp Mon Nov 3 16:33:57 2008
@@ -0,0 +1,230 @@
+//===--- 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/Driver/PathDiagnosticClients.h"
+#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+
+using namespace clang;
+typedef llvm::DenseMap<unsigned,unsigned> FIDMap;
+
+namespace {
+ class VISIBILITY_HIDDEN PlistDiagnostics : public PathDiagnosticClient {
+ llvm::sys::Path Directory, FilePrefix;
+ bool createdDir, noDir;
+ public:
+ PlistDiagnostics(const std::string& prefix);
+ ~PlistDiagnostics() {}
+ void HandlePathDiagnostic(const PathDiagnostic* D);
+ };
+} // end anonymous namespace
+
+PlistDiagnostics::PlistDiagnostics(const std::string& prefix)
+ : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false) {
+ FilePrefix.appendComponent("report"); // All Plist files begin with "report"
+}
+
+PathDiagnosticClient* clang::CreatePlistDiagnosticClient(const std::string& s) {
+ return new PlistDiagnostics(s);
+}
+
+static void AddFID(FIDMap& FIDs,
+ llvm::SmallVectorImpl<unsigned>& V,
+ SourceManager& SM, SourceLocation L) {
+
+ unsigned fid = SM.getCanonicalFileID(SM.getLogicalLoc(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,
+ SourceManager& SM, SourceLocation L) {
+
+ unsigned fid = SM.getCanonicalFileID(SM.getLogicalLoc(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, SourceManager& SM,
+ SourceLocation L, const FIDMap& FM,
+ const unsigned indent) {
+
+ Indent(o, indent) << "<dict>\n";
+ Indent(o, indent) << " <key>line</key><integer>"
+ << SM.getLogicalLineNumber(L) << "</integer>\n";
+ Indent(o, indent) << " <key>col</key><integer>"
+ << SM.getLogicalColumnNumber(L) << "</integer>\n";
+ Indent(o, indent) << " <key>file</key><integer>"
+ << GetFID(FM, SM, L) << "</integer>\n";
+ Indent(o, indent) << "</dict>\n";
+}
+
+static void EmitRange(llvm::raw_ostream& o, SourceManager& SM, SourceRange R,
+ const FIDMap& FM, const unsigned indent) {
+
+ Indent(o, indent) << "<array>\n";
+ EmitLocation(o, SM, R.getBegin(), FM, indent+1);
+ EmitLocation(o, SM, R.getEnd(), FM, indent+1);
+ Indent(o, indent) << "</array>\n";
+}
+
+static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
+ const FIDMap& FM, SourceManager& SM) {
+
+ unsigned indent = 2;
+ Indent(o, indent) << "<dict>\n";
+ ++indent;
+
+ // Output the location.
+ FullSourceLoc L = P.getLocation();
+
+ Indent(o, indent) << "<key>location</key>\n";
+ EmitLocation(o, SM, L.getLocation(), 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";
+ for ( ; RI != RE; ++RI ) EmitRange(o, SM, *RI, FM, indent+1);
+ Indent(o, indent) << "</array>\n";
+ }
+
+ // Output the text.
+ Indent(o, indent) << "<key>message</key>\n";
+ Indent(o, indent) << "<string>" << P.getString() << "</string>";
+
+ // Output the hint.
+ Indent(o, indent) << "<key>displayhint</key>\n";
+ Indent(o, indent) << "<string>"
+ << (P.getDisplayHint() == PathDiagnosticPiece::Above
+ ? "above" : "below")
+ << "</string>\n";
+
+
+ // Finish up.
+ --indent;
+ Indent(o, indent); o << "</dict>\n";
+}
+
+void PlistDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
+
+ // 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));
+
+ // Create the directory to contain the plist files if it is missing.
+ if (!createdDir) {
+ createdDir = true;
+ std::string ErrorMsg;
+ Directory.createDirectoryOnDisk(true, &ErrorMsg);
+
+ if (!Directory.isDirectory()) {
+ llvm::errs() << "warning: could not create directory '"
+ << Directory.toString() << "'\n"
+ << "reason: " << ErrorMsg << '\n';
+
+ noDir = true;
+
+ return;
+ }
+ }
+
+ if (noDir)
+ return;
+
+ // Get the source manager.
+ SourceManager& SM = D->begin()->getLocation().getManager();
+
+ // Build up a set of FIDs that we use by scanning the locations and
+ // ranges of the diagnostics.
+ FIDMap FM;
+ llvm::SmallVector<unsigned, 10> Fids;
+
+ for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I) {
+ AddFID(FM, Fids, SM, I->getLocation().getLocation());
+
+ 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());
+ }
+ }
+
+ // Create a path for the target Plist file.
+ llvm::sys::Path F(FilePrefix);
+ F.makeUnique(false, NULL);
+
+ // Rename the file with an Plist extension.
+ llvm::sys::Path H(F);
+ H.appendSuffix("plist");
+ F.renamePathOnDisk(H, NULL);
+
+ // Now create the plist file.
+ std::string ErrMsg;
+ llvm::raw_fd_ostream o(H.toString().c_str(), ErrMsg);
+
+ if (!ErrMsg.empty()) {
+ llvm::errs() << "warning: could not creat file: " << H.toString() << '\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<unsigned>::iterator I=Fids.begin(), E=Fids.end();
+ I!=E; ++I)
+ o << " <string>" << SM.getFileEntryForID(*I)->getName() << "</string>\n";
+
+ o << " </array>\n"
+ " <key>diagnostics</key>\n"
+ " <array>\n";
+
+ for (PathDiagnostic::const_iterator I=D->begin(), E=D->end(); I != E; ++I)
+ ReportDiag(o, *I, FM, SM);
+
+ o << " </array>\n";
+
+ // Output the bug type and bug category.
+ o << " <key>description</key><string>" << D->getDescription() << "</string>\n"
+ " <key>category</key><string>" << D->getCategory() << "</string>\n";
+
+ // Finish.
+ o << "</dict>\n";
+}
More information about the cfe-commits
mailing list