clang  5.0.0
HTMLRewrite.cpp
Go to the documentation of this file.
1 //== HTMLRewrite.cpp - Translate source code into prettified HTML --*- C++ -*-//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the HTMLRewriter class, which is used to translate the
11 // text of a source file into prettified HTML.
12 //
13 //===----------------------------------------------------------------------===//
14 
17 #include "clang/Lex/Preprocessor.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <memory>
25 using namespace clang;
26 
27 
28 /// HighlightRange - Highlight a range in the source code with the specified
29 /// start/end tags. B/E must be in the same file. This ensures that
30 /// start/end tags are placed at the start/end of each line if the range is
31 /// multiline.
33  const char *StartTag, const char *EndTag) {
35  B = SM.getExpansionLoc(B);
36  E = SM.getExpansionLoc(E);
37  FileID FID = SM.getFileID(B);
38  assert(SM.getFileID(E) == FID && "B/E not in the same file!");
39 
40  unsigned BOffset = SM.getFileOffset(B);
41  unsigned EOffset = SM.getFileOffset(E);
42 
43  // Include the whole end token in the range.
44  EOffset += Lexer::MeasureTokenLength(E, R.getSourceMgr(), R.getLangOpts());
45 
46  bool Invalid = false;
47  const char *BufferStart = SM.getBufferData(FID, &Invalid).data();
48  if (Invalid)
49  return;
50 
51  HighlightRange(R.getEditBuffer(FID), BOffset, EOffset,
52  BufferStart, StartTag, EndTag);
53 }
54 
55 /// HighlightRange - This is the same as the above method, but takes
56 /// decomposed file locations.
57 void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E,
58  const char *BufferStart,
59  const char *StartTag, const char *EndTag) {
60  // Insert the tag at the absolute start/end of the range.
61  RB.InsertTextAfter(B, StartTag);
62  RB.InsertTextBefore(E, EndTag);
63 
64  // Scan the range to see if there is a \r or \n. If so, and if the line is
65  // not blank, insert tags on that line as well.
66  bool HadOpenTag = true;
67 
68  unsigned LastNonWhiteSpace = B;
69  for (unsigned i = B; i != E; ++i) {
70  switch (BufferStart[i]) {
71  case '\r':
72  case '\n':
73  // Okay, we found a newline in the range. If we have an open tag, we need
74  // to insert a close tag at the first non-whitespace before the newline.
75  if (HadOpenTag)
76  RB.InsertTextBefore(LastNonWhiteSpace+1, EndTag);
77 
78  // Instead of inserting an open tag immediately after the newline, we
79  // wait until we see a non-whitespace character. This prevents us from
80  // inserting tags around blank lines, and also allows the open tag to
81  // be put *after* whitespace on a non-blank line.
82  HadOpenTag = false;
83  break;
84  case '\0':
85  case ' ':
86  case '\t':
87  case '\f':
88  case '\v':
89  // Ignore whitespace.
90  break;
91 
92  default:
93  // If there is no tag open, do it now.
94  if (!HadOpenTag) {
95  RB.InsertTextAfter(i, StartTag);
96  HadOpenTag = true;
97  }
98 
99  // Remember this character.
100  LastNonWhiteSpace = i;
101  break;
102  }
103  }
104 }
105 
107  bool EscapeSpaces, bool ReplaceTabs) {
108 
109  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID);
110  const char* C = Buf->getBufferStart();
111  const char* FileEnd = Buf->getBufferEnd();
112 
113  assert (C <= FileEnd);
114 
115  RewriteBuffer &RB = R.getEditBuffer(FID);
116 
117  unsigned ColNo = 0;
118  for (unsigned FilePos = 0; C != FileEnd ; ++C, ++FilePos) {
119  switch (*C) {
120  default: ++ColNo; break;
121  case '\n':
122  case '\r':
123  ColNo = 0;
124  break;
125 
126  case ' ':
127  if (EscapeSpaces)
128  RB.ReplaceText(FilePos, 1, "&nbsp;");
129  ++ColNo;
130  break;
131  case '\f':
132  RB.ReplaceText(FilePos, 1, "<hr>");
133  ColNo = 0;
134  break;
135 
136  case '\t': {
137  if (!ReplaceTabs)
138  break;
139  unsigned NumSpaces = 8-(ColNo&7);
140  if (EscapeSpaces)
141  RB.ReplaceText(FilePos, 1,
142  StringRef("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
143  "&nbsp;&nbsp;&nbsp;", 6*NumSpaces));
144  else
145  RB.ReplaceText(FilePos, 1, StringRef(" ", NumSpaces));
146  ColNo += NumSpaces;
147  break;
148  }
149  case '<':
150  RB.ReplaceText(FilePos, 1, "&lt;");
151  ++ColNo;
152  break;
153 
154  case '>':
155  RB.ReplaceText(FilePos, 1, "&gt;");
156  ++ColNo;
157  break;
158 
159  case '&':
160  RB.ReplaceText(FilePos, 1, "&amp;");
161  ++ColNo;
162  break;
163  }
164  }
165 }
166 
167 std::string html::EscapeText(StringRef s, bool EscapeSpaces, bool ReplaceTabs) {
168 
169  unsigned len = s.size();
170  std::string Str;
171  llvm::raw_string_ostream os(Str);
172 
173  for (unsigned i = 0 ; i < len; ++i) {
174 
175  char c = s[i];
176  switch (c) {
177  default:
178  os << c; break;
179 
180  case ' ':
181  if (EscapeSpaces) os << "&nbsp;";
182  else os << ' ';
183  break;
184 
185  case '\t':
186  if (ReplaceTabs) {
187  if (EscapeSpaces)
188  for (unsigned i = 0; i < 4; ++i)
189  os << "&nbsp;";
190  else
191  for (unsigned i = 0; i < 4; ++i)
192  os << " ";
193  }
194  else
195  os << c;
196 
197  break;
198 
199  case '<': os << "&lt;"; break;
200  case '>': os << "&gt;"; break;
201  case '&': os << "&amp;"; break;
202  }
203  }
204 
205  return os.str();
206 }
207 
208 static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo,
209  unsigned B, unsigned E) {
210  SmallString<256> Str;
211  llvm::raw_svector_ostream OS(Str);
212 
213  OS << "<tr><td class=\"num\" id=\"LN"
214  << LineNo << "\">"
215  << LineNo << "</td><td class=\"line\">";
216 
217  if (B == E) { // Handle empty lines.
218  OS << " </td></tr>";
219  RB.InsertTextBefore(B, OS.str());
220  } else {
221  RB.InsertTextBefore(B, OS.str());
222  RB.InsertTextBefore(E, "</td></tr>");
223  }
224 }
225 
227 
228  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID);
229  const char* FileBeg = Buf->getBufferStart();
230  const char* FileEnd = Buf->getBufferEnd();
231  const char* C = FileBeg;
232  RewriteBuffer &RB = R.getEditBuffer(FID);
233 
234  assert (C <= FileEnd);
235 
236  unsigned LineNo = 0;
237  unsigned FilePos = 0;
238 
239  while (C != FileEnd) {
240 
241  ++LineNo;
242  unsigned LineStartPos = FilePos;
243  unsigned LineEndPos = FileEnd - FileBeg;
244 
245  assert (FilePos <= LineEndPos);
246  assert (C < FileEnd);
247 
248  // Scan until the newline (or end-of-file).
249 
250  while (C != FileEnd) {
251  char c = *C;
252  ++C;
253 
254  if (c == '\n') {
255  LineEndPos = FilePos++;
256  break;
257  }
258 
259  ++FilePos;
260  }
261 
262  AddLineNumber(RB, LineNo, LineStartPos, LineEndPos);
263  }
264 
265  // Add one big table tag that surrounds all of the code.
266  RB.InsertTextBefore(0, "<table class=\"code\">\n");
267  RB.InsertTextAfter(FileEnd - FileBeg, "</table>");
268 }
269 
271  StringRef title) {
272 
273  const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FID);
274  const char* FileStart = Buf->getBufferStart();
275  const char* FileEnd = Buf->getBufferEnd();
276 
278  SourceLocation EndLoc = StartLoc.getLocWithOffset(FileEnd-FileStart);
279 
280  std::string s;
281  llvm::raw_string_ostream os(s);
282  os << "<!doctype html>\n" // Use HTML 5 doctype
283  "<html>\n<head>\n";
284 
285  if (!title.empty())
286  os << "<title>" << html::EscapeText(title) << "</title>\n";
287 
288  os << "<style type=\"text/css\">\n"
289  " body { color:#000000; background-color:#ffffff }\n"
290  " body { font-family:Helvetica, sans-serif; font-size:10pt }\n"
291  " h1 { font-size:14pt }\n"
292  " .code { border-collapse:collapse; width:100%; }\n"
293  " .code { font-family: \"Monospace\", monospace; font-size:10pt }\n"
294  " .code { line-height: 1.2em }\n"
295  " .comment { color: green; font-style: oblique }\n"
296  " .keyword { color: blue }\n"
297  " .string_literal { color: red }\n"
298  " .directive { color: darkmagenta }\n"
299  // Macro expansions.
300  " .expansion { display: none; }\n"
301  " .macro:hover .expansion { display: block; border: 2px solid #FF0000; "
302  "padding: 2px; background-color:#FFF0F0; font-weight: normal; "
303  " -webkit-border-radius:5px; -webkit-box-shadow:1px 1px 7px #000; "
304  " border-radius:5px; box-shadow:1px 1px 7px #000; "
305  "position: absolute; top: -1em; left:10em; z-index: 1 } \n"
306  " .macro { color: darkmagenta; background-color:LemonChiffon;"
307  // Macros are position: relative to provide base for expansions.
308  " position: relative }\n"
309  " .num { width:2.5em; padding-right:2ex; background-color:#eeeeee }\n"
310  " .num { text-align:right; font-size:8pt }\n"
311  " .num { color:#444444 }\n"
312  " .line { padding-left: 1ex; border-left: 3px solid #ccc }\n"
313  " .line { white-space: pre }\n"
314  " .msg { -webkit-box-shadow:1px 1px 7px #000 }\n"
315  " .msg { box-shadow:1px 1px 7px #000 }\n"
316  " .msg { -webkit-border-radius:5px }\n"
317  " .msg { border-radius:5px }\n"
318  " .msg { font-family:Helvetica, sans-serif; font-size:8pt }\n"
319  " .msg { float:left }\n"
320  " .msg { padding:0.25em 1ex 0.25em 1ex }\n"
321  " .msg { margin-top:10px; margin-bottom:10px }\n"
322  " .msg { font-weight:bold }\n"
323  " .msg { max-width:60em; word-wrap: break-word; white-space: pre-wrap }\n"
324  " .msgT { padding:0x; spacing:0x }\n"
325  " .msgEvent { background-color:#fff8b4; color:#000000 }\n"
326  " .msgControl { background-color:#bbbbbb; color:#000000 }\n"
327  " .msgNote { background-color:#ddeeff; color:#000000 }\n"
328  " .mrange { background-color:#dfddf3 }\n"
329  " .mrange { border-bottom:1px solid #6F9DBE }\n"
330  " .PathIndex { font-weight: bold; padding:0px 5px; "
331  "margin-right:5px; }\n"
332  " .PathIndex { -webkit-border-radius:8px }\n"
333  " .PathIndex { border-radius:8px }\n"
334  " .PathIndexEvent { background-color:#bfba87 }\n"
335  " .PathIndexControl { background-color:#8c8c8c }\n"
336  " .PathNav a { text-decoration:none; font-size: larger }\n"
337  " .CodeInsertionHint { font-weight: bold; background-color: #10dd10 }\n"
338  " .CodeRemovalHint { background-color:#de1010 }\n"
339  " .CodeRemovalHint { border-bottom:1px solid #6F9DBE }\n"
340  " table.simpletable {\n"
341  " padding: 5px;\n"
342  " font-size:12pt;\n"
343  " margin:20px;\n"
344  " border-collapse: collapse; border-spacing: 0px;\n"
345  " }\n"
346  " td.rowname {\n"
347  " text-align: right;\n"
348  " vertical-align: top;\n"
349  " font-weight: bold;\n"
350  " color:#444444;\n"
351  " padding-right:2ex;\n"
352  " }\n"
353  "</style>\n</head>\n<body>";
354 
355  // Generate header
356  R.InsertTextBefore(StartLoc, os.str());
357  // Generate footer
358 
359  R.InsertTextAfter(EndLoc, "</body></html>\n");
360 }
361 
362 /// SyntaxHighlight - Relex the specified FileID and annotate the HTML with
363 /// information about keywords, macro expansions etc. This uses the macro
364 /// table state from the end of the file, so it won't be perfectly perfect,
365 /// but it will be reasonably close.
367  RewriteBuffer &RB = R.getEditBuffer(FID);
368 
369  const SourceManager &SM = PP.getSourceManager();
370  const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
371  Lexer L(FID, FromFile, SM, PP.getLangOpts());
372  const char *BufferStart = L.getBuffer().data();
373 
374  // Inform the preprocessor that we want to retain comments as tokens, so we
375  // can highlight them.
376  L.SetCommentRetentionState(true);
377 
378  // Lex all the tokens in raw mode, to avoid entering #includes or expanding
379  // macros.
380  Token Tok;
381  L.LexFromRawLexer(Tok);
382 
383  while (Tok.isNot(tok::eof)) {
384  // Since we are lexing unexpanded tokens, all tokens are from the main
385  // FileID.
386  unsigned TokOffs = SM.getFileOffset(Tok.getLocation());
387  unsigned TokLen = Tok.getLength();
388  switch (Tok.getKind()) {
389  default: break;
390  case tok::identifier:
391  llvm_unreachable("tok::identifier in raw lexing mode!");
392  case tok::raw_identifier: {
393  // Fill in Result.IdentifierInfo and update the token kind,
394  // looking up the identifier in the identifier table.
395  PP.LookUpIdentifierInfo(Tok);
396 
397  // If this is a pp-identifier, for a keyword, highlight it as such.
398  if (Tok.isNot(tok::identifier))
399  HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
400  "<span class='keyword'>", "</span>");
401  break;
402  }
403  case tok::comment:
404  HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
405  "<span class='comment'>", "</span>");
406  break;
407  case tok::utf8_string_literal:
408  // Chop off the u part of u8 prefix
409  ++TokOffs;
410  --TokLen;
411  // FALL THROUGH to chop the 8
412  LLVM_FALLTHROUGH;
413  case tok::wide_string_literal:
414  case tok::utf16_string_literal:
415  case tok::utf32_string_literal:
416  // Chop off the L, u, U or 8 prefix
417  ++TokOffs;
418  --TokLen;
419  // FALL THROUGH.
420  case tok::string_literal:
421  // FIXME: Exclude the optional ud-suffix from the highlighted range.
422  HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart,
423  "<span class='string_literal'>", "</span>");
424  break;
425  case tok::hash: {
426  // If this is a preprocessor directive, all tokens to end of line are too.
427  if (!Tok.isAtStartOfLine())
428  break;
429 
430  // Eat all of the tokens until we get to the next one at the start of
431  // line.
432  unsigned TokEnd = TokOffs+TokLen;
433  L.LexFromRawLexer(Tok);
434  while (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) {
435  TokEnd = SM.getFileOffset(Tok.getLocation())+Tok.getLength();
436  L.LexFromRawLexer(Tok);
437  }
438 
439  // Find end of line. This is a hack.
440  HighlightRange(RB, TokOffs, TokEnd, BufferStart,
441  "<span class='directive'>", "</span>");
442 
443  // Don't skip the next token.
444  continue;
445  }
446  }
447 
448  L.LexFromRawLexer(Tok);
449  }
450 }
451 
452 /// HighlightMacros - This uses the macro table state from the end of the
453 /// file, to re-expand macros and insert (into the HTML) information about the
454 /// macro expansions. This won't be perfectly perfect, but it will be
455 /// reasonably close.
457  // Re-lex the raw token stream into a token buffer.
458  const SourceManager &SM = PP.getSourceManager();
459  std::vector<Token> TokenStream;
460 
461  const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
462  Lexer L(FID, FromFile, SM, PP.getLangOpts());
463 
464  // Lex all the tokens in raw mode, to avoid entering #includes or expanding
465  // macros.
466  while (1) {
467  Token Tok;
468  L.LexFromRawLexer(Tok);
469 
470  // If this is a # at the start of a line, discard it from the token stream.
471  // We don't want the re-preprocess step to see #defines, #includes or other
472  // preprocessor directives.
473  if (Tok.is(tok::hash) && Tok.isAtStartOfLine())
474  continue;
475 
476  // If this is a ## token, change its kind to unknown so that repreprocessing
477  // it will not produce an error.
478  if (Tok.is(tok::hashhash))
479  Tok.setKind(tok::unknown);
480 
481  // If this raw token is an identifier, the raw lexer won't have looked up
482  // the corresponding identifier info for it. Do this now so that it will be
483  // macro expanded when we re-preprocess it.
484  if (Tok.is(tok::raw_identifier))
485  PP.LookUpIdentifierInfo(Tok);
486 
487  TokenStream.push_back(Tok);
488 
489  if (Tok.is(tok::eof)) break;
490  }
491 
492  // Temporarily change the diagnostics object so that we ignore any generated
493  // diagnostics from this pass.
497 
498  // FIXME: This is a huge hack; we reuse the input preprocessor because we want
499  // its state, but we aren't actually changing it (we hope). This should really
500  // construct a copy of the preprocessor.
501  Preprocessor &TmpPP = const_cast<Preprocessor&>(PP);
502  DiagnosticsEngine *OldDiags = &TmpPP.getDiagnostics();
503  TmpPP.setDiagnostics(TmpDiags);
504 
505  // Inform the preprocessor that we don't want comments.
506  TmpPP.SetCommentRetentionState(false, false);
507 
508  // We don't want pragmas either. Although we filtered out #pragma, removing
509  // _Pragma and __pragma is much harder.
510  bool PragmasPreviouslyEnabled = TmpPP.getPragmasEnabled();
511  TmpPP.setPragmasEnabled(false);
512 
513  // Enter the tokens we just lexed. This will cause them to be macro expanded
514  // but won't enter sub-files (because we removed #'s).
515  TmpPP.EnterTokenStream(TokenStream, false);
516 
517  TokenConcatenation ConcatInfo(TmpPP);
518 
519  // Lex all the tokens.
520  Token Tok;
521  TmpPP.Lex(Tok);
522  while (Tok.isNot(tok::eof)) {
523  // Ignore non-macro tokens.
524  if (!Tok.getLocation().isMacroID()) {
525  TmpPP.Lex(Tok);
526  continue;
527  }
528 
529  // Okay, we have the first token of a macro expansion: highlight the
530  // expansion by inserting a start tag before the macro expansion and
531  // end tag after it.
532  std::pair<SourceLocation, SourceLocation> LLoc =
533  SM.getExpansionRange(Tok.getLocation());
534 
535  // Ignore tokens whose instantiation location was not the main file.
536  if (SM.getFileID(LLoc.first) != FID) {
537  TmpPP.Lex(Tok);
538  continue;
539  }
540 
541  assert(SM.getFileID(LLoc.second) == FID &&
542  "Start and end of expansion must be in the same ultimate file!");
543 
544  std::string Expansion = EscapeText(TmpPP.getSpelling(Tok));
545  unsigned LineLen = Expansion.size();
546 
547  Token PrevPrevTok;
548  Token PrevTok = Tok;
549  // Okay, eat this token, getting the next one.
550  TmpPP.Lex(Tok);
551 
552  // Skip all the rest of the tokens that are part of this macro
553  // instantiation. It would be really nice to pop up a window with all the
554  // spelling of the tokens or something.
555  while (!Tok.is(tok::eof) &&
556  SM.getExpansionLoc(Tok.getLocation()) == LLoc.first) {
557  // Insert a newline if the macro expansion is getting large.
558  if (LineLen > 60) {
559  Expansion += "<br>";
560  LineLen = 0;
561  }
562 
563  LineLen -= Expansion.size();
564 
565  // If the tokens were already space separated, or if they must be to avoid
566  // them being implicitly pasted, add a space between them.
567  if (Tok.hasLeadingSpace() ||
568  ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok))
569  Expansion += ' ';
570 
571  // Escape any special characters in the token text.
572  Expansion += EscapeText(TmpPP.getSpelling(Tok));
573  LineLen += Expansion.size();
574 
575  PrevPrevTok = PrevTok;
576  PrevTok = Tok;
577  TmpPP.Lex(Tok);
578  }
579 
580 
581  // Insert the expansion as the end tag, so that multi-line macros all get
582  // highlighted.
583  Expansion = "<span class='expansion'>" + Expansion + "</span></span>";
584 
585  HighlightRange(R, LLoc.first, LLoc.second,
586  "<span class='macro'>", Expansion.c_str());
587  }
588 
589  // Restore the preprocessor's old state.
590  TmpPP.setDiagnostics(*OldDiags);
591  TmpPP.setPragmasEnabled(PragmasPreviouslyEnabled);
592 }
bool isAtStartOfLine() const
isAtStartOfLine - Return true if this token is at the start of a line.
Definition: Token.h:266
SourceManager & getSourceManager() const
Definition: Preprocessor.h:729
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens...
Definition: Lexer.h:46
bool isMacroID() const
SourceManager & getSourceMgr() const
Definition: Rewriter.h:64
Defines the SourceManager interface.
bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok, const Token &Tok) const
AvoidConcat - If printing PrevTok immediately followed by Tok would cause the two individual tokens t...
TokenConcatenation class, which answers the question of "Is it safe to emit two tokens without a whit...
llvm::MemoryBuffer * getBuffer(FileID FID, SourceLocation Loc, bool *Invalid=nullptr) const
Return the buffer for the specified FileID.
bool hasLeadingSpace() const
Return true if this token has whitespace before it.
Definition: Token.h:270
StringRef getBuffer() const
Gets source code buffer.
Definition: Lexer.h:202
RewriteBuffer & getEditBuffer(FileID FID)
getEditBuffer - This is like getRewriteBufferFor, but always returns a buffer, and allows you to writ...
Definition: Rewriter.cpp:223
RewriteBuffer - As code is rewritten, SourceBuffer's from the original input with modifications get a...
Definition: RewriteBuffer.h:27
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
std::pair< SourceLocation, SourceLocation > getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
static void AddLineNumber(RewriteBuffer &RB, unsigned LineNo, unsigned B, unsigned E)
void HighlightMacros(Rewriter &R, FileID FID, const Preprocessor &PP)
HighlightMacros - This uses the macro table state from the end of the file, to reexpand macros and in...
void AddLineNumbers(Rewriter &R, FileID FID)
const LangOptions & getLangOpts() const
Definition: Preprocessor.h:725
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
void setKind(tok::TokenKind K)
Definition: Token.h:91
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:147
void SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP)
SyntaxHighlight - Relex the specified FileID and annotate the HTML with information about keywords...
const IntrusiveRefCntPtr< DiagnosticIDs > & getDiagnosticIDs() const
Definition: Diagnostic.h:412
tok::TokenKind getKind() const
Definition: Token.h:90
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
Definition: Lexer.cpp:417
Defines the clang::Preprocessor interface.
void InsertTextAfter(unsigned OrigOffset, StringRef Str)
InsertTextAfter - Insert some text at the specified point, where the offset in the buffer is specifie...
Definition: RewriteBuffer.h:80
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file. ...
Definition: Token.h:124
bool isNot(tok::TokenKind K) const
Definition: Token.h:96
const SourceManager & SM
Definition: Format.cpp:1293
void ReplaceText(unsigned OrigOffset, unsigned OrigLength, StringRef NewStr)
ReplaceText - This method replaces a range of characters in the input buffer with a new string...
Definition: Rewriter.cpp:108
Encodes a location in the source.
void EscapeText(Rewriter &R, FileID FID, bool EscapeSpaces=false, bool ReplaceTabs=false)
EscapeText - HTMLize a specified file so that special characters are are translated so that they are ...
bool InsertTextAfter(SourceLocation Loc, StringRef Str)
InsertTextAfter - Insert the specified string at the specified location in the original buffer...
Definition: Rewriter.h:102
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
Definition: Diagnostic.h:417
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {...
Definition: Token.h:95
DiagnosticsEngine & getDiagnostics() const
Definition: Preprocessor.h:722
bool InsertTextBefore(SourceLocation Loc, StringRef Str)
InsertText - Insert the specified string at the specified location in the original buffer...
Definition: Rewriter.h:115
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
void InsertTextBefore(unsigned OrigOffset, StringRef Str)
InsertTextBefore - Insert some text before the specified point, where the offset in the buffer is spe...
Definition: RewriteBuffer.h:73
A diagnostic client that ignores all diagnostics.
Definition: Diagnostic.h:1451
detail::InMemoryDirectory::const_iterator E
void AddHeaderFooterInternalBuiltinCSS(Rewriter &R, FileID FID, StringRef title)
const LangOptions & getLangOpts() const
Definition: Rewriter.h:65
Rewriter - This is the main interface to the rewrite buffers.
Definition: Rewriter.h:31
IdentifierInfo * LookUpIdentifierInfo(Token &Identifier) const
Given a tok::raw_identifier token, look up the identifier information for the token and install it in...
unsigned getLength() const
Definition: Token.h:127
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file. ...
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
This class handles loading and caching of source files into memory.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:98
void HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, const char *StartTag, const char *EndTag)
HighlightRange - Highlight a range in the source code with the specified start/end tags...
Definition: HTMLRewrite.cpp:32