zcov: / lib/Frontend/HTMLDiagnostics.cpp


Files: 1 Branches Taken: 50.0% 78 / 156
Generated: 2010-02-10 01:31 Branches Executed: 83.3% 130 / 156
Line Coverage: 71.7% 175 / 244


Programs: 1 Runs 2897


       1                 : //===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- 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 HTMLDiagnostics object.
      11                 : //
      12                 : //===----------------------------------------------------------------------===//
      13                 : 
      14                 : #include "clang/Frontend/PathDiagnosticClients.h"
      15                 : #include "clang/Checker/BugReporter/PathDiagnostic.h"
      16                 : #include "clang/AST/ASTContext.h"
      17                 : #include "clang/AST/Decl.h"
      18                 : #include "clang/Basic/SourceManager.h"
      19                 : #include "clang/Basic/FileManager.h"
      20                 : #include "clang/Rewrite/Rewriter.h"
      21                 : #include "clang/Rewrite/HTMLRewrite.h"
      22                 : #include "clang/Lex/Lexer.h"
      23                 : #include "clang/Lex/Preprocessor.h"
      24                 : #include "llvm/Support/MemoryBuffer.h"
      25                 : #include "llvm/Support/raw_ostream.h"
      26                 : #include "llvm/System/Path.h"
      27                 : 
      28                 : using namespace clang;
      29                 : 
      30                 : //===----------------------------------------------------------------------===//
      31                 : // Boilerplate.
      32                 : //===----------------------------------------------------------------------===//
      33                 : 
      34                 : namespace {
      35                 : 
      36                 : class HTMLDiagnostics : public PathDiagnosticClient {
      37                 :   llvm::sys::Path Directory, FilePrefix;
      38                 :   bool createdDir, noDir;
      39                 :   const Preprocessor &PP;
      40                 :   std::vector<const PathDiagnostic*> BatchedDiags;
      41                 : public:
      42                 :   HTMLDiagnostics(const std::string& prefix, const Preprocessor &pp);
      43                 :   
                        1: branch 5 taken
                        0: branch 6 not taken
                        0: branch 13 not taken
                        0: branch 14 not taken
      44                1:   virtual ~HTMLDiagnostics() { FlushDiagnostics(NULL); }
      45                 :   
      46                 :   virtual void FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade);
      47                 : 
      48                 :   virtual void HandlePathDiagnostic(const PathDiagnostic* D);
      49                 :   
      50                0:   virtual llvm::StringRef getName() const {
      51                0:     return "HTMLDiagnostics";
      52                 :   }
      53                 : 
      54                 :   unsigned ProcessMacroPiece(llvm::raw_ostream& os,
      55                 :                              const PathDiagnosticMacroPiece& P,
      56                 :                              unsigned num);
      57                 : 
      58                 :   void HandlePiece(Rewriter& R, FileID BugFileID,
      59                 :                    const PathDiagnosticPiece& P, unsigned num, unsigned max);
      60                 : 
      61                 :   void HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range,
      62                 :                       const char *HighlightStart = "<span class=\"mrange\">",
      63                 :                       const char *HighlightEnd = "</span>");
      64                 : 
      65                 :   void ReportDiag(const PathDiagnostic& D,
      66                 :                   llvm::SmallVectorImpl<std::string> *FilesMade);
      67                 : };
      68                 : 
      69                 : } // end anonymous namespace
      70                 : 
      71                 : HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
      72                1:                                  const Preprocessor &pp)
      73                 :   : Directory(prefix), FilePrefix(prefix), createdDir(false), noDir(false),
      74                1:     PP(pp) {
      75                 :   // All html files begin with "report"
      76                1:   FilePrefix.appendComponent("report");
      77                1: }
      78                 : 
      79                 : PathDiagnosticClient*
      80                 : clang::CreateHTMLDiagnosticClient(const std::string& prefix,
      81                1:                                   const Preprocessor &PP) {
      82                1:   return new HTMLDiagnostics(prefix, PP);
      83                 : }
      84                 : 
      85                 : //===----------------------------------------------------------------------===//
      86                 : // Report processing.
      87                 : //===----------------------------------------------------------------------===//
      88                 : 
      89                1: void HTMLDiagnostics::HandlePathDiagnostic(const PathDiagnostic* D) {
                        0: branch 0 not taken
                        1: branch 1 taken
      90                1:   if (!D)
      91                0:     return;
      92                 : 
                        0: branch 1 not taken
                        1: branch 2 taken
      93                1:   if (D->empty()) {
                        0: branch 0 not taken
                        0: branch 1 not taken
      94                0:     delete D;
      95                0:     return;
      96                 :   }
      97                 : 
      98                1:   const_cast<PathDiagnostic*>(D)->flattenLocations();
      99                1:   BatchedDiags.push_back(D);
     100                 : }
     101                 : 
     102                 : void
     103                2: HTMLDiagnostics::FlushDiagnostics(llvm::SmallVectorImpl<std::string> *FilesMade)
     104                 : {
                        1: branch 1 taken
                        2: branch 2 taken
     105                5:   while (!BatchedDiags.empty()) {
     106                1:     const PathDiagnostic* D = BatchedDiags.back();
     107                1:     BatchedDiags.pop_back();
     108                1:     ReportDiag(*D, FilesMade);
                        1: branch 0 taken
                        0: branch 1 not taken
     109                1:     delete D;
     110                 :   }
     111                 :   
     112                2:   BatchedDiags.clear();
     113                2: }
     114                 : 
     115                 : void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
     116                1:                                  llvm::SmallVectorImpl<std::string> *FilesMade){
     117                 :   // Create the HTML directory if it is missing.
                        1: branch 0 taken
                        0: branch 1 not taken
     118                1:   if (!createdDir) {
     119                1:     createdDir = true;
     120                1:     std::string ErrorMsg;
     121                1:     Directory.createDirectoryOnDisk(true, &ErrorMsg);
     122                 : 
                        0: branch 1 not taken
                        1: branch 2 taken
     123                1:     if (!Directory.isDirectory()) {
     124                 :       llvm::errs() << "warning: could not create directory '"
     125                 :                    << Directory.str() << "'\n"
     126                0:                    << "reason: " << ErrorMsg << '\n';
     127                 : 
     128                0:       noDir = true;
     129                 : 
     130                0:       return;
                        1: branch 1 taken
                        0: branch 2 not taken
     131                1:     }
     132                 :   }
     133                 : 
                        0: branch 0 not taken
                        1: branch 1 taken
     134                1:   if (noDir)
     135                0:     return;
     136                 : 
     137                1:   const SourceManager &SMgr = D.begin()->getLocation().getManager();
     138                1:   FileID FID;
     139                 : 
     140                 :   // Verify that the entire path is from the same FileID.
                        4: branch 4 taken
                        1: branch 5 taken
     141                5:   for (PathDiagnostic::const_iterator I = D.begin(), E = D.end(); I != E; ++I) {
     142                4:     FullSourceLoc L = I->getLocation().asLocation().getInstantiationLoc();
     143                 : 
                        1: branch 1 taken
                        3: branch 2 taken
     144                4:     if (FID.isInvalid()) {
     145                1:       FID = SMgr.getFileID(L);
                        0: branch 2 not taken
                        3: branch 3 taken
     146                3:     } else if (SMgr.getFileID(L) != FID)
     147                0:       return; // FIXME: Emit a warning?
     148                 : 
     149                 :     // Check the source ranges.
                        2: branch 2 taken
                        4: branch 3 taken
     150               10:     for (PathDiagnosticPiece::range_iterator RI=I->ranges_begin(),
     151                4:                                              RE=I->ranges_end(); RI!=RE; ++RI) {
     152                 : 
     153                2:       SourceLocation L = SMgr.getInstantiationLoc(RI->getBegin());
     154                 : 
                        2: branch 1 taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        2: branch 6 taken
                        0: branch 7 not taken
                        2: branch 8 taken
     155                2:       if (!L.isFileID() || SMgr.getFileID(L) != FID)
     156                0:         return; // FIXME: Emit a warning?
     157                 : 
     158                2:       L = SMgr.getInstantiationLoc(RI->getEnd());
     159                 : 
                        2: branch 1 taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        2: branch 6 taken
                        0: branch 7 not taken
                        2: branch 8 taken
     160                2:       if (!L.isFileID() || SMgr.getFileID(L) != FID)
     161                0:         return; // FIXME: Emit a warning?
     162                 :     }
     163                 :   }
     164                 : 
                        0: branch 1 not taken
                        1: branch 2 taken
     165                1:   if (FID.isInvalid())
     166                0:     return; // FIXME: Emit a warning?
     167                 : 
     168                 :   // Create a new rewriter to generate HTML.
     169                1:   Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOptions());
     170                 : 
     171                 :   // Process the path.
     172                1:   unsigned n = D.size();
     173                1:   unsigned max = n;
     174                 : 
                        4: branch 4 taken
                        1: branch 5 taken
     175                5:   for (PathDiagnostic::const_reverse_iterator I=D.rbegin(), E=D.rend();
     176                 :         I!=E; ++I, --n)
     177                4:     HandlePiece(R, FID, *I, n, max);
     178                 : 
     179                 :   // Add line numbers, header, footer, etc.
     180                 : 
     181                 :   // unsigned FID = R.getSourceMgr().getMainFileID();
     182                1:   html::EscapeText(R, FID);
     183                1:   html::AddLineNumbers(R, FID);
     184                 : 
     185                 :   // If we have a preprocessor, relex the file and syntax highlight.
     186                 :   // We might not have a preprocessor if we come from a deserialized AST file,
     187                 :   // for example.
     188                 : 
     189                1:   html::SyntaxHighlight(R, FID, PP);
     190                1:   html::HighlightMacros(R, FID, PP);
     191                 : 
     192                 :   // Get the full directory name of the analyzed file.
     193                 : 
     194                1:   const FileEntry* Entry = SMgr.getFileEntryForID(FID);
     195                 : 
     196                 :   // This is a cludge; basically we want to append either the full
     197                 :   // working directory if we have no directory information.  This is
     198                 :   // a work in progress.
     199                 : 
     200                1:   std::string DirName = "";
     201                 : 
                        0: branch 5 not taken
                        1: branch 6 taken
     202                1:   if (!llvm::sys::Path(Entry->getName()).isAbsolute()) {
     203                0:     llvm::sys::Path P = llvm::sys::Path::GetCurrentDirectory();
     204                0:     DirName = P.str() + "/";
     205                 :   }
     206                 : 
     207                 :   // Add the name of the file as an <h1> tag.
     208                 : 
     209                 :   {
     210                1:     std::string s;
     211                1:     llvm::raw_string_ostream os(s);
     212                 : 
     213                 :     os << "<!-- REPORTHEADER -->\n"
     214                 :       << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
     215                 :           "<tr><td class=\"rowname\">File:</td><td>"
     216                 :       << html::EscapeText(DirName)
     217                 :       << html::EscapeText(Entry->getName())
     218                 :       << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
     219                 :          "<a href=\"#EndPath\">line "
     220                 :       << (*D.rbegin()).getLocation().asLocation().getInstantiationLineNumber()
     221                 :       << ", column "
     222                 :       << (*D.rbegin()).getLocation().asLocation().getInstantiationColumnNumber()
     223                 :       << "</a></td></tr>\n"
     224                 :          "<tr><td class=\"rowname\">Description:</td><td>"
     225                1:       << D.getDescription() << "</td></tr>\n";
     226                 : 
     227                 :     // Output any other meta data.
     228                 : 
                        0: branch 4 not taken
                        1: branch 5 taken
     229                1:     for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
     230                 :          I!=E; ++I) {
     231                0:       os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
     232                 :     }
     233                 : 
     234                 :     os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n"
     235                1:           "<h3>Annotated Source Code</h3>\n";
     236                 : 
     237                1:     R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
     238                 :   }
     239                 : 
     240                 :   // Embed meta-data tags.
     241                 :   {
     242                1:     std::string s;
     243                1:     llvm::raw_string_ostream os(s);
     244                 : 
     245                1:     const std::string& BugDesc = D.getDescription();
                        1: branch 1 taken
                        0: branch 2 not taken
     246                1:     if (!BugDesc.empty())
     247                1:       os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
     248                 : 
     249                1:     const std::string& BugType = D.getBugType();
                        1: branch 1 taken
                        0: branch 2 not taken
     250                1:     if (!BugType.empty())
     251                1:       os << "\n<!-- BUGTYPE " << BugType << " -->\n";
     252                 : 
     253                1:     const std::string& BugCategory = D.getCategory();
                        1: branch 1 taken
                        0: branch 2 not taken
     254                1:     if (!BugCategory.empty())
     255                1:       os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
     256                 : 
     257                1:     os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
     258                 : 
     259                 :     os << "\n<!-- BUGLINE "
     260                 :        << D.back()->getLocation().asLocation().getInstantiationLineNumber()
     261                1:        << " -->\n";
     262                 : 
     263                1:     os << "\n<!-- BUGPATHLENGTH " << D.size() << " -->\n";
     264                 : 
     265                 :     // Mark the end of the tags.
     266                1:     os << "\n<!-- BUGMETAEND -->\n";
     267                 : 
     268                 :     // Insert the text.
     269                1:     R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
     270                 :   }
     271                 : 
     272                 :   // Add CSS, header, and footer.
     273                 : 
     274                1:   html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
     275                 : 
     276                 :   // Get the rewrite buffer.
     277                1:   const RewriteBuffer *Buf = R.getRewriteBufferFor(FID);
     278                 : 
                        0: branch 0 not taken
                        1: branch 1 taken
     279                1:   if (!Buf) {
     280                0:     llvm::errs() << "warning: no diagnostics generated for main file.\n";
     281                0:     return;
     282                 :   }
     283                 : 
     284                 :   // Create a path for the target HTML file.
     285                1:   llvm::sys::Path F(FilePrefix);
     286                1:   F.makeUnique(false, NULL);
     287                 : 
     288                 :   // Rename the file with an HTML extension.
     289                1:   llvm::sys::Path H(F);
     290                1:   H.appendSuffix("html");
     291                1:   F.renamePathOnDisk(H, NULL);
     292                 : 
     293                1:   std::string ErrorMsg;
     294                1:   llvm::raw_fd_ostream os(H.c_str(), ErrorMsg);
     295                 : 
                        0: branch 1 not taken
                        1: branch 2 taken
     296                1:   if (!ErrorMsg.empty()) {
     297                 :     (llvm::errs() << "warning: could not create file '" << F.str() 
     298                0:                   << "'\n").flush();
     299                 :     return;
     300                 :   }
     301                 : 
                        0: branch 0 not taken
                        1: branch 1 taken
     302                1:   if (FilesMade)
     303                0:     FilesMade->push_back(H.getLast());
     304                 : 
     305                 :   // Emit the HTML to disk.
                     6106: branch 4 taken
                        1: branch 5 taken
     306             6107:   for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
                        1: branch 3 taken
                        0: branch 4 not taken
                        1: branch 6 taken
                        0: branch 7 not taken
                        1: branch 9 taken
                        0: branch 10 not taken
                        1: branch 12 taken
                        0: branch 13 not taken
                        1: branch 15 taken
                        0: branch 16 not taken
                        1: branch 18 taken
                        0: branch 19 not taken
     307             6107:       os << *I;
     308                 : }
     309                 : 
     310                 : void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
     311                 :                                   const PathDiagnosticPiece& P,
     312                4:                                   unsigned num, unsigned max) {
     313                 : 
     314                 :   // For now, just draw a box above the line in question, and emit the
     315                 :   // warning.
     316                4:   FullSourceLoc Pos = P.getLocation().asLocation();
     317                 : 
                        0: branch 1 not taken
                        4: branch 2 taken
     318                4:   if (!Pos.isValid())
     319                0:     return;
     320                 : 
     321                4:   SourceManager &SM = R.getSourceMgr();
                        4: branch 1 taken
                        0: branch 2 not taken
     322                4:   assert(&Pos.getManager() == &SM && "SourceManagers are different!");
     323                4:   std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedInstantiationLoc(Pos);
     324                 : 
                        0: branch 1 not taken
                        4: branch 2 taken
     325                4:   if (LPosInfo.first != BugFileID)
     326                0:     return;
     327                 : 
     328                4:   const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first);
     329                4:   const char* FileStart = Buf->getBufferStart();
     330                 : 
     331                 :   // Compute the column number.  Rewind from the current position to the start
     332                 :   // of the line.
     333                4:   unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second);
     334                4:   const char *TokInstantiationPtr =Pos.getInstantiationLoc().getCharacterData();
     335                4:   const char *LineStart = TokInstantiationPtr-ColNo;
     336                 : 
     337                 :   // Compute LineEnd.
     338                4:   const char *LineEnd = TokInstantiationPtr;
     339                4:   const char* FileEnd = Buf->getBufferEnd();
                       39: branch 0 taken
                        4: branch 1 taken
                       39: branch 2 taken
                        0: branch 3 not taken
     340               47:   while (*LineEnd != '\n' && LineEnd != FileEnd)
     341               39:     ++LineEnd;
     342                 : 
     343                 :   // Compute the margin offset by counting tabs and non-tabs.
     344                4:   unsigned PosNo = 0;
                       18: branch 0 taken
                        4: branch 1 taken
     345               22:   for (const char* c = LineStart; c != TokInstantiationPtr; ++c)
                        0: branch 0 not taken
                       18: branch 1 taken
     346               18:     PosNo += *c == '\t' ? 8 : 1;
     347                 : 
     348                 :   // Create the html for the message.
     349                 : 
     350                4:   const char *Kind = 0;
                        2: branch 1 taken
                        2: branch 2 taken
                        0: branch 3 not taken
                        0: branch 4 not taken
     351                4:   switch (P.getKind()) {
     352                2:   case PathDiagnosticPiece::Event:  Kind = "Event"; break;
     353                2:   case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
     354                 :     // Setting Kind to "Control" is intentional.
     355                0:   case PathDiagnosticPiece::Macro: Kind = "Control"; break;
     356                 :   }
     357                 : 
     358                4:   std::string sbuf;
     359                4:   llvm::raw_string_ostream os(sbuf);
     360                 : 
     361                4:   os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\"";
     362                 : 
                        1: branch 0 taken
                        3: branch 1 taken
     363                4:   if (num == max)
     364                1:     os << "EndPath";
     365                 :   else
     366                3:     os << "Path" << num;
     367                 : 
     368                4:   os << "\" class=\"msg";
                        4: branch 0 taken
                        0: branch 1 not taken
     369                4:   if (Kind)
     370                4:     os << " msg" << Kind;
     371                4:   os << "\" style=\"margin-left:" << PosNo << "ex";
     372                 : 
     373                 :   // Output a maximum size.
                        4: branch 1 taken
                        0: branch 2 not taken
     374                4:   if (!isa<PathDiagnosticMacroPiece>(P)) {
     375                 :     // Get the string and determining its maximum substring.
     376                4:     const std::string& Msg = P.getString();
     377                4:     unsigned max_token = 0;
     378                4:     unsigned cnt = 0;
     379                4:     unsigned len = Msg.size();
     380                 : 
                      120: branch 4 taken
                        4: branch 5 taken
     381              124:     for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I)
                      104: branch 1 taken
                       16: branch 2 taken
     382              120:       switch (*I) {
     383                 :       default:
     384              104:         ++cnt;
     385              104:         continue;
     386                 :       case ' ':
     387                 :       case '\t':
     388                 :       case '\n':
                        5: branch 0 taken
                       11: branch 1 taken
     389               16:         if (cnt > max_token) max_token = cnt;
     390               16:         cnt = 0;
     391                 :       }
     392                 : 
                        0: branch 0 not taken
                        4: branch 1 taken
     393                4:     if (cnt > max_token)
     394                0:       max_token = cnt;
     395                 : 
     396                 :     // Determine the approximate size of the message bubble in em.
     397                 :     unsigned em;
     398                4:     const unsigned max_line = 120;
     399                 : 
                        0: branch 0 not taken
                        4: branch 1 taken
     400                4:     if (max_token >= max_line)
     401                0:       em = max_token / 2;
     402                 :     else {
     403                4:       unsigned characters = max_line;
     404                4:       unsigned lines = len / max_line;
     405                 : 
                        0: branch 0 not taken
                        4: branch 1 taken
     406                4:       if (lines > 0) {
                        0: branch 0 not taken
                        0: branch 1 not taken
     407                0:         for (; characters > max_token; --characters)
                        0: branch 0 not taken
                        0: branch 1 not taken
     408                0:           if (len / characters > lines) {
     409                0:             ++characters;
     410                0:             break;
     411                 :           }
     412                 :       }
     413                 : 
     414                4:       em = characters / 2;
     415                 :     }
     416                 : 
                        0: branch 0 not taken
                        4: branch 1 taken
     417                4:     if (em < max_line/2)
     418                0:       os << "; max-width:" << em << "em";
     419                 :   }
     420                 :   else
     421                0:     os << "; max-width:100em";
     422                 : 
     423                4:   os << "\">";
     424                 : 
                        4: branch 0 taken
                        0: branch 1 not taken
     425                4:   if (max > 1) {
     426                4:     os << "<table class=\"msgT\"><tr><td valign=\"top\">";
     427                4:     os << "<div class=\"PathIndex";
                        4: branch 0 taken
                        0: branch 1 not taken
     428                4:     if (Kind) os << " PathIndex" << Kind;
     429                4:     os << "\">" << num << "</div>";
     430                4:     os << "</td><td>";
     431                 :   }
     432                 : 
                        0: branch 0 not taken
                        4: branch 1 taken
     433                4:   if (const PathDiagnosticMacroPiece *MP =
     434                4:         dyn_cast<PathDiagnosticMacroPiece>(&P)) {
     435                 : 
     436                0:     os << "Within the expansion of the macro '";
     437                 : 
     438                 :     // Get the name of the macro by relexing it.
     439                 :     {
     440                0:       FullSourceLoc L = MP->getLocation().asLocation().getInstantiationLoc();
                        0: branch 1 not taken
                        0: branch 2 not taken
     441                0:       assert(L.isFileID());
     442                0:       std::pair<const char*, const char*> BufferInfo = L.getBufferData();
     443                0:       const char* MacroName = L.getDecomposedLoc().second + BufferInfo.first;
     444                 :       Lexer rawLexer(L, PP.getLangOptions(), BufferInfo.first,
     445                0:                      MacroName, BufferInfo.second);
     446                 : 
     447                0:       Token TheTok;
     448                0:       rawLexer.LexFromRawLexer(TheTok);
                        0: branch 1 not taken
                        0: branch 2 not taken
     449                0:       for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i)
     450                0:         os << MacroName[i];
     451                 :     }
     452                 : 
     453                0:     os << "':\n";
     454                 : 
                        0: branch 0 not taken
                        0: branch 1 not taken
     455                0:     if (max > 1)
     456                0:       os << "</td></tr></table>";
     457                 : 
     458                 :     // Within a macro piece.  Write out each event.
     459                0:     ProcessMacroPiece(os, *MP, 0);
     460                 :   }
     461                 :   else {
     462                4:     os << html::EscapeText(P.getString());
     463                 : 
                        4: branch 0 taken
                        0: branch 1 not taken
     464                4:     if (max > 1)
     465                4:       os << "</td></tr></table>";
     466                 :   }
     467                 : 
     468                4:   os << "</div></td></tr>";
     469                 : 
     470                 :   // Insert the new html.
     471                4:   unsigned DisplayPos = LineEnd - FileStart;
     472                 :   SourceLocation Loc =
     473                4:     SM.getLocForStartOfFile(LPosInfo.first).getFileLocWithOffset(DisplayPos);
     474                 : 
     475                4:   R.InsertTextBefore(Loc, os.str());
     476                 : 
     477                 :   // Now highlight the ranges.
                        2: branch 2 taken
                        4: branch 3 taken
     478                6:   for (const SourceRange *I = P.ranges_begin(), *E = P.ranges_end();
     479                 :         I != E; ++I)
     480                6:     HighlightRange(R, LPosInfo.first, *I);
     481                 : 
     482                 : #if 0
     483                 :   // If there is a code insertion hint, insert that code.
     484                 :   // FIXME: This code is disabled because it seems to mangle the HTML
     485                 :   // output. I'm leaving it here because it's generally the right idea,
     486                 :   // but needs some help from someone more familiar with the rewriter.
     487                 :   for (const CodeModificationHint *Hint = P.code_modifications_begin(),
     488                 :                                *HintEnd = P.code_modifications_end();
     489                 :        Hint != HintEnd; ++Hint) {
     490                 :     if (Hint->RemoveRange.isValid()) {
     491                 :       HighlightRange(R, LPosInfo.first, Hint->RemoveRange,
     492                 :                      "<span class=\"CodeRemovalHint\">", "</span>");
     493                 :     }
     494                 :     if (Hint->InsertionLoc.isValid()) {
     495                 :       std::string EscapedCode = html::EscapeText(Hint->CodeToInsert, true);
     496                 :       EscapedCode = "<span class=\"CodeInsertionHint\">" + EscapedCode
     497                 :         + "</span>";
     498                 :       R.InsertTextBefore(Hint->InsertionLoc, EscapedCode);
     499                 :     }
     500                 :   }
     501                 : #endif
     502                 : }
     503                 : 
     504                0: static void EmitAlphaCounter(llvm::raw_ostream& os, unsigned n) {
     505                0:   llvm::SmallVector<char, 10> buf;
     506                 : 
                        0: branch 0 not taken
                        0: branch 1 not taken
     507                0:   do {
     508                0:     unsigned x = n % ('z' - 'a');
     509                0:     buf.push_back('a' + x);
     510                0:     n = n / ('z' - 'a');
     511                 :   } while (n);
     512                 : 
                        0: branch 1 not taken
                        0: branch 2 not taken
     513                0:   assert(!buf.empty());
     514                 : 
                        0: branch 3 not taken
                        0: branch 4 not taken
     515                0:   for (llvm::SmallVectorImpl<char>::reverse_iterator I=buf.rbegin(),
     516                0:        E=buf.rend(); I!=E; ++I)
     517                0:     os << *I;
     518                0: }
     519                 : 
     520                 : unsigned HTMLDiagnostics::ProcessMacroPiece(llvm::raw_ostream& os,
     521                 :                                             const PathDiagnosticMacroPiece& P,
     522                0:                                             unsigned num) {
     523                 : 
                        0: branch 4 not taken
                        0: branch 5 not taken
     524                0:   for (PathDiagnosticMacroPiece::const_iterator I=P.begin(), E=P.end();
     525                 :         I!=E; ++I) {
     526                 : 
                        0: branch 0 not taken
                        0: branch 1 not taken
     527                0:     if (const PathDiagnosticMacroPiece *MP =
     528                0:           dyn_cast<PathDiagnosticMacroPiece>(*I)) {
     529                0:       num = ProcessMacroPiece(os, *MP, num);
     530                0:       continue;
     531                 :     }
     532                 : 
                        0: branch 2 not taken
                        0: branch 3 not taken
     533                0:     if (PathDiagnosticEventPiece *EP = dyn_cast<PathDiagnosticEventPiece>(*I)) {
     534                 :       os << "<div class=\"msg msgEvent\" style=\"width:94%; "
     535                 :             "margin-left:5px\">"
     536                 :             "<table class=\"msgT\"><tr>"
     537                0:             "<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">";
     538                0:       EmitAlphaCounter(os, num++);
     539                 :       os << "</div></td><td valign=\"top\">"
     540                 :          << html::EscapeText(EP->getString())
     541                0:          << "</td></tr></table></div>\n";
     542                 :     }
     543                 :   }
     544                 : 
     545                0:   return num;
     546                 : }
     547                 : 
     548                 : void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
     549                 :                                      SourceRange Range,
     550                 :                                      const char *HighlightStart,
     551                2:                                      const char *HighlightEnd) {
     552                2:   SourceManager &SM = R.getSourceMgr();
     553                2:   const LangOptions &LangOpts = R.getLangOpts();
     554                 : 
     555                2:   SourceLocation InstantiationStart = SM.getInstantiationLoc(Range.getBegin());
     556                2:   unsigned StartLineNo = SM.getInstantiationLineNumber(InstantiationStart);
     557                 : 
     558                2:   SourceLocation InstantiationEnd = SM.getInstantiationLoc(Range.getEnd());
     559                2:   unsigned EndLineNo = SM.getInstantiationLineNumber(InstantiationEnd);
     560                 : 
                        0: branch 0 not taken
                        2: branch 1 taken
     561                2:   if (EndLineNo < StartLineNo)
     562                0:     return;
     563                 : 
                        2: branch 2 taken
                        0: branch 3 not taken
                        0: branch 6 not taken
                        2: branch 7 taken
                        0: branch 8 not taken
                        2: branch 9 taken
     564                2:   if (SM.getFileID(InstantiationStart) != BugFileID ||
     565                 :       SM.getFileID(InstantiationEnd) != BugFileID)
     566                0:     return;
     567                 : 
     568                 :   // Compute the column number of the end.
     569                2:   unsigned EndColNo = SM.getInstantiationColumnNumber(InstantiationEnd);
     570                2:   unsigned OldEndColNo = EndColNo;
     571                 : 
                        2: branch 0 taken
                        0: branch 1 not taken
     572                2:   if (EndColNo) {
     573                 :     // Add in the length of the token, so that we cover multi-char tokens.
     574                2:     EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1;
     575                 :   }
     576                 : 
     577                 :   // Highlight the range.  Make the span tag the outermost tag for the
     578                 :   // selected range.
     579                 : 
     580                 :   SourceLocation E =
     581                2:     InstantiationEnd.getFileLocWithOffset(EndColNo - OldEndColNo);
     582                 : 
     583                2:   html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd);
     584                 : }

Generated: 2010-02-10 01:31 by zcov