PathDiagnostic.cpp revision 99ba9e3bd70671f3441fb974895f226a83ce0e66
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 PathDiagnosticConsumer::anchor() { } 86 87void PathDiagnosticConsumer::HandlePathDiagnostic(const PathDiagnostic *D) { 88 // For now this simply forwards to HandlePathDiagnosticImpl. In the future 89 // we can use this indirection to control for multi-threaded access to 90 // the PathDiagnosticConsumer from multiple bug reporters. 91 HandlePathDiagnosticImpl(D); 92} 93 94//===----------------------------------------------------------------------===// 95// PathDiagnosticLocation methods. 96//===----------------------------------------------------------------------===// 97 98static SourceLocation getValidSourceLocation(const Stmt* S, 99 LocationOrAnalysisDeclContext LAC) { 100 SourceLocation L = S->getLocStart(); 101 assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should " 102 "be passed to PathDiagnosticLocation upon creation."); 103 104 // S might be a temporary statement that does not have a location in the 105 // source code, so find an enclosing statement and use it's location. 106 if (!L.isValid()) { 107 108 ParentMap *PM = 0; 109 if (LAC.is<const LocationContext*>()) 110 PM = &LAC.get<const LocationContext*>()->getParentMap(); 111 else 112 PM = &LAC.get<AnalysisDeclContext*>()->getParentMap(); 113 114 while (!L.isValid()) { 115 S = PM->getParent(S); 116 L = S->getLocStart(); 117 } 118 } 119 120 return L; 121} 122 123PathDiagnosticLocation 124 PathDiagnosticLocation::createBegin(const Decl *D, 125 const SourceManager &SM) { 126 return PathDiagnosticLocation(D->getLocStart(), SM, SingleLocK); 127} 128 129PathDiagnosticLocation 130 PathDiagnosticLocation::createBegin(const Stmt *S, 131 const SourceManager &SM, 132 LocationOrAnalysisDeclContext LAC) { 133 return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 134 SM, SingleLocK); 135} 136 137PathDiagnosticLocation 138 PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 139 const SourceManager &SM) { 140 return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 141} 142 143PathDiagnosticLocation 144 PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 145 const SourceManager &SM) { 146 return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 147} 148 149PathDiagnosticLocation 150 PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 151 const SourceManager &SM) { 152 SourceLocation L = CS->getLBracLoc(); 153 return PathDiagnosticLocation(L, SM, SingleLocK); 154} 155 156PathDiagnosticLocation 157 PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 158 const SourceManager &SM) { 159 SourceLocation L = CS->getRBracLoc(); 160 return PathDiagnosticLocation(L, SM, SingleLocK); 161} 162 163PathDiagnosticLocation 164 PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 165 const SourceManager &SM) { 166 // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 167 if (const CompoundStmt *CS = 168 dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 169 if (!CS->body_empty()) { 170 SourceLocation Loc = (*CS->body_begin())->getLocStart(); 171 return PathDiagnosticLocation(Loc, SM, SingleLocK); 172 } 173 174 return PathDiagnosticLocation(); 175} 176 177PathDiagnosticLocation 178 PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 179 const SourceManager &SM) { 180 SourceLocation L = LC->getDecl()->getBodyRBrace(); 181 return PathDiagnosticLocation(L, SM, SingleLocK); 182} 183 184PathDiagnosticLocation 185 PathDiagnosticLocation::create(const ProgramPoint& P, 186 const SourceManager &SMng) { 187 188 const Stmt* S = 0; 189 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 190 const CFGBlock *BSrc = BE->getSrc(); 191 S = BSrc->getTerminatorCondition(); 192 } 193 else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { 194 S = PS->getStmt(); 195 } 196 197 return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 198} 199 200PathDiagnosticLocation 201 PathDiagnosticLocation::createEndOfPath(const ExplodedNode* N, 202 const SourceManager &SM) { 203 assert(N && "Cannot create a location with a null node."); 204 205 const ExplodedNode *NI = N; 206 207 while (NI) { 208 ProgramPoint P = NI->getLocation(); 209 const LocationContext *LC = P.getLocationContext(); 210 if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) 211 return PathDiagnosticLocation(PS->getStmt(), SM, LC); 212 else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { 213 const Stmt *Term = BE->getSrc()->getTerminator(); 214 assert(Term); 215 return PathDiagnosticLocation(Term, SM, LC); 216 } 217 NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); 218 } 219 220 return createDeclEnd(N->getLocationContext(), SM); 221} 222 223PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 224 const PathDiagnosticLocation &PDL) { 225 FullSourceLoc L = PDL.asLocation(); 226 return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 227} 228 229FullSourceLoc 230 PathDiagnosticLocation::genLocation(SourceLocation L, 231 LocationOrAnalysisDeclContext LAC) const { 232 assert(isValid()); 233 // Note that we want a 'switch' here so that the compiler can warn us in 234 // case we add more cases. 235 switch (K) { 236 case SingleLocK: 237 case RangeK: 238 break; 239 case StmtK: 240 return FullSourceLoc(getValidSourceLocation(S, LAC), 241 const_cast<SourceManager&>(*SM)); 242 case DeclK: 243 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 244 } 245 246 return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 247} 248 249PathDiagnosticRange 250 PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 251 assert(isValid()); 252 // Note that we want a 'switch' here so that the compiler can warn us in 253 // case we add more cases. 254 switch (K) { 255 case SingleLocK: 256 return PathDiagnosticRange(SourceRange(Loc,Loc), true); 257 case RangeK: 258 break; 259 case StmtK: { 260 const Stmt *S = asStmt(); 261 switch (S->getStmtClass()) { 262 default: 263 break; 264 case Stmt::DeclStmtClass: { 265 const DeclStmt *DS = cast<DeclStmt>(S); 266 if (DS->isSingleDecl()) { 267 // Should always be the case, but we'll be defensive. 268 return SourceRange(DS->getLocStart(), 269 DS->getSingleDecl()->getLocation()); 270 } 271 break; 272 } 273 // FIXME: Provide better range information for different 274 // terminators. 275 case Stmt::IfStmtClass: 276 case Stmt::WhileStmtClass: 277 case Stmt::DoStmtClass: 278 case Stmt::ForStmtClass: 279 case Stmt::ChooseExprClass: 280 case Stmt::IndirectGotoStmtClass: 281 case Stmt::SwitchStmtClass: 282 case Stmt::BinaryConditionalOperatorClass: 283 case Stmt::ConditionalOperatorClass: 284 case Stmt::ObjCForCollectionStmtClass: { 285 SourceLocation L = getValidSourceLocation(S, LAC); 286 return SourceRange(L, L); 287 } 288 } 289 SourceRange R = S->getSourceRange(); 290 if (R.isValid()) 291 return R; 292 break; 293 } 294 case DeclK: 295 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 296 return MD->getSourceRange(); 297 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 298 if (Stmt *Body = FD->getBody()) 299 return Body->getSourceRange(); 300 } 301 else { 302 SourceLocation L = D->getLocation(); 303 return PathDiagnosticRange(SourceRange(L, L), true); 304 } 305 } 306 307 return SourceRange(Loc,Loc); 308} 309 310void PathDiagnosticLocation::flatten() { 311 if (K == StmtK) { 312 K = RangeK; 313 S = 0; 314 D = 0; 315 } 316 else if (K == DeclK) { 317 K = SingleLocK; 318 S = 0; 319 D = 0; 320 } 321} 322 323//===----------------------------------------------------------------------===// 324// FoldingSet profiling methods. 325//===----------------------------------------------------------------------===// 326 327void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 328 ID.AddInteger(Range.getBegin().getRawEncoding()); 329 ID.AddInteger(Range.getEnd().getRawEncoding()); 330 ID.AddInteger(Loc.getRawEncoding()); 331 return; 332} 333 334void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 335 ID.AddInteger((unsigned) getKind()); 336 ID.AddString(str); 337 // FIXME: Add profiling support for code hints. 338 ID.AddInteger((unsigned) getDisplayHint()); 339 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) { 340 ID.AddInteger(I->getBegin().getRawEncoding()); 341 ID.AddInteger(I->getEnd().getRawEncoding()); 342 } 343} 344 345void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 346 PathDiagnosticPiece::Profile(ID); 347 ID.Add(Pos); 348} 349 350void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 351 PathDiagnosticPiece::Profile(ID); 352 for (const_iterator I = begin(), E = end(); I != E; ++I) 353 ID.Add(*I); 354} 355 356void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 357 PathDiagnosticSpotPiece::Profile(ID); 358 for (const_iterator I = begin(), E = end(); I != E; ++I) 359 ID.Add(**I); 360} 361 362void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 363 ID.AddInteger(Size); 364 ID.AddString(BugType); 365 ID.AddString(Desc); 366 ID.AddString(Category); 367 for (const_iterator I = begin(), E = end(); I != E; ++I) 368 ID.Add(*I); 369 370 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 371 ID.AddString(*I); 372} 373