| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | #include "clang/Rewrite/Core/HTMLRewrite.h" |
| 15 | #include "clang/Basic/SourceManager.h" |
| 16 | #include "clang/Lex/Preprocessor.h" |
| 17 | #include "clang/Lex/TokenConcatenation.h" |
| 18 | #include "clang/Rewrite/Core/Rewriter.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 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | void html::HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, |
| 32 | const char *StartTag, const char *EndTag, |
| 33 | bool IsTokenRange) { |
| 34 | SourceManager &SM = R.getSourceMgr(); |
| 35 | B = SM.getExpansionLoc(B); |
| 36 | E = SM.getExpansionLoc(E); |
| 37 | FileID FID = SM.getFileID(B); |
| 38 | (0) . __assert_fail ("SM.getFileID(E) == FID && \"B/E not in the same file!\"", "/home/seafit/code_projects/clang_source/clang/lib/Rewrite/HTMLRewrite.cpp", 38, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">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 | |
| 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 | |
| 57 | |
| 58 | void html::HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E, |
| 59 | const char *BufferStart, |
| 60 | const char *StartTag, const char *EndTag) { |
| 61 | |
| 62 | RB.InsertTextAfter(B, StartTag); |
| 63 | RB.InsertTextBefore(E, EndTag); |
| 64 | |
| 65 | |
| 66 | |
| 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 | |
| 75 | |
| 76 | if (HadOpenTag) |
| 77 | RB.InsertTextBefore(LastNonWhiteSpace+1, EndTag); |
| 78 | |
| 79 | |
| 80 | |
| 81 | |
| 82 | |
| 83 | HadOpenTag = false; |
| 84 | break; |
| 85 | case '\0': |
| 86 | case ' ': |
| 87 | case '\t': |
| 88 | case '\f': |
| 89 | case '\v': |
| 90 | |
| 91 | break; |
| 92 | |
| 93 | default: |
| 94 | |
| 95 | if (!HadOpenTag) { |
| 96 | RB.InsertTextAfter(i, StartTag); |
| 97 | HadOpenTag = true; |
| 98 | } |
| 99 | |
| 100 | |
| 101 | LastNonWhiteSpace = i; |
| 102 | break; |
| 103 | } |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | void html::EscapeText(Rewriter &R, FileID FID, |
| 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, " "); |
| 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(" " |
| 144 | " ", 6*NumSpaces)); |
| 145 | else |
| 146 | RB.ReplaceText(FilePos, 1, StringRef(" ", NumSpaces)); |
| 147 | ColNo += NumSpaces; |
| 148 | break; |
| 149 | } |
| 150 | case '<': |
| 151 | RB.ReplaceText(FilePos, 1, "<"); |
| 152 | ++ColNo; |
| 153 | break; |
| 154 | |
| 155 | case '>': |
| 156 | RB.ReplaceText(FilePos, 1, ">"); |
| 157 | ++ColNo; |
| 158 | break; |
| 159 | |
| 160 | case '&': |
| 161 | RB.ReplaceText(FilePos, 1, "&"); |
| 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 << " "; |
| 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 << " "; |
| 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 << "<"; break; |
| 201 | case '>': os << ">"; break; |
| 202 | case '&': os << "&"; 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) { |
| 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 | |
| 227 | void html::AddLineNumbers(Rewriter& R, FileID FID) { |
| 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 | |
| 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 | |
| 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 | |
| 274 | void html::(Rewriter &R, FileID FID, |
| 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 | |
| 281 | SourceLocation StartLoc = R.getSourceMgr().getLocForStartOfFile(FID); |
| 282 | SourceLocation EndLoc = StartLoc.getLocWithOffset(FileEnd-FileStart); |
| 283 | |
| 284 | std::string s; |
| 285 | llvm::raw_string_ostream os(s); |
| 286 | os << "<!doctype html>\n" |
| 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 | |
| 416 | R.InsertTextBefore(StartLoc, os.str()); |
| 417 | |
| 418 | |
| 419 | R.InsertTextAfter(EndLoc, "</body></html>\n"); |
| 420 | } |
| 421 | |
| 422 | |
| 423 | |
| 424 | |
| 425 | |
| 426 | void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { |
| 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 | |
| 435 | |
| 436 | L.SetCommentRetentionState(true); |
| 437 | |
| 438 | |
| 439 | |
| 440 | Token Tok; |
| 441 | L.LexFromRawLexer(Tok); |
| 442 | |
| 443 | while (Tok.isNot(tok::eof)) { |
| 444 | |
| 445 | |
| 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 | |
| 454 | |
| 455 | PP.LookUpIdentifierInfo(Tok); |
| 456 | |
| 457 | |
| 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 | |
| 469 | ++TokOffs; |
| 470 | --TokLen; |
| 471 | |
| 472 | LLVM_FALLTHROUGH; |
| 473 | case tok::wide_string_literal: |
| 474 | case tok::utf16_string_literal: |
| 475 | case tok::utf32_string_literal: |
| 476 | |
| 477 | ++TokOffs; |
| 478 | --TokLen; |
| 479 | LLVM_FALLTHROUGH; |
| 480 | case tok::string_literal: |
| 481 | |
| 482 | HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, |
| 483 | "<span class='string_literal'>", "</span>"); |
| 484 | break; |
| 485 | case tok::hash: { |
| 486 | |
| 487 | if (!Tok.isAtStartOfLine()) |
| 488 | break; |
| 489 | |
| 490 | |
| 491 | |
| 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 | |
| 500 | HighlightRange(RB, TokOffs, TokEnd, BufferStart, |
| 501 | "<span class='directive'>", "</span>"); |
| 502 | |
| 503 | |
| 504 | continue; |
| 505 | } |
| 506 | } |
| 507 | |
| 508 | L.LexFromRawLexer(Tok); |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | |
| 513 | |
| 514 | |
| 515 | |
| 516 | void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { |
| 517 | |
| 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 | |
| 525 | |
| 526 | while (1) { |
| 527 | Token Tok; |
| 528 | L.LexFromRawLexer(Tok); |
| 529 | |
| 530 | |
| 531 | |
| 532 | |
| 533 | if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) |
| 534 | continue; |
| 535 | |
| 536 | |
| 537 | |
| 538 | if (Tok.is(tok::hashhash)) |
| 539 | Tok.setKind(tok::unknown); |
| 540 | |
| 541 | |
| 542 | |
| 543 | |
| 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 | |
| 553 | |
| 554 | DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(), |
| 555 | &PP.getDiagnostics().getDiagnosticOptions(), |
| 556 | new IgnoringDiagConsumer); |
| 557 | |
| 558 | |
| 559 | |
| 560 | |
| 561 | Preprocessor &TmpPP = const_cast<Preprocessor&>(PP); |
| 562 | DiagnosticsEngine *OldDiags = &TmpPP.getDiagnostics(); |
| 563 | TmpPP.setDiagnostics(TmpDiags); |
| 564 | |
| 565 | |
| 566 | TmpPP.SetCommentRetentionState(false, false); |
| 567 | |
| 568 | |
| 569 | |
| 570 | bool PragmasPreviouslyEnabled = TmpPP.getPragmasEnabled(); |
| 571 | TmpPP.setPragmasEnabled(false); |
| 572 | |
| 573 | |
| 574 | |
| 575 | TmpPP.EnterTokenStream(TokenStream, false); |
| 576 | |
| 577 | TokenConcatenation ConcatInfo(TmpPP); |
| 578 | |
| 579 | |
| 580 | Token Tok; |
| 581 | TmpPP.Lex(Tok); |
| 582 | while (Tok.isNot(tok::eof)) { |
| 583 | |
| 584 | if (!Tok.getLocation().isMacroID()) { |
| 585 | TmpPP.Lex(Tok); |
| 586 | continue; |
| 587 | } |
| 588 | |
| 589 | |
| 590 | |
| 591 | |
| 592 | CharSourceRange LLoc = SM.getExpansionRange(Tok.getLocation()); |
| 593 | |
| 594 | |
| 595 | if (SM.getFileID(LLoc.getBegin()) != FID) { |
| 596 | TmpPP.Lex(Tok); |
| 597 | continue; |
| 598 | } |
| 599 | |
| 600 | (0) . __assert_fail ("SM.getFileID(LLoc.getEnd()) == FID && \"Start and end of expansion must be in the same ultimate file!\"", "/home/seafit/code_projects/clang_source/clang/lib/Rewrite/HTMLRewrite.cpp", 601, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(SM.getFileID(LLoc.getEnd()) == FID && |
| 601 | (0) . __assert_fail ("SM.getFileID(LLoc.getEnd()) == FID && \"Start and end of expansion must be in the same ultimate file!\"", "/home/seafit/code_projects/clang_source/clang/lib/Rewrite/HTMLRewrite.cpp", 601, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "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 | |
| 609 | TmpPP.Lex(Tok); |
| 610 | |
| 611 | |
| 612 | |
| 613 | |
| 614 | while (!Tok.is(tok::eof) && |
| 615 | SM.getExpansionLoc(Tok.getLocation()) == LLoc.getBegin()) { |
| 616 | |
| 617 | if (LineLen > 60) { |
| 618 | Expansion += "<br>"; |
| 619 | LineLen = 0; |
| 620 | } |
| 621 | |
| 622 | LineLen -= Expansion.size(); |
| 623 | |
| 624 | |
| 625 | |
| 626 | if (Tok.hasLeadingSpace() || |
| 627 | ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok)) |
| 628 | Expansion += ' '; |
| 629 | |
| 630 | |
| 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 | |
| 641 | |
| 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 | |
| 649 | TmpPP.setDiagnostics(*OldDiags); |
| 650 | TmpPP.setPragmasEnabled(PragmasPreviouslyEnabled); |
| 651 | } |
| 652 | |