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