2008-03-27 14:17:42 +08:00
|
|
|
//===--- HTMLDiagnostics.cpp - HTML Diagnostics for Paths ----*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines the HTMLDiagnostics object.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-08-11 12:54:23 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/Decl.h"
|
2008-03-27 15:35:49 +08:00
|
|
|
#include "clang/Basic/FileManager.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
2008-03-27 14:17:42 +08:00
|
|
|
#include "clang/Lex/Lexer.h"
|
2009-03-10 13:16:17 +08:00
|
|
|
#include "clang/Lex/Preprocessor.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Rewrite/Core/HTMLRewrite.h"
|
|
|
|
#include "clang/Rewrite/Core/Rewriter.h"
|
|
|
|
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
|
2015-01-14 19:29:14 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
2015-10-22 19:53:04 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/IssueHash.h"
|
|
|
|
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
|
2015-06-14 01:23:13 +08:00
|
|
|
#include "llvm/Support/Errc.h"
|
2011-01-11 09:21:20 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2008-03-27 14:17:42 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2010-11-30 02:12:39 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2014-06-14 17:28:27 +08:00
|
|
|
#include <sstream>
|
2009-10-09 01:44:41 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
using namespace clang;
|
2010-12-23 15:20:52 +08:00
|
|
|
using namespace ento;
|
2008-03-27 14:17:42 +08:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Boilerplate.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2011-09-26 08:51:36 +08:00
|
|
|
class HTMLDiagnostics : public PathDiagnosticConsumer {
|
2013-06-13 02:13:05 +08:00
|
|
|
std::string Directory;
|
2008-03-27 14:17:42 +08:00
|
|
|
bool createdDir, noDir;
|
2009-11-05 10:41:58 +08:00
|
|
|
const Preprocessor &PP;
|
2014-06-14 16:45:32 +08:00
|
|
|
AnalyzerOptions &AnalyzerOpts;
|
2008-03-27 14:17:42 +08:00
|
|
|
public:
|
2014-06-14 16:45:32 +08:00
|
|
|
HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string& prefix, const Preprocessor &pp);
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2015-04-11 10:00:23 +08:00
|
|
|
~HTMLDiagnostics() override { FlushDiagnostics(nullptr); }
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2014-03-15 12:29:04 +08:00
|
|
|
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
|
|
|
|
FilesMade *filesMade) override;
|
2010-03-13 18:17:05 +08:00
|
|
|
|
2014-03-15 12:29:04 +08:00
|
|
|
StringRef getName() const override {
|
2009-11-05 10:09:23 +08:00
|
|
|
return "HTMLDiagnostics";
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
unsigned ProcessMacroPiece(raw_ostream &os,
|
2009-03-10 13:16:17 +08:00
|
|
|
const PathDiagnosticMacroPiece& P,
|
|
|
|
unsigned num);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-17 14:22:33 +08:00
|
|
|
void HandlePiece(Rewriter& R, FileID BugFileID,
|
2008-07-24 07:18:15 +08:00
|
|
|
const PathDiagnosticPiece& P, unsigned num, unsigned max);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Introduce code modification hints into the diagnostics system. When we
know how to recover from an error, we can attach a hint to the
diagnostic that states how to modify the code, which can be one of:
- Insert some new code (a text string) at a particular source
location
- Remove the code within a given range
- Replace the code within a given range with some new code (a text
string)
Right now, we use these hints to annotate diagnostic information. For
example, if one uses the '>>' in a template argument in C++98, as in
this code:
template<int I> class B { };
B<1000 >> 2> *b1;
we'll warn that the behavior will change in C++0x. The fix is to
insert parenthese, so we use code insertion annotations to illustrate
where the parentheses go:
test.cpp:10:10: warning: use of right-shift operator ('>>') in template
argument will require parentheses in C++0x
B<1000 >> 2> *b1;
^
( )
Use of these annotations is partially implemented for HTML
diagnostics, but it's not (yet) producing valid HTML, which may be
related to PR2386, so it has been #if 0'd out.
In this future, we could consider hooking this mechanism up to the
rewriter to actually try to fix these problems during compilation (or,
after a compilation whose only errors have fixes). For now, however, I
suggest that we use these code modification hints whenever we can, so
that we get better diagnostics now and will have better coverage when
we find better ways to use this information.
This also fixes PR3410 by placing the complaint about missing tokens
just after the previous token (rather than at the location of the next
token).
llvm-svn: 65570
2009-02-27 05:00:50 +08:00
|
|
|
void HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range,
|
|
|
|
const char *HighlightStart = "<span class=\"mrange\">",
|
|
|
|
const char *HighlightEnd = "</span>");
|
2008-04-23 00:15:03 +08:00
|
|
|
|
2009-11-05 10:09:23 +08:00
|
|
|
void ReportDiag(const PathDiagnostic& D,
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
FilesMade *filesMade);
|
2008-03-27 14:17:42 +08:00
|
|
|
};
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
} // end anonymous namespace
|
|
|
|
|
2014-06-14 16:45:32 +08:00
|
|
|
HTMLDiagnostics::HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts,
|
|
|
|
const std::string& prefix,
|
2009-11-05 10:41:58 +08:00
|
|
|
const Preprocessor &pp)
|
2014-06-14 16:45:32 +08:00
|
|
|
: Directory(prefix), createdDir(false), noDir(false), PP(pp), AnalyzerOpts(AnalyzerOpts) {
|
2008-03-27 14:17:42 +08:00
|
|
|
}
|
|
|
|
|
2012-12-19 09:35:35 +08:00
|
|
|
void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
|
|
|
|
PathDiagnosticConsumers &C,
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
const std::string& prefix,
|
|
|
|
const Preprocessor &PP) {
|
2014-06-14 16:45:32 +08:00
|
|
|
C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP));
|
2008-03-27 14:17:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Report processing.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-01-26 07:47:14 +08:00
|
|
|
void HTMLDiagnostics::FlushDiagnosticsImpl(
|
|
|
|
std::vector<const PathDiagnostic *> &Diags,
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
FilesMade *filesMade) {
|
2012-01-26 07:47:14 +08:00
|
|
|
for (std::vector<const PathDiagnostic *>::iterator it = Diags.begin(),
|
|
|
|
et = Diags.end(); it != et; ++it) {
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
ReportDiag(**it, filesMade);
|
2008-04-23 00:15:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-05 10:09:23 +08:00
|
|
|
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
|
Allow multiple PathDiagnosticConsumers to be used with a BugReporter at the same time.
This fixes several issues:
- removes egregious hack where PlistDiagnosticConsumer would forward to HTMLDiagnosticConsumer,
but diagnostics wouldn't be generated consistently in the same way if PlistDiagnosticConsumer
was used by itself.
- emitting diagnostics to the terminal (using clang's diagnostic machinery) is no longer a special
case, just another PathDiagnosticConsumer. This also magically resolved some duplicate warnings,
as we now use PathDiagnosticConsumer's diagnostic pruning, which has scope for the entire translation
unit, not just the scope of a BugReporter (which is limited to a particular ExprEngine).
As an interesting side-effect, diagnostics emitted to the terminal also have their trailing "." stripped,
just like with diagnostics emitted to plists and HTML. This required some tests to be updated, but now
the tests have higher fidelity with what users will see.
There are some inefficiencies in this patch. We currently generate the report graph (from the ExplodedGraph)
once per PathDiagnosticConsumer, which is a bit wasteful, but that could be pulled up higher in the
logic stack. There is some intended duplication, however, as we now generate different PathDiagnostics (for the same issue)
for different PathDiagnosticConsumers. This is necessary to produce the diagnostics that a particular
consumer expects.
llvm-svn: 162028
2012-08-17 01:45:23 +08:00
|
|
|
FilesMade *filesMade) {
|
2014-06-14 16:45:32 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Create the HTML directory if it is missing.
|
|
|
|
if (!createdDir) {
|
|
|
|
createdDir = true;
|
2014-06-12 22:02:15 +08:00
|
|
|
if (std::error_code ec = llvm::sys::fs::create_directories(Directory)) {
|
2009-08-23 20:08:50 +08:00
|
|
|
llvm::errs() << "warning: could not create directory '"
|
2013-06-13 02:13:05 +08:00
|
|
|
<< Directory << "': " << ec.message() << '\n';
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
noDir = true;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
if (noDir)
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-24 14:00:00 +08:00
|
|
|
// First flatten out the entire path to make it easier to use.
|
2012-08-04 07:08:54 +08:00
|
|
|
PathPieces path = D.path.flatten(/*ShouldFlattenMacros=*/false);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-02-29 07:27:39 +08:00
|
|
|
// The path as already been prechecked that all parts of the path are
|
|
|
|
// from the same file and that it is non-empty.
|
2013-04-30 07:12:59 +08:00
|
|
|
const SourceManager &SMgr = (*path.begin())->getLocation().getManager();
|
2012-02-29 07:27:39 +08:00
|
|
|
assert(!path.empty());
|
|
|
|
FileID FID =
|
2013-04-30 07:12:59 +08:00
|
|
|
(*path.begin())->getLocation().asLocation().getExpansionLoc().getFileID();
|
2015-10-03 18:46:20 +08:00
|
|
|
assert(FID.isValid());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-07-24 07:18:15 +08:00
|
|
|
// Create a new rewriter to generate HTML.
|
2012-03-11 15:00:24 +08:00
|
|
|
Rewriter R(const_cast<SourceManager&>(SMgr), PP.getLangOpts());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-06-14 16:45:32 +08:00
|
|
|
// Get the function/method name
|
|
|
|
SmallString<128> declName("unknown");
|
|
|
|
int offsetDecl = 0;
|
|
|
|
if (const Decl *DeclWithIssue = D.getDeclWithIssue()) {
|
|
|
|
if (const NamedDecl *ND = dyn_cast<NamedDecl>(DeclWithIssue)) {
|
|
|
|
declName = ND->getDeclName().getAsString();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const Stmt *Body = DeclWithIssue->getBody()) {
|
|
|
|
// Retrieve the relative position of the declaration which will be used
|
|
|
|
// for the file name
|
|
|
|
FullSourceLoc L(
|
|
|
|
SMgr.getExpansionLoc((*path.rbegin())->getLocation().asLocation()),
|
|
|
|
SMgr);
|
|
|
|
FullSourceLoc FunL(SMgr.getExpansionLoc(Body->getLocStart()), SMgr);
|
|
|
|
offsetDecl = L.getExpansionLineNumber() - FunL.getExpansionLineNumber();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Process the path.
|
2012-02-24 14:00:00 +08:00
|
|
|
unsigned n = path.size();
|
2008-04-01 07:30:12 +08:00
|
|
|
unsigned max = n;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-06-14 16:45:32 +08:00
|
|
|
for (PathPieces::const_reverse_iterator I = path.rbegin(),
|
2012-02-24 14:00:00 +08:00
|
|
|
E = path.rend();
|
2012-02-08 12:32:34 +08:00
|
|
|
I != E; ++I, --n)
|
2013-04-30 07:12:59 +08:00
|
|
|
HandlePiece(R, FID, **I, n, max);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Add line numbers, header, footer, etc.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-17 14:22:33 +08:00
|
|
|
// unsigned FID = R.getSourceMgr().getMainFileID();
|
|
|
|
html::EscapeText(R, FID);
|
|
|
|
html::AddLineNumbers(R, FID);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-17 00:39:56 +08:00
|
|
|
// If we have a preprocessor, relex the file and syntax highlight.
|
|
|
|
// We might not have a preprocessor if we come from a deserialized AST file,
|
|
|
|
// for example.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-11-05 10:41:58 +08:00
|
|
|
html::SyntaxHighlight(R, FID, PP);
|
|
|
|
html::HighlightMacros(R, FID, PP);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-03 04:44:16 +08:00
|
|
|
// Get the full directory name of the analyzed file.
|
|
|
|
|
2009-01-17 14:22:33 +08:00
|
|
|
const FileEntry* Entry = SMgr.getFileEntryForID(FID);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-25 07:37:03 +08:00
|
|
|
// This is a cludge; basically we want to append either the full
|
|
|
|
// working directory if we have no directory information. This is
|
|
|
|
// a work in progress.
|
|
|
|
|
2013-06-13 02:13:05 +08:00
|
|
|
llvm::SmallString<0> DirName;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-12-18 05:22:22 +08:00
|
|
|
if (llvm::sys::path::is_relative(Entry->getName())) {
|
2013-06-13 02:13:05 +08:00
|
|
|
llvm::sys::fs::current_path(DirName);
|
|
|
|
DirName += '/';
|
2008-05-03 06:04:53 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-06-14 16:45:32 +08:00
|
|
|
int LineNumber = (*path.rbegin())->getLocation().asLocation().getExpansionLineNumber();
|
|
|
|
int ColumnNumber = (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber();
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Add the name of the file as an <h1> tag.
|
|
|
|
|
2008-04-03 04:44:16 +08:00
|
|
|
{
|
2008-09-13 13:16:45 +08:00
|
|
|
std::string s;
|
|
|
|
llvm::raw_string_ostream os(s);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-23 01:33:32 +08:00
|
|
|
os << "<!-- REPORTHEADER -->\n"
|
2009-04-01 14:13:56 +08:00
|
|
|
<< "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
|
2008-04-16 05:25:08 +08:00
|
|
|
"<tr><td class=\"rowname\">File:</td><td>"
|
2009-04-01 14:13:56 +08:00
|
|
|
<< html::EscapeText(DirName)
|
|
|
|
<< html::EscapeText(Entry->getName())
|
|
|
|
<< "</td></tr>\n<tr><td class=\"rowname\">Location:</td><td>"
|
2009-09-09 23:08:12 +08:00
|
|
|
"<a href=\"#EndPath\">line "
|
2014-06-14 16:45:32 +08:00
|
|
|
<< LineNumber
|
2009-04-01 14:13:56 +08:00
|
|
|
<< ", column "
|
2014-06-14 16:45:32 +08:00
|
|
|
<< ColumnNumber
|
2009-04-01 14:13:56 +08:00
|
|
|
<< "</a></td></tr>\n"
|
|
|
|
"<tr><td class=\"rowname\">Description:</td><td>"
|
2012-08-31 08:36:26 +08:00
|
|
|
<< D.getVerboseDescription() << "</td></tr>\n";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-05-01 07:47:44 +08:00
|
|
|
// Output any other meta data.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-05-01 07:47:44 +08:00
|
|
|
for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
|
|
|
|
I!=E; ++I) {
|
|
|
|
os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-23 01:33:32 +08:00
|
|
|
os << "</table>\n<!-- REPORTSUMMARYEXTRA -->\n"
|
2009-09-09 23:08:12 +08:00
|
|
|
"<h3>Annotated Source Code</h3>\n";
|
|
|
|
|
2009-08-20 04:32:38 +08:00
|
|
|
R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
|
2008-04-02 15:04:46 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-03 04:44:16 +08:00
|
|
|
// Embed meta-data tags.
|
2009-08-04 07:44:55 +08:00
|
|
|
{
|
2009-01-27 09:53:39 +08:00
|
|
|
std::string s;
|
|
|
|
llvm::raw_string_ostream os(s);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-08-31 08:36:26 +08:00
|
|
|
StringRef BugDesc = D.getVerboseDescription();
|
2009-08-04 07:44:55 +08:00
|
|
|
if (!BugDesc.empty())
|
|
|
|
os << "\n<!-- BUGDESC " << BugDesc << " -->\n";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-08-31 08:36:26 +08:00
|
|
|
StringRef BugType = D.getBugType();
|
2009-08-04 07:44:55 +08:00
|
|
|
if (!BugType.empty())
|
|
|
|
os << "\n<!-- BUGTYPE " << BugType << " -->\n";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-10-22 19:53:04 +08:00
|
|
|
PathDiagnosticLocation UPDLoc = D.getUniqueingLoc();
|
|
|
|
FullSourceLoc L(SMgr.getExpansionLoc(UPDLoc.isValid()
|
|
|
|
? UPDLoc.asLocation()
|
|
|
|
: D.getLocation().asLocation()),
|
|
|
|
SMgr);
|
|
|
|
const Decl *DeclWithIssue = D.getDeclWithIssue();
|
|
|
|
|
2012-08-31 08:36:26 +08:00
|
|
|
StringRef BugCategory = D.getCategory();
|
2009-08-04 07:44:55 +08:00
|
|
|
if (!BugCategory.empty())
|
|
|
|
os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
|
|
|
|
|
2008-04-25 07:37:03 +08:00
|
|
|
os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
|
2009-08-04 07:44:55 +08:00
|
|
|
|
2014-06-14 16:49:40 +08:00
|
|
|
os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry->getName()) << " -->\n";
|
|
|
|
|
|
|
|
os << "\n<!-- FUNCTIONNAME " << declName << " -->\n";
|
|
|
|
|
2015-10-22 19:53:04 +08:00
|
|
|
os << "\n<!-- ISSUEHASHCONTENTOFLINEINCONTEXT "
|
|
|
|
<< GetIssueHash(SMgr, L, D.getCheckName(), D.getBugType(), DeclWithIssue)
|
|
|
|
<< " -->\n";
|
|
|
|
|
2009-01-16 15:36:28 +08:00
|
|
|
os << "\n<!-- BUGLINE "
|
2014-06-14 16:45:32 +08:00
|
|
|
<< LineNumber
|
2009-04-01 14:13:56 +08:00
|
|
|
<< " -->\n";
|
2009-08-04 07:44:55 +08:00
|
|
|
|
2013-11-15 10:11:11 +08:00
|
|
|
os << "\n<!-- BUGCOLUMN "
|
2014-06-14 16:45:32 +08:00
|
|
|
<< ColumnNumber
|
2013-11-15 10:11:11 +08:00
|
|
|
<< " -->\n";
|
|
|
|
|
2012-02-24 14:00:00 +08:00
|
|
|
os << "\n<!-- BUGPATHLENGTH " << path.size() << " -->\n";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-04 07:44:55 +08:00
|
|
|
// Mark the end of the tags.
|
|
|
|
os << "\n<!-- BUGMETAEND -->\n";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-08-04 07:44:55 +08:00
|
|
|
// Insert the text.
|
2009-08-20 04:32:38 +08:00
|
|
|
R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
|
2008-04-03 04:44:16 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Add CSS, header, and footer.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-17 14:22:33 +08:00
|
|
|
html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Get the rewrite buffer.
|
2009-01-17 14:22:33 +08:00
|
|
|
const RewriteBuffer *Buf = R.getRewriteBufferFor(FID);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
if (!Buf) {
|
2009-08-23 20:08:50 +08:00
|
|
|
llvm::errs() << "warning: no diagnostics generated for main file.\n";
|
2008-03-27 14:17:42 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-10-09 01:44:41 +08:00
|
|
|
// Create a path for the target HTML file.
|
2013-06-13 02:13:05 +08:00
|
|
|
int FD;
|
|
|
|
SmallString<128> Model, ResultPath;
|
|
|
|
|
2014-06-14 16:45:32 +08:00
|
|
|
if (!AnalyzerOpts.shouldWriteStableReportFilename()) {
|
|
|
|
llvm::sys::path::append(Model, Directory, "report-%%%%%%.html");
|
2015-10-01 09:24:59 +08:00
|
|
|
if (std::error_code EC =
|
|
|
|
llvm::sys::fs::make_absolute(Model)) {
|
|
|
|
llvm::errs() << "warning: could not make '" << Model
|
|
|
|
<< "' absolute: " << EC.message() << '\n';
|
|
|
|
return;
|
|
|
|
}
|
2014-06-14 16:45:32 +08:00
|
|
|
if (std::error_code EC =
|
2015-03-18 18:17:07 +08:00
|
|
|
llvm::sys::fs::createUniqueFile(Model, FD, ResultPath)) {
|
2014-06-14 16:45:32 +08:00
|
|
|
llvm::errs() << "warning: could not create file in '" << Directory
|
|
|
|
<< "': " << EC.message() << '\n';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
int i = 1;
|
|
|
|
std::error_code EC;
|
|
|
|
do {
|
|
|
|
// Find a filename which is not already used
|
2014-06-14 17:28:27 +08:00
|
|
|
std::stringstream filename;
|
2014-06-14 16:45:32 +08:00
|
|
|
Model = "";
|
2014-06-14 17:28:27 +08:00
|
|
|
filename << "report-"
|
|
|
|
<< llvm::sys::path::filename(Entry->getName()).str()
|
|
|
|
<< "-" << declName.c_str()
|
|
|
|
<< "-" << offsetDecl
|
|
|
|
<< "-" << i << ".html";
|
2014-06-14 16:45:32 +08:00
|
|
|
llvm::sys::path::append(Model, Directory,
|
2014-06-14 17:28:27 +08:00
|
|
|
filename.str());
|
2015-03-18 18:17:07 +08:00
|
|
|
EC = llvm::sys::fs::openFileForWrite(Model,
|
2014-06-14 16:45:32 +08:00
|
|
|
FD,
|
|
|
|
llvm::sys::fs::F_RW |
|
|
|
|
llvm::sys::fs::F_Excl);
|
2015-06-14 01:23:13 +08:00
|
|
|
if (EC && EC != llvm::errc::file_exists) {
|
2015-03-18 18:17:07 +08:00
|
|
|
llvm::errs() << "warning: could not create file '" << Model
|
2014-06-14 16:45:32 +08:00
|
|
|
<< "': " << EC.message() << '\n';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
} while (EC);
|
2008-03-27 14:17:42 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-06-13 02:13:05 +08:00
|
|
|
llvm::raw_fd_ostream os(FD, true);
|
|
|
|
|
|
|
|
if (filesMade)
|
|
|
|
filesMade->addDiagnostic(D, getName(),
|
|
|
|
llvm::sys::path::filename(ResultPath));
|
2009-10-09 01:44:41 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Emit the HTML to disk.
|
2008-04-20 09:02:33 +08:00
|
|
|
for (RewriteBuffer::iterator I = Buf->begin(), E = Buf->end(); I!=E; ++I)
|
2009-09-09 23:08:12 +08:00
|
|
|
os << *I;
|
2008-03-27 14:17:42 +08:00
|
|
|
}
|
|
|
|
|
2009-01-17 14:22:33 +08:00
|
|
|
void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
|
2008-03-27 14:17:42 +08:00
|
|
|
const PathDiagnosticPiece& P,
|
2008-04-01 07:30:12 +08:00
|
|
|
unsigned num, unsigned max) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// For now, just draw a box above the line in question, and emit the
|
|
|
|
// warning.
|
2009-04-01 14:13:56 +08:00
|
|
|
FullSourceLoc Pos = P.getLocation().asLocation();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
if (!Pos.isValid())
|
2009-09-09 23:08:12 +08:00
|
|
|
return;
|
|
|
|
|
2009-01-17 14:22:33 +08:00
|
|
|
SourceManager &SM = R.getSourceMgr();
|
2009-02-04 08:55:58 +08:00
|
|
|
assert(&Pos.getManager() == &SM && "SourceManagers are different!");
|
2011-07-26 04:52:32 +08:00
|
|
|
std::pair<FileID, unsigned> LPosInfo = SM.getDecomposedExpansionLoc(Pos);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-04 08:55:58 +08:00
|
|
|
if (LPosInfo.first != BugFileID)
|
2008-03-27 14:17:42 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-02-04 08:55:58 +08:00
|
|
|
const llvm::MemoryBuffer *Buf = SM.getBuffer(LPosInfo.first);
|
2009-09-09 23:08:12 +08:00
|
|
|
const char* FileStart = Buf->getBufferStart();
|
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Compute the column number. Rewind from the current position to the start
|
|
|
|
// of the line.
|
2009-02-04 08:55:58 +08:00
|
|
|
unsigned ColNo = SM.getColumnNumber(LPosInfo.first, LPosInfo.second);
|
2011-07-26 00:49:02 +08:00
|
|
|
const char *TokInstantiationPtr =Pos.getExpansionLoc().getCharacterData();
|
2009-01-16 15:36:28 +08:00
|
|
|
const char *LineStart = TokInstantiationPtr-ColNo;
|
2008-05-07 07:42:18 +08:00
|
|
|
|
2009-02-19 06:10:00 +08:00
|
|
|
// Compute LineEnd.
|
2009-01-16 15:36:28 +08:00
|
|
|
const char *LineEnd = TokInstantiationPtr;
|
2009-02-19 06:10:00 +08:00
|
|
|
const char* FileEnd = Buf->getBufferEnd();
|
|
|
|
while (*LineEnd != '\n' && LineEnd != FileEnd)
|
|
|
|
++LineEnd;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-04-01 05:40:14 +08:00
|
|
|
// Compute the margin offset by counting tabs and non-tabs.
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned PosNo = 0;
|
2009-01-16 15:36:28 +08:00
|
|
|
for (const char* c = LineStart; c != TokInstantiationPtr; ++c)
|
2008-05-07 07:42:18 +08:00
|
|
|
PosNo += *c == '\t' ? 8 : 1;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Create the html for the message.
|
2009-03-10 13:16:17 +08:00
|
|
|
|
2014-05-27 10:45:47 +08:00
|
|
|
const char *Kind = nullptr;
|
2009-03-10 13:16:17 +08:00
|
|
|
switch (P.getKind()) {
|
2012-02-24 14:00:00 +08:00
|
|
|
case PathDiagnosticPiece::Call:
|
|
|
|
llvm_unreachable("Calls should already be handled");
|
2010-01-20 10:03:14 +08:00
|
|
|
case PathDiagnosticPiece::Event: Kind = "Event"; break;
|
|
|
|
case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
|
|
|
|
// Setting Kind to "Control" is intentional.
|
|
|
|
case PathDiagnosticPiece::Macro: Kind = "Control"; break;
|
2009-03-10 13:16:17 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
std::string sbuf;
|
|
|
|
llvm::raw_string_ostream os(sbuf);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
os << "\n<tr><td class=\"num\"></td><td class=\"line\"><div id=\"";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
if (num == max)
|
|
|
|
os << "EndPath";
|
|
|
|
else
|
|
|
|
os << "Path" << num;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
os << "\" class=\"msg";
|
|
|
|
if (Kind)
|
2009-09-09 23:08:12 +08:00
|
|
|
os << " msg" << Kind;
|
2009-03-10 13:16:17 +08:00
|
|
|
os << "\" style=\"margin-left:" << PosNo << "ex";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
// Output a maximum size.
|
|
|
|
if (!isa<PathDiagnosticMacroPiece>(P)) {
|
2008-09-22 02:52:59 +08:00
|
|
|
// Get the string and determining its maximum substring.
|
|
|
|
const std::string& Msg = P.getString();
|
|
|
|
unsigned max_token = 0;
|
|
|
|
unsigned cnt = 0;
|
|
|
|
unsigned len = Msg.size();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-22 02:52:59 +08:00
|
|
|
for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I)
|
|
|
|
switch (*I) {
|
2010-01-20 10:03:14 +08:00
|
|
|
default:
|
|
|
|
++cnt;
|
|
|
|
continue;
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '\n':
|
|
|
|
if (cnt > max_token) max_token = cnt;
|
|
|
|
cnt = 0;
|
2008-09-22 02:52:59 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
if (cnt > max_token)
|
|
|
|
max_token = cnt;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
// Determine the approximate size of the message bubble in em.
|
2008-09-22 02:52:59 +08:00
|
|
|
unsigned em;
|
2009-03-03 07:06:15 +08:00
|
|
|
const unsigned max_line = 120;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-22 02:52:59 +08:00
|
|
|
if (max_token >= max_line)
|
|
|
|
em = max_token / 2;
|
|
|
|
else {
|
|
|
|
unsigned characters = max_line;
|
|
|
|
unsigned lines = len / max_line;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-09-22 02:52:59 +08:00
|
|
|
if (lines > 0) {
|
|
|
|
for (; characters > max_token; --characters)
|
|
|
|
if (len / characters > lines) {
|
|
|
|
++characters;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
em = characters / 2;
|
2009-03-03 07:05:40 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
if (em < max_line/2)
|
2009-09-09 23:08:12 +08:00
|
|
|
os << "; max-width:" << em << "em";
|
2009-03-10 13:16:17 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
os << "; max-width:100em";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
os << "\">";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
if (max > 1) {
|
|
|
|
os << "<table class=\"msgT\"><tr><td valign=\"top\">";
|
|
|
|
os << "<div class=\"PathIndex";
|
|
|
|
if (Kind) os << " PathIndex" << Kind;
|
|
|
|
os << "\">" << num << "</div>";
|
2012-08-02 10:26:19 +08:00
|
|
|
|
|
|
|
if (num > 1) {
|
|
|
|
os << "</td><td><div class=\"PathNav\"><a href=\"#Path"
|
|
|
|
<< (num - 1)
|
|
|
|
<< "\" title=\"Previous event ("
|
|
|
|
<< (num - 1)
|
|
|
|
<< ")\">←</a></div></td>";
|
|
|
|
}
|
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
os << "</td><td>";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const PathDiagnosticMacroPiece *MP =
|
2009-09-09 23:08:12 +08:00
|
|
|
dyn_cast<PathDiagnosticMacroPiece>(&P)) {
|
2009-03-10 13:16:17 +08:00
|
|
|
|
|
|
|
os << "Within the expansion of the macro '";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
// Get the name of the macro by relexing it.
|
|
|
|
{
|
2011-07-26 00:49:02 +08:00
|
|
|
FullSourceLoc L = MP->getLocation().asLocation().getExpansionLoc();
|
2009-03-10 13:16:17 +08:00
|
|
|
assert(L.isFileID());
|
2011-07-23 18:55:15 +08:00
|
|
|
StringRef BufferInfo = L.getBufferData();
|
2012-05-12 05:39:18 +08:00
|
|
|
std::pair<FileID, unsigned> LocInfo = L.getDecomposedLoc();
|
|
|
|
const char* MacroName = LocInfo.second + BufferInfo.data();
|
|
|
|
Lexer rawLexer(SM.getLocForStartOfFile(LocInfo.first), PP.getLangOpts(),
|
|
|
|
BufferInfo.begin(), MacroName, BufferInfo.end());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
Token TheTok;
|
|
|
|
rawLexer.LexFromRawLexer(TheTok);
|
|
|
|
for (unsigned i = 0, n = TheTok.getLength(); i < n; ++i)
|
|
|
|
os << MacroName[i];
|
2009-03-03 07:05:40 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
os << "':\n";
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-08-02 10:43:42 +08:00
|
|
|
if (max > 1) {
|
|
|
|
os << "</td>";
|
|
|
|
if (num < max) {
|
|
|
|
os << "<td><div class=\"PathNav\"><a href=\"#";
|
|
|
|
if (num == max - 1)
|
|
|
|
os << "EndPath";
|
|
|
|
else
|
|
|
|
os << "Path" << (num + 1);
|
|
|
|
os << "\" title=\"Next event ("
|
|
|
|
<< (num + 1)
|
|
|
|
<< ")\">→</a></div></td>";
|
|
|
|
}
|
|
|
|
|
|
|
|
os << "</tr></table>";
|
|
|
|
}
|
2008-09-22 02:52:59 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
// Within a macro piece. Write out each event.
|
|
|
|
ProcessMacroPiece(os, *MP, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
os << html::EscapeText(P.getString());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-08-02 10:26:19 +08:00
|
|
|
if (max > 1) {
|
|
|
|
os << "</td>";
|
|
|
|
if (num < max) {
|
|
|
|
os << "<td><div class=\"PathNav\"><a href=\"#";
|
|
|
|
if (num == max - 1)
|
|
|
|
os << "EndPath";
|
|
|
|
else
|
|
|
|
os << "Path" << (num + 1);
|
|
|
|
os << "\" title=\"Next event ("
|
|
|
|
<< (num + 1)
|
|
|
|
<< ")\">→</a></div></td>";
|
|
|
|
}
|
2014-06-14 16:45:32 +08:00
|
|
|
|
2012-08-02 10:26:19 +08:00
|
|
|
os << "</tr></table>";
|
|
|
|
}
|
2008-09-22 02:52:59 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
os << "</div></td></tr>";
|
|
|
|
|
|
|
|
// Insert the new html.
|
2009-09-09 23:08:12 +08:00
|
|
|
unsigned DisplayPos = LineEnd - FileStart;
|
|
|
|
SourceLocation Loc =
|
2011-09-20 04:40:19 +08:00
|
|
|
SM.getLocForStartOfFile(LPosInfo.first).getLocWithOffset(DisplayPos);
|
2009-03-10 13:16:17 +08:00
|
|
|
|
2009-08-20 04:32:38 +08:00
|
|
|
R.InsertTextBefore(Loc, os.str());
|
2009-03-10 13:16:17 +08:00
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Now highlight the ranges.
|
2012-08-17 01:45:29 +08:00
|
|
|
ArrayRef<SourceRange> Ranges = P.getRanges();
|
|
|
|
for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
|
|
|
|
E = Ranges.end(); I != E; ++I) {
|
2009-02-04 08:55:58 +08:00
|
|
|
HighlightRange(R, LPosInfo.first, *I);
|
2012-08-17 01:45:29 +08:00
|
|
|
}
|
2008-03-27 14:17:42 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
static void EmitAlphaCounter(raw_ostream &os, unsigned n) {
|
2010-03-13 19:34:41 +08:00
|
|
|
unsigned x = n % ('z' - 'a');
|
|
|
|
n /= 'z' - 'a';
|
2009-03-10 13:16:17 +08:00
|
|
|
|
2010-03-13 19:34:41 +08:00
|
|
|
if (n > 0)
|
|
|
|
EmitAlphaCounter(os, n);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-03-13 19:34:41 +08:00
|
|
|
os << char('a' + x);
|
2009-03-10 13:16:17 +08:00
|
|
|
}
|
|
|
|
|
2011-08-13 07:37:29 +08:00
|
|
|
unsigned HTMLDiagnostics::ProcessMacroPiece(raw_ostream &os,
|
2009-03-10 13:16:17 +08:00
|
|
|
const PathDiagnosticMacroPiece& P,
|
|
|
|
unsigned num) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-04-30 07:12:59 +08:00
|
|
|
for (PathPieces::const_iterator I = P.subPieces.begin(), E=P.subPieces.end();
|
2009-03-10 13:16:17 +08:00
|
|
|
I!=E; ++I) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
if (const PathDiagnosticMacroPiece *MP =
|
2013-04-30 07:12:59 +08:00
|
|
|
dyn_cast<PathDiagnosticMacroPiece>(*I)) {
|
2009-03-10 13:16:17 +08:00
|
|
|
num = ProcessMacroPiece(os, *MP, num);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-04-30 07:12:59 +08:00
|
|
|
if (PathDiagnosticEventPiece *EP = dyn_cast<PathDiagnosticEventPiece>(*I)) {
|
2009-03-10 13:16:17 +08:00
|
|
|
os << "<div class=\"msg msgEvent\" style=\"width:94%; "
|
|
|
|
"margin-left:5px\">"
|
|
|
|
"<table class=\"msgT\"><tr>"
|
|
|
|
"<td valign=\"top\"><div class=\"PathIndex PathIndexEvent\">";
|
|
|
|
EmitAlphaCounter(os, num++);
|
|
|
|
os << "</div></td><td valign=\"top\">"
|
|
|
|
<< html::EscapeText(EP->getString())
|
|
|
|
<< "</td></tr></table></div>\n";
|
|
|
|
}
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-10 13:16:17 +08:00
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2009-01-17 14:22:33 +08:00
|
|
|
void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID,
|
Introduce code modification hints into the diagnostics system. When we
know how to recover from an error, we can attach a hint to the
diagnostic that states how to modify the code, which can be one of:
- Insert some new code (a text string) at a particular source
location
- Remove the code within a given range
- Replace the code within a given range with some new code (a text
string)
Right now, we use these hints to annotate diagnostic information. For
example, if one uses the '>>' in a template argument in C++98, as in
this code:
template<int I> class B { };
B<1000 >> 2> *b1;
we'll warn that the behavior will change in C++0x. The fix is to
insert parenthese, so we use code insertion annotations to illustrate
where the parentheses go:
test.cpp:10:10: warning: use of right-shift operator ('>>') in template
argument will require parentheses in C++0x
B<1000 >> 2> *b1;
^
( )
Use of these annotations is partially implemented for HTML
diagnostics, but it's not (yet) producing valid HTML, which may be
related to PR2386, so it has been #if 0'd out.
In this future, we could consider hooking this mechanism up to the
rewriter to actually try to fix these problems during compilation (or,
after a compilation whose only errors have fixes). For now, however, I
suggest that we use these code modification hints whenever we can, so
that we get better diagnostics now and will have better coverage when
we find better ways to use this information.
This also fixes PR3410 by placing the complaint about missing tokens
just after the previous token (rather than at the location of the next
token).
llvm-svn: 65570
2009-02-27 05:00:50 +08:00
|
|
|
SourceRange Range,
|
|
|
|
const char *HighlightStart,
|
|
|
|
const char *HighlightEnd) {
|
2009-04-15 07:22:57 +08:00
|
|
|
SourceManager &SM = R.getSourceMgr();
|
|
|
|
const LangOptions &LangOpts = R.getLangOpts();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-26 00:49:02 +08:00
|
|
|
SourceLocation InstantiationStart = SM.getExpansionLoc(Range.getBegin());
|
2011-07-26 05:09:52 +08:00
|
|
|
unsigned StartLineNo = SM.getExpansionLineNumber(InstantiationStart);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-26 00:49:02 +08:00
|
|
|
SourceLocation InstantiationEnd = SM.getExpansionLoc(Range.getEnd());
|
2011-07-26 05:09:52 +08:00
|
|
|
unsigned EndLineNo = SM.getExpansionLineNumber(InstantiationEnd);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
if (EndLineNo < StartLineNo)
|
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-19 15:46:45 +08:00
|
|
|
if (SM.getFileID(InstantiationStart) != BugFileID ||
|
|
|
|
SM.getFileID(InstantiationEnd) != BugFileID)
|
2008-03-27 14:17:42 +08:00
|
|
|
return;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Compute the column number of the end.
|
2011-07-26 04:57:57 +08:00
|
|
|
unsigned EndColNo = SM.getExpansionColumnNumber(InstantiationEnd);
|
2008-03-27 14:17:42 +08:00
|
|
|
unsigned OldEndColNo = EndColNo;
|
|
|
|
|
|
|
|
if (EndColNo) {
|
|
|
|
// Add in the length of the token, so that we cover multi-char tokens.
|
2009-04-15 07:22:57 +08:00
|
|
|
EndColNo += Lexer::MeasureTokenLength(Range.getEnd(), SM, LangOpts)-1;
|
2008-03-27 14:17:42 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-03-27 14:17:42 +08:00
|
|
|
// Highlight the range. Make the span tag the outermost tag for the
|
|
|
|
// selected range.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-16 15:36:28 +08:00
|
|
|
SourceLocation E =
|
2011-09-20 04:40:19 +08:00
|
|
|
InstantiationEnd.getLocWithOffset(EndColNo - OldEndColNo);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
Introduce code modification hints into the diagnostics system. When we
know how to recover from an error, we can attach a hint to the
diagnostic that states how to modify the code, which can be one of:
- Insert some new code (a text string) at a particular source
location
- Remove the code within a given range
- Replace the code within a given range with some new code (a text
string)
Right now, we use these hints to annotate diagnostic information. For
example, if one uses the '>>' in a template argument in C++98, as in
this code:
template<int I> class B { };
B<1000 >> 2> *b1;
we'll warn that the behavior will change in C++0x. The fix is to
insert parenthese, so we use code insertion annotations to illustrate
where the parentheses go:
test.cpp:10:10: warning: use of right-shift operator ('>>') in template
argument will require parentheses in C++0x
B<1000 >> 2> *b1;
^
( )
Use of these annotations is partially implemented for HTML
diagnostics, but it's not (yet) producing valid HTML, which may be
related to PR2386, so it has been #if 0'd out.
In this future, we could consider hooking this mechanism up to the
rewriter to actually try to fix these problems during compilation (or,
after a compilation whose only errors have fixes). For now, however, I
suggest that we use these code modification hints whenever we can, so
that we get better diagnostics now and will have better coverage when
we find better ways to use this information.
This also fixes PR3410 by placing the complaint about missing tokens
just after the previous token (rather than at the location of the next
token).
llvm-svn: 65570
2009-02-27 05:00:50 +08:00
|
|
|
html::HighlightRange(R, InstantiationStart, E, HighlightStart, HighlightEnd);
|
2008-03-27 14:17:42 +08:00
|
|
|
}
|