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