blob: 165689d143faf864c82713db9bd18e379152b60c [file] [log] [blame]
Steve Narofffe53a122008-04-14 21:39:16 +00001//===--- HTMLPrint.cpp - Playground for the HTML code rewriter ------------===//
Ted Kremenekd1cf5592008-03-18 22:21:07 +00002//
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// Hacks and fun related to the code rewriter.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ASTConsumers.h"
15#include "clang/AST/ASTConsumer.h"
16#include "clang/Rewrite/Rewriter.h"
17#include "clang/Rewrite/HTMLRewrite.h"
18#include "clang/Basic/SourceManager.h"
19#include "llvm/Support/MemoryBuffer.h"
20#include "clang/AST/ASTContext.h"
Ted Kremeneke1a79d82008-03-19 07:53:42 +000021#include "clang/Basic/Diagnostic.h"
22#include "clang/Analysis/LocalCheckers.h"
23#include "clang/AST/CFG.h"
Ted Kremeneka3881842008-03-18 23:55:46 +000024#include <sstream>
Ted Kremenekd1cf5592008-03-18 22:21:07 +000025
26using namespace clang;
27
Ted Kremeneke1a79d82008-03-19 07:53:42 +000028//===----------------------------------------------------------------------===//
29// Functional HTML pretty-printing.
30//===----------------------------------------------------------------------===//
31
Ted Kremenekd1cf5592008-03-18 22:21:07 +000032namespace {
33 class HTMLPrinter : public ASTConsumer {
34 Rewriter R;
35 public:
36 HTMLPrinter() {}
37 virtual ~HTMLPrinter();
38
39 void Initialize(ASTContext &context);
40 };
41}
42
43ASTConsumer* clang::CreateHTMLPrinter() { return new HTMLPrinter(); }
44
45void HTMLPrinter::Initialize(ASTContext &context) {
46 R.setSourceMgr(context.getSourceManager());
47}
48
49HTMLPrinter::~HTMLPrinter() {
Ted Kremenekd1cf5592008-03-18 22:21:07 +000050
Ted Kremeneke1a79d82008-03-19 07:53:42 +000051 unsigned FileID = R.getSourceMgr().getMainFileID();
Ted Kremenekbb404482008-04-08 23:25:54 +000052 html::EscapeText(R, FileID, false, true);
Ted Kremenekd1cf5592008-03-18 22:21:07 +000053 html::AddLineNumbers(R, FileID);
Ted Kremenek0735c172008-03-19 06:14:37 +000054 html::AddHeaderFooterInternalBuiltinCSS(R, FileID);
Ted Kremenekd1cf5592008-03-18 22:21:07 +000055
56 // Emit the HTML.
57
58 if (const RewriteBuffer *RewriteBuf = R.getRewriteBufferFor(FileID)) {
Chris Lattnerf8dea312008-04-16 03:46:57 +000059 char *Buffer = (char*)malloc(RewriteBuf->size());
60 std::copy(RewriteBuf->begin(), RewriteBuf->end(), Buffer);
61 fwrite(Buffer, 1, RewriteBuf->size(), stdout);
62 free(Buffer);
Ted Kremenekd1cf5592008-03-18 22:21:07 +000063 }
64}
Ted Kremeneke1a79d82008-03-19 07:53:42 +000065
66//===----------------------------------------------------------------------===//
67// Other HTML pretty-printing code used to test new features.
68//===----------------------------------------------------------------------===//
69
70namespace {
71 class HTMLTest : public ASTConsumer {
72 Rewriter R;
73 ASTContext* Ctx;
74 public:
75 HTMLTest() : Ctx(NULL) {}
76 virtual ~HTMLTest();
77 virtual void HandleTopLevelDecl(Decl* D);
78
79 void Initialize(ASTContext &context);
80 void ProcessBody(Stmt* S);
81 };
82}
83
84ASTConsumer* clang::CreateHTMLTest() { return new HTMLTest(); }
85
86void HTMLTest::Initialize(ASTContext &context) {
87 Ctx = &context;
88 R.setSourceMgr(context.getSourceManager());
89}
90
91void HTMLTest::HandleTopLevelDecl(Decl* D) {
92 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
93 if (Stmt* B = FD->getBody()) {
94 SourceLocation L = B->getLocStart();
95
96 if (L.isFileID() && L.getFileID() == R.getSourceMgr().getMainFileID())
97 ProcessBody(B);
98 }
99}
100
101HTMLTest::~HTMLTest() {
102
103 unsigned FileID = R.getSourceMgr().getMainFileID();
104 html::EscapeText(R, FileID);
105 html::AddLineNumbers(R, FileID);
106 html::AddHeaderFooterInternalBuiltinCSS(R, FileID);
107
108 // Emit the HTML.
109
110 if (const RewriteBuffer *RewriteBuf = R.getRewriteBufferFor(FileID)) {
111 std::string S(RewriteBuf->begin(), RewriteBuf->end());
112 printf("%s\n", S.c_str());
113 }
114}
115
116namespace {
117 class HTMLDiagnostic : public DiagnosticClient {
118 Rewriter& R;
119 public:
120 HTMLDiagnostic(Rewriter& r) : R(r) {}
121 virtual void HandleDiagnostic(Diagnostic &Diags,
122 Diagnostic::Level DiagLevel,
123 FullSourceLoc Pos,
124 diag::kind ID,
125 const std::string *Strs,
126 unsigned NumStrs,
127 const SourceRange *Ranges,
128 unsigned NumRanges);
129 };
130}
131
132void HTMLTest::ProcessBody(Stmt* S) {
133 CFG* cfg = CFG::buildCFG(S);
134
135 if (!cfg)
136 return;
137
138 HTMLDiagnostic HD(R);
139 Diagnostic D(HD);
140
141 CheckDeadStores(*cfg, *Ctx, D);
142}
143
144void HTMLDiagnostic::HandleDiagnostic(Diagnostic &Diags,
145 Diagnostic::Level DiagLevel,
146 FullSourceLoc Pos,
147 diag::kind ID,
148 const std::string *Strs,
149 unsigned NumStrs,
150 const SourceRange *Ranges,
151 unsigned NumRanges) {
152
153 // For now, just draw a box above the line in question, and emit the
154 // warning.
155
156 if (!Pos.isValid())
157 return;
158
Ted Kremenek9c2c0ef2008-03-19 23:55:53 +0000159 SourceManager& SM = R.getSourceMgr();
160
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000161 FullSourceLoc LPos = Pos.getLogicalLoc();
Ted Kremenekdce3d3e2008-04-14 21:14:03 +0000162 unsigned FileID = SM.getCanonicalFileID(LPos.getLocation());
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000163
Ted Kremenek9c2c0ef2008-03-19 23:55:53 +0000164 assert (&LPos.getManager() == &SM && "SourceManagers are different!");
165
Ted Kremenekdce3d3e2008-04-14 21:14:03 +0000166 if (!SM.isFromMainFile(LPos.getLocation()))
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000167 return;
168
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000169 // Compute the column number. Rewind from the current position to the start
170 // of the line.
171
172 unsigned ColNo = LPos.getColumnNumber();
173 const char *TokLogicalPtr = LPos.getCharacterData();
174 const char *LineStart = TokLogicalPtr-ColNo;
175
176 // Ripped from TextDiagnostics::FormatDiagnostic:
177
178 std::string Msg = Diags.getDescription(ID);
179
180 for (unsigned i = 0; i < Msg.size() - 1; ++i) {
181 if (Msg[i] == '%' && isdigit(Msg[i + 1])) {
182 unsigned StrNo = Msg[i + 1] - '0';
183 Msg = std::string(Msg.begin(), Msg.begin() + i) +
184 (StrNo < NumStrs ? Strs[StrNo] : "<<<INTERNAL ERROR>>>") +
185 std::string(Msg.begin() + i + 2, Msg.end());
186 }
Ted Kremenekb8b86e22008-03-19 21:59:05 +0000187 }
188
189 // Create the html for the message.
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000190
191 std::ostringstream os;
192
Ted Kremenekb8b86e22008-03-19 21:59:05 +0000193 os << "\n<tr><td class=\"num\"></td><td class=\"line\">"
194 << "<div class=\"msg\" style=\"margin-left:"
195 << ColNo << "ex\">";
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000196
197 switch (DiagLevel) {
198 default: assert(0 && "Unknown diagnostic type!");
199 case Diagnostic::Note: os << "note: "; break;
200 case Diagnostic::Warning: os << "warning: "; break;
201 case Diagnostic::Error: os << "error: "; break;
202 case Diagnostic::Fatal: os << "fatal error: "; break;
203 break;
204 }
205
Ted Kremenekb8b86e22008-03-19 21:59:05 +0000206 os << Msg << "</div></td></tr>";
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000207
Ted Kremenekb8b86e22008-03-19 21:59:05 +0000208 // Insert the new html.
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000209
Ted Kremenek9c2c0ef2008-03-19 23:55:53 +0000210 const llvm::MemoryBuffer *Buf = SM.getBuffer(FileID);
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000211 const char* FileStart = Buf->getBufferStart();
212
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000213 R.InsertStrBefore(SourceLocation::getFileLoc(FileID, LineStart - FileStart),
214 os.str());
Ted Kremenek9c2c0ef2008-03-19 23:55:53 +0000215
216 // Now highlight the ranges.
217
218 for (unsigned i = 0; i < NumRanges; ++i) {
219
220 SourceLocation B = SM.getLogicalLoc(Ranges->getBegin());
221 SourceLocation E = SM.getLogicalLoc(Ranges->getEnd());
222
223 // We do this because the position seems to point to the beginning of
224 // the last character. FIXME: Is this what is suppose to happen?
225 std::pair<unsigned,unsigned> X = SM.getDecomposedFileLoc(E);
226 E = SourceLocation::getFileLoc(X.first, X.second+1);
227
228 ++Ranges;
229
Ted Kremenekdce3d3e2008-04-14 21:14:03 +0000230 if (!SM.isFromMainFile(B) || !SM.isFromMainFile(E))
Ted Kremenek9c2c0ef2008-03-19 23:55:53 +0000231 continue;
232
233 // Highlight the range. Make the span tag the outermost tag for the
234 // selected range.
235 R.InsertCStrBefore(B, "<span class=\"mrange\">");
236 R.InsertCStrAfter(E, "</span>");
Ted Kremenekdce3d3e2008-04-14 21:14:03 +0000237 }
Ted Kremeneke1a79d82008-03-19 07:53:42 +0000238}