Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 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 | |
David Blaikie | 0cc4943 | 2011-09-27 01:43:33 +0000 | [diff] [blame] | 14 | #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" |
Daniel Dunbar | 221fa94 | 2008-08-11 04:54:23 +0000 | [diff] [blame] | 15 | #include "clang/AST/ASTContext.h" |
| 16 | #include "clang/AST/Decl.h" |
Ted Kremenek | 8cc4842 | 2008-03-27 07:35:49 +0000 | [diff] [blame] | 17 | #include "clang/Basic/FileManager.h" |
Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 18 | #include "clang/Basic/SourceManager.h" |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 19 | #include "clang/Lex/Lexer.h" |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 20 | #include "clang/Lex/Preprocessor.h" |
Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 21 | #include "clang/Rewrite/Core/HTMLRewrite.h" |
| 22 | #include "clang/Rewrite/Core/Rewriter.h" |
| 23 | #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" |
Chandler Carruth | 0d9593d | 2015-01-14 11:29:14 +0000 | [diff] [blame] | 24 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
Michael J. Spencer | e503f89 | 2011-01-11 01:21:20 +0000 | [diff] [blame] | 25 | #include "llvm/Support/FileSystem.h" |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 26 | #include "llvm/Support/MemoryBuffer.h" |
Michael J. Spencer | 8aaf499 | 2010-11-29 18:12:39 +0000 | [diff] [blame] | 27 | #include "llvm/Support/Path.h" |
Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 28 | #include "llvm/Support/raw_ostream.h" |
Sylvestre Ledru | 06aebc4 | 2014-06-14 09:28:27 +0000 | [diff] [blame] | 29 | #include <sstream> |
Ted Kremenek | 490b8c0 | 2009-10-08 17:44:41 +0000 | [diff] [blame] | 30 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 31 | using namespace clang; |
Ted Kremenek | 98857c9 | 2010-12-23 07:20:52 +0000 | [diff] [blame] | 32 | using namespace ento; |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 33 | |
| 34 | //===----------------------------------------------------------------------===// |
| 35 | // Boilerplate. |
| 36 | //===----------------------------------------------------------------------===// |
| 37 | |
| 38 | namespace { |
| 39 | |
David Blaikie | 53c125d | 2011-09-26 00:51:36 +0000 | [diff] [blame] | 40 | class HTMLDiagnostics : public PathDiagnosticConsumer { |
Benjamin Kramer | fbf914c | 2013-06-12 18:13:05 +0000 | [diff] [blame] | 41 | std::string Directory; |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 42 | bool createdDir, noDir; |
Daniel Dunbar | b5f2025 | 2009-11-05 02:41:58 +0000 | [diff] [blame] | 43 | const Preprocessor &PP; |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 44 | AnalyzerOptions &AnalyzerOpts; |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 45 | public: |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 46 | HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp); |
Kovarththanan Rajaratnam | ba2c652 | 2010-03-13 10:17:05 +0000 | [diff] [blame] | 47 | |
Alexander Kornienko | 34eb207 | 2015-04-11 02:00:23 +0000 | [diff] [blame^] | 48 | ~HTMLDiagnostics() override { FlushDiagnostics(nullptr); } |
Kovarththanan Rajaratnam | ba2c652 | 2010-03-13 10:17:05 +0000 | [diff] [blame] | 49 | |
Craig Topper | fb6b25b | 2014-03-15 04:29:04 +0000 | [diff] [blame] | 50 | void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, |
| 51 | FilesMade *filesMade) override; |
Kovarththanan Rajaratnam | ba2c652 | 2010-03-13 10:17:05 +0000 | [diff] [blame] | 52 | |
Craig Topper | fb6b25b | 2014-03-15 04:29:04 +0000 | [diff] [blame] | 53 | StringRef getName() const override { |
Ted Kremenek | 5e86044 | 2009-11-05 02:09:23 +0000 | [diff] [blame] | 54 | return "HTMLDiagnostics"; |
| 55 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 56 | |
Ted Kremenek | 5ef32db | 2011-08-12 23:37:29 +0000 | [diff] [blame] | 57 | unsigned ProcessMacroPiece(raw_ostream &os, |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 58 | const PathDiagnosticMacroPiece& P, |
| 59 | unsigned num); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 60 | |
Chris Lattner | d32480d | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 61 | void HandlePiece(Rewriter& R, FileID BugFileID, |
Ted Kremenek | c99332c | 2008-07-23 23:18:15 +0000 | [diff] [blame] | 62 | const PathDiagnosticPiece& P, unsigned num, unsigned max); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 63 | |
Douglas Gregor | 87f95b0 | 2009-02-26 21:00:50 +0000 | [diff] [blame] | 64 | void HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range, |
| 65 | const char *HighlightStart = "<span class=\"mrange\">", |
| 66 | const char *HighlightEnd = "</span>"); |
Ted Kremenek | 9718c9e | 2008-04-22 16:15:03 +0000 | [diff] [blame] | 67 | |
Ted Kremenek | 5e86044 | 2009-11-05 02:09:23 +0000 | [diff] [blame] | 68 | void ReportDiag(const PathDiagnostic& D, |
Ted Kremenek | 9bf9af9 | 2012-08-16 17:45:23 +0000 | [diff] [blame] | 69 | FilesMade *filesMade); |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 70 | }; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 71 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 72 | } // end anonymous namespace |
| 73 | |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 74 | HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, |
| 75 | const std::string& prefix, |
Daniel Dunbar | b5f2025 | 2009-11-05 02:41:58 +0000 | [diff] [blame] | 76 | const Preprocessor &pp) |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 77 | : Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) { |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 78 | } |
| 79 | |
Ted Kremenek | 3a081a0 | 2012-12-19 01:35:35 +0000 | [diff] [blame] | 80 | void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, |
| 81 | PathDiagnosticConsumers &C, |
Ted Kremenek | 9bf9af9 | 2012-08-16 17:45:23 +0000 | [diff] [blame] | 82 | const std::string& prefix, |
| 83 | const Preprocessor &PP) { |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 84 | C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP)); |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | //===----------------------------------------------------------------------===// |
| 88 | // Report processing. |
| 89 | //===----------------------------------------------------------------------===// |
| 90 | |
Ted Kremenek | 8e4c426 | 2012-01-25 23:47:14 +0000 | [diff] [blame] | 91 | void HTMLDiagnostics::FlushDiagnosticsImpl( |
| 92 | std::vector<const PathDiagnostic *> &Diags, |
Ted Kremenek | 9bf9af9 | 2012-08-16 17:45:23 +0000 | [diff] [blame] | 93 | FilesMade *filesMade) { |
Ted Kremenek | 8e4c426 | 2012-01-25 23:47:14 +0000 | [diff] [blame] | 94 | for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(), |
| 95 | et = Diags.end(); it != et; ++it) { |
Ted Kremenek | 9bf9af9 | 2012-08-16 17:45:23 +0000 | [diff] [blame] | 96 | ReportDiag(**it, filesMade); |
Ted Kremenek | 9718c9e | 2008-04-22 16:15:03 +0000 | [diff] [blame] | 97 | } |
Ted Kremenek | 9718c9e | 2008-04-22 16:15:03 +0000 | [diff] [blame] | 98 | } |
| 99 | |
Ted Kremenek | 5e86044 | 2009-11-05 02:09:23 +0000 | [diff] [blame] | 100 | void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, |
Ted Kremenek | 9bf9af9 | 2012-08-16 17:45:23 +0000 | [diff] [blame] | 101 | FilesMade *filesMade) { |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 102 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 103 | // Create the HTML directory if it is missing. |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 104 | if (!createdDir) { |
| 105 | createdDir = true; |
Rafael Espindola | c080917 | 2014-06-12 14:02:15 +0000 | [diff] [blame] | 106 | if (std::error_code ec = llvm::sys::fs::create_directories(Directory)) { |
Benjamin Kramer | 89b422c | 2009-08-23 12:08:50 +0000 | [diff] [blame] | 107 | llvm::errs() << "warning: could not create directory '" |
Benjamin Kramer | fbf914c | 2013-06-12 18:13:05 +0000 | [diff] [blame] | 108 | << Directory << "': " << ec.message() << '\n'; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 109 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 110 | noDir = true; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 111 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 112 | return; |
| 113 | } |
| 114 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 115 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 116 | if (noDir) |
| 117 | return; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 118 | |
Ted Kremenek | 60a7820 | 2012-02-24 06:00:00 +0000 | [diff] [blame] | 119 | // First flatten out the entire path to make it easier to use. |
Jordan Rose | 3eb3cd4 | 2012-08-03 23:08:54 +0000 | [diff] [blame] | 120 | PathPieces path = D.path.flatten(/*ShouldFlattenMacros=*/false); |
Ted Kremenek | 0f70a6f | 2012-02-28 23:27:39 +0000 | [diff] [blame] | 121 | |
| 122 | // The path as already been prechecked that all parts of the path are |
| 123 | // from the same file and that it is non-empty. |
Ted Kremenek | eba09fa | 2013-04-29 23:12:59 +0000 | [diff] [blame] | 124 | const SourceManager &SMgr = (*path.begin())->getLocation().getManager(); |
Ted Kremenek | 0f70a6f | 2012-02-28 23:27:39 +0000 | [diff] [blame] | 125 | assert(!path.empty()); |
| 126 | FileID FID = |
Ted Kremenek | eba09fa | 2013-04-29 23:12:59 +0000 | [diff] [blame] | 127 | (*path.begin())->getLocation().asLocation().getExpansionLoc().getFileID(); |
Ted Kremenek | 0f70a6f | 2012-02-28 23:27:39 +0000 | [diff] [blame] | 128 | assert(!FID.isInvalid()); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 129 | |
Ted Kremenek | c99332c | 2008-07-23 23:18:15 +0000 | [diff] [blame] | 130 | // Create a new rewriter to generate HTML. |
David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 131 | Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts()); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 132 | |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 133 | // Get the function/method name |
| 134 | SmallString<128> declName("unknown"); |
| 135 | int offsetDecl = 0; |
| 136 | if (const Decl *DeclWithIssue = D.getDeclWithIssue()) { |
| 137 | if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) { |
| 138 | declName = ND->getDeclName().getAsString(); |
| 139 | } |
| 140 | |
| 141 | if (const Stmt *Body = DeclWithIssue->getBody()) { |
| 142 | // Retrieve the relative position of the declaration which will be used |
| 143 | // for the file name |
| 144 | FullSourceLoc L( |
| 145 | SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()), |
| 146 | SMgr); |
| 147 | FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr); |
| 148 | offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber(); |
| 149 | } |
| 150 | } |
| 151 | |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 152 | // Process the path. |
Ted Kremenek | 60a7820 | 2012-02-24 06:00:00 +0000 | [diff] [blame] | 153 | unsigned n = path.size(); |
Ted Kremenek | a9590d1 | 2008-03-31 23:30:12 +0000 | [diff] [blame] | 154 | unsigned max = n; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 155 | |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 156 | for (PathPieces::const_reverse_iterator I = path.rbegin(), |
Ted Kremenek | 60a7820 | 2012-02-24 06:00:00 +0000 | [diff] [blame] | 157 | E = path.rend(); |
Ted Kremenek | afa6e249 | 2012-02-08 04:32:34 +0000 | [diff] [blame] | 158 | I != E; ++I, --n) |
Ted Kremenek | eba09fa | 2013-04-29 23:12:59 +0000 | [diff] [blame] | 159 | HandlePiece(R, FID, **I, n, max); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 160 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 161 | // Add line numbers, header, footer, etc. |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 162 | |
Chris Lattner | d32480d | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 163 | // unsigned FID = R.getSourceMgr().getMainFileID(); |
| 164 | html::EscapeText(R, FID); |
| 165 | html::AddLineNumbers(R, FID); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 166 | |
Ted Kremenek | f2e6fcf | 2008-04-16 16:39:56 +0000 | [diff] [blame] | 167 | // If we have a preprocessor, relex the file and syntax highlight. |
| 168 | // We might not have a preprocessor if we come from a deserialized AST file, |
| 169 | // for example. |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 170 | |
Daniel Dunbar | b5f2025 | 2009-11-05 02:41:58 +0000 | [diff] [blame] | 171 | html::SyntaxHighlight(R, FID, PP); |
| 172 | html::HighlightMacros(R, FID, PP); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 173 | |
Ted Kremenek | 3276af4 | 2008-04-02 20:44:16 +0000 | [diff] [blame] | 174 | // Get the full directory name of the analyzed file. |
| 175 | |
Chris Lattner | d32480d | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 176 | const FileEntry* Entry = SMgr.getFileEntryForID(FID); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 177 | |
Ted Kremenek | 64fa3be | 2008-04-24 23:37:03 +0000 | [diff] [blame] | 178 | // This is a cludge; basically we want to append either the full |
| 179 | // working directory if we have no directory information. This is |
| 180 | // a work in progress. |
| 181 | |
Benjamin Kramer | fbf914c | 2013-06-12 18:13:05 +0000 | [diff] [blame] | 182 | llvm::SmallString<0> DirName; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 183 | |
Michael J. Spencer | f28df4c | 2010-12-17 21:22:22 +0000 | [diff] [blame] | 184 | if (llvm::sys::path::is_relative(Entry->getName())) { |
Benjamin Kramer | fbf914c | 2013-06-12 18:13:05 +0000 | [diff] [blame] | 185 | llvm::sys::fs::current_path(DirName); |
| 186 | DirName += '/'; |
Ted Kremenek | 5f56cbb | 2008-05-02 22:04:53 +0000 | [diff] [blame] | 187 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 188 | |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 189 | int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber(); |
| 190 | int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber(); |
| 191 | |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 192 | // Add the name of the file as an <h1> tag. |
| 193 | |
Ted Kremenek | 8cc4842 | 2008-03-27 07:35:49 +0000 | [diff] [blame] | 194 | { |
Ted Kremenek | 2d470fc | 2008-09-13 05:16:45 +0000 | [diff] [blame] | 195 | std::string s; |
| 196 | llvm::raw_string_ostream os(s); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 197 | |
Ted Kremenek | b76a3f44 | 2008-09-22 17:33:32 +0000 | [diff] [blame] | 198 | os << "<!-- REPORTHEADER -->\n" |
Ted Kremenek | 0bb0909 | 2009-04-01 06:13:56 +0000 | [diff] [blame] | 199 | << "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n" |
Ted Kremenek | 7d6219f | 2008-04-15 21:25:08 +0000 | [diff] [blame] | 200 | "<tr><td class=\"rowname\">File:</td><td>" |
Ted Kremenek | 0bb0909 | 2009-04-01 06:13:56 +0000 | [diff] [blame] | 201 | << html::EscapeText(DirName) |
| 202 | << html::EscapeText(Entry->getName()) |
| 203 | << "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>" |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 204 | "<a href=\"#EndPath\">line " |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 205 | << LineNumber |
Ted Kremenek | 0bb0909 | 2009-04-01 06:13:56 +0000 | [diff] [blame] | 206 | << ", column " |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 207 | << ColumnNumber |
Ted Kremenek | 0bb0909 | 2009-04-01 06:13:56 +0000 | [diff] [blame] | 208 | << "</a></td></tr>\n" |
| 209 | "<tr><td class=\"rowname\">Description:</td><td>" |
Jordan Rose | cc0b1bf | 2012-08-31 00:36:26 +0000 | [diff] [blame] | 210 | << D.getVerboseDescription() << "</td></tr>\n"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 211 | |
Ted Kremenek | b0f87c4 | 2008-04-30 23:47:44 +0000 | [diff] [blame] | 212 | // Output any other meta data. |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 213 | |
Ted Kremenek | b0f87c4 | 2008-04-30 23:47:44 +0000 | [diff] [blame] | 214 | for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end(); |
| 215 | I!=E; ++I) { |
| 216 | os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n"; |
| 217 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 218 | |
Ted Kremenek | b76a3f44 | 2008-09-22 17:33:32 +0000 | [diff] [blame] | 219 | os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n" |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 220 | "<h3>Annotated Source Code</h3>\n"; |
| 221 | |
Daniel Dunbar | 62c850f | 2009-08-19 20:32:38 +0000 | [diff] [blame] | 222 | R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str()); |
Ted Kremenek | e6eed29 | 2008-04-02 07:04:46 +0000 | [diff] [blame] | 223 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 224 | |
Ted Kremenek | 3276af4 | 2008-04-02 20:44:16 +0000 | [diff] [blame] | 225 | // Embed meta-data tags. |
Ted Kremenek | 3276af4 | 2008-04-02 20:44:16 +0000 | [diff] [blame] | 226 | { |
Ted Kremenek | 2d470fc | 2008-09-13 05:16:45 +0000 | [diff] [blame] | 227 | std::string s; |
| 228 | llvm::raw_string_ostream os(s); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 229 | |
Jordan Rose | cc0b1bf | 2012-08-31 00:36:26 +0000 | [diff] [blame] | 230 | StringRef BugDesc = D.getVerboseDescription(); |
Ted Kremenek | 3724cde | 2009-08-03 23:44:55 +0000 | [diff] [blame] | 231 | if (!BugDesc.empty()) |
| 232 | os << "\n<!-- BUGDESC " << BugDesc << " -->\n"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 233 | |
Jordan Rose | cc0b1bf | 2012-08-31 00:36:26 +0000 | [diff] [blame] | 234 | StringRef BugType = D.getBugType(); |
Ted Kremenek | 3724cde | 2009-08-03 23:44:55 +0000 | [diff] [blame] | 235 | if (!BugType.empty()) |
| 236 | os << "\n<!-- BUGTYPE " << BugType << " -->\n"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 237 | |
Jordan Rose | cc0b1bf | 2012-08-31 00:36:26 +0000 | [diff] [blame] | 238 | StringRef BugCategory = D.getCategory(); |
Ted Kremenek | 3724cde | 2009-08-03 23:44:55 +0000 | [diff] [blame] | 239 | if (!BugCategory.empty()) |
| 240 | os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n"; |
| 241 | |
Ted Kremenek | 64fa3be | 2008-04-24 23:37:03 +0000 | [diff] [blame] | 242 | os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n"; |
Ted Kremenek | 3724cde | 2009-08-03 23:44:55 +0000 | [diff] [blame] | 243 | |
Sylvestre Ledru | ac5a08a | 2014-06-14 08:49:40 +0000 | [diff] [blame] | 244 | os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry->getName()) << " -->\n"; |
| 245 | |
| 246 | os << "\n<!-- FUNCTIONNAME " << declName << " -->\n"; |
| 247 | |
Chris Lattner | 8a42586 | 2009-01-16 07:36:28 +0000 | [diff] [blame] | 248 | os << "\n<!-- BUGLINE " |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 249 | << LineNumber |
Ted Kremenek | 0bb0909 | 2009-04-01 06:13:56 +0000 | [diff] [blame] | 250 | << " -->\n"; |
Ted Kremenek | 3724cde | 2009-08-03 23:44:55 +0000 | [diff] [blame] | 251 | |
Jordan Rose | 11288ce | 2013-11-15 02:11:11 +0000 | [diff] [blame] | 252 | os << "\n<!-- BUGCOLUMN " |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 253 | << ColumnNumber |
Jordan Rose | 11288ce | 2013-11-15 02:11:11 +0000 | [diff] [blame] | 254 | << " -->\n"; |
| 255 | |
Ted Kremenek | 60a7820 | 2012-02-24 06:00:00 +0000 | [diff] [blame] | 256 | os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 257 | |
Ted Kremenek | 3724cde | 2009-08-03 23:44:55 +0000 | [diff] [blame] | 258 | // Mark the end of the tags. |
| 259 | os << "\n<!-- BUGMETAEND -->\n"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 260 | |
Ted Kremenek | 3724cde | 2009-08-03 23:44:55 +0000 | [diff] [blame] | 261 | // Insert the text. |
Daniel Dunbar | 62c850f | 2009-08-19 20:32:38 +0000 | [diff] [blame] | 262 | R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str()); |
Ted Kremenek | 3276af4 | 2008-04-02 20:44:16 +0000 | [diff] [blame] | 263 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 264 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 265 | // Add CSS, header, and footer. |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 266 | |
Chris Lattner | d32480d | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 267 | html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName()); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 268 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 269 | // Get the rewrite buffer. |
Chris Lattner | d32480d | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 270 | const RewriteBuffer *Buf = R.getRewriteBufferFor(FID); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 271 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 272 | if (!Buf) { |
Benjamin Kramer | 89b422c | 2009-08-23 12:08:50 +0000 | [diff] [blame] | 273 | llvm::errs() << "warning: no diagnostics generated for main file.\n"; |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 274 | return; |
| 275 | } |
| 276 | |
Ted Kremenek | 490b8c0 | 2009-10-08 17:44:41 +0000 | [diff] [blame] | 277 | // Create a path for the target HTML file. |
Benjamin Kramer | fbf914c | 2013-06-12 18:13:05 +0000 | [diff] [blame] | 278 | int FD; |
| 279 | SmallString<128> Model, ResultPath; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 280 | |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 281 | if (!AnalyzerOpts.shouldWriteStableReportFilename()) { |
| 282 | llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); |
| 283 | |
| 284 | if (std::error_code EC = |
Yaron Keren | 92e1b62 | 2015-03-18 10:17:07 +0000 | [diff] [blame] | 285 | llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) { |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 286 | llvm::errs() << "warning: could not create file in '" << Directory |
| 287 | << "': " << EC.message() << '\n'; |
| 288 | return; |
| 289 | } |
| 290 | |
| 291 | } else { |
| 292 | int i = 1; |
| 293 | std::error_code EC; |
| 294 | do { |
| 295 | // Find a filename which is not already used |
Sylvestre Ledru | 06aebc4 | 2014-06-14 09:28:27 +0000 | [diff] [blame] | 296 | std::stringstream filename; |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 297 | Model = ""; |
Sylvestre Ledru | 06aebc4 | 2014-06-14 09:28:27 +0000 | [diff] [blame] | 298 | filename << "report-" |
| 299 | << llvm::sys::path::filename(Entry->getName()).str() |
| 300 | << "-" << declName.c_str() |
| 301 | << "-" << offsetDecl |
| 302 | << "-" << i << ".html"; |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 303 | llvm::sys::path::append(Model, Directory, |
Sylvestre Ledru | 06aebc4 | 2014-06-14 09:28:27 +0000 | [diff] [blame] | 304 | filename.str()); |
Yaron Keren | 92e1b62 | 2015-03-18 10:17:07 +0000 | [diff] [blame] | 305 | EC = llvm::sys::fs::openFileForWrite(Model, |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 306 | FD, |
| 307 | llvm::sys::fs::F_RW | |
| 308 | llvm::sys::fs::F_Excl); |
| 309 | if (EC && EC != std::errc::file_exists) { |
Yaron Keren | 92e1b62 | 2015-03-18 10:17:07 +0000 | [diff] [blame] | 310 | llvm::errs() << "warning: could not create file '" << Model |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 311 | << "': " << EC.message() << '\n'; |
| 312 | return; |
| 313 | } |
| 314 | i++; |
| 315 | } while (EC); |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 316 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 317 | |
Benjamin Kramer | fbf914c | 2013-06-12 18:13:05 +0000 | [diff] [blame] | 318 | llvm::raw_fd_ostream os(FD, true); |
| 319 | |
| 320 | if (filesMade) |
| 321 | filesMade->addDiagnostic(D, getName(), |
| 322 | llvm::sys::path::filename(ResultPath)); |
Ted Kremenek | 490b8c0 | 2009-10-08 17:44:41 +0000 | [diff] [blame] | 323 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 324 | // Emit the HTML to disk. |
Ted Kremenek | 076d133 | 2008-04-20 01:02:33 +0000 | [diff] [blame] | 325 | for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I) |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 326 | os << *I; |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 327 | } |
| 328 | |
Chris Lattner | d32480d | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 329 | void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID, |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 330 | const PathDiagnosticPiece& P, |
Ted Kremenek | a9590d1 | 2008-03-31 23:30:12 +0000 | [diff] [blame] | 331 | unsigned num, unsigned max) { |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 332 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 333 | // For now, just draw a box above the line in question, and emit the |
| 334 | // warning. |
Ted Kremenek | 0bb0909 | 2009-04-01 06:13:56 +0000 | [diff] [blame] | 335 | FullSourceLoc Pos = P.getLocation().asLocation(); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 336 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 337 | if (!Pos.isValid()) |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 338 | return; |
| 339 | |
Chris Lattner | d32480d | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 340 | SourceManager &SM = R.getSourceMgr(); |
Chris Lattner | e4ad417 | 2009-02-04 00:55:58 +0000 | [diff] [blame] | 341 | assert(&Pos.getManager() == &SM && "SourceManagers are different!"); |
Chandler Carruth | c7ca521 | 2011-07-25 20:52:32 +0000 | [diff] [blame] | 342 | std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedExpansionLoc(Pos); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 343 | |
Chris Lattner | e4ad417 | 2009-02-04 00:55:58 +0000 | [diff] [blame] | 344 | if (LPosInfo.first != BugFileID) |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 345 | return; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 346 | |
Chris Lattner | e4ad417 | 2009-02-04 00:55:58 +0000 | [diff] [blame] | 347 | const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 348 | const char* FileStart = Buf->getBufferStart(); |
| 349 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 350 | // Compute the column number. Rewind from the current position to the start |
| 351 | // of the line. |
Chris Lattner | e4ad417 | 2009-02-04 00:55:58 +0000 | [diff] [blame] | 352 | unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second); |
Chandler Carruth | 35f5320 | 2011-07-25 16:49:02 +0000 | [diff] [blame] | 353 | const char *TokInstantiationPtr =Pos.getExpansionLoc().getCharacterData(); |
Chris Lattner | 8a42586 | 2009-01-16 07:36:28 +0000 | [diff] [blame] | 354 | const char *LineStart = TokInstantiationPtr-ColNo; |
Ted Kremenek | e6d2419 | 2008-05-06 23:42:18 +0000 | [diff] [blame] | 355 | |
Ted Kremenek | ea3a9e2 | 2009-02-18 22:10:00 +0000 | [diff] [blame] | 356 | // Compute LineEnd. |
Chris Lattner | 8a42586 | 2009-01-16 07:36:28 +0000 | [diff] [blame] | 357 | const char *LineEnd = TokInstantiationPtr; |
Ted Kremenek | ea3a9e2 | 2009-02-18 22:10:00 +0000 | [diff] [blame] | 358 | const char* FileEnd = Buf->getBufferEnd(); |
| 359 | while (*LineEnd != '\n' && LineEnd != FileEnd) |
| 360 | ++LineEnd; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 361 | |
Ted Kremenek | 01fa5d2 | 2008-03-31 21:40:14 +0000 | [diff] [blame] | 362 | // Compute the margin offset by counting tabs and non-tabs. |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 363 | unsigned PosNo = 0; |
Chris Lattner | 8a42586 | 2009-01-16 07:36:28 +0000 | [diff] [blame] | 364 | for (const char* c = LineStart; c != TokInstantiationPtr; ++c) |
Ted Kremenek | e6d2419 | 2008-05-06 23:42:18 +0000 | [diff] [blame] | 365 | PosNo += *c == '\t' ? 8 : 1; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 366 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 367 | // Create the html for the message. |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 368 | |
Craig Topper | 0dbb783 | 2014-05-27 02:45:47 +0000 | [diff] [blame] | 369 | const char *Kind = nullptr; |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 370 | switch (P.getKind()) { |
Ted Kremenek | 60a7820 | 2012-02-24 06:00:00 +0000 | [diff] [blame] | 371 | case PathDiagnosticPiece::Call: |
| 372 | llvm_unreachable("Calls should already be handled"); |
Mike Stump | 281d6d7 | 2010-01-20 02:03:14 +0000 | [diff] [blame] | 373 | case PathDiagnosticPiece::Event: Kind = "Event"; break; |
| 374 | case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break; |
| 375 | // Setting Kind to "Control" is intentional. |
| 376 | case PathDiagnosticPiece::Macro: Kind = "Control"; break; |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 377 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 378 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 379 | std::string sbuf; |
| 380 | llvm::raw_string_ostream os(sbuf); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 381 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 382 | os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\""; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 383 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 384 | if (num == max) |
| 385 | os << "EndPath"; |
| 386 | else |
| 387 | os << "Path" << num; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 388 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 389 | os << "\" class=\"msg"; |
| 390 | if (Kind) |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 391 | os << " msg" << Kind; |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 392 | os << "\" style=\"margin-left:" << PosNo << "ex"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 393 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 394 | // Output a maximum size. |
| 395 | if (!isa<PathDiagnosticMacroPiece>(P)) { |
Ted Kremenek | 80b2b16 | 2008-09-21 18:52:59 +0000 | [diff] [blame] | 396 | // Get the string and determining its maximum substring. |
| 397 | const std::string& Msg = P.getString(); |
| 398 | unsigned max_token = 0; |
| 399 | unsigned cnt = 0; |
| 400 | unsigned len = Msg.size(); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 401 | |
Ted Kremenek | 80b2b16 | 2008-09-21 18:52:59 +0000 | [diff] [blame] | 402 | for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I) |
| 403 | switch (*I) { |
Mike Stump | 281d6d7 | 2010-01-20 02:03:14 +0000 | [diff] [blame] | 404 | default: |
| 405 | ++cnt; |
| 406 | continue; |
| 407 | case ' ': |
| 408 | case '\t': |
| 409 | case '\n': |
| 410 | if (cnt > max_token) max_token = cnt; |
| 411 | cnt = 0; |
Ted Kremenek | 80b2b16 | 2008-09-21 18:52:59 +0000 | [diff] [blame] | 412 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 413 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 414 | if (cnt > max_token) |
| 415 | max_token = cnt; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 416 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 417 | // Determine the approximate size of the message bubble in em. |
Ted Kremenek | 80b2b16 | 2008-09-21 18:52:59 +0000 | [diff] [blame] | 418 | unsigned em; |
Ted Kremenek | 7f16ed4 | 2009-03-02 23:06:15 +0000 | [diff] [blame] | 419 | const unsigned max_line = 120; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 420 | |
Ted Kremenek | 80b2b16 | 2008-09-21 18:52:59 +0000 | [diff] [blame] | 421 | if (max_token >= max_line) |
| 422 | em = max_token / 2; |
| 423 | else { |
| 424 | unsigned characters = max_line; |
| 425 | unsigned lines = len / max_line; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 426 | |
Ted Kremenek | 80b2b16 | 2008-09-21 18:52:59 +0000 | [diff] [blame] | 427 | if (lines > 0) { |
| 428 | for (; characters > max_token; --characters) |
| 429 | if (len / characters > lines) { |
| 430 | ++characters; |
| 431 | break; |
| 432 | } |
| 433 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 434 | |
Ted Kremenek | 80b2b16 | 2008-09-21 18:52:59 +0000 | [diff] [blame] | 435 | em = characters / 2; |
| 436 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 437 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 438 | if (em < max_line/2) |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 439 | os << "; max-width:" << em << "em"; |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 440 | } |
| 441 | else |
| 442 | os << "; max-width:100em"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 443 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 444 | os << "\">"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 445 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 446 | if (max > 1) { |
| 447 | os << "<table class=\"msgT\"><tr><td valign=\"top\">"; |
| 448 | os << "<div class=\"PathIndex"; |
| 449 | if (Kind) os << " PathIndex" << Kind; |
| 450 | os << "\">" << num << "</div>"; |
Jordan Rose | 11790a4 | 2012-08-02 02:26:19 +0000 | [diff] [blame] | 451 | |
| 452 | if (num > 1) { |
| 453 | os << "</td><td><div class=\"PathNav\"><a href=\"#Path" |
| 454 | << (num - 1) |
| 455 | << "\" title=\"Previous event (" |
| 456 | << (num - 1) |
| 457 | << ")\">←</a></div></td>"; |
| 458 | } |
| 459 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 460 | os << "</td><td>"; |
| 461 | } |
| 462 | |
| 463 | if (const PathDiagnosticMacroPiece *MP = |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 464 | dyn_cast<PathDiagnosticMacroPiece>(&P)) { |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 465 | |
| 466 | os << "Within the expansion of the macro '"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 467 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 468 | // Get the name of the macro by relexing it. |
| 469 | { |
Chandler Carruth | 35f5320 | 2011-07-25 16:49:02 +0000 | [diff] [blame] | 470 | FullSourceLoc L = MP->getLocation().asLocation().getExpansionLoc(); |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 471 | assert(L.isFileID()); |
Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 472 | StringRef BufferInfo = L.getBufferData(); |
Argyrios Kyrtzidis | 45f5118 | 2012-05-11 21:39:18 +0000 | [diff] [blame] | 473 | std::pair<FileID, unsigned> LocInfo = L.getDecomposedLoc(); |
| 474 | const char* MacroName = LocInfo.second + BufferInfo.data(); |
| 475 | Lexer rawLexer(SM.getLocForStartOfFile(LocInfo.first), PP.getLangOpts(), |
| 476 | BufferInfo.begin(), MacroName, BufferInfo.end()); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 477 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 478 | Token TheTok; |
| 479 | rawLexer.LexFromRawLexer(TheTok); |
| 480 | for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i) |
| 481 | os << MacroName[i]; |
Ted Kremenek | c62af6c | 2009-03-02 23:05:40 +0000 | [diff] [blame] | 482 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 483 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 484 | os << "':\n"; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 485 | |
Jordan Rose | fa49c92 | 2012-08-02 02:43:42 +0000 | [diff] [blame] | 486 | if (max > 1) { |
| 487 | os << "</td>"; |
| 488 | if (num < max) { |
| 489 | os << "<td><div class=\"PathNav\"><a href=\"#"; |
| 490 | if (num == max - 1) |
| 491 | os << "EndPath"; |
| 492 | else |
| 493 | os << "Path" << (num + 1); |
| 494 | os << "\" title=\"Next event (" |
| 495 | << (num + 1) |
| 496 | << ")\">→</a></div></td>"; |
| 497 | } |
| 498 | |
| 499 | os << "</tr></table>"; |
| 500 | } |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 501 | |
| 502 | // Within a macro piece. Write out each event. |
| 503 | ProcessMacroPiece(os, *MP, 0); |
| 504 | } |
| 505 | else { |
| 506 | os << html::EscapeText(P.getString()); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 507 | |
Jordan Rose | 11790a4 | 2012-08-02 02:26:19 +0000 | [diff] [blame] | 508 | if (max > 1) { |
| 509 | os << "</td>"; |
| 510 | if (num < max) { |
| 511 | os << "<td><div class=\"PathNav\"><a href=\"#"; |
| 512 | if (num == max - 1) |
| 513 | os << "EndPath"; |
| 514 | else |
| 515 | os << "Path" << (num + 1); |
| 516 | os << "\" title=\"Next event (" |
| 517 | << (num + 1) |
| 518 | << ")\">→</a></div></td>"; |
| 519 | } |
Sylvestre Ledru | 9882e1a | 2014-06-14 08:45:32 +0000 | [diff] [blame] | 520 | |
Jordan Rose | 11790a4 | 2012-08-02 02:26:19 +0000 | [diff] [blame] | 521 | os << "</tr></table>"; |
| 522 | } |
Ted Kremenek | 80b2b16 | 2008-09-21 18:52:59 +0000 | [diff] [blame] | 523 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 524 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 525 | os << "</div></td></tr>"; |
| 526 | |
| 527 | // Insert the new html. |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 528 | unsigned DisplayPos = LineEnd - FileStart; |
| 529 | SourceLocation Loc = |
Argyrios Kyrtzidis | e6e67de | 2011-09-19 20:40:19 +0000 | [diff] [blame] | 530 | SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos); |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 531 | |
Daniel Dunbar | 62c850f | 2009-08-19 20:32:38 +0000 | [diff] [blame] | 532 | R.InsertTextBefore(Loc, os.str()); |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 533 | |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 534 | // Now highlight the ranges. |
Ted Kremenek | 1e60273 | 2012-08-16 17:45:29 +0000 | [diff] [blame] | 535 | ArrayRef<SourceRange> Ranges = P.getRanges(); |
| 536 | for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), |
| 537 | E = Ranges.end(); I != E; ++I) { |
Chris Lattner | e4ad417 | 2009-02-04 00:55:58 +0000 | [diff] [blame] | 538 | HighlightRange(R, LPosInfo.first, *I); |
Ted Kremenek | 1e60273 | 2012-08-16 17:45:29 +0000 | [diff] [blame] | 539 | } |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 540 | } |
| 541 | |
Ted Kremenek | 5ef32db | 2011-08-12 23:37:29 +0000 | [diff] [blame] | 542 | static void EmitAlphaCounter(raw_ostream &os, unsigned n) { |
Benjamin Kramer | 5ac3b0b | 2010-03-13 11:34:41 +0000 | [diff] [blame] | 543 | unsigned x = n % ('z' - 'a'); |
| 544 | n /= 'z' - 'a'; |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 545 | |
Benjamin Kramer | 5ac3b0b | 2010-03-13 11:34:41 +0000 | [diff] [blame] | 546 | if (n > 0) |
| 547 | EmitAlphaCounter(os, n); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 548 | |
Benjamin Kramer | 5ac3b0b | 2010-03-13 11:34:41 +0000 | [diff] [blame] | 549 | os << char('a' + x); |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 550 | } |
| 551 | |
Ted Kremenek | 5ef32db | 2011-08-12 23:37:29 +0000 | [diff] [blame] | 552 | unsigned HTMLDiagnostics::ProcessMacroPiece(raw_ostream &os, |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 553 | const PathDiagnosticMacroPiece& P, |
| 554 | unsigned num) { |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 555 | |
Ted Kremenek | eba09fa | 2013-04-29 23:12:59 +0000 | [diff] [blame] | 556 | for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end(); |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 557 | I!=E; ++I) { |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 558 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 559 | if (const PathDiagnosticMacroPiece *MP = |
Ted Kremenek | eba09fa | 2013-04-29 23:12:59 +0000 | [diff] [blame] | 560 | dyn_cast<PathDiagnosticMacroPiece>(*I)) { |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 561 | num = ProcessMacroPiece(os, *MP, num); |
| 562 | continue; |
| 563 | } |
| 564 | |
Ted Kremenek | eba09fa | 2013-04-29 23:12:59 +0000 | [diff] [blame] | 565 | if (PathDiagnosticEventPiece *EP = dyn_cast<PathDiagnosticEventPiece>(*I)) { |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 566 | os << "<div class=\"msg msgEvent\" style=\"width:94%; " |
| 567 | "margin-left:5px\">" |
| 568 | "<table class=\"msgT\"><tr>" |
| 569 | "<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">"; |
| 570 | EmitAlphaCounter(os, num++); |
| 571 | os << "</div></td><td valign=\"top\">" |
| 572 | << html::EscapeText(EP->getString()) |
| 573 | << "</td></tr></table></div>\n"; |
| 574 | } |
| 575 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 576 | |
Ted Kremenek | b4947e4 | 2009-03-10 05:16:17 +0000 | [diff] [blame] | 577 | return num; |
| 578 | } |
| 579 | |
Chris Lattner | d32480d | 2009-01-17 06:22:33 +0000 | [diff] [blame] | 580 | void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID, |
Douglas Gregor | 87f95b0 | 2009-02-26 21:00:50 +0000 | [diff] [blame] | 581 | SourceRange Range, |
| 582 | const char *HighlightStart, |
| 583 | const char *HighlightEnd) { |
Chris Lattner | 184e65d | 2009-04-14 23:22:57 +0000 | [diff] [blame] | 584 | SourceManager &SM = R.getSourceMgr(); |
| 585 | const LangOptions &LangOpts = R.getLangOpts(); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 586 | |
Chandler Carruth | 35f5320 | 2011-07-25 16:49:02 +0000 | [diff] [blame] | 587 | SourceLocation InstantiationStart = SM.getExpansionLoc(Range.getBegin()); |
Chandler Carruth | d48db21 | 2011-07-25 21:09:52 +0000 | [diff] [blame] | 588 | unsigned StartLineNo = SM.getExpansionLineNumber(InstantiationStart); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 589 | |
Chandler Carruth | 35f5320 | 2011-07-25 16:49:02 +0000 | [diff] [blame] | 590 | SourceLocation InstantiationEnd = SM.getExpansionLoc(Range.getEnd()); |
Chandler Carruth | d48db21 | 2011-07-25 21:09:52 +0000 | [diff] [blame] | 591 | unsigned EndLineNo = SM.getExpansionLineNumber(InstantiationEnd); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 592 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 593 | if (EndLineNo < StartLineNo) |
| 594 | return; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 595 | |
Chris Lattner | cbc35ecb | 2009-01-19 07:46:45 +0000 | [diff] [blame] | 596 | if (SM.getFileID(InstantiationStart) != BugFileID || |
| 597 | SM.getFileID(InstantiationEnd) != BugFileID) |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 598 | return; |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 599 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 600 | // Compute the column number of the end. |
Chandler Carruth | 42f35f9 | 2011-07-25 20:57:57 +0000 | [diff] [blame] | 601 | unsigned EndColNo = SM.getExpansionColumnNumber(InstantiationEnd); |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 602 | unsigned OldEndColNo = EndColNo; |
| 603 | |
| 604 | if (EndColNo) { |
| 605 | // Add in the length of the token, so that we cover multi-char tokens. |
Chris Lattner | 184e65d | 2009-04-14 23:22:57 +0000 | [diff] [blame] | 606 | EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1; |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 607 | } |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 608 | |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 609 | // Highlight the range. Make the span tag the outermost tag for the |
| 610 | // selected range. |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 611 | |
Chris Lattner | 8a42586 | 2009-01-16 07:36:28 +0000 | [diff] [blame] | 612 | SourceLocation E = |
Argyrios Kyrtzidis | e6e67de | 2011-09-19 20:40:19 +0000 | [diff] [blame] | 613 | InstantiationEnd.getLocWithOffset(EndColNo - OldEndColNo); |
Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 614 | |
Douglas Gregor | 87f95b0 | 2009-02-26 21:00:50 +0000 | [diff] [blame] | 615 | html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd); |
Ted Kremenek | 6efb026 | 2008-03-27 06:17:42 +0000 | [diff] [blame] | 616 | } |