PathDiagnostic.cpp revision 43f48b0b1bc763dc56db6e01de4fcc44ad389bef
11b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===//
21b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//
31b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//                     The LLVM Compiler Infrastructure
41b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//
51b268ca467c924004286c97bac133db489cf43d0Ben Murdoch// This file is distributed under the University of Illinois Open Source
61b268ca467c924004286c97bac133db489cf43d0Ben Murdoch// License. See LICENSE.TXT for details.
71b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//
81b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//===----------------------------------------------------------------------===//
91b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//
101b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//  This file defines the PathDiagnostic-related interfaces.
111b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//
121b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//===----------------------------------------------------------------------===//
131b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
141b268ca467c924004286c97bac133db489cf43d0Ben Murdoch#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
151b268ca467c924004286c97bac133db489cf43d0Ben Murdoch#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
161b268ca467c924004286c97bac133db489cf43d0Ben Murdoch#include "clang/AST/Expr.h"
171b268ca467c924004286c97bac133db489cf43d0Ben Murdoch#include "clang/AST/Decl.h"
181b268ca467c924004286c97bac133db489cf43d0Ben Murdoch#include "clang/AST/DeclObjC.h"
191b268ca467c924004286c97bac133db489cf43d0Ben Murdoch#include "clang/AST/StmtCXX.h"
201b268ca467c924004286c97bac133db489cf43d0Ben Murdoch#include "llvm/ADT/SmallString.h"
211b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
221b268ca467c924004286c97bac133db489cf43d0Ben Murdochusing namespace clang;
231b268ca467c924004286c97bac133db489cf43d0Ben Murdochusing namespace ento;
241b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
251b268ca467c924004286c97bac133db489cf43d0Ben Murdochbool PathDiagnosticMacroPiece::containsEvent() const {
261b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  for (const_iterator I = begin(), E = end(); I!=E; ++I) {
271b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (isa<PathDiagnosticEventPiece>(*I))
281b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      return true;
291b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
301b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I))
311b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      if (MP->containsEvent())
321b268ca467c924004286c97bac133db489cf43d0Ben Murdoch        return true;
331b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
341b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
351b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  return false;
361b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
371b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
381b268ca467c924004286c97bac133db489cf43d0Ben Murdochstatic StringRef StripTrailingDots(StringRef s) {
391b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  for (StringRef::size_type i = s.size(); i != 0; --i)
401b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (s[i - 1] != '.')
411b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      return s.substr(0, i);
421b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  return "";
431b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
441b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
451b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnosticPiece::PathDiagnosticPiece(StringRef s,
461b268ca467c924004286c97bac133db489cf43d0Ben Murdoch                                         Kind k, DisplayHint hint)
471b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  : str(StripTrailingDots(s)), kind(k), Hint(hint) {}
4821efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
491b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint)
501b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  : kind(k), Hint(hint) {}
511b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
521b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnosticPiece::~PathDiagnosticPiece() {}
531b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnosticEventPiece::~PathDiagnosticEventPiece() {}
541b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {}
551b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
561b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {
571b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  for (iterator I = begin(), E = end(); I != E; ++I) delete *I;
581b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
591b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
601b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnostic::PathDiagnostic() : Size(0) {}
611b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
621b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnostic::~PathDiagnostic() {
631b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  for (iterator I = begin(), E = end(); I != E; ++I) delete &*I;
641b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
651b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
661b268ca467c924004286c97bac133db489cf43d0Ben Murdochvoid PathDiagnostic::resetPath(bool deletePieces) {
671b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  Size = 0;
681b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
691b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  if (deletePieces)
701b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    for (iterator I=begin(), E=end(); I!=E; ++I)
711b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      delete &*I;
721b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
731b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  path.clear();
741b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
751b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
761b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
771b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc,
781b268ca467c924004286c97bac133db489cf43d0Ben Murdoch                               StringRef category)
791b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  : Size(0),
801b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    BugType(StripTrailingDots(bugtype)),
811b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    Desc(StripTrailingDots(desc)),
821b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    Category(StripTrailingDots(category)) {}
831b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
841b268ca467c924004286c97bac133db489cf43d0Ben Murdochvoid PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
851b268ca467c924004286c97bac133db489cf43d0Ben Murdoch                                            const DiagnosticInfo &Info) {
861b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  // Default implementation (Warnings/errors count).
871b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  DiagnosticClient::HandleDiagnostic(DiagLevel, Info);
881b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
891b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  // Create a PathDiagnostic with a single piece.
901b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
911b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  PathDiagnostic* D = new PathDiagnostic();
921b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
931b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  const char *LevelStr;
941b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  switch (DiagLevel) {
951b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  default:
961b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type");
971b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  case Diagnostic::Note:    LevelStr = "note: "; break;
981b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  case Diagnostic::Warning: LevelStr = "warning: "; break;
991b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  case Diagnostic::Error:   LevelStr = "error: "; break;
1001b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  case Diagnostic::Fatal:   LevelStr = "fatal error: "; break;
1011b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1021b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1031b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  llvm::SmallString<100> StrC;
1041b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  StrC += LevelStr;
1051b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  Info.FormatDiagnostic(StrC);
1061b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1071b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  PathDiagnosticPiece *P =
1081b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(),
1091b268ca467c924004286c97bac133db489cf43d0Ben Murdoch                                               Info.getSourceManager()),
1101b268ca467c924004286c97bac133db489cf43d0Ben Murdoch                                 StrC.str());
1111b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1121b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i)
1131b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    P->addRange(Info.getRange(i).getAsRange());
1141b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i)
1151b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    P->addFixItHint(Info.getFixItHint(i));
1161b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  D->push_front(P);
1171b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1181b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  HandlePathDiagnostic(D);
1191b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
1201b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1211b268ca467c924004286c97bac133db489cf43d0Ben Murdochvoid PathDiagnosticClient::HandlePathDiagnostic(const PathDiagnostic *D) {
1221b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  // For now this simply forwards to HandlePathDiagnosticImpl.  In the future
1231b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  // we can use this indirection to control for multi-threaded access to
1241b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  // the PathDiagnosticClient from multiple bug reporters.
1251b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  HandlePathDiagnosticImpl(D);
1261b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
1271b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1281b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//===----------------------------------------------------------------------===//
1291b268ca467c924004286c97bac133db489cf43d0Ben Murdoch// PathDiagnosticLocation methods.
1301b268ca467c924004286c97bac133db489cf43d0Ben Murdoch//===----------------------------------------------------------------------===//
1311b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1321b268ca467c924004286c97bac133db489cf43d0Ben MurdochPathDiagnosticLocation PathDiagnosticLocation::create(const ExplodedNode* N,
1331b268ca467c924004286c97bac133db489cf43d0Ben Murdoch                                                      const SourceManager &SM) {
1341b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  assert(N && "Cannot create a location with a null node.");
1351b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1361b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  const ExplodedNode *NI = N;
1371b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1381b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  while (NI) {
1391b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    ProgramPoint P = NI->getLocation();
1401b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1411b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) {
1421b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      return PathDiagnosticLocation(PS->getStmt(), SM);
1431b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    }
1441b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
1451b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      const Stmt *Term = BE->getSrc()->getTerminator();
1461b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      assert(Term);
1471b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      return PathDiagnosticLocation(Term, SM);
1481b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    }
1491b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
1501b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  }
1511b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1521b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  const Decl &D = N->getCodeDecl();
1531b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  return PathDiagnosticLocation(D.getBodyRBrace(), SM);
1541b268ca467c924004286c97bac133db489cf43d0Ben Murdoch}
1551b268ca467c924004286c97bac133db489cf43d0Ben Murdoch
1561b268ca467c924004286c97bac133db489cf43d0Ben MurdochFullSourceLoc PathDiagnosticLocation::asLocation() const {
1571b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  assert(isValid());
1581b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  // Note that we want a 'switch' here so that the compiler can warn us in
1591b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  // case we add more cases.
1601b268ca467c924004286c97bac133db489cf43d0Ben Murdoch  switch (K) {
1611b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    case SingleLocK:
1621b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    case RangeK:
1631b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      break;
1641b268ca467c924004286c97bac133db489cf43d0Ben Murdoch    case StmtK:
1651b268ca467c924004286c97bac133db489cf43d0Ben Murdoch      return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM));
166    case DeclK:
167      return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM));
168  }
169
170  return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM));
171}
172
173PathDiagnosticRange PathDiagnosticLocation::asRange() const {
174  assert(isValid());
175  // Note that we want a 'switch' here so that the compiler can warn us in
176  // case we add more cases.
177  switch (K) {
178    case SingleLocK:
179      return PathDiagnosticRange(R, true);
180    case RangeK:
181      break;
182    case StmtK: {
183      const Stmt *S = asStmt();
184      switch (S->getStmtClass()) {
185        default:
186          break;
187        case Stmt::DeclStmtClass: {
188          const DeclStmt *DS = cast<DeclStmt>(S);
189          if (DS->isSingleDecl()) {
190            // Should always be the case, but we'll be defensive.
191            return SourceRange(DS->getLocStart(),
192                               DS->getSingleDecl()->getLocation());
193          }
194          break;
195        }
196          // FIXME: Provide better range information for different
197          //  terminators.
198        case Stmt::IfStmtClass:
199        case Stmt::WhileStmtClass:
200        case Stmt::DoStmtClass:
201        case Stmt::ForStmtClass:
202        case Stmt::ChooseExprClass:
203        case Stmt::IndirectGotoStmtClass:
204        case Stmt::SwitchStmtClass:
205        case Stmt::BinaryConditionalOperatorClass:
206        case Stmt::ConditionalOperatorClass:
207        case Stmt::ObjCForCollectionStmtClass: {
208          SourceLocation L = S->getLocStart();
209          return SourceRange(L, L);
210        }
211      }
212
213      return S->getSourceRange();
214    }
215    case DeclK:
216      if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
217        return MD->getSourceRange();
218      if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
219        if (Stmt *Body = FD->getBody())
220          return Body->getSourceRange();
221      }
222      else {
223        SourceLocation L = D->getLocation();
224        return PathDiagnosticRange(SourceRange(L, L), true);
225      }
226  }
227
228  return R;
229}
230
231void PathDiagnosticLocation::flatten() {
232  if (K == StmtK) {
233    R = asRange();
234    K = RangeK;
235    S = 0;
236    D = 0;
237  }
238  else if (K == DeclK) {
239    SourceLocation L = D->getLocation();
240    R = SourceRange(L, L);
241    K = SingleLocK;
242    S = 0;
243    D = 0;
244  }
245}
246
247//===----------------------------------------------------------------------===//
248// FoldingSet profiling methods.
249//===----------------------------------------------------------------------===//
250
251void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const {
252  ID.AddInteger((unsigned) K);
253  switch (K) {
254    case RangeK:
255      ID.AddInteger(R.getBegin().getRawEncoding());
256      ID.AddInteger(R.getEnd().getRawEncoding());
257      break;
258    case SingleLocK:
259      ID.AddInteger(R.getBegin().getRawEncoding());
260      break;
261    case StmtK:
262      ID.Add(S);
263      break;
264    case DeclK:
265      ID.Add(D);
266      break;
267  }
268  return;
269}
270
271void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
272  ID.AddInteger((unsigned) getKind());
273  ID.AddString(str);
274  // FIXME: Add profiling support for code hints.
275  ID.AddInteger((unsigned) getDisplayHint());
276  for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) {
277    ID.AddInteger(I->getBegin().getRawEncoding());
278    ID.AddInteger(I->getEnd().getRawEncoding());
279  }
280}
281
282void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const {
283  PathDiagnosticPiece::Profile(ID);
284  ID.Add(Pos);
285}
286
287void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const {
288  PathDiagnosticPiece::Profile(ID);
289  for (const_iterator I = begin(), E = end(); I != E; ++I)
290    ID.Add(*I);
291}
292
293void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const {
294  PathDiagnosticSpotPiece::Profile(ID);
295  for (const_iterator I = begin(), E = end(); I != E; ++I)
296    ID.Add(**I);
297}
298
299void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const {
300  ID.AddInteger(Size);
301  ID.AddString(BugType);
302  ID.AddString(Desc);
303  ID.AddString(Category);
304  for (const_iterator I = begin(), E = end(); I != E; ++I)
305    ID.Add(*I);
306
307  for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I)
308    ID.AddString(*I);
309}
310