PathDiagnostic.cpp revision 07453ac7b3d46f930733b44a593737bdd98706b6
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/AST/Expr.h" 16#include "clang/AST/Decl.h" 17#include "clang/AST/DeclObjC.h" 18#include "clang/AST/StmtCXX.h" 19#include "llvm/ADT/SmallString.h" 20 21using namespace clang; 22using namespace ento; 23 24bool PathDiagnosticMacroPiece::containsEvent() const { 25 for (const_iterator I = begin(), E = end(); I!=E; ++I) { 26 if (isa<PathDiagnosticEventPiece>(*I)) 27 return true; 28 29 if (PathDiagnosticMacroPiece *MP = dyn_cast<PathDiagnosticMacroPiece>(*I)) 30 if (MP->containsEvent()) 31 return true; 32 } 33 34 return false; 35} 36 37static StringRef StripTrailingDots(StringRef s) { 38 for (StringRef::size_type i = s.size(); i != 0; --i) 39 if (s[i - 1] != '.') 40 return s.substr(0, i); 41 return ""; 42} 43 44PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 45 Kind k, DisplayHint hint) 46 : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 47 48PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 49 : kind(k), Hint(hint) {} 50 51PathDiagnosticPiece::~PathDiagnosticPiece() {} 52PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 53PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 54 55PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() { 56 for (iterator I = begin(), E = end(); I != E; ++I) delete *I; 57} 58 59PathDiagnostic::PathDiagnostic() : Size(0) {} 60 61PathDiagnostic::~PathDiagnostic() { 62 for (iterator I = begin(), E = end(); I != E; ++I) delete &*I; 63} 64 65void PathDiagnostic::resetPath(bool deletePieces) { 66 Size = 0; 67 68 if (deletePieces) 69 for (iterator I=begin(), E=end(); I!=E; ++I) 70 delete &*I; 71 72 path.clear(); 73} 74 75 76PathDiagnostic::PathDiagnostic(StringRef bugtype, StringRef desc, 77 StringRef category) 78 : Size(0), 79 BugType(StripTrailingDots(bugtype)), 80 Desc(StripTrailingDots(desc)), 81 Category(StripTrailingDots(category)) {} 82 83void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, 84 const DiagnosticInfo &Info) { 85 // Default implementation (Warnings/errors count). 86 DiagnosticClient::HandleDiagnostic(DiagLevel, Info); 87 88 // Create a PathDiagnostic with a single piece. 89 90 PathDiagnostic* D = new PathDiagnostic(); 91 92 const char *LevelStr; 93 switch (DiagLevel) { 94 default: 95 case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); 96 case Diagnostic::Note: LevelStr = "note: "; break; 97 case Diagnostic::Warning: LevelStr = "warning: "; break; 98 case Diagnostic::Error: LevelStr = "error: "; break; 99 case Diagnostic::Fatal: LevelStr = "fatal error: "; break; 100 } 101 102 llvm::SmallString<100> StrC; 103 StrC += LevelStr; 104 Info.FormatDiagnostic(StrC); 105 106 PathDiagnosticPiece *P = 107 new PathDiagnosticEventPiece(FullSourceLoc(Info.getLocation(), 108 Info.getSourceManager()), 109 StrC.str()); 110 111 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) 112 P->addRange(Info.getRange(i).getAsRange()); 113 for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) 114 P->addFixItHint(Info.getFixItHint(i)); 115 D->push_front(P); 116 117 HandlePathDiagnostic(D); 118} 119 120void PathDiagnosticClient::HandlePathDiagnostic(const PathDiagnostic *D) { 121 // For now this simply forwards to HandlePathDiagnosticImpl. In the future 122 // we can use this indirection to control for multi-threaded access to 123 // the PathDiagnosticClient from multiple bug reporters. 124 HandlePathDiagnosticImpl(D); 125} 126 127//===----------------------------------------------------------------------===// 128// PathDiagnosticLocation methods. 129//===----------------------------------------------------------------------===// 130 131FullSourceLoc PathDiagnosticLocation::asLocation() const { 132 assert(isValid()); 133 // Note that we want a 'switch' here so that the compiler can warn us in 134 // case we add more cases. 135 switch (K) { 136 case SingleLocK: 137 case RangeK: 138 break; 139 case StmtK: 140 return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM)); 141 case DeclK: 142 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 143 } 144 145 return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM)); 146} 147 148PathDiagnosticRange PathDiagnosticLocation::asRange() const { 149 assert(isValid()); 150 // Note that we want a 'switch' here so that the compiler can warn us in 151 // case we add more cases. 152 switch (K) { 153 case SingleLocK: 154 return PathDiagnosticRange(R, true); 155 case RangeK: 156 break; 157 case StmtK: { 158 const Stmt *S = asStmt(); 159 switch (S->getStmtClass()) { 160 default: 161 break; 162 case Stmt::DeclStmtClass: { 163 const DeclStmt *DS = cast<DeclStmt>(S); 164 if (DS->isSingleDecl()) { 165 // Should always be the case, but we'll be defensive. 166 return SourceRange(DS->getLocStart(), 167 DS->getSingleDecl()->getLocation()); 168 } 169 break; 170 } 171 // FIXME: Provide better range information for different 172 // terminators. 173 case Stmt::IfStmtClass: 174 case Stmt::WhileStmtClass: 175 case Stmt::DoStmtClass: 176 case Stmt::ForStmtClass: 177 case Stmt::ChooseExprClass: 178 case Stmt::IndirectGotoStmtClass: 179 case Stmt::SwitchStmtClass: 180 case Stmt::BinaryConditionalOperatorClass: 181 case Stmt::ConditionalOperatorClass: 182 case Stmt::ObjCForCollectionStmtClass: { 183 SourceLocation L = S->getLocStart(); 184 return SourceRange(L, L); 185 } 186 } 187 188 return S->getSourceRange(); 189 } 190 case DeclK: 191 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 192 return MD->getSourceRange(); 193 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 194 if (Stmt *Body = FD->getBody()) 195 return Body->getSourceRange(); 196 } 197 else { 198 SourceLocation L = D->getLocation(); 199 return PathDiagnosticRange(SourceRange(L, L), true); 200 } 201 } 202 203 return R; 204} 205 206void PathDiagnosticLocation::flatten() { 207 if (K == StmtK) { 208 R = asRange(); 209 K = RangeK; 210 S = 0; 211 D = 0; 212 } 213 else if (K == DeclK) { 214 SourceLocation L = D->getLocation(); 215 R = SourceRange(L, L); 216 K = SingleLocK; 217 S = 0; 218 D = 0; 219 } 220} 221 222//===----------------------------------------------------------------------===// 223// FoldingSet profiling methods. 224//===----------------------------------------------------------------------===// 225 226void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 227 ID.AddInteger((unsigned) K); 228 switch (K) { 229 case RangeK: 230 ID.AddInteger(R.getBegin().getRawEncoding()); 231 ID.AddInteger(R.getEnd().getRawEncoding()); 232 break; 233 case SingleLocK: 234 ID.AddInteger(R.getBegin().getRawEncoding()); 235 break; 236 case StmtK: 237 ID.Add(S); 238 break; 239 case DeclK: 240 ID.Add(D); 241 break; 242 } 243 return; 244} 245 246void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 247 ID.AddInteger((unsigned) getKind()); 248 ID.AddString(str); 249 // FIXME: Add profiling support for code hints. 250 ID.AddInteger((unsigned) getDisplayHint()); 251 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) { 252 ID.AddInteger(I->getBegin().getRawEncoding()); 253 ID.AddInteger(I->getEnd().getRawEncoding()); 254 } 255} 256 257void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 258 PathDiagnosticPiece::Profile(ID); 259 ID.Add(Pos); 260} 261 262void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 263 PathDiagnosticPiece::Profile(ID); 264 for (const_iterator I = begin(), E = end(); I != E; ++I) 265 ID.Add(*I); 266} 267 268void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 269 PathDiagnosticSpotPiece::Profile(ID); 270 for (const_iterator I = begin(), E = end(); I != E; ++I) 271 ID.Add(**I); 272} 273 274void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 275 ID.AddInteger(Size); 276 ID.AddString(BugType); 277 ID.AddString(Desc); 278 ID.AddString(Category); 279 for (const_iterator I = begin(), E = end(); I != E; ++I) 280 ID.Add(*I); 281 282 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 283 ID.AddString(*I); 284} 285