Files
llvm/clang/lib/Checker/PathDiagnostic.cpp
Chris Lattner ed8b6b799d introduce a new CharSourceRange class, and enhance the diagnostics routines
to use them instead of SourceRange.  CharSourceRange is just a SourceRange
plus a bool that indicates whether the range has the end character resolved
or whether the end location is the start of the end token.  While most of
the compiler wants to think of ranges that have ends that are the start of
the end token, the printf diagnostic stuff wants to highlight ranges within
tokens.

This is transparent to the diagnostic stuff.  To start taking advantage of
the new capabilities, you can do something like this:
  Diag(..) << CharSourceRange::getCharRange(Begin,End)

llvm-svn: 106338
2010-06-18 22:45:06 +00:00

282 lines
8.3 KiB
C++

//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- 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 PathDiagnostic-related interfaces.
//
//===----------------------------------------------------------------------===//
#include "clang/Checker/BugReporter/PathDiagnostic.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtCXX.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Casting.h"
using namespace clang;
using llvm::dyn_cast;
using llvm::isa;
bool PathDiagnosticMacroPiece::containsEvent() const {
for (const_iterator I = begin(), E = end(); I!=E; ++I) {
if (isa<PathDiagnosticEventPiece>(*I))
return true;
if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
if (MP->containsEvent())
return true;
}
return false;
}
static llvm::StringRef StripTrailingDots(llvm::StringRef s) {
for (llvm::StringRef::size_type i = s.size(); i != 0; --i)
if (s[i - 1] != '.')
return s.substr(0, i);
return "";
}
PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s,
Kind k, DisplayHint hint)
: str(StripTrailingDots(s)), kind(k), Hint(hint) {}
PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
: kind(k), Hint(hint) {}
PathDiagnosticPiece::~PathDiagnosticPiece() {}
PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
}
PathDiagnostic::PathDiagnostic() : Size(0) {}
PathDiagnostic::~PathDiagnostic() {
for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
}
void PathDiagnostic::resetPath(bool deletePieces) {
Size = 0;
if (deletePieces)
for (iterator I=begin(), E=end(); I!=E; ++I)
delete &*I;
path.clear();
}
PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc,
llvm::StringRef category)
: Size(0),
BugType(StripTrailingDots(bugtype)),
Desc(StripTrailingDots(desc)),
Category(StripTrailingDots(category)) {}
void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
const DiagnosticInfo &Info) {
// Create a PathDiagnostic with a single piece.
PathDiagnostic* D = new PathDiagnostic();
const char *LevelStr;
switch (DiagLevel) {
default:
case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
case Diagnostic::Note: LevelStr = "note: "; break;
case Diagnostic::Warning: LevelStr = "warning: "; break;
case Diagnostic::Error: LevelStr = "error: "; break;
case Diagnostic::Fatal: LevelStr = "fatal error: "; break;
}
llvm::SmallString<100> StrC;
StrC += LevelStr;
Info.FormatDiagnostic(StrC);
PathDiagnosticPiece *P =
new PathDiagnosticEventPiece(Info.getLocation(), StrC.str());
for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
P->addRange(Info.getRange(i).getAsRange());
for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
P->addFixItHint(Info.getFixItHint(i));
D->push_front(P);
HandlePathDiagnostic(D);
}
//===----------------------------------------------------------------------===//
// PathDiagnosticLocation methods.
//===----------------------------------------------------------------------===//
FullSourceLoc PathDiagnosticLocation::asLocation() const {
assert(isValid());
// Note that we want a 'switch' here so that the compiler can warn us in
// case we add more cases.
switch (K) {
case SingleLocK:
case RangeK:
break;
case StmtK:
return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
case DeclK:
return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
}
return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
}
PathDiagnosticRange PathDiagnosticLocation::asRange() const {
assert(isValid());
// Note that we want a 'switch' here so that the compiler can warn us in
// case we add more cases.
switch (K) {
case SingleLocK:
return PathDiagnosticRange(R, true);
case RangeK:
break;
case StmtK: {
const Stmt *S = asStmt();
switch (S->getStmtClass()) {
default:
break;
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(S);
if (DS->isSingleDecl()) {
// Should always be the case, but we'll be defensive.
return SourceRange(DS->getLocStart(),
DS->getSingleDecl()->getLocation());
}
break;
}
// FIXME: Provide better range information for different
// terminators.
case Stmt::IfStmtClass:
case Stmt::WhileStmtClass:
case Stmt::DoStmtClass:
case Stmt::ForStmtClass:
case Stmt::ChooseExprClass:
case Stmt::IndirectGotoStmtClass:
case Stmt::SwitchStmtClass:
case Stmt::ConditionalOperatorClass:
case Stmt::ObjCForCollectionStmtClass: {
SourceLocation L = S->getLocStart();
return SourceRange(L, L);
}
}
return S->getSourceRange();
}
case DeclK:
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getSourceRange();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// FIXME: We would like to always get the function body, even
// when it needs to be de-serialized, but getting the
// ASTContext here requires significant changes.
if (Stmt *Body = FD->getBody()) {
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
return CS->getSourceRange();
else
return cast<CXXTryStmt>(Body)->getSourceRange();
}
}
else {
SourceLocation L = D->getLocation();
return PathDiagnosticRange(SourceRange(L, L), true);
}
}
return R;
}
void PathDiagnosticLocation::flatten() {
if (K == StmtK) {
R = asRange();
K = RangeK;
S = 0;
D = 0;
}
else if (K == DeclK) {
SourceLocation L = D->getLocation();
R = SourceRange(L, L);
K = SingleLocK;
S = 0;
D = 0;
}
}
//===----------------------------------------------------------------------===//
// FoldingSet profiling methods.
//===----------------------------------------------------------------------===//
void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger((unsigned) K);
switch (K) {
case RangeK:
ID.AddInteger(R.getBegin().getRawEncoding());
ID.AddInteger(R.getEnd().getRawEncoding());
break;
case SingleLocK:
ID.AddInteger(R.getBegin().getRawEncoding());
break;
case StmtK:
ID.Add(S);
break;
case DeclK:
ID.Add(D);
break;
}
return;
}
void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger((unsigned) getKind());
ID.AddString(str);
// FIXME: Add profiling support for code hints.
ID.AddInteger((unsigned) getDisplayHint());
for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
ID.AddInteger(I->getBegin().getRawEncoding());
ID.AddInteger(I->getEnd().getRawEncoding());
}
}
void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
PathDiagnosticPiece::Profile(ID);
ID.Add(Pos);
}
void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
PathDiagnosticPiece::Profile(ID);
for (const_iterator I = begin(), E = end(); I != E; ++I)
ID.Add(*I);
}
void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
PathDiagnosticSpotPiece::Profile(ID);
for (const_iterator I = begin(), E = end(); I != E; ++I)
ID.Add(**I);
}
void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Size);
ID.AddString(BugType);
ID.AddString(Desc);
ID.AddString(Category);
for (const_iterator I = begin(), E = end(); I != E; ++I)
ID.Add(*I);
for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
ID.AddString(*I);
}