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/Analysis/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 22 using namespace clang; 23 using llvm::dyn_cast; 24 using llvm::isa; 25 26 bool 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 39 static llvm::StringRef StripTrailingDots(llvm::StringRef s) { 40 for (llvm::StringRef::size_type i = s.size(); i != 0; --i) 41 if (s[i - 1] != '.') 42 return s.substr(0, i); 43 return ""; 44 } 45 46 PathDiagnosticPiece::PathDiagnosticPiece(llvm::StringRef s, 47 Kind k, DisplayHint hint) 48 : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 49 50 PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 51 : kind(k), Hint(hint) {} 52 53 PathDiagnosticPiece::~PathDiagnosticPiece() {} 54 PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} 55 PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} 56 57 PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() { 58 for (iterator I = begin(), E = end(); I != E; ++I) delete *I; 59 } 60 61 PathDiagnostic::PathDiagnostic() : Size(0) {} 62 63 PathDiagnostic::~PathDiagnostic() { 64 for (iterator I = begin(), E = end(); I != E; ++I) delete &*I; 65 } 66 67 void 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 78 PathDiagnostic::PathDiagnostic(llvm::StringRef bugtype, llvm::StringRef desc, 79 llvm::StringRef category) 80 : Size(0), 81 BugType(StripTrailingDots(bugtype)), 82 Desc(StripTrailingDots(desc)), 83 Category(StripTrailingDots(category)) {} 84 85 void PathDiagnosticClient::HandleDiagnostic(Diagnostic::Level DiagLevel, 86 const DiagnosticInfo &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(Info.getLocation(), StrC.str()); 108 109 for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) 110 P->addRange(Info.getRange(i)); 111 for (unsigned i = 0, e = Info.getNumCodeModificationHints(); i != e; ++i) 112 P->addCodeModificationHint(Info.getCodeModificationHint(i)); 113 D->push_front(P); 114 115 HandlePathDiagnostic(D); 116 } 117 118 //===----------------------------------------------------------------------===// 119 // PathDiagnosticLocation methods. 120 //===----------------------------------------------------------------------===// 121 122 FullSourceLoc PathDiagnosticLocation::asLocation() const { 123 assert(isValid()); 124 // Note that we want a 'switch' here so that the compiler can warn us in 125 // case we add more cases. 126 switch (K) { 127 case SingleLocK: 128 case RangeK: 129 break; 130 case StmtK: 131 return FullSourceLoc(S->getLocStart(), const_cast<SourceManager&>(*SM)); 132 case DeclK: 133 return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 134 } 135 136 return FullSourceLoc(R.getBegin(), const_cast<SourceManager&>(*SM)); 137 } 138 139 PathDiagnosticRange PathDiagnosticLocation::asRange() const { 140 assert(isValid()); 141 // Note that we want a 'switch' here so that the compiler can warn us in 142 // case we add more cases. 143 switch (K) { 144 case SingleLocK: 145 return PathDiagnosticRange(R, true); 146 case RangeK: 147 break; 148 case StmtK: { 149 const Stmt *S = asStmt(); 150 switch (S->getStmtClass()) { 151 default: 152 break; 153 case Stmt::DeclStmtClass: { 154 const DeclStmt *DS = cast<DeclStmt>(S); 155 if (DS->isSingleDecl()) { 156 // Should always be the case, but we'll be defensive. 157 return SourceRange(DS->getLocStart(), 158 DS->getSingleDecl()->getLocation()); 159 } 160 break; 161 } 162 // FIXME: Provide better range information for different 163 // terminators. 164 case Stmt::IfStmtClass: 165 case Stmt::WhileStmtClass: 166 case Stmt::DoStmtClass: 167 case Stmt::ForStmtClass: 168 case Stmt::ChooseExprClass: 169 case Stmt::IndirectGotoStmtClass: 170 case Stmt::SwitchStmtClass: 171 case Stmt::ConditionalOperatorClass: 172 case Stmt::ObjCForCollectionStmtClass: { 173 SourceLocation L = S->getLocStart(); 174 return SourceRange(L, L); 175 } 176 } 177 178 return S->getSourceRange(); 179 } 180 case DeclK: 181 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) 182 return MD->getSourceRange(); 183 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 184 // FIXME: We would like to always get the function body, even 185 // when it needs to be de-serialized, but getting the 186 // ASTContext here requires significant changes. 187 if (Stmt *Body = FD->getBody()) { 188 if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body)) 189 return CS->getSourceRange(); 190 else 191 return cast<CXXTryStmt>(Body)->getSourceRange(); 192 } 193 } 194 else { 195 SourceLocation L = D->getLocation(); 196 return PathDiagnosticRange(SourceRange(L, L), true); 197 } 198 } 199 200 return R; 201 } 202 203 void PathDiagnosticLocation::flatten() { 204 if (K == StmtK) { 205 R = asRange(); 206 K = RangeK; 207 S = 0; 208 D = 0; 209 } 210 else if (K == DeclK) { 211 SourceLocation L = D->getLocation(); 212 R = SourceRange(L, L); 213 K = SingleLocK; 214 S = 0; 215 D = 0; 216 } 217 } 218 219 //===----------------------------------------------------------------------===// 220 // FoldingSet profiling methods. 221 //===----------------------------------------------------------------------===// 222 223 void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 224 ID.AddInteger((unsigned) K); 225 switch (K) { 226 case RangeK: 227 ID.AddInteger(R.getBegin().getRawEncoding()); 228 ID.AddInteger(R.getEnd().getRawEncoding()); 229 break; 230 case SingleLocK: 231 ID.AddInteger(R.getBegin().getRawEncoding()); 232 break; 233 case StmtK: 234 ID.Add(S); 235 break; 236 case DeclK: 237 ID.Add(D); 238 break; 239 } 240 return; 241 } 242 243 void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 244 ID.AddInteger((unsigned) getKind()); 245 ID.AddString(str); 246 // FIXME: Add profiling support for code hints. 247 ID.AddInteger((unsigned) getDisplayHint()); 248 for (range_iterator I = ranges_begin(), E = ranges_end(); I != E; ++I) { 249 ID.AddInteger(I->getBegin().getRawEncoding()); 250 ID.AddInteger(I->getEnd().getRawEncoding()); 251 } 252 } 253 254 void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 255 PathDiagnosticPiece::Profile(ID); 256 ID.Add(Pos); 257 } 258 259 void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 260 PathDiagnosticPiece::Profile(ID); 261 for (const_iterator I = begin(), E = end(); I != E; ++I) 262 ID.Add(*I); 263 } 264 265 void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 266 PathDiagnosticSpotPiece::Profile(ID); 267 for (const_iterator I = begin(), E = end(); I != E; ++I) 268 ID.Add(**I); 269 } 270 271 void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 272 ID.AddInteger(Size); 273 ID.AddString(BugType); 274 ID.AddString(Desc); 275 ID.AddString(Category); 276 for (const_iterator I = begin(), E = end(); I != E; ++I) 277 ID.Add(*I); 278 279 for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 280 ID.AddString(*I); 281 } 282