blob: 1108bc3bdaabbdc3872d2cf6c291720a76797f56 [file] [log] [blame]
Ted Kremenek5e0020e2008-03-18 22:21:07 +00001//===--- RewriteTest.cpp - Playground for the code rewriter ---------------===//
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// 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 Kremenek13e479b2008-03-19 07:53:42 +000021#include "clang/Basic/Diagnostic.h"
22#include "clang/Analysis/LocalCheckers.h"
23#include "clang/AST/CFG.h"
Ted Kremenek1b3188c2008-03-18 23:55:46 +000024#include <sstream>
Ted Kremenek5e0020e2008-03-18 22:21:07 +000025
26using namespace clang;
27
Ted Kremenek13e479b2008-03-19 07:53:42 +000028//===----------------------------------------------------------------------===//
29// Functional HTML pretty-printing.
30//===----------------------------------------------------------------------===//
31
Ted Kremenek5e0020e2008-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 Kremenek5e0020e2008-03-18 22:21:07 +000050
Ted Kremenek13e479b2008-03-19 07:53:42 +000051 unsigned FileID = R.getSourceMgr().getMainFileID();
Ted Kremenek5e0020e2008-03-18 22:21:07 +000052 html::EscapeText(R, FileID);
53 html::AddLineNumbers(R, FileID);
Ted Kremenekad0a2032008-03-19 06:14:37 +000054 html::AddHeaderFooterInternalBuiltinCSS(R, FileID);
Ted Kremenek5e0020e2008-03-18 22:21:07 +000055
56 // Emit the HTML.
57
58 if (const RewriteBuffer *RewriteBuf = R.getRewriteBufferFor(FileID)) {
59 std::string S(RewriteBuf->begin(), RewriteBuf->end());
60 printf("%s\n", S.c_str());
61 }
62}
Ted Kremenek13e479b2008-03-19 07:53:42 +000063
64//===----------------------------------------------------------------------===//
65// Other HTML pretty-printing code used to test new features.
66//===----------------------------------------------------------------------===//
67
68namespace {
69 class HTMLTest : public ASTConsumer {
70 Rewriter R;
71 ASTContext* Ctx;
72 public:
73 HTMLTest() : Ctx(NULL) {}
74 virtual ~HTMLTest();
75 virtual void HandleTopLevelDecl(Decl* D);
76
77 void Initialize(ASTContext &context);
78 void ProcessBody(Stmt* S);
79 };
80}
81
82ASTConsumer* clang::CreateHTMLTest() { return new HTMLTest(); }
83
84void HTMLTest::Initialize(ASTContext &context) {
85 Ctx = &context;
86 R.setSourceMgr(context.getSourceManager());
87}
88
89void HTMLTest::HandleTopLevelDecl(Decl* D) {
90 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
91 if (Stmt* B = FD->getBody()) {
92 SourceLocation L = B->getLocStart();
93
94 if (L.isFileID() && L.getFileID() == R.getSourceMgr().getMainFileID())
95 ProcessBody(B);
96 }
97}
98
99HTMLTest::~HTMLTest() {
100
101 unsigned FileID = R.getSourceMgr().getMainFileID();
102 html::EscapeText(R, FileID);
103 html::AddLineNumbers(R, FileID);
104 html::AddHeaderFooterInternalBuiltinCSS(R, FileID);
105
106 // Emit the HTML.
107
108 if (const RewriteBuffer *RewriteBuf = R.getRewriteBufferFor(FileID)) {
109 std::string S(RewriteBuf->begin(), RewriteBuf->end());
110 printf("%s\n", S.c_str());
111 }
112}
113
114namespace {
115 class HTMLDiagnostic : public DiagnosticClient {
116 Rewriter& R;
117 public:
118 HTMLDiagnostic(Rewriter& r) : R(r) {}
119 virtual void HandleDiagnostic(Diagnostic &Diags,
120 Diagnostic::Level DiagLevel,
121 FullSourceLoc Pos,
122 diag::kind ID,
123 const std::string *Strs,
124 unsigned NumStrs,
125 const SourceRange *Ranges,
126 unsigned NumRanges);
127 };
128}
129
130void HTMLTest::ProcessBody(Stmt* S) {
131 CFG* cfg = CFG::buildCFG(S);
132
133 if (!cfg)
134 return;
135
136 HTMLDiagnostic HD(R);
137 Diagnostic D(HD);
138
139 CheckDeadStores(*cfg, *Ctx, D);
140}
141
142void HTMLDiagnostic::HandleDiagnostic(Diagnostic &Diags,
143 Diagnostic::Level DiagLevel,
144 FullSourceLoc Pos,
145 diag::kind ID,
146 const std::string *Strs,
147 unsigned NumStrs,
148 const SourceRange *Ranges,
149 unsigned NumRanges) {
150
151 // For now, just draw a box above the line in question, and emit the
152 // warning.
153
154 if (!Pos.isValid())
155 return;
156
157 FullSourceLoc LPos = Pos.getLogicalLoc();
158 unsigned FileID = LPos.getLocation().getFileID();
159
160 if (FileID != LPos.getManager().getMainFileID())
161 return;
162
163
164 // Compute the column number. Rewind from the current position to the start
165 // of the line.
166
167 unsigned ColNo = LPos.getColumnNumber();
168 const char *TokLogicalPtr = LPos.getCharacterData();
169 const char *LineStart = TokLogicalPtr-ColNo;
170
171 // Ripped from TextDiagnostics::FormatDiagnostic:
172
173 std::string Msg = Diags.getDescription(ID);
174
175 for (unsigned i = 0; i < Msg.size() - 1; ++i) {
176 if (Msg[i] == '%' && isdigit(Msg[i + 1])) {
177 unsigned StrNo = Msg[i + 1] - '0';
178 Msg = std::string(Msg.begin(), Msg.begin() + i) +
179 (StrNo < NumStrs ? Strs[StrNo] : "<<<INTERNAL ERROR>>>") +
180 std::string(Msg.begin() + i + 2, Msg.end());
181 }
182 }
183
184 // Start making the div tag.
185
186 std::ostringstream os;
187
188 os << "\n<div class=\"codeline\"><div class=\"nums\">&nbsp;</div>"
189 << "<div class=\"lines\">";
190
191 for (unsigned i = 0; i < ColNo+1; ++i)
192 os << ' ';
193
194 os << "</div><span class=\"msg\">";
195
196 switch (DiagLevel) {
197 default: assert(0 && "Unknown diagnostic type!");
198 case Diagnostic::Note: os << "note: "; break;
199 case Diagnostic::Warning: os << "warning: "; break;
200 case Diagnostic::Error: os << "error: "; break;
201 case Diagnostic::Fatal: os << "fatal error: "; break;
202 break;
203 }
204
205 os << Msg; // FIXME: HTML escape "Msg"
206 os << "</span></div";
207
208 // Insert a div tag with the warning.
209
210 const llvm::MemoryBuffer *Buf = R.getSourceMgr().getBuffer(FileID);
211 const char* FileStart = Buf->getBufferStart();
212
213
214 R.InsertStrBefore(SourceLocation::getFileLoc(FileID, LineStart - FileStart),
215 os.str());
216}