2008-04-15 05:39:16 +08:00
|
|
|
//===--- HTMLPrint.cpp - Playground for the HTML code rewriter ------------===//
|
2008-03-19 06:21:07 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Hacks and fun related to the code rewriter.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "ASTConsumers.h"
|
|
|
|
#include "clang/AST/ASTConsumer.h"
|
|
|
|
#include "clang/Rewrite/Rewriter.h"
|
|
|
|
#include "clang/Rewrite/HTMLRewrite.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
2008-03-19 15:53:42 +08:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
|
|
|
#include "clang/Analysis/LocalCheckers.h"
|
|
|
|
#include "clang/AST/CFG.h"
|
2008-03-19 07:55:46 +08:00
|
|
|
#include <sstream>
|
2008-03-19 06:21:07 +08:00
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
|
2008-03-19 15:53:42 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Functional HTML pretty-printing.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-03-19 06:21:07 +08:00
|
|
|
namespace {
|
|
|
|
class HTMLPrinter : public ASTConsumer {
|
|
|
|
Rewriter R;
|
|
|
|
public:
|
|
|
|
HTMLPrinter() {}
|
|
|
|
virtual ~HTMLPrinter();
|
|
|
|
|
|
|
|
void Initialize(ASTContext &context);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTConsumer* clang::CreateHTMLPrinter() { return new HTMLPrinter(); }
|
|
|
|
|
|
|
|
void HTMLPrinter::Initialize(ASTContext &context) {
|
|
|
|
R.setSourceMgr(context.getSourceManager());
|
|
|
|
}
|
|
|
|
|
|
|
|
HTMLPrinter::~HTMLPrinter() {
|
2008-03-19 15:53:42 +08:00
|
|
|
|
2008-03-19 06:21:07 +08:00
|
|
|
unsigned FileID = R.getSourceMgr().getMainFileID();
|
2008-04-09 07:25:54 +08:00
|
|
|
html::EscapeText(R, FileID, false, true);
|
2008-03-19 15:53:42 +08:00
|
|
|
html::AddLineNumbers(R, FileID);
|
|
|
|
html::AddHeaderFooterInternalBuiltinCSS(R, FileID);
|
2008-03-19 06:21:07 +08:00
|
|
|
|
2008-03-19 15:53:42 +08:00
|
|
|
// Emit the HTML.
|
|
|
|
|
|
|
|
if (const RewriteBuffer *RewriteBuf = R.getRewriteBufferFor(FileID)) {
|
2008-04-16 11:46:57 +08:00
|
|
|
char *Buffer = (char*)malloc(RewriteBuf->size());
|
|
|
|
std::copy(RewriteBuf->begin(), RewriteBuf->end(), Buffer);
|
|
|
|
fwrite(Buffer, 1, RewriteBuf->size(), stdout);
|
|
|
|
free(Buffer);
|
2008-03-19 15:53:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Other HTML pretty-printing code used to test new features.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class HTMLTest : public ASTConsumer {
|
|
|
|
Rewriter R;
|
|
|
|
ASTContext* Ctx;
|
|
|
|
public:
|
|
|
|
HTMLTest() : Ctx(NULL) {}
|
|
|
|
virtual ~HTMLTest();
|
|
|
|
virtual void HandleTopLevelDecl(Decl* D);
|
|
|
|
|
|
|
|
void Initialize(ASTContext &context);
|
|
|
|
void ProcessBody(Stmt* S);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
ASTConsumer* clang::CreateHTMLTest() { return new HTMLTest(); }
|
|
|
|
|
|
|
|
void HTMLTest::Initialize(ASTContext &context) {
|
|
|
|
Ctx = &context;
|
|
|
|
R.setSourceMgr(context.getSourceManager());
|
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLTest::HandleTopLevelDecl(Decl* D) {
|
|
|
|
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
|
|
|
|
if (Stmt* B = FD->getBody()) {
|
|
|
|
SourceLocation L = B->getLocStart();
|
|
|
|
|
|
|
|
if (L.isFileID() && L.getFileID() == R.getSourceMgr().getMainFileID())
|
|
|
|
ProcessBody(B);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HTMLTest::~HTMLTest() {
|
|
|
|
|
|
|
|
unsigned FileID = R.getSourceMgr().getMainFileID();
|
2008-03-19 06:21:07 +08:00
|
|
|
html::EscapeText(R, FileID);
|
|
|
|
html::AddLineNumbers(R, FileID);
|
2008-03-19 14:14:37 +08:00
|
|
|
html::AddHeaderFooterInternalBuiltinCSS(R, FileID);
|
2008-03-19 06:21:07 +08:00
|
|
|
|
|
|
|
// Emit the HTML.
|
|
|
|
|
|
|
|
if (const RewriteBuffer *RewriteBuf = R.getRewriteBufferFor(FileID)) {
|
|
|
|
std::string S(RewriteBuf->begin(), RewriteBuf->end());
|
|
|
|
printf("%s\n", S.c_str());
|
|
|
|
}
|
|
|
|
}
|
2008-03-19 15:53:42 +08:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
class HTMLDiagnostic : public DiagnosticClient {
|
|
|
|
Rewriter& R;
|
|
|
|
public:
|
|
|
|
HTMLDiagnostic(Rewriter& r) : R(r) {}
|
|
|
|
virtual void HandleDiagnostic(Diagnostic &Diags,
|
|
|
|
Diagnostic::Level DiagLevel,
|
|
|
|
FullSourceLoc Pos,
|
|
|
|
diag::kind ID,
|
|
|
|
const std::string *Strs,
|
|
|
|
unsigned NumStrs,
|
|
|
|
const SourceRange *Ranges,
|
|
|
|
unsigned NumRanges);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLTest::ProcessBody(Stmt* S) {
|
|
|
|
CFG* cfg = CFG::buildCFG(S);
|
|
|
|
|
|
|
|
if (!cfg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
HTMLDiagnostic HD(R);
|
|
|
|
Diagnostic D(HD);
|
|
|
|
|
|
|
|
CheckDeadStores(*cfg, *Ctx, D);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HTMLDiagnostic::HandleDiagnostic(Diagnostic &Diags,
|
|
|
|
Diagnostic::Level DiagLevel,
|
|
|
|
FullSourceLoc Pos,
|
|
|
|
diag::kind ID,
|
|
|
|
const std::string *Strs,
|
|
|
|
unsigned NumStrs,
|
|
|
|
const SourceRange *Ranges,
|
|
|
|
unsigned NumRanges) {
|
|
|
|
|
|
|
|
// For now, just draw a box above the line in question, and emit the
|
|
|
|
// warning.
|
|
|
|
|
|
|
|
if (!Pos.isValid())
|
|
|
|
return;
|
|
|
|
|
2008-03-20 07:55:53 +08:00
|
|
|
SourceManager& SM = R.getSourceMgr();
|
|
|
|
|
2008-03-19 15:53:42 +08:00
|
|
|
FullSourceLoc LPos = Pos.getLogicalLoc();
|
2008-04-15 05:14:03 +08:00
|
|
|
unsigned FileID = SM.getCanonicalFileID(LPos.getLocation());
|
2008-03-19 15:53:42 +08:00
|
|
|
|
2008-03-20 07:55:53 +08:00
|
|
|
assert (&LPos.getManager() == &SM && "SourceManagers are different!");
|
|
|
|
|
2008-04-15 05:14:03 +08:00
|
|
|
if (!SM.isFromMainFile(LPos.getLocation()))
|
2008-03-19 15:53:42 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Compute the column number. Rewind from the current position to the start
|
|
|
|
// of the line.
|
|
|
|
|
|
|
|
unsigned ColNo = LPos.getColumnNumber();
|
|
|
|
const char *TokLogicalPtr = LPos.getCharacterData();
|
|
|
|
const char *LineStart = TokLogicalPtr-ColNo;
|
|
|
|
|
|
|
|
// Ripped from TextDiagnostics::FormatDiagnostic:
|
|
|
|
|
|
|
|
std::string Msg = Diags.getDescription(ID);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < Msg.size() - 1; ++i) {
|
|
|
|
if (Msg[i] == '%' && isdigit(Msg[i + 1])) {
|
|
|
|
unsigned StrNo = Msg[i + 1] - '0';
|
|
|
|
Msg = std::string(Msg.begin(), Msg.begin() + i) +
|
|
|
|
(StrNo < NumStrs ? Strs[StrNo] : "<<<INTERNAL ERROR>>>") +
|
|
|
|
std::string(Msg.begin() + i + 2, Msg.end());
|
|
|
|
}
|
2008-03-20 05:59:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the html for the message.
|
2008-03-19 15:53:42 +08:00
|
|
|
|
|
|
|
std::ostringstream os;
|
|
|
|
|
2008-03-20 05:59:05 +08:00
|
|
|
os << "\n<tr><td class=\"num\"></td><td class=\"line\">"
|
|
|
|
<< "<div class=\"msg\" style=\"margin-left:"
|
|
|
|
<< ColNo << "ex\">";
|
2008-03-19 15:53:42 +08:00
|
|
|
|
|
|
|
switch (DiagLevel) {
|
|
|
|
default: assert(0 && "Unknown diagnostic type!");
|
|
|
|
case Diagnostic::Note: os << "note: "; break;
|
|
|
|
case Diagnostic::Warning: os << "warning: "; break;
|
|
|
|
case Diagnostic::Error: os << "error: "; break;
|
|
|
|
case Diagnostic::Fatal: os << "fatal error: "; break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-03-20 05:59:05 +08:00
|
|
|
os << Msg << "</div></td></tr>";
|
2008-03-19 15:53:42 +08:00
|
|
|
|
2008-03-20 05:59:05 +08:00
|
|
|
// Insert the new html.
|
2008-03-19 15:53:42 +08:00
|
|
|
|
2008-03-20 07:55:53 +08:00
|
|
|
const llvm::MemoryBuffer *Buf = SM.getBuffer(FileID);
|
2008-03-19 15:53:42 +08:00
|
|
|
const char* FileStart = Buf->getBufferStart();
|
|
|
|
|
|
|
|
R.InsertStrBefore(SourceLocation::getFileLoc(FileID, LineStart - FileStart),
|
|
|
|
os.str());
|
2008-03-20 07:55:53 +08:00
|
|
|
|
|
|
|
// Now highlight the ranges.
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < NumRanges; ++i) {
|
|
|
|
|
|
|
|
SourceLocation B = SM.getLogicalLoc(Ranges->getBegin());
|
|
|
|
SourceLocation E = SM.getLogicalLoc(Ranges->getEnd());
|
|
|
|
|
|
|
|
// We do this because the position seems to point to the beginning of
|
|
|
|
// the last character. FIXME: Is this what is suppose to happen?
|
|
|
|
std::pair<unsigned,unsigned> X = SM.getDecomposedFileLoc(E);
|
|
|
|
E = SourceLocation::getFileLoc(X.first, X.second+1);
|
|
|
|
|
|
|
|
++Ranges;
|
|
|
|
|
2008-04-15 05:14:03 +08:00
|
|
|
if (!SM.isFromMainFile(B) || !SM.isFromMainFile(E))
|
2008-03-20 07:55:53 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// Highlight the range. Make the span tag the outermost tag for the
|
|
|
|
// selected range.
|
|
|
|
R.InsertCStrBefore(B, "<span class=\"mrange\">");
|
|
|
|
R.InsertCStrAfter(E, "</span>");
|
2008-04-15 05:14:03 +08:00
|
|
|
}
|
2008-03-19 15:53:42 +08:00
|
|
|
}
|