static void ReportEvent(llvm::raw_ostream& o, const PathDiagnosticPiece& P, const FIDMap& FM, const SourceManager &SM, const LangOptions &LangOpts, unsigned indent) { Indent(o, indent) << "<dict>\n"; ++indent; Indent(o, indent) << "<key>kind</key><string>event</string>\n"; // Output the location. FullSourceLoc L = P.getLocation().asLocation(); Indent(o, indent) << "<key>location</key>\n"; EmitLocation(o, SM, LangOpts, L, FM, indent); // Output the ranges (if any). PathDiagnosticPiece::range_iterator RI = P.ranges_begin(), RE = P.ranges_end(); if (RI != RE) { Indent(o, indent) << "<key>ranges</key>\n"; Indent(o, indent) << "<array>\n"; ++indent; for (; RI != RE; ++RI) EmitRange(o, SM, LangOpts, *RI, FM, indent+1); --indent; Indent(o, indent) << "</array>\n"; } // Output the text. assert(!P.getString().empty()); Indent(o, indent) << "<key>extended_message</key>\n"; Indent(o, indent); EmitString(o, P.getString()) << '\n'; // Output the short text. // FIXME: Really use a short string. Indent(o, indent) << "<key>message</key>\n"; EmitString(o, P.getString()) << '\n'; // Finish up. --indent; Indent(o, indent); o << "</dict>\n"; }
void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, const PathDiagnosticPiece& P, unsigned num, unsigned max) { // For now, just draw a box above the line in question, and emit the // warning. FullSourceLoc Pos = P.getLocation().asLocation(); if (!Pos.isValid()) return; SourceManager &SM = R.getSourceMgr(); assert(&Pos.getManager() == &SM && "SourceManagers are different!"); std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedExpansionLoc(Pos); if (LPosInfo.first != BugFileID) return; const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first); const char* FileStart = Buf->getBufferStart(); // Compute the column number. Rewind from the current position to the start // of the line. unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second); const char *TokInstantiationPtr =Pos.getExpansionLoc().getCharacterData(); const char *LineStart = TokInstantiationPtr-ColNo; // Compute LineEnd. const char *LineEnd = TokInstantiationPtr; const char* FileEnd = Buf->getBufferEnd(); while (*LineEnd != '\n' && LineEnd != FileEnd) ++LineEnd; // Compute the margin offset by counting tabs and non-tabs. unsigned PosNo = 0; for (const char* c = LineStart; c != TokInstantiationPtr; ++c) PosNo += *c == '\t' ? 8 : 1; // Create the html for the message. const char *Kind = 0; switch (P.getKind()) { case PathDiagnosticPiece::Call: llvm_unreachable("Calls should already be handled"); case PathDiagnosticPiece::Event: Kind = "Event"; break; case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break; // Setting Kind to "Control" is intentional. case PathDiagnosticPiece::Macro: Kind = "Control"; break; } std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\""; if (num == max) os << "EndPath"; else os << "Path" << num; os << "\" class=\"msg"; if (Kind) os << " msg" << Kind; os << "\" style=\"margin-left:" << PosNo << "ex"; // Output a maximum size. if (!isa<PathDiagnosticMacroPiece>(P)) { // Get the string and determining its maximum substring. const std::string& Msg = P.getString(); unsigned max_token = 0; unsigned cnt = 0; unsigned len = Msg.size(); for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I) switch (*I) { default: ++cnt; continue; case ' ': case '\t': case '\n': if (cnt > max_token) max_token = cnt; cnt = 0; } if (cnt > max_token) max_token = cnt; // Determine the approximate size of the message bubble in em. unsigned em; const unsigned max_line = 120; if (max_token >= max_line) em = max_token / 2; else { unsigned characters = max_line; unsigned lines = len / max_line; if (lines > 0) { for (; characters > max_token; --characters) if (len / characters > lines) { ++characters; break; } } em = characters / 2; } if (em < max_line/2) os << "; max-width:" << em << "em"; } else os << "; max-width:100em"; os << "\">"; if (max > 1) { os << "<table class=\"msgT\"><tr><td valign=\"top\">"; os << "<div class=\"PathIndex"; if (Kind) os << " PathIndex" << Kind; os << "\">" << num << "</div>"; if (num > 1) { os << "</td><td><div class=\"PathNav\"><a href=\"#Path" << (num - 1) << "\" title=\"Previous event (" << (num - 1) << ")\">←</a></div></td>"; } os << "</td><td>"; } if (const PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(&P)) { os << "Within the expansion of the macro '"; // Get the name of the macro by relexing it. { FullSourceLoc L = MP->getLocation().asLocation().getExpansionLoc(); assert(L.isFileID()); StringRef BufferInfo = L.getBufferData(); std::pair<FileID, unsigned> LocInfo = L.getDecomposedLoc(); const char* MacroName = LocInfo.second + BufferInfo.data(); Lexer rawLexer(SM.getLocForStartOfFile(LocInfo.first), PP.getLangOpts(), BufferInfo.begin(), MacroName, BufferInfo.end()); Token TheTok; rawLexer.LexFromRawLexer(TheTok); for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i) os << MacroName[i]; } os << "':\n"; if (max > 1) { os << "</td>"; if (num < max) { os << "<td><div class=\"PathNav\"><a href=\"#"; if (num == max - 1) os << "EndPath"; else os << "Path" << (num + 1); os << "\" title=\"Next event (" << (num + 1) << ")\">→</a></div></td>"; } os << "</tr></table>"; } // Within a macro piece. Write out each event. ProcessMacroPiece(os, *MP, 0); } else { os << html::EscapeText(P.getString()); if (max > 1) { os << "</td>"; if (num < max) { os << "<td><div class=\"PathNav\"><a href=\"#"; if (num == max - 1) os << "EndPath"; else os << "Path" << (num + 1); os << "\" title=\"Next event (" << (num + 1) << ")\">→</a></div></td>"; } os << "</tr></table>"; } } os << "</div></td></tr>"; // Insert the new html. unsigned DisplayPos = LineEnd - FileStart; SourceLocation Loc = SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos); R.InsertTextBefore(Loc, os.str()); // Now highlight the ranges. for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end(); I != E; ++I) HighlightRange(R, LPosInfo.first, *I); #if 0 // If there is a code insertion hint, insert that code. // FIXME: This code is disabled because it seems to mangle the HTML // output. I'm leaving it here because it's generally the right idea, // but needs some help from someone more familiar with the rewriter. for (const FixItHint *Hint = P.fixit_begin(), *HintEnd = P.fixit_end(); Hint != HintEnd; ++Hint) { if (Hint->RemoveRange.isValid()) { HighlightRange(R, LPosInfo.first, Hint->RemoveRange, "<span class=\"CodeRemovalHint\">", "</span>"); } if (Hint->InsertionLoc.isValid()) { std::string EscapedCode = html::EscapeText(Hint->CodeToInsert, true); EscapedCode = "<span class=\"CodeInsertionHint\">" + EscapedCode + "</span>"; R.InsertTextBefore(Hint->InsertionLoc, EscapedCode); } } #endif }