HTMLDiagnostics.cpp revision b23b711ad3dfb96dc9c457bd55c6e959bd1e0b8a
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- C++ -*-===//
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                     The LLVM Compiler Infrastructure
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// License. See LICENSE.TXT for details.
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===//
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//  This file defines the HTMLDiagnostics object.
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (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"
168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "clang/AST/ASTContext.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/AST/Decl.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Basic/SourceManager.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "clang/Basic/FileManager.h"
208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "clang/Rewrite/Rewriter.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "clang/Rewrite/HTMLRewrite.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Lex/Lexer.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "clang/Lex/Preprocessor.h"
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "llvm/Support/FileSystem.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/MemoryBuffer.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/raw_ostream.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/Path.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace ento;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)//===----------------------------------------------------------------------===//
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Boilerplate.
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)//===----------------------------------------------------------------------===//
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class HTMLDiagnostics : public PathDiagnosticConsumer {
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  llvm::sys::Path Directory, FilePrefix;
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool createdDir, noDir;
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const Preprocessor &PP;
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)public:
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp);
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); }
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                    SmallVectorImpl<std::string> *FilesMade);
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual StringRef getName() const {
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return "HTMLDiagnostics";
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  unsigned ProcessMacroPiece(raw_ostream &os,
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             const PathDiagnosticMacroPiece& P,
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                             unsigned num);
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void HandlePiece(Rewriter& R, FileID BugFileID,
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                   const PathDiagnosticPiece& P, unsigned num, unsigned max);
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range,
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                      const char *HighlightStart = "<span class=\"mrange\">",
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                      const char *HighlightEnd = "</span>");
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  void ReportDiag(const PathDiagnostic& D,
664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                  SmallVectorImpl<std::string> *FilesMade);
674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} // end anonymous namespace
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 const Preprocessor &pp)
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    PP(pp) {
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // All html files begin with "report"
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  FilePrefix.appendComponent("report");
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)PathDiagnosticConsumer*
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ento::createHTMLDiagnosticConsumer(const std::string& prefix,
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 const Preprocessor &PP) {
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return new HTMLDiagnostics(prefix, PP);
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//===----------------------------------------------------------------------===//
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Report processing.
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//===----------------------------------------------------------------------===//
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HTMLDiagnostics::FlushDiagnosticsImpl(
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<const PathDiagnostic *> &Diags,
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SmallVectorImpl<std::string> *FilesMade) {
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       et = Diags.end(); it != et; ++it) {
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ReportDiag(**it, FilesMade);
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static void flattenPath(PathPieces &primaryPath, PathPieces &currentPath,
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        const PathPieces &oldPath) {
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (PathPieces::const_iterator it = oldPath.begin(), et = oldPath.end();
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != et; ++it ) {
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PathDiagnosticPiece *piece = it->getPtr();
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (const PathDiagnosticCallPiece *call =
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dyn_cast<PathDiagnosticCallPiece>(piece)) {
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        call->getCallEnterEvent();
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (callEnter)
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        currentPath.push_back(callEnter);
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      flattenPath(primaryPath, primaryPath, call->path);
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        call->getCallExitEvent();
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (callExit)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        currentPath.push_back(callExit);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (PathDiagnosticMacroPiece *macro =
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dyn_cast<PathDiagnosticMacroPiece>(piece)) {
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      currentPath.push_back(piece);
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PathPieces newPath;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      flattenPath(primaryPath, newPath, macro->subPieces);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      macro->subPieces = newPath;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    currentPath.push_back(piece);
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 SmallVectorImpl<std::string> *FilesMade) {
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create the HTML directory if it is missing.
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!createdDir) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    createdDir = true;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string ErrorMsg;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Directory.createDirectoryOnDisk(true, &ErrorMsg);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool IsDirectory;
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (llvm::sys::fs::is_directory(Directory.str(), IsDirectory) ||
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        !IsDirectory) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      llvm::errs() << "warning: could not create directory '"
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   << Directory.str() << "'\n"
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << "reason: " << ErrorMsg << '\n';
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      noDir = true;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      return;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (noDir)
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // First flatten out the entire path to make it easier to use.
1558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  PathPieces path;
1568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  flattenPath(path, path, D.path);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The path as already been prechecked that all parts of the path are
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from the same file and that it is non-empty.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const SourceManager &SMgr = (*path.begin())->getLocation().getManager();
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  assert(!path.empty());
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  FileID FID =
1634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    (*path.begin())->getLocation().asLocation().getExpansionLoc().getFileID();
1644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  assert(!FID.isInvalid());
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Create a new rewriter to generate HTML.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Process the path.
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  unsigned n = path.size();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned max = n;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (PathPieces::const_reverse_iterator I = path.rbegin(),
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       E = path.rend();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        I != E; ++I, --n)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HandlePiece(R, FID, **I, n, max);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add line numbers, header, footer, etc.
179d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
180d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // unsigned FID = R.getSourceMgr().getMainFileID();
181d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  html::EscapeText(R, FID);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  html::AddLineNumbers(R, FID);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we have a preprocessor, relex the file and syntax highlight.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We might not have a preprocessor if we come from a deserialized AST file,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for example.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
188d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  html::SyntaxHighlight(R, FID, PP);
189d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  html::HighlightMacros(R, FID, PP);
190d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the full directory name of the analyzed file.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const FileEntry* Entry = SMgr.getFileEntryForID(FID);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is a cludge; basically we want to append either the full
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // working directory if we have no directory information.  This is
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // a work in progress.
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string DirName = "";
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (llvm::sys::path::is_relative(Entry->getName())) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DirName = P.str() + "/";
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add the name of the file as an <h1> tag.
20768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    std::string s;
21068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    llvm::raw_string_ostream os(s);
21168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    os << "<!-- REPORTHEADER -->\n"
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "<tr><td class=\"rowname\">File:</td><td>"
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << html::EscapeText(DirName)
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      << html::EscapeText(Entry->getName())
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         "<a href=\"#EndPath\">line "
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber()
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << ", column "
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber()
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      << "</a></td></tr>\n"
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         "<tr><td class=\"rowname\">Description:</td><td>"
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      << D.getDescription() << "</td></tr>\n";
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Output any other meta data.
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         I!=E; ++I) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n"
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          "<h3>Annotated Source Code</h3>\n";
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Embed meta-data tags.
2407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  {
241d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    std::string s;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    llvm::raw_string_ostream os(s);
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& BugDesc = D.getDescription();
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!BugDesc.empty())
246d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& BugType = D.getBugType();
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!BugType.empty())
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os << "\n<!-- BUGTYPE " << BugType << " -->\n";
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& BugCategory = D.getCategory();
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!BugCategory.empty())
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "\n<!-- BUGLINE "
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       << path.back()->getLocation().asLocation().getExpansionLineNumber()
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       << " -->\n";
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n";
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Mark the end of the tags.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "\n<!-- BUGMETAEND -->\n";
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Insert the text.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add CSS, header, and footer.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Get the rewrite buffer.
276d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const RewriteBuffer *Buf = R.getRewriteBufferFor(FID);
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Buf) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    llvm::errs() << "warning: no diagnostics generated for main file.\n";
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a path for the target HTML file.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  llvm::sys::Path F(FilePrefix);
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  F.makeUnique(false, NULL);
286d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
287d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Rename the file with an HTML extension.
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  llvm::sys::Path H(F);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  H.appendSuffix("html");
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  F.renamePathOnDisk(H, NULL);
291d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
292d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string ErrorMsg;
293d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  llvm::raw_fd_ostream os(H.c_str(), ErrorMsg);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ErrorMsg.empty()) {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    llvm::errs() << "warning: could not create file '" << F.str()
297d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 << "'\n";
298d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FilesMade)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilesMade->push_back(llvm::sys::path::filename(H.str()));
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Emit the HTML to disk.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      os << *I;
3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const PathDiagnosticPiece& P,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  unsigned num, unsigned max) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For now, just draw a box above the line in question, and emit the
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // warning.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FullSourceLoc Pos = P.getLocation().asLocation();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!Pos.isValid())
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SourceManager &SM = R.getSourceMgr();
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  assert(&Pos.getManager() == &SM && "SourceManagers are different!");
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedExpansionLoc(Pos);
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (LPosInfo.first != BugFileID)
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first);
328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const char* FileStart = Buf->getBufferStart();
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Compute the column number.  Rewind from the current position to the start
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // of the line.
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second);
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char *TokInstantiationPtr =Pos.getExpansionLoc().getCharacterData();
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char *LineStart = TokInstantiationPtr-ColNo;
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Compute LineEnd.
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char *LineEnd = TokInstantiationPtr;
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const char* FileEnd = Buf->getBufferEnd();
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (*LineEnd != '\n' && LineEnd != FileEnd)
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ++LineEnd;
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Compute the margin offset by counting tabs and non-tabs.
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  unsigned PosNo = 0;
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (const char* c = LineStart; c != TokInstantiationPtr; ++c)
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    PosNo += *c == '\t' ? 8 : 1;
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Create the html for the message.
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *Kind = 0;
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (P.getKind()) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case PathDiagnosticPiece::Call:
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      llvm_unreachable("Calls should already be handled");
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case PathDiagnosticPiece::Event:  Kind = "Event"; break;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Setting Kind to "Control" is intentional.
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  case PathDiagnosticPiece::Macro: Kind = "Control"; break;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string sbuf;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  llvm::raw_string_ostream os(sbuf);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\"";
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (num == max)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "EndPath";
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "Path" << num;
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  os << "\" class=\"msg";
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (Kind)
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << " msg" << Kind;
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  os << "\" style=\"margin-left:" << PosNo << "ex";
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Output a maximum size.
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!isa<PathDiagnosticMacroPiece>(P)) {
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the string and determining its maximum substring.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& Msg = P.getString();
378d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    unsigned max_token = 0;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned cnt = 0;
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    unsigned len = Msg.size();
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      switch (*I) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ++cnt;
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        continue;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case ' ':
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case '\t':
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      case '\n':
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (cnt > max_token) max_token = cnt;
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        cnt = 0;
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (cnt > max_token)
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      max_token = cnt;
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Determine the approximate size of the message bubble in em.
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    unsigned em;
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const unsigned max_line = 120;
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (max_token >= max_line)
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      em = max_token / 2;
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    else {
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      unsigned characters = max_line;
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      unsigned lines = len / max_line;
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (lines > 0) {
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for (; characters > max_token; --characters)
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if (len / characters > lines) {
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            ++characters;
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            break;
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          }
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      em = characters / 2;
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (em < max_line/2)
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      os << "; max-width:" << em << "em";
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
422d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    os << "; max-width:100em";
423d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
424d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  os << "\">";
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (max > 1) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "<table class=\"msgT\"><tr><td valign=\"top\">";
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os << "<div class=\"PathIndex";
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (Kind) os << " PathIndex" << Kind;
430    os << "\">" << num << "</div>";
431
432    if (num > 1) {
433      os << "</td><td><div class=\"PathNav\"><a href=\"#Path"
434         << (num - 1)
435         << "\" title=\"Previous event ("
436         << (num - 1)
437         << ")\">&#x2190;</a></div></td>";
438    }
439
440    os << "</td><td>";
441  }
442
443  if (const PathDiagnosticMacroPiece *MP =
444        dyn_cast<PathDiagnosticMacroPiece>(&P)) {
445
446    os << "Within the expansion of the macro '";
447
448    // Get the name of the macro by relexing it.
449    {
450      FullSourceLoc L = MP->getLocation().asLocation().getExpansionLoc();
451      assert(L.isFileID());
452      StringRef BufferInfo = L.getBufferData();
453      std::pair<FileID, unsigned> LocInfo = L.getDecomposedLoc();
454      const char* MacroName = LocInfo.second + BufferInfo.data();
455      Lexer rawLexer(SM.getLocForStartOfFile(LocInfo.first), PP.getLangOpts(),
456                     BufferInfo.begin(), MacroName, BufferInfo.end());
457
458      Token TheTok;
459      rawLexer.LexFromRawLexer(TheTok);
460      for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i)
461        os << MacroName[i];
462    }
463
464    os << "':\n";
465
466    if (max > 1)
467      os << "</td></tr></table>";
468
469    // Within a macro piece.  Write out each event.
470    ProcessMacroPiece(os, *MP, 0);
471  }
472  else {
473    os << html::EscapeText(P.getString());
474
475    if (max > 1) {
476      os << "</td>";
477      if (num < max) {
478        os << "<td><div class=\"PathNav\"><a href=\"#";
479        if (num == max - 1)
480          os << "EndPath";
481        else
482          os << "Path" << (num + 1);
483        os << "\" title=\"Next event ("
484           << (num + 1)
485           << ")\">&#x2192;</a></div></td>";
486      }
487
488      os << "</tr></table>";
489    }
490  }
491
492  os << "</div></td></tr>";
493
494  // Insert the new html.
495  unsigned DisplayPos = LineEnd - FileStart;
496  SourceLocation Loc =
497    SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos);
498
499  R.InsertTextBefore(Loc, os.str());
500
501  // Now highlight the ranges.
502  for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
503        I != E; ++I)
504    HighlightRange(R, LPosInfo.first, *I);
505
506#if 0
507  // If there is a code insertion hint, insert that code.
508  // FIXME: This code is disabled because it seems to mangle the HTML
509  // output. I'm leaving it here because it's generally the right idea,
510  // but needs some help from someone more familiar with the rewriter.
511  for (const FixItHint *Hint = P.fixit_begin(), *HintEnd = P.fixit_end();
512       Hint != HintEnd; ++Hint) {
513    if (Hint->RemoveRange.isValid()) {
514      HighlightRange(R, LPosInfo.first, Hint->RemoveRange,
515                     "<span class=\"CodeRemovalHint\">", "</span>");
516    }
517    if (Hint->InsertionLoc.isValid()) {
518      std::string EscapedCode = html::EscapeText(Hint->CodeToInsert, true);
519      EscapedCode = "<span class=\"CodeInsertionHint\">" + EscapedCode
520        + "</span>";
521      R.InsertTextBefore(Hint->InsertionLoc, EscapedCode);
522    }
523  }
524#endif
525}
526
527static void EmitAlphaCounter(raw_ostream &os, unsigned n) {
528  unsigned x = n % ('z' - 'a');
529  n /= 'z' - 'a';
530
531  if (n > 0)
532    EmitAlphaCounter(os, n);
533
534  os << char('a' + x);
535}
536
537unsigned HTMLDiagnostics::ProcessMacroPiece(raw_ostream &os,
538                                            const PathDiagnosticMacroPiece& P,
539                                            unsigned num) {
540
541  for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end();
542        I!=E; ++I) {
543
544    if (const PathDiagnosticMacroPiece *MP =
545          dyn_cast<PathDiagnosticMacroPiece>(*I)) {
546      num = ProcessMacroPiece(os, *MP, num);
547      continue;
548    }
549
550    if (PathDiagnosticEventPiece *EP = dyn_cast<PathDiagnosticEventPiece>(*I)) {
551      os << "<div class=\"msg msgEvent\" style=\"width:94%; "
552            "margin-left:5px\">"
553            "<table class=\"msgT\"><tr>"
554            "<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">";
555      EmitAlphaCounter(os, num++);
556      os << "</div></td><td valign=\"top\">"
557         << html::EscapeText(EP->getString())
558         << "</td></tr></table></div>\n";
559    }
560  }
561
562  return num;
563}
564
565void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
566                                     SourceRange Range,
567                                     const char *HighlightStart,
568                                     const char *HighlightEnd) {
569  SourceManager &SM = R.getSourceMgr();
570  const LangOptions &LangOpts = R.getLangOpts();
571
572  SourceLocation InstantiationStart = SM.getExpansionLoc(Range.getBegin());
573  unsigned StartLineNo = SM.getExpansionLineNumber(InstantiationStart);
574
575  SourceLocation InstantiationEnd = SM.getExpansionLoc(Range.getEnd());
576  unsigned EndLineNo = SM.getExpansionLineNumber(InstantiationEnd);
577
578  if (EndLineNo < StartLineNo)
579    return;
580
581  if (SM.getFileID(InstantiationStart) != BugFileID ||
582      SM.getFileID(InstantiationEnd) != BugFileID)
583    return;
584
585  // Compute the column number of the end.
586  unsigned EndColNo = SM.getExpansionColumnNumber(InstantiationEnd);
587  unsigned OldEndColNo = EndColNo;
588
589  if (EndColNo) {
590    // Add in the length of the token, so that we cover multi-char tokens.
591    EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1;
592  }
593
594  // Highlight the range.  Make the span tag the outermost tag for the
595  // selected range.
596
597  SourceLocation E =
598    InstantiationEnd.getLocWithOffset(EndColNo - OldEndColNo);
599
600  html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd);
601}
602