PathDiagnostic.cpp revision 590dd8e0959d8df5621827768987c4792b74fc06
1//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file defines the PathDiagnostic-related interfaces. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 15#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 16#include "clang/AST/Expr.h" 17#include "clang/AST/Decl.h" 18#include "clang/AST/DeclObjC.h" 19#include "clang/AST/ParentMap.h" 20#include "clang/AST/StmtCXX.h" 21#include "llvm/ADT/SmallString.h" 22 23using namespace clang; 24using namespace ento; 25 26bool PathDiagnosticMacroPiece::containsEvent() const { 27 for (const_iterator I = begin(), E = end(); I!=E; ++I) { 28 if (isa<PathDiagnosticEventPiece>(*I)) 29 return true; 30 31 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 32 if (MP->containsEvent()) 33 return true; 34 } 35 36 return false; 37} 38 39static StringRef StripTrailingDots(StringRef s) { 40 for (StringRef::size_type i = s.size(); i != 0; --i) 41 if (s[i - 1] != '.') 42 return s.substr(0, i); 43 return ""; 44} 45 46PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 47 Kind k, DisplayHint hint) 48 : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 49 50PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 51 : kind(k), Hint(hint) {} 52 53PathDiagnosticPiece::~PathDiagnosticPiece() {} 54PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 55PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 56 57PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() { 58 for (iterator I = begin(), E = end(); I != E; ++I) delete *I; 59} 60 61PathDiagnostic::PathDiagnostic() : Size(0) {} 62 63PathDiagnostic::~PathDiagnostic() { 64 for (iterator I = begin(), E = end(); I != E; ++I) delete &*I; 65} 66 67void PathDiagnostic::resetPath(bool deletePieces) { 68 Size = 0; 69 70 if (deletePieces) 71 for (iterator I=begin(), E=end(); I!=E; ++I) 72 delete &*I; 73 74 path.clear(); 75} 76 77 78PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc, 79 StringRef category) 80 : Size(0), 81 BugType(StripTrailingDots(bugtype)), 82 Desc(StripTrailingDots(desc)), 83 Category(StripTrailingDots(category)) {} 84 85void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, 86 const DiagnosticInfo &Info) { 87 // Default implementation (Warnings/errors count). 88 DiagnosticClient::HandleDiagnostic(DiagLevel, Info); 89 90 // Create a PathDiagnostic with a single piece. 91 92 PathDiagnostic* D = new PathDiagnostic(); 93 94 const char *LevelStr; 95 switch (DiagLevel) { 96 default: 97 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); 98 case Diagnostic::Note: LevelStr = "note: "; break; 99 case Diagnostic::Warning: LevelStr = "warning: "; break; 100 case Diagnostic::Error: LevelStr = "error: "; break; 101 case Diagnostic::Fatal: LevelStr = "fatal error: "; break; 102 } 103 104 llvm::SmallString<100> StrC; 105 StrC += LevelStr; 106 Info.FormatDiagnostic(StrC); 107 108 PathDiagnosticPiece *P = 109 new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(), 110 Info.getSourceManager()), 111 StrC.str()); 112 113 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) 114 P->addRange(Info.getRange(i).getAsRange()); 115 for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) 116 P->addFixItHint(Info.getFixItHint(i)); 117 D->push_front(P); 118 119 HandlePathDiagnostic(D); 120} 121 122void PathDiagnosticClient::HandlePathDiagnostic(const PathDiagnostic *D) { 123 // For now this simply forwards to HandlePathDiagnosticImpl. In the future 124 // we can use this indirection to control for multi-threaded access to 125 // the PathDiagnosticClient from multiple bug reporters. 126 HandlePathDiagnosticImpl(D); 127} 128 129//===----------------------------------------------------------------------===// 130// PathDiagnosticLocation methods. 131//===----------------------------------------------------------------------===// 132 133static SourceLocation getValidSourceLocation(const Stmt* S, 134 LocationOrAnalysisContext LAC) { 135 SourceLocation L = S->getLocStart(); 136 assert(!LAC.isNull() && "A valid LocationContext or AnalysisContext should " 137 "be passed to PathDiagnosticLocation upon creation."); 138 139 // S might be a temporary statement that does not have a location in the 140 // source code, so find an enclosing statement and use it's location. 141 if (!L.isValid()) { 142 143 ParentMap *PM = 0; 144 if (LAC.is<const LocationContext*>()) 145 PM = &LAC.get<const LocationContext*>()->getParentMap(); 146 else 147 PM = &LAC.get<AnalysisContext*>()->getParentMap(); 148 149 while (!L.isValid()) { 150 S = PM->getParent(S); 151 L = S->getLocStart(); 152 } 153 } 154 155 return L; 156} 157 158PathDiagnosticLocation 159 PathDiagnosticLocation::createBegin(const Decl *D, 160 const SourceManager &SM) { 161 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 162} 163 164PathDiagnosticLocation 165 PathDiagnosticLocation::createBegin(const Stmt *S, 166 const SourceManager &SM, 167 LocationOrAnalysisContext LAC) { 168 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 169 SM, SingleLocK); 170} 171 172PathDiagnosticLocation 173 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 174 const SourceManager &SM) { 175 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 176} 177 178PathDiagnosticLocation 179 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 180 const SourceManager &SM) { 181 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 182} 183 184PathDiagnosticLocation 185 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 186 const SourceManager &SM) { 187 SourceLocation L = CS->getLBracLoc(); 188 return PathDiagnosticLocation(L, SM, SingleLocK); 189} 190 191PathDiagnosticLocation 192 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 193 const SourceManager &SM) { 194 SourceLocation L = CS->getRBracLoc(); 195 return PathDiagnosticLocation(L, SM, SingleLocK); 196} 197 198PathDiagnosticLocation 199 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 200 const SourceManager &SM) { 201 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 202 if (const CompoundStmt *CS = 203 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 204 if (!CS->body_empty()) { 205 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 206 return PathDiagnosticLocation(Loc, SM, SingleLocK); 207 } 208 209 return PathDiagnosticLocation(); 210} 211 212PathDiagnosticLocation 213 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 214 const SourceManager &SM) { 215 SourceLocation L = LC->getDecl()->getBodyRBrace(); 216 return PathDiagnosticLocation(L, SM, SingleLocK); 217} 218 219PathDiagnosticLocation 220 PathDiagnosticLocation::create(const ProgramPoint& P, 221 const SourceManager &SMng) { 222 223 const Stmt* S = 0; 224 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 225 const CFGBlock *BSrc = BE->getSrc(); 226 S = BSrc->getTerminatorCondition(); 227 } 228 else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { 229 S = PS->getStmt(); 230 } 231 232 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 233 234 if (!S) 235 return PathDiagnosticLocation(); 236} 237 238PathDiagnosticLocation 239 PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, 240 const SourceManager &SM) { 241 assert(N && "Cannot create a location with a null node."); 242 243 const ExplodedNode *NI = N; 244 245 while (NI) { 246 ProgramPoint P = NI->getLocation(); 247 const LocationContext *LC = P.getLocationContext(); 248 if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) 249 return PathDiagnosticLocation(PS->getStmt(), SM, LC); 250 else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 251 const Stmt *Term = BE->getSrc()->getTerminator(); 252 assert(Term); 253 return PathDiagnosticLocation(Term, SM, LC); 254 } 255 NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); 256 } 257 258 return createDeclEnd(N->getLocationContext(), SM); 259} 260 261PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 262 const PathDiagnosticLocation &PDL) { 263 FullSourceLoc L = PDL.asLocation(); 264 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 265} 266 267FullSourceLoc 268 PathDiagnosticLocation::genLocation(LocationOrAnalysisContext LAC) const { 269 assert(isValid()); 270 // Note that we want a 'switch' here so that the compiler can warn us in 271 // case we add more cases. 272 switch (K) { 273 case SingleLocK: 274 case RangeK: 275 break; 276 case StmtK: 277 return FullSourceLoc(getValidSourceLocation(S, LAC), 278 const_cast<SourceManager&>(*SM)); 279 case DeclK: 280 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 281 } 282 283 return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM)); 284} 285 286PathDiagnosticRange 287 PathDiagnosticLocation::genRange(LocationOrAnalysisContext LAC) const { 288 assert(isValid()); 289 // Note that we want a 'switch' here so that the compiler can warn us in 290 // case we add more cases. 291 switch (K) { 292 case SingleLocK: 293 return PathDiagnosticRange(R, true); 294 case RangeK: 295 break; 296 case StmtK: { 297 const Stmt *S = asStmt(); 298 switch (S->getStmtClass()) { 299 default: 300 break; 301 case Stmt::DeclStmtClass: { 302 const DeclStmt *DS = cast<DeclStmt>(S); 303 if (DS->isSingleDecl()) { 304 // Should always be the case, but we'll be defensive. 305 return SourceRange(DS->getLocStart(), 306 DS->getSingleDecl()->getLocation()); 307 } 308 break; 309 } 310 // FIXME: Provide better range information for different 311 // terminators. 312 case Stmt::IfStmtClass: 313 case Stmt::WhileStmtClass: 314 case Stmt::DoStmtClass: 315 case Stmt::ForStmtClass: 316 case Stmt::ChooseExprClass: 317 case Stmt::IndirectGotoStmtClass: 318 case Stmt::SwitchStmtClass: 319 case Stmt::BinaryConditionalOperatorClass: 320 case Stmt::ConditionalOperatorClass: 321 case Stmt::ObjCForCollectionStmtClass: { 322 SourceLocation L = getValidSourceLocation(S, LAC); 323 return SourceRange(L, L); 324 } 325 } 326 327 return S->getSourceRange(); 328 } 329 case DeclK: 330 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 331 return MD->getSourceRange(); 332 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 333 if (Stmt *Body = FD->getBody()) 334 return Body->getSourceRange(); 335 } 336 else { 337 SourceLocation L = D->getLocation(); 338 return PathDiagnosticRange(SourceRange(L, L), true); 339 } 340 } 341 342 return R; 343} 344 345void PathDiagnosticLocation::flatten() { 346 if (K == StmtK) { 347 R = asRange(); 348 K = RangeK; 349 S = 0; 350 D = 0; 351 } 352 else if (K == DeclK) { 353 SourceLocation L = D->getLocation(); 354 R = SourceRange(L, L); 355 K = SingleLocK; 356 S = 0; 357 D = 0; 358 } 359} 360 361//===----------------------------------------------------------------------===// 362// FoldingSet profiling methods. 363//===----------------------------------------------------------------------===// 364 365void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 366 ID.AddInteger(Range.getBegin().getRawEncoding()); 367 ID.AddInteger(Range.getEnd().getRawEncoding()); 368 ID.AddInteger(Loc.getRawEncoding()); 369 return; 370} 371 372void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 373 ID.AddInteger((unsigned) getKind()); 374 ID.AddString(str); 375 // FIXME: Add profiling support for code hints. 376 ID.AddInteger((unsigned) getDisplayHint()); 377 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) { 378 ID.AddInteger(I->getBegin().getRawEncoding()); 379 ID.AddInteger(I->getEnd().getRawEncoding()); 380 } 381} 382 383void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 384 PathDiagnosticPiece::Profile(ID); 385 ID.Add(Pos); 386} 387 388void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 389 PathDiagnosticPiece::Profile(ID); 390 for (const_iterator I = begin(), E = end(); I != E; ++I) 391 ID.Add(*I); 392} 393 394void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 395 PathDiagnosticSpotPiece::Profile(ID); 396 for (const_iterator I = begin(), E = end(); I != E; ++I) 397 ID.Add(**I); 398} 399 400void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 401 ID.AddInteger(Size); 402 ID.AddString(BugType); 403 ID.AddString(Desc); 404 ID.AddString(Category); 405 for (const_iterator I = begin(), E = end(); I != E; ++I) 406 ID.Add(*I); 407 408 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 409 ID.AddString(*I); 410} 411