HTMLRewrite.cpp revision a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2
16a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-// 26a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// 36a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// The LLVM Compiler Infrastructure 46a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// 56a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// This file is distributed under the University of Illinois Open Source 66a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// License. See LICENSE.TXT for details. 76a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// 86a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//===----------------------------------------------------------------------===// 96a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// 106a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// This file defines the HTMLRewriter clas, which is used to translate the 116a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// text of a source file into prettified HTML. 126a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek// 136a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek//===----------------------------------------------------------------------===// 146a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek 156a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "clang/Rewrite/Rewriter.h" 166a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "clang/Rewrite/HTMLRewrite.h" 173245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner#include "clang/Lex/Preprocessor.h" 186a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "clang/Basic/SourceManager.h" 1957df3b950061c73d13d3116f747e79d7955a216aChris Lattner#include "llvm/ADT/SmallString.h" 206a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include "llvm/Support/MemoryBuffer.h" 216a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek#include <sstream> 226a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenekusing namespace clang; 236a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek 24fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenekvoid html::EscapeText(Rewriter& R, unsigned FileID, 25fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek bool EscapeSpaces, bool ReplaceTabs) { 266a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek 276a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); 286a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek const char* C = Buf->getBufferStart(); 296a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek const char* FileEnd = Buf->getBufferEnd(); 306a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek 316a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek assert (C <= FileEnd); 326a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek 33735271479ac57c27f744806859efd5b001dea248Chris Lattner RewriteBuffer &RB = R.getEditBuffer(FileID); 34735271479ac57c27f744806859efd5b001dea248Chris Lattner 356a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) { 3649cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek 376a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek switch (*C) { 38735271479ac57c27f744806859efd5b001dea248Chris Lattner default: break; 39735271479ac57c27f744806859efd5b001dea248Chris Lattner 40735271479ac57c27f744806859efd5b001dea248Chris Lattner case ' ': 41735271479ac57c27f744806859efd5b001dea248Chris Lattner if (EscapeSpaces) 42735271479ac57c27f744806859efd5b001dea248Chris Lattner RB.ReplaceText(FilePos, 1, " ", 6); 43735271479ac57c27f744806859efd5b001dea248Chris Lattner break; 446a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek 45735271479ac57c27f744806859efd5b001dea248Chris Lattner case '\t': 46735271479ac57c27f744806859efd5b001dea248Chris Lattner if (!ReplaceTabs) 4749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek break; 48735271479ac57c27f744806859efd5b001dea248Chris Lattner if (EscapeSpaces) 49735271479ac57c27f744806859efd5b001dea248Chris Lattner RB.ReplaceText(FilePos, 1, " ", 6*4); 50735271479ac57c27f744806859efd5b001dea248Chris Lattner else 51735271479ac57c27f744806859efd5b001dea248Chris Lattner RB.ReplaceText(FilePos, 1, " ", 4); 52735271479ac57c27f744806859efd5b001dea248Chris Lattner break; 53735271479ac57c27f744806859efd5b001dea248Chris Lattner 54735271479ac57c27f744806859efd5b001dea248Chris Lattner case '<': 55735271479ac57c27f744806859efd5b001dea248Chris Lattner RB.ReplaceText(FilePos, 1, "<", 4); 56735271479ac57c27f744806859efd5b001dea248Chris Lattner break; 57735271479ac57c27f744806859efd5b001dea248Chris Lattner 58735271479ac57c27f744806859efd5b001dea248Chris Lattner case '>': 59735271479ac57c27f744806859efd5b001dea248Chris Lattner RB.ReplaceText(FilePos, 1, ">", 4); 60735271479ac57c27f744806859efd5b001dea248Chris Lattner break; 61735271479ac57c27f744806859efd5b001dea248Chris Lattner 62735271479ac57c27f744806859efd5b001dea248Chris Lattner case '&': 63735271479ac57c27f744806859efd5b001dea248Chris Lattner RB.ReplaceText(FilePos, 1, "&", 5); 64735271479ac57c27f744806859efd5b001dea248Chris Lattner break; 656a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek } 666a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek } 676a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek} 686a34083e9f74a45e2f79c9fab66f177809a5db66Ted Kremenek 69fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenekstd::string html::EscapeText(const std::string& s, bool EscapeSpaces, 70fa5be3617294f0e3c341f0ecb6b2076478b1b5acTed Kremenek bool ReplaceTabs) { 71053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek 72053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek unsigned len = s.size(); 73053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek std::ostringstream os; 74053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek 75053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek for (unsigned i = 0 ; i < len; ++i) { 76053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek 77053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek char c = s[i]; 78053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek switch (c) { 798570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner default: 808570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner os << c; break; 818570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner 828570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner case ' ': 838570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner if (EscapeSpaces) os << " "; 848570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner else os << ' '; 858570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner break; 868570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner 878570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner case '\t': 888570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner if (ReplaceTabs) 898570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner for (unsigned i = 0; i < 4; ++i) 908570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner os << " "; 918570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner else 928570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner os << c; 938570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner 94053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek break; 958570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner 968570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner case '<': os << "<"; break; 978570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner case '>': os << ">"; break; 988570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner case '&': os << "&"; break; 99053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek } 100053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek } 101053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek 102053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek return os.str(); 103053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek} 104053ef593fa9d2b890645a914eee203231fb34458Ted Kremenek 1058570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattnerstatic void AddLineNumber(RewriteBuffer &RB, unsigned LineNo, 1068570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner unsigned B, unsigned E) { 10757df3b950061c73d13d3116f747e79d7955a216aChris Lattner llvm::SmallString<100> Str; 10857df3b950061c73d13d3116f747e79d7955a216aChris Lattner Str += "<tr><td class=\"num\" id=\"LN"; 10957df3b950061c73d13d3116f747e79d7955a216aChris Lattner Str.append_uint(LineNo); 11057df3b950061c73d13d3116f747e79d7955a216aChris Lattner Str += "\">"; 11157df3b950061c73d13d3116f747e79d7955a216aChris Lattner Str.append_uint(LineNo); 11257df3b950061c73d13d3116f747e79d7955a216aChris Lattner Str += "</td><td class=\"line\">"; 11357df3b950061c73d13d3116f747e79d7955a216aChris Lattner 11449cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek if (B == E) { // Handle empty lines. 11557df3b950061c73d13d3116f747e79d7955a216aChris Lattner Str += " </td></tr>"; 1168570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner RB.InsertTextBefore(B, &Str[0], Str.size()); 11757df3b950061c73d13d3116f747e79d7955a216aChris Lattner } else { 1188570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner RB.InsertTextBefore(B, &Str[0], Str.size()); 1198570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner RB.InsertTextBefore(E, "</td></tr>", strlen("</td></tr>")); 12049cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek } 121b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek} 122b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 123b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenekvoid html::AddLineNumbers(Rewriter& R, unsigned FileID) { 124b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 125b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); 126b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek const char* FileBeg = Buf->getBufferStart(); 127b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek const char* FileEnd = Buf->getBufferEnd(); 128b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek const char* C = FileBeg; 1298570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner RewriteBuffer &RB = R.getEditBuffer(FileID); 130b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 131b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek assert (C <= FileEnd); 132b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 133b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek unsigned LineNo = 0; 134b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek unsigned FilePos = 0; 135b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 136b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek while (C != FileEnd) { 137b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 138b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek ++LineNo; 139b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek unsigned LineStartPos = FilePos; 140b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek unsigned LineEndPos = FileEnd - FileBeg; 141b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 142b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek assert (FilePos <= LineEndPos); 143b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek assert (C < FileEnd); 144b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 145b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek // Scan until the newline (or end-of-file). 146b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 14749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek while (C != FileEnd) { 14849cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek char c = *C; 14949cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek ++C; 15049cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek 15149cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek if (c == '\n') { 15249cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek LineEndPos = FilePos++; 153b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek break; 154b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek } 15549cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek 15649cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek ++FilePos; 15749cd6354d5373245dd2e69ca7b7113e6a795d36eTed Kremenek } 158b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek 1598570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner AddLineNumber(RB, LineNo, LineStartPos, LineEndPos); 160d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek } 161d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek 1628570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner // Add one big table tag that surrounds all of the code. 1638570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner RB.InsertTextBefore(0, "<table class=\"code\">\n", 1648570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner strlen("<table class=\"code\">\n")); 165d6c1360c2bf234c73572a865f119d0518aca8154Ted Kremenek 1668570f0b0fde7ca812f8d37f52305f3df4dd2ce01Chris Lattner RB.InsertTextAfter(FileEnd - FileBeg, "</table>", strlen("</table>")); 167b485cd1e0a5a1e942d0e682b9b1c4bc9df111528Ted Kremenek} 168ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek 169ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenekvoid html::AddHeaderFooterInternalBuiltinCSS(Rewriter& R, unsigned FileID) { 170ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek 171ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID); 172ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek const char* FileStart = Buf->getBufferStart(); 173ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek const char* FileEnd = Buf->getBufferEnd(); 174ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek 175ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek SourceLocation StartLoc = SourceLocation::getFileLoc(FileID, 0); 176ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek SourceLocation EndLoc = SourceLocation::getFileLoc(FileID, FileEnd-FileStart); 177ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek 178ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek // Generate header 17970bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek R.InsertCStrBefore(StartLoc, 18070bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek "<html>\n<head>\n" 18170bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek "<style type=\"text/css\">\n" 18270bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " body { color:#000000; background-color:#ffffff }\n" 18370bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " body { font-family:Helvetica, sans-serif; font-size:10pt }\n" 1844b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " h1 { font-size:14pt }\n" 18570bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .code { border-spacing:0px; width:100%; }\n" 18670bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .code { font-family: \"Andale Mono\", monospace; font-size:10pt }\n" 18770bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .code { line-height: 1.2em }\n" 188c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner " .comment { color: #A0A0A0 }\n" 189c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner " .keyword { color: #FF00FF }\n" 19074ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner " .directive { color: #FFFF00 }\n" 191c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner " .macro { color: #FF0000; background-color:#FFC0C0 }\n" 19270bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n" 19370bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .num { text-align:right; font-size: smaller }\n" 19470bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .num { color:#444444 }\n" 19570bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n" 19670bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .line { white-space: pre }\n" 19770bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .msg { background-color:#fff8b4; color:#000000 }\n" 19870bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n" 19970bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .msg { -webkit-border-radius:5px }\n" 20070bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .msg { font-family:Helvetica, sans-serif; font-size: smaller }\n" 20170bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .msg { font-weight: bold }\n" 20270bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .msg { float:left }\n" 20370bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .msg { padding:0.5em 1ex 0.5em 1ex }\n" 20470bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .msg { margin-top:10px; margin-bottom:10px }\n" 20570bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .mrange { background-color:#dfddf3 }\n" 20670bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .mrange { border-bottom:1px solid #6F9DBE }\n" 20770bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek " .PathIndex { font-weight: bold }\n" 2084b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " table.simpletable {\n" 2094b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " padding: 5px;\n" 2104b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " font-size:12pt;\n" 2114b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " margin:20px;\n" 2124b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " border-collapse: collapse; border-spacing: 0px;\n" 2134b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " }\n" 2144b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " td.rowname {\n" 2154b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " text-align:right; font-weight:bold; color:#444444;\n" 2164b0f81323b518429203051bbcd4864bbf4b000a9Ted Kremenek " padding-right:2ex; }\n" 21770bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek "</style>\n</head>\n<body>"); 21870bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek 219ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek // Generate footer 220ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek 22170bcba6030a76edf46c4f941ad9a5297a1f98c47Ted Kremenek R.InsertCStrAfter(EndLoc, "</body></html>\n"); 222ad0a203130dc5d1fb7231b88767174511424fa98Ted Kremenek} 2233245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner 2243245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with 2253245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner/// information about keywords, macro expansions etc. This uses the macro 2263245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner/// table state from the end of the file, so it won't be perfectly perfect, 2273245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner/// but it will be reasonably close. 2283245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattnervoid html::SyntaxHighlight(Rewriter &R, unsigned FileID, Preprocessor &PP) { 2293245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner RewriteBuffer &RB = R.getEditBuffer(FileID); 2303245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner 231a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner const SourceManager &SourceMgr = PP.getSourceManager(); 232a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner std::pair<const char*, const char*> File = SourceMgr.getBufferData(FileID); 233a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner const char *BufferStart = File.first; 234a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner 235a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner Lexer L(SourceLocation::getFileLoc(FileID, 0), PP.getLangOptions(), 236a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner File.first, File.second); 237a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner 2383245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner // Inform the preprocessor that we want to retain comments as tokens, so we 2393245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner // can highlight them. 240a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner //PP.SetCommentRetentionState(true, false); 2413245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner 242c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Lex all the tokens in raw mode, to avoid entering #includes or expanding 243c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // macros. 2443245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner Token Tok; 245a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner L.LexRawToken(Tok); 24674ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner 24774ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner while (Tok.isNot(tok::eof)) { 24874ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner // Since we are lexing unexpanded tokens, all tokens are from the main 24974ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner // FileID. 25074ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner unsigned TokOffs = SourceMgr.getFullFilePos(Tok.getLocation()); 2513245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner unsigned TokLen = Tok.getLength(); 2523245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner switch (Tok.getKind()) { 253a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner default: break; 254a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner case tok::identifier: { 255a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner // Fill in Result.IdentifierInfo, looking up the identifier in the 256a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner // identifier table. 257a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner IdentifierInfo *II = PP.LookUpIdentifierInfo(Tok, BufferStart+TokOffs); 258a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner 259a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner // If this is a pp-identifier, for a keyword, highlight it as such. 260a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner if (II->getTokenID() != tok::identifier) { 261c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner RB.InsertTextAfter(TokOffs, "<span class='keyword'>", 262c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner strlen("<span class='keyword'>")); 263c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>")); 264c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner } 265c4586c234edd8df0477a895aebcbc3eb220aed6bChris Lattner break; 266a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner } 2673245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner case tok::comment: 2683245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner RB.InsertTextAfter(TokOffs, "<span class='comment'>", 2693245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner strlen("<span class='comment'>")); 2703245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>")); 2713245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner break; 27274ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner case tok::hash: 27374ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner // FIXME: This isn't working because we're not in raw mode in the lexer. 27474ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner // Just cons up our own lexer here? 27574ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner 27674ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner // If this is a preprocessor directive, all tokens to end of line are too. 27774ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner if (Tok.isAtStartOfLine()) { 27874ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner RB.InsertTextAfter(TokOffs, "<span class='directive'>", 27974ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner strlen("<span class='directive'>")); 28074ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner // Find end of line. This is a hack. 28174ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner const char *LineEnd = SourceMgr.getCharacterData(Tok.getLocation()); 28274ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner unsigned TokEnd = TokOffs+strcspn(LineEnd, "\n\r"); 28374ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner RB.InsertTextBefore(TokEnd, "</span>", strlen("</span>")); 28474ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner } 28574ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner break; 2863245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner } 2873245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner 288a745e8c52839d9c8dd0fd8d5276b4eab182ec7f2Chris Lattner L.LexRawToken(Tok); 28974ea3e5c57c087c046223096a97ea4e365f85eb6Chris Lattner } 2903245a0a1c7a4fd74fca845b2edba275bb126d773Chris Lattner} 291c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 292c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner/// HighlightMacros - This uses the macro table state from the end of the 293c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner/// file, to reexpand macros and insert (into the HTML) information about the 294c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner/// macro expansions. This won't be perfectly perfect, but it will be 295c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner/// reasonably close. 296c54d50a4180520370c12dd7d06d035263d357d56Chris Lattnervoid html::HighlightMacros(Rewriter &R, unsigned FileID, Preprocessor &PP) { 297c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner RewriteBuffer &RB = R.getEditBuffer(FileID); 298c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 299c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Inform the preprocessor that we don't want comments. 300c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner PP.SetCommentRetentionState(false, false); 301c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 302c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Start parsing the specified input file. 303c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner PP.EnterMainSourceFile(); 304c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 305c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Lex all the tokens. 306c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner const SourceManager &SourceMgr = PP.getSourceManager(); 307c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner Token Tok; 308c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner PP.Lex(Tok); 309c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner while (Tok.isNot(tok::eof)) { 310c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Ignore non-macro tokens. 311c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner if (!Tok.getLocation().isMacroID()) { 312c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner PP.Lex(Tok); 313c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner continue; 314c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner } 315c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 316c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Ignore tokens whose logical location was not the main file. 317c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner SourceLocation LLoc = SourceMgr.getLogicalLoc(Tok.getLocation()); 318c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner std::pair<unsigned, unsigned> LLocInfo = 319c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner SourceMgr.getDecomposedFileLoc(LLoc); 320c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 321c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner if (LLocInfo.first != FileID) { 322c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner PP.Lex(Tok); 323c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner continue; 324c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner } 325c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 326c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Okay, we have the first token of a macro expansion: highlight the 327c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // instantiation. 328c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 329c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Get the size of current macro call itself. 330c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // FIXME: This should highlight the args of a function-like 331c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // macro, using a heuristic. 332c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner unsigned TokLen = Lexer::MeasureTokenLength(LLoc, SourceMgr); 333c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 334c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner unsigned TokOffs = LLocInfo.second; 335c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner RB.InsertTextAfter(TokOffs, "<span class='macro'>", 336c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner strlen("<span class='macro'>")); 337c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner RB.InsertTextBefore(TokOffs+TokLen, "</span>", strlen("</span>")); 338c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 339c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Okay, eat this token, getting the next one. 340c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner PP.Lex(Tok); 341c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 342c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // Skip all the rest of the tokens that are part of this macro 343c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // instantiation. It would be really nice to pop up a window with all the 344c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner // spelling of the tokens or something. 345c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner while (!Tok.is(tok::eof) && 346c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner SourceMgr.getLogicalLoc(Tok.getLocation()) == LLoc) 347c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner PP.Lex(Tok); 348c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner } 349c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner} 350c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 351c54d50a4180520370c12dd7d06d035263d357d56Chris Lattner 352