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 ¤tPath, 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 << ")\">←</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 << ")\">→</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