;
56usingllvm::RewriteBuffer;
68std::string Directory;
69 boolcreatedDir =
false;
72 const boolSupportsCrossFileDiagnostics;
73llvm::StringSet<> EmittedHashes;
80 boolsupportsMultipleFiles)
81: DiagOpts(
std::move(DiagOpts)), Directory(OutputDir), PP(pp),
82SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
87FilesMade *filesMade)
override;
89StringRef
getName()
const override{
return "HTMLDiagnostics"; }
92 returnSupportsCrossFileDiagnostics;
103 conststd::vector<SourceRange> &PopUpRanges,
unsignednum,
107 const char*HighlightStart =
"<span class=\"mrange\">",
108 const char*HighlightEnd =
"</span>");
115 const char*declName);
131 constArrowMap &ArrowIndices);
134StringRef showHelpJavascript();
137StringRef generateKeyboardNavigationJavascript();
140StringRef generateArrowDrawingJavascript();
148llvm::raw_string_ostream &os);
152 returnisa<PathDiagnosticControlFlowPiece>(
P) &&
P.getString().empty();
156 unsignedTotalPieces =
Path.size();
157 unsignedTotalArrowPieces = llvm::count_if(
159 returnTotalPieces - TotalArrowPieces;
162classArrowMap :
publicstd::vector<unsigned> {
163 using Base= std::vector<unsigned>;
166ArrowMap(
unsignedSize) :
Base(
Size, 0) {}
167 unsignedgetTotalNumberOfArrows()
const{
returnat(0); }
170llvm::raw_ostream &
operator<<(llvm::raw_ostream &OS,
constArrowMap &Indices) {
172llvm::interleave(Indices, OS,
",");
178voidento::createHTMLDiagnosticConsumer(
189createTextMinimalPathDiagnosticConsumer(DiagOpts,
C, OutputDir, PP, CTU,
193 if(OutputDir.empty())
196 C.push_back(
newHTMLDiagnostics(std::move(DiagOpts), OutputDir, PP,
true));
199voidento::createHTMLSingleFileDiagnosticConsumer(
204createTextMinimalPathDiagnosticConsumer(DiagOpts,
C, OutputDir, PP, CTU,
208 if(OutputDir.empty())
211 C.push_back(
newHTMLDiagnostics(std::move(DiagOpts), OutputDir, PP,
false));
214voidento::createPlistHTMLDiagnosticConsumer(
219createHTMLDiagnosticConsumer(
220DiagOpts,
C, std::string(llvm::sys::path::parent_path(prefix)), PP, CTU,
222createPlistMultiFileDiagnosticConsumer(DiagOpts,
C, prefix, PP, CTU,
224createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts),
C, prefix, PP,
225CTU, MacroExpansions);
228voidento::createSarifHTMLDiagnosticConsumer(
233createHTMLDiagnosticConsumer(
234DiagOpts,
C, std::string(llvm::sys::path::parent_path(sarif_file)), PP,
235CTU, MacroExpansions);
236createSarifDiagnosticConsumer(DiagOpts,
C, sarif_file, PP, CTU,
238createTextMinimalPathDiagnosticConsumer(std::move(DiagOpts),
C, sarif_file,
239PP, CTU, MacroExpansions);
246voidHTMLDiagnostics::FlushDiagnosticsImpl(
247std::vector<const PathDiagnostic *> &Diags,
248FilesMade *filesMade) {
249 for(
const auto Diag: Diags)
250ReportDiag(*
Diag, filesMade);
266FilesMade *filesMade) {
270 if(std::error_code ec = llvm::sys::fs::create_directories(Directory)) {
271llvm::errs() <<
"warning: could not create directory '" 272<< Directory <<
"': "<< ec.message() <<
'\n';
285assert(!path.empty());
286 const SourceManager&SMgr = path.front()->getLocation().getManager();
294 if(
const Decl*DeclWithIssue =
D.getDeclWithIssue()) {
295 if(
const auto*ND = dyn_cast<NamedDecl>(DeclWithIssue))
296declName = ND->getDeclName().getAsString();
298 if(
const Stmt*Body = DeclWithIssue->getBody()) {
305offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber();
310 auto[It, IsNew] = EmittedHashes.insert(IssueHash);
316std::string report = GenerateHTML(
D, R, SMgr, path, declName.c_str());
317 if(report.empty()) {
318llvm::errs() <<
"warning: no diagnostics generated for main file.\n";
326llvm::raw_svector_ostream
FileName(FileNameStr);
339path.back()->getLocation().asLocation().getExpansionLoc().getFileID();
344<< declName.c_str() <<
"-"<< offsetDecl <<
"-";
347 FileName<< StringRef(IssueHash).substr(0, 6).str() <<
".html";
350llvm::sys::path::append(ResultPath, Directory,
FileName.str());
351 if(std::error_code EC = llvm::sys::fs::make_absolute(ResultPath)) {
352llvm::errs() <<
"warning: could not make '"<< ResultPath
353<<
"' absolute: "<< EC.message() <<
'\n';
357 if(std::error_code EC = llvm::sys::fs::openFileForReadWrite(
358ResultPath, FD, llvm::sys::fs::CD_CreateNew,
359llvm::sys::fs::OF_Text)) {
365 if(EC != llvm::errc::file_exists) {
366llvm::errs() <<
"warning: could not create file in '"<< Directory
367<<
"': "<< EC.message() <<
'\n';
372llvm::raw_fd_ostream os(FD,
true);
375filesMade->addDiagnostic(
D,
getName(),
376llvm::sys::path::filename(ResultPath));
385std::vector<FileID> FileIDs;
386 for(
autoI : path) {
387 FileIDFID = I->getLocation().asLocation().getExpansionLoc().getFileID();
388 if(llvm::is_contained(FileIDs, FID))
391FileIDs.push_back(FID);
392RewriteFile(R, path, FID);
395 if(SupportsCrossFileDiagnostics && FileIDs.size() > 1) {
397 for(
autoI = FileIDs.begin(),
E= FileIDs.end(); I !=
E; I++) {
399llvm::raw_string_ostream os(
s);
401 if(I != FileIDs.begin())
402os <<
"<hr class=divider>\n";
404os <<
"<div id=File"<< I->getHashValue() <<
">\n";
407 if(I != FileIDs.begin())
408os <<
"<div class=FileNav><a href=\"#File"<< (I - 1)->getHashValue()
409<<
"\">←</a></div>";
416os <<
"<div class=FileNav><a href=\"#File"<< (I + 1)->getHashValue()
417<<
"\">→</a></div>";
425 for(
autoI : llvm::drop_begin(FileIDs)) {
427llvm::raw_string_ostream os(
s);
430 for(
autoBI : *Buf)
443path.back()->getLocation().asLocation().getExpansionLoc().getFileID();
445FinalizeHTML(
D, R, SMgr, path, FileIDs[0], *Entry, declName);
448llvm::raw_string_ostream os(file);
449 for(
autoBI : *Buf)
455voidHTMLDiagnostics::dumpCoverageData(
458llvm::raw_string_ostream &os) {
462os <<
"var relevant_lines = {";
463 for(
autoI = ExecutedLines.begin(),
464 E= ExecutedLines.end(); I !=
E; ++I) {
465 if(I != ExecutedLines.begin())
468os <<
"\""<< I->first.getHashValue() <<
"\": {";
469 for(
unsignedLineNo : I->second) {
470 if(LineNo != *(I->second.begin()))
473os <<
"\""<< LineNo <<
"\": 1";
481std::string HTMLDiagnostics::showRelevantLinesJavascript(
484llvm::raw_string_ostream os(
s);
485os <<
"<script type='text/javascript'>\n";
486dumpCoverageData(
D, path, os);
489var filterCounterexample = function (hide) { 490 var tables = document.getElementsByClassName("code"); 491 for (var t=0; t<tables.length; t++) { 492 var table = tables[t]; 493 var file_id = table.getAttribute("data-fileid"); 494 var lines_in_fid = relevant_lines[file_id]; 498 var lines = table.getElementsByClassName("codeline"); 499 for (var i=0; i<lines.length; i++) { 501 var lineNo = el.getAttribute("data-linenumber"); 502 if (!lines_in_fid[lineNo]) { 504 el.setAttribute("hidden", ""); 506 el.removeAttribute("hidden"); 513window.addEventListener("keydown", function (event) { 514 if (event.defaultPrevented) { 518 if (event.shiftKey && event.keyCode == 83) { 519 var checked = document.getElementsByName("showCounterexample")[0].checked; 520 filterCounterexample(!checked); 521 document.getElementsByName("showCounterexample")[0].click(); 525 event.preventDefault(); 528document.addEventListener("DOMContentLoaded", function() { 529 document.querySelector('input[name="showCounterexample"]').onchange= 531 filterCounterexample(this.checked); 537 <input type="checkbox" name="showCounterexample" id="showCounterexample" /> 538 <label for="showCounterexample"> 539 Show only relevant lines 541 <input type="checkbox" name="showArrows" 542 id="showArrows" style="margin-left: 10px" /> 543 <label for="showArrows"> 544 Show control flow arrows 562 if(llvm::sys::path::is_relative(Entry.
getName())) {
563llvm::sys::fs::current_path(DirName);
567 intLineNumber = path.back()->getLocation().asLocation().getExpansionLineNumber();
568 intColumnNumber = path.back()->getLocation().asLocation().getExpansionColumnNumber();
573generateKeyboardNavigationJavascript());
576generateArrowDrawingJavascript());
580showRelevantLinesJavascript(
D, path));
585llvm::raw_string_ostream os(
s);
587os <<
"<!-- REPORTHEADER -->\n" 588<<
"<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n" 589 "<tr><td class=\"rowname\">File:</td><td>" 592<<
"</td></tr>\n<tr><td class=\"rowname\">Warning:</td><td>" 593 "<a href=\"#EndPath\">line " 598<<
D.getVerboseDescription() <<
"</td></tr>\n";
601 unsignedNumExtraPieces = 0;
602 for(
const auto&Piece : path) {
603 if(
const auto*
P= dyn_cast<PathDiagnosticNotePiece>(Piece.get())) {
605 P->getLocation().asLocation().getExpansionLineNumber();
607 P->getLocation().asLocation().getExpansionColumnNumber();
609os <<
"<tr><td class=\"rowname\">Note:</td><td>" 610<<
"<a href=\"#Note"<< NumExtraPieces <<
"\">line " 611<< LineNumber <<
", column "<< ColumnNumber <<
"</a><br />" 612<<
P->getString() <<
"</td></tr>";
618 for(
conststd::string &Metadata :
619llvm::make_range(
D.meta_begin(),
D.meta_end())) {
620os <<
"<tr><td></td><td>"<<
html::EscapeText(Metadata) <<
"</td></tr>\n";
625<!-- REPORTSUMMARYEXTRA --> 626<h3>Annotated Source Code</h3> 627<p>Press <a href="#" onclick="toggleHelp(); return false;">'?'</a> 628 to see keyboard shortcuts</p> 629<input type="checkbox" class="spoilerhider" id="showinvocation" /> 630<label for="showinvocation" >Show analyzer invocation</label> 631<div class="spoiler">clang -cc1 )<<<"; 635<div id='tooltiphint' hidden="true"> 636 <p>Keyboard shortcuts: </p> 638 <li>Use 'j/k' keys for keyboard navigation</li> 639 <li>Use 'Shift+S' to show/hide relevant lines</li> 640 <li>Use '?' to toggle this window</li> 642 <a href="#" onclick="toggleHelp(); return false;">Close</a> 652llvm::raw_string_ostream os(
s);
654StringRef BugDesc =
D.getVerboseDescription();
655 if(!BugDesc.empty())
656os <<
"\n<!-- BUGDESC "<< BugDesc <<
" -->\n";
658StringRef
BugType=
D.getBugType();
660os <<
"\n<!-- BUGTYPE "<<
BugType<<
" -->\n";
668StringRef BugCategory =
D.getCategory();
669 if(!BugCategory.empty())
670os <<
"\n<!-- BUGCATEGORY "<< BugCategory <<
" -->\n";
672os <<
"\n<!-- BUGFILE "<< DirName << Entry.
getName() <<
" -->\n";
674os <<
"\n<!-- FILENAME "<< llvm::sys::path::filename(Entry.
getName()) <<
" -->\n";
676os <<
"\n<!-- FUNCTIONNAME "<< declName <<
" -->\n";
678os <<
"\n<!-- ISSUEHASHCONTENTOFLINEINCONTEXT "<<
getIssueHash(
D, PP)
681os <<
"\n<!-- BUGLINE " 685os <<
"\n<!-- BUGCOLUMN " 689os <<
"\n<!-- BUGPATHLENGTH "<< getPathSizeWithoutArrows(path) <<
" -->\n";
692os <<
"\n<!-- BUGMETAEND -->\n";
701StringRef HTMLDiagnostics::showHelpJavascript() {
703<script type='text/javascript'> 705var toggleHelp = function() { 706 var hint = document.querySelector("#tooltiphint"); 707 var attributeName = "hidden"; 708 if (hint.hasAttribute(attributeName)) { 709 hint.removeAttribute(attributeName); 711 hint.setAttribute("hidden", "true"); 714window.addEventListener("keydown", function (event) { 715 if (event.defaultPrevented) { 718 if (event.key == "?") { 723 event.preventDefault(); 730 return!(
Range.getBegin().isMacroID() ||
Range.getEnd().isMacroID());
735 conststd::vector<SourceRange> &PopUpRanges) {
736 for(
const auto&
Range: PopUpRanges) {
741 "<table class='variable_popup'><tbody>",
748std::vector<SourceRange> &PopUpRanges,
749 unsigned intLastReportedPieceIndex,
750 unsigned intPopUpPieceIndex) {
752llvm::raw_svector_ostream Out(Buf);
759Out <<
"<tr><td valign='top'><div class='PathIndex PathIndexPopUp'>" 760<< LastReportedPieceIndex;
763Out <<
'.'<< PopUpPieceIndex;
765Out <<
"</div></td><td>"<< Piece.
getString() <<
"</td></tr>";
768 if(!llvm::is_contained(PopUpRanges,
Range)) {
770PopUpRanges.push_back(
Range);
772Out <<
"</tbody></table></span>";
774 "<span class='variable'>", Buf.c_str(),
788 unsignedTotalPieces = getPathSizeWithoutArrows(path);
789 unsignedTotalNotePieces =
791 returnisa<PathDiagnosticNotePiece>(*p);
793 unsignedPopUpPieceCount =
795 returnisa<PathDiagnosticPopUpPiece>(*p);
798 unsignedTotalRegularPieces = TotalPieces - TotalNotePieces - PopUpPieceCount;
799 unsignedNumRegularPieces = TotalRegularPieces;
800 unsignedNumNotePieces = TotalNotePieces;
801 unsignedNumberOfArrows = 0;
803std::map<int, int> IndexMap;
804ArrowMap ArrowIndices(TotalRegularPieces + 1);
807std::vector<SourceRange> PopUpRanges;
809 const auto&Piece = *I.get();
811 if(isa<PathDiagnosticPopUpPiece>(Piece)) {
812++IndexMap[NumRegularPieces];
813}
else if(isa<PathDiagnosticNotePiece>(Piece)) {
817HandlePiece(R, FID, Piece, PopUpRanges, NumNotePieces, TotalNotePieces);
820}
else if(isArrowPiece(Piece)) {
821NumberOfArrows = ProcessControlFlowPiece(
822R, FID, cast<PathDiagnosticControlFlowPiece>(Piece), NumberOfArrows);
823ArrowIndices[NumRegularPieces] = NumberOfArrows;
826HandlePiece(R, FID, Piece, PopUpRanges, NumRegularPieces,
829ArrowIndices[NumRegularPieces] = ArrowIndices[NumRegularPieces + 1];
832ArrowIndices[0] = NumberOfArrows;
842assert(ArrowIndices.back() == 0 &&
843 "No arrows should be after the last event");
845assert(llvm::is_sorted(ArrowIndices, std::greater<unsigned>()) &&
846 "Incorrect arrow indices map");
850NumRegularPieces = TotalRegularPieces;
852 const auto&Piece = *I.get();
854 if(
const auto*PopUpP = dyn_cast<PathDiagnosticPopUpPiece>(&Piece)) {
855 intPopUpPieceIndex = IndexMap[NumRegularPieces];
865 if(PopUpPieceIndex > 0)
866--IndexMap[NumRegularPieces];
868}
else if(!isa<PathDiagnosticNotePiece>(Piece) && !isArrowPiece(Piece)) {
880addArrowSVGs(R, FID, ArrowIndices);
891 conststd::vector<SourceRange> &PopUpRanges,
892 unsignednum,
unsigned max) {
901assert(&Pos.
getManager() == &
SM&&
"SourceManagers are different!");
902std::pair<FileID, unsigned> LPosInfo =
SM.getDecomposedExpansionLoc(Pos);
904 if(LPosInfo.first != BugFileID)
907llvm::MemoryBufferRef Buf =
SM.getBufferOrFake(LPosInfo.first);
908 const char*FileStart = Buf.getBufferStart();
912 unsignedColNo =
SM.getColumnNumber(LPosInfo.first, LPosInfo.second);
914 const char*LineStart = TokInstantiationPtr-ColNo;
917 const char*LineEnd = TokInstantiationPtr;
918 const char*FileEnd = Buf.getBufferEnd();
919 while(*LineEnd !=
'\n'&& LineEnd != FileEnd)
924 for(
const char*
c= LineStart;
c!= TokInstantiationPtr; ++
c)
925PosNo += *
c==
'\t'? 8 : 1;
929 const char*
Kind=
nullptr;
930 boolIsNote =
false;
931 boolSuppressIndex = (
max== 1);
932 switch(
P.getKind()) {
940SuppressIndex =
true;
944llvm_unreachable(
"Calls and extra notes should already be handled");
948llvm::raw_string_ostream os(sbuf);
950os <<
"\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\"";
954 else if(num ==
max)
959os <<
"\" class=\"msg";
961os <<
" msg"<<
Kind;
962os <<
"\" style=\"margin-left:"<< PosNo <<
"ex";
965 if(!isa<PathDiagnosticMacroPiece>(
P)) {
967 const auto&Msg =
P.getString();
968 unsignedmax_token = 0;
970 unsignedlen = Msg.size();
980 if(cnt > max_token) max_token = cnt;
989 const unsignedmax_line = 120;
991 if(max_token >= max_line)
994 unsignedcharacters = max_line;
995 unsignedlines = len / max_line;
998 for(; characters > max_token; --characters)
999 if(len / characters > lines) {
1005em = characters / 2;
1008 if(em < max_line/2)
1009os <<
"; max-width:"<< em <<
"em";
1012os <<
"; max-width:100em";
1016 if(!SuppressIndex) {
1017os <<
"<table class=\"msgT\"><tr><td valign=\"top\">";
1018os <<
"<div class=\"PathIndex";
1019 if(Kind) os <<
" PathIndex"<<
Kind;
1020os <<
"\">"<< num <<
"</div>";
1023os <<
"</td><td><div class=\"PathNav\"><a href=\"#Path" 1025<<
"\" title=\"Previous event (" 1027<<
")\">←</a></div>";
1033 if(
const auto*MP = dyn_cast<PathDiagnosticMacroPiece>(&
P)) {
1034os <<
"Within the expansion of the macro '";
1042 const char* MacroName = LocInfo.second + BufferInfo.data();
1044BufferInfo.begin(), MacroName, BufferInfo.end());
1048 for(
unsignedi = 0, n = TheTok.
getLength(); i < n; ++i)
1054 if(!SuppressIndex) {
1057os <<
"<td><div class=\"PathNav\"><a href=\"#";
1061os <<
"Path"<< (num + 1);
1062os <<
"\" title=\"Next event (" 1064<<
")\">→</a></div></td>";
1067os <<
"</tr></table>";
1071ProcessMacroPiece(os, *MP, 0);
1076 if(!SuppressIndex) {
1079os <<
"<td><div class=\"PathNav\"><a href=\"#";
1083os <<
"Path"<< (num + 1);
1084os <<
"\" title=\"Next event (" 1086<<
")\">→</a></div></td>";
1089os <<
"</tr></table>";
1093os <<
"</div></td></tr>";
1096 unsignedDisplayPos = LineEnd - FileStart;
1098 SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos);
1104 for(
const auto&
Range: Ranges) {
1106 if(llvm::is_contained(PopUpRanges,
Range))
1109HighlightRange(R, LPosInfo.first,
Range);
1114 unsignedx = n % (
'z'-
'a');
1120os << char(
'a'+ x);
1123unsignedHTMLDiagnostics::ProcessMacroPiece(raw_ostream &os,
1126 for(
const auto&subPiece :
P.subPieces) {
1127 if(
const auto*MP = dyn_cast<PathDiagnosticMacroPiece>(subPiece.get())) {
1128num = ProcessMacroPiece(os, *MP, num);
1132 if(
const auto*EP = dyn_cast<PathDiagnosticEventPiece>(subPiece.get())) {
1133os <<
"<div class=\"msg msgEvent\" style=\"width:94%; " 1134 "margin-left:5px\">" 1135 "<table class=\"msgT\"><tr>" 1136 "<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">";
1138os <<
"</div></td><td valign=\"top\">" 1140<<
"</td></tr></table></div>\n";
1147voidHTMLDiagnostics::addArrowSVGs(
Rewriter&R,
FileIDBugFileID,
1148 constArrowMap &ArrowIndices) {
1150llvm::raw_string_ostream OS(S);
1153<style type="text/css"> 1160 pointer-events: none; 1164 stroke-opacity: 0.2; 1166 marker-end: url(#arrowhead); 1170 stroke-opacity: 0.6; 1172 marker-end: url(#arrowheadSelected); 1182<svg xmlns="http://www.w3.org/2000/svg"> 1184 <marker id="arrowheadSelected" class="arrowhead" opacity="0.6" 1185 viewBox="0 0 10 10" refX="3" refY="5" 1186 markerWidth="4" markerHeight="4"> 1187 <path d="M 0 0 L 10 5 L 0 10 z" /> 1189 <marker id="arrowhead" class="arrowhead" opacity="0.2" 1190 viewBox="0 0 10 10" refX="3" refY="5" 1191 markerWidth="4" markerHeight="4"> 1192 <path d="M 0 0 L 10 5 L 0 10 z" /> 1195 <g id="arrows" fill="none" stroke="blue" visibility="hidden"> 1198 for(
unsignedIndex : llvm::seq(0u, ArrowIndices.getTotalNumberOfArrows())) {
1199OS <<
" <path class=\"arrow\" id=\"arrow"<< Index <<
"\"/>\n";
1205<script type='text/javascript'> 1206const arrowIndices = )<<<"; 1208 OS << ArrowIndices << "\n</script>\n";
1217llvm::raw_string_ostream OS(Result);
1218OS <<
"<span id=\""<< ClassName << Index <<
"\">";
1230unsignedHTMLDiagnostics::ProcessControlFlowPiece(
1237 HighlightRange(R, BugFileID, LPair.getStart().asRange().getBegin(),
1239 HighlightRange(R, BugFileID, LPair.getEnd().asRange().getBegin(),
1246voidHTMLDiagnostics::HighlightRange(
Rewriter& R,
FileIDBugFileID,
1248 const char*HighlightStart,
1249 const char*HighlightEnd) {
1254 unsignedStartLineNo =
SM.getExpansionLineNumber(InstantiationStart);
1257 unsignedEndLineNo =
SM.getExpansionLineNumber(InstantiationEnd);
1259 if(EndLineNo < StartLineNo)
1262 if(
SM.getFileID(InstantiationStart) != BugFileID ||
1263 SM.getFileID(InstantiationEnd) != BugFileID)
1267 unsignedEndColNo =
SM.getExpansionColumnNumber(InstantiationEnd);
1268 unsignedOldEndColNo = EndColNo;
1284StringRef HTMLDiagnostics::generateKeyboardNavigationJavascript() {
1286<script type='text/javascript'> 1287var digitMatcher = new RegExp("[0-9]+"); 1289var querySelectorAllArray = function(selector) { 1290 return Array.prototype.slice.call( 1291 document.querySelectorAll(selector)); 1294document.addEventListener("DOMContentLoaded", function() { 1295 querySelectorAllArray(".PathNav > a").forEach( 1296 function(currentValue, currentIndex) { 1297 var hrefValue = currentValue.getAttribute("href"); 1298 currentValue.onclick = function() { 1299 scrollTo(document.querySelector(hrefValue)); 1305var findNum = function() { 1306 var s = document.querySelector(".msg.selected"); 1307 if (!s || s.id == "EndPath") { 1310 var out = parseInt(digitMatcher.exec(s.id)[0]); 1314var classListAdd = function(el, theClass) { 1315 if(!el.className.baseVal) 1316 el.className += " " + theClass; 1318 el.className.baseVal += " " + theClass; 1321var classListRemove = function(el, theClass) { 1322 var className = (!el.className.baseVal) ? 1323 el.className : el.className.baseVal; 1324 className = className.replace(" " + theClass, ""); 1325 if(!el.className.baseVal) 1326 el.className = className; 1328 el.className.baseVal = className; 1331var scrollTo = function(el) { 1332 querySelectorAllArray(".selected").forEach(function(s) { 1333 classListRemove(s, "selected"); 1335 classListAdd(el, "selected"); 1336 window.scrollBy(0, el.getBoundingClientRect().top - 1337 (window.innerHeight / 2)); 1338 highlightArrowsForSelectedEvent(); 1341var move = function(num, up, numItems) { 1342 if (num == 1 && up || num == numItems - 1 && !up) { 1344 } else if (num == 0 && up) { 1345 return numItems - 1; 1346 } else if (num == 0 && !up) { 1347 return 1 % numItems; 1349 return up ? num - 1 : num + 1; 1352var numToId = function(num) { 1354 return document.getElementById("EndPath") 1356 return document.getElementById("Path" + num); 1359var navigateTo = function(up) { 1360 var numItems = document.querySelectorAll( 1361 ".line > .msgEvent, .line > .msgControl").length; 1362 var currentSelected = findNum(); 1363 var newSelected = move(currentSelected, up, numItems); 1364 var newEl = numToId(newSelected, numItems); 1366 // Scroll element into center. 1370window.addEventListener("keydown", function (event) { 1371 if (event.defaultPrevented) { 1375 if (event.keyCode == 74) { 1376 navigateTo(/*up=*/false); 1378 } else if (event.keyCode == 75) { 1379 navigateTo(/*up=*/true); 1383 event.preventDefault(); 1389StringRef HTMLDiagnostics::generateArrowDrawingJavascript() { 1391<script type='text/javascript'> 1392// Return range of numbers from a range [lower, upper). 1393function range(lower, upper) { 1395 for (var i = lower; i <= upper; ++i) { 1401var getRelatedArrowIndices = function(pathId) { 1402 // HTML numeration of events is a bit different than it is in the path. 1403 // Everything is rotated one step to the right, so the last element 1404 // (error diagnostic) has index 0. 1406 // arrowIndices has at least 2 elements 1407 pathId = arrowIndices.length - 1; 1410 return range(arrowIndices[pathId], arrowIndices[pathId - 1]); 1413var highlightArrowsForSelectedEvent = function() { 1414 const selectedNum = findNum(); 1415 const arrowIndicesToHighlight = getRelatedArrowIndices(selectedNum); 1416 arrowIndicesToHighlight.forEach((index) => { 1417 var arrow = document.querySelector("#arrow" + index); 1419 classListAdd(arrow, "selected") 1424var getAbsoluteBoundingRect = function(element) { 1425 const relative = element.getBoundingClientRect(); 1427 left: relative.left + window.pageXOffset, 1428 right: relative.right + window.pageXOffset, 1429 top: relative.top + window.pageYOffset, 1430 bottom: relative.bottom + window.pageYOffset, 1431 height: relative.height, 1432 width: relative.width 1436var drawArrow = function(index) { 1437 // This function is based on the great answer from SO: 1438 // https://stackoverflow.com/a/39575674/11582326 1439 var start = document.querySelector("#start" + index); 1440 var end = document.querySelector("#end" + index); 1441 var arrow = document.querySelector("#arrow" + index); 1443 var startRect = getAbsoluteBoundingRect(start); 1444 var endRect = getAbsoluteBoundingRect(end); 1446 // It is an arrow from a token to itself, no need to visualize it. 1447 if (startRect.top == endRect.top && 1448 startRect.left == endRect.left) 1451 // Each arrow is a very simple Bézier curve, with two nodes and 1452 // two handles. So, we need to calculate four points in the window: 1454 var posStart = { x: 0, y: 0 }; 1456 var posEnd = { x: 0, y: 0 }; 1457 // * handle for the start node 1458 var startHandle = { x: 0, y: 0 }; 1459 // * handle for the end node 1460 var endHandle = { x: 0, y: 0 }; 1461 // One can visualize it as follows: 1477 // NOTE: (0, 0) is the top left corner of the window. 1479 // We have 3 similar, but still different scenarios to cover: 1481 // 1. Two tokens on different lines. 1486 // In this situation, we draw arrow on the left curving to the left. 1487 // 2. Two tokens on the same line, and the destination is on the right. 1492 // In this situation, we draw arrow above curving upwards. 1493 // 3. Two tokens on the same line, and the destination is on the left. 1497 // In this situation, we draw arrow below curving downwards. 1498 const onDifferentLines = startRect.top <= endRect.top - 5 || 1499 startRect.top >= endRect.top + 5; 1500 const leftToRight = startRect.left < endRect.left; 1502 // NOTE: various magic constants are chosen empirically for 1503 // better positioning and look 1504 if (onDifferentLines) { 1506 const topToBottom = startRect.top < endRect.top; 1507 posStart.x = startRect.left - 1; 1508 // We don't want to start it at the top left corner of the token, 1509 // it doesn't feel like this is where the arrow comes from. 1510 // For this reason, we start it in the middle of the left side 1512 posStart.y = startRect.top + startRect.height / 2; 1514 // End node has arrow head and we give it a bit more space. 1515 posEnd.x = endRect.left - 4; 1516 posEnd.y = endRect.top; 1518 // Utility object with x and y offsets for handles. 1520 // We want bottom-to-top arrow to curve a bit more, so it doesn't 1521 // overlap much with top-to-bottom curves (much more frequent). 1522 x: topToBottom ? 15 : 25, 1523 y: Math.min((posEnd.y - posStart.y) / 3, 10) 1526 // When destination is on the different line, we can make a 1527 // curvier arrow because we have space for it. 1528 // So, instead of using 1530 // startHandle.x = posStart.x - curvature.x 1531 // endHandle.x = posEnd.x - curvature.x 1533 // We use the leftmost of these two values for both handles. 1534 startHandle.x = Math.min(posStart.x, posEnd.x) - curvature.x; 1535 endHandle.x = startHandle.x; 1537 // Curving downwards from the start node... 1538 startHandle.y = posStart.y + curvature.y; 1539 // ... and upwards from the end node. 1540 endHandle.y = posEnd.y - curvature.y; 1542 } else if (leftToRight) { 1544 // Starting from the top right corner... 1545 posStart.x = startRect.right - 1; 1546 posStart.y = startRect.top; 1548 // ...and ending at the top left corner of the end token. 1549 posEnd.x = endRect.left + 1; 1550 posEnd.y = endRect.top - 1; 1552 // Utility object with x and y offsets for handles. 1554 x: Math.min((posEnd.x - posStart.x) / 3, 15), 1558 // Curving to the right... 1559 startHandle.x = posStart.x + curvature.x; 1560 // ... and upwards from the start node. 1561 startHandle.y = posStart.y - curvature.y; 1563 // And to the left... 1564 endHandle.x = posEnd.x - curvature.x; 1565 // ... and upwards from the end node. 1566 endHandle.y = posEnd.y - curvature.y; 1570 // Starting from the bottom right corner... 1571 posStart.x = startRect.right; 1572 posStart.y = startRect.bottom; 1574 // ...and ending also at the bottom right corner, but of the end token. 1575 posEnd.x = endRect.right - 1; 1576 posEnd.y = endRect.bottom + 1; 1578 // Utility object with x and y offsets for handles. 1580 x: Math.min((posStart.x - posEnd.x) / 3, 15), 1584 // Curving to the left... 1585 startHandle.x = posStart.x - curvature.x; 1586 // ... and downwards from the start node. 1587 startHandle.y = posStart.y + curvature.y; 1589 // And to the right... 1590 endHandle.x = posEnd.x + curvature.x; 1591 // ... and downwards from the end node. 1592 endHandle.y = posEnd.y + curvature.y; 1595 // Put it all together into a path. 1596 // More information on the format: 1597 // https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths 1598 var pathStr = "M" + posStart.x + "," + posStart.y + " " + 1599 "C" + startHandle.x + "," + startHandle.y + " " + 1600 endHandle.x + "," + endHandle.y + " " + 1601 posEnd.x + "," + posEnd.y; 1603 arrow.setAttribute("d", pathStr); 1606var drawArrows = function() { 1607 const numOfArrows = document.querySelectorAll("path[id^=arrow]").length; 1608 for (var i = 0; i < numOfArrows; ++i) { 1613var toggleArrows = function(event) { 1614 const arrows = document.querySelector("#arrows"); 1615 if (event.target.checked) { 1616 arrows.setAttribute("visibility", "visible"); 1618 arrows.setAttribute("visibility", "hidden"); 1622window.addEventListener("resize", drawArrows); 1623document.addEventListener("DOMContentLoaded", function() { 1624 // Whenever we show invocation, locations change, i.e. we 1625 // need to redraw arrows. 1627 .querySelector('input[id="showinvocation"]') 1628 .addEventListener("click", drawArrows); 1629 // Hiding irrelevant lines also should cause arrow rerender. 1631 .querySelector('input[name="showCounterexample"]') 1632 .addEventListener("change", drawArrows); 1634 .querySelector('input[name="showArrows"]') 1635 .addEventListener("change", toggleArrows); 1637 // Default highlighting for the last event. 1638 highlightArrowsForSelectedEvent();Defines the clang::FileManager interface and associated types.
static bool shouldDisplayPopUpRange(const SourceRange &Range)
static void EmitAlphaCounter(raw_ostream &os, unsigned n)
static std::string getSpanBeginForControl(const char *ClassName, unsigned Index)
static llvm::SmallString< 32 > getIssueHash(const PathDiagnostic &D, const Preprocessor &PP)
static void HandlePopUpPieceStartTag(Rewriter &R, const std::vector< SourceRange > &PopUpRanges)
static std::string getSpanBeginForControlEnd(unsigned Index)
static void HandlePopUpPieceEndTag(Rewriter &R, const PathDiagnosticPopUpPiece &Piece, std::vector< SourceRange > &PopUpRanges, unsigned int LastReportedPieceIndex, unsigned int PopUpPieceIndex)
static std::string getSpanBeginForControlStart(unsigned Index)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
Defines the clang::Preprocessor interface.
static std::string getName(const CallEvent &Call)
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
__DEVICE__ int max(int __a, int __b)
__device__ __2f16 float __ockl_bool s
__device__ __2f16 float c
Decl - This represents one declaration (or definition), e.g.
SourceLocation getLocation() const
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
StringRef getName() const
The name of this FileEntry.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
A SourceLocation and its associated SourceManager.
FullSourceLoc getExpansionLoc() const
const char * getCharacterData(bool *Invalid=nullptr) const
StringRef getBufferData(bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
std::pair< FileID, unsigned > getDecomposedLoc() const
Decompose the specified location into a raw FileID + Offset pair.
const SourceManager & getManager() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
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 ...
MacroExpansionContext tracks the macro expansions processed by the Preprocessor.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
SourceManager & getSourceManager() const
const LangOptions & getLangOpts() const
Rewriter - This is the main interface to the rewrite buffers.
bool InsertTextBefore(SourceLocation Loc, StringRef Str)
InsertText - Insert the specified string at the specified location in the original buffer.
SourceManager & getSourceMgr() const
const LangOptions & getLangOpts() const
const llvm::RewriteBuffer * getRewriteBufferFor(FileID FID) const
getRewriteBufferFor - Return the rewrite buffer for the specified FileID.
bool InsertTextAfter(SourceLocation Loc, StringRef Str)
InsertTextAfter - Insert the specified string at the specified location in the original buffer.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
SourceLocation getLocForEndOfFile(FileID FID) const
Return the source location corresponding to the last byte of the specified file.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID.
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
Token - This structure provides full information about a lexed token.
unsigned getLength() const
This class is used for tools that requires cross translation unit capability.
@ Everything
Used for HTML, shows both "arrows" and control notes.
virtual void FlushDiagnosticsImpl(std::vector< const PathDiagnostic * > &Diags, FilesMade *filesMade)=0
virtual bool supportsCrossFileDiagnostics() const
Return true if the PathDiagnosticConsumer supports individual PathDiagnostics that span multiple file...
virtual StringRef getName() const =0
virtual PathGenerationScheme getGenerationScheme() const
void FlushDiagnostics(FilesMade *FilesMade)
PathDiagnosticRange asRange() const
FullSourceLoc asLocation() const
StringRef getString() const
PathDiagnosticLocation getLocation() const override
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
A Range represents the closed range [from, to].
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
void AddHeaderFooterInternalBuiltinCSS(Rewriter &R, FileID FID, StringRef title)
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.
RelexRewriteCacheRef instantiateRelexRewriteCache()
If you need to rewrite the same file multiple times, you can instantiate a RelexRewriteCache and refe...
void AddLineNumbers(Rewriter &R, FileID FID)
void SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP, RelexRewriteCacheRef Cache=nullptr)
SyntaxHighlight - Relex the specified FileID and annotate the HTML with information about keywords,...
void HighlightMacros(Rewriter &R, FileID FID, const Preprocessor &PP, RelexRewriteCacheRef Cache=nullptr)
HighlightMacros - This uses the macro table state from the end of the file, to reexpand macros and in...
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 ...
std::shared_ptr< RelexRewriteCache > RelexRewriteCacheRef
The JSON file list parser is used to communicate input to InstallAPI.
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ASTContext::SectionInfo &Section)
Insertion operator for diagnostics.
These options tweak the behavior of path diangostic consumers.
bool ShouldWriteVerboseReportFilename
If the consumer intends to produce multiple output files, should it use a pseudo-random file name or ...
std::string ToolInvocation
Run-line of the tool that produced the diagnostic.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4