summaryrefslogtreecommitdiffstats
path: root/lib/Checker/PathDiagnostic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Checker/PathDiagnostic.cpp')
-rw-r--r--lib/Checker/PathDiagnostic.cpp281
1 files changed, 281 insertions, 0 deletions
diff --git a/lib/Checker/PathDiagnostic.cpp b/lib/Checker/PathDiagnostic.cpp
new file mode 100644
index 0000000..97500d9
--- /dev/null
+++ b/lib/Checker/PathDiagnostic.cpp
@@ -0,0 +1,281 @@
+//===--- 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));
+ for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i)
+ P->addCodeModificationHint(Info.getCodeModificationHint(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);
+}
OpenPOWER on IntegriCloud