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