1 1.1 joerg //===- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -------------===// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // 9 1.1 joerg // This file defines the PathDiagnostic-related interfaces. 10 1.1 joerg // 11 1.1 joerg //===----------------------------------------------------------------------===// 12 1.1 joerg 13 1.1 joerg #include "clang/Analysis/PathDiagnostic.h" 14 1.1 joerg #include "clang/AST/Decl.h" 15 1.1 joerg #include "clang/AST/DeclBase.h" 16 1.1 joerg #include "clang/AST/DeclCXX.h" 17 1.1 joerg #include "clang/AST/DeclObjC.h" 18 1.1 joerg #include "clang/AST/DeclTemplate.h" 19 1.1 joerg #include "clang/AST/Expr.h" 20 1.1 joerg #include "clang/AST/ExprCXX.h" 21 1.1 joerg #include "clang/AST/OperationKinds.h" 22 1.1 joerg #include "clang/AST/ParentMap.h" 23 1.1.1.2 joerg #include "clang/AST/PrettyPrinter.h" 24 1.1 joerg #include "clang/AST/Stmt.h" 25 1.1 joerg #include "clang/AST/Type.h" 26 1.1 joerg #include "clang/Analysis/AnalysisDeclContext.h" 27 1.1 joerg #include "clang/Analysis/CFG.h" 28 1.1 joerg #include "clang/Analysis/ProgramPoint.h" 29 1.1 joerg #include "clang/Basic/FileManager.h" 30 1.1 joerg #include "clang/Basic/LLVM.h" 31 1.1 joerg #include "clang/Basic/SourceLocation.h" 32 1.1 joerg #include "clang/Basic/SourceManager.h" 33 1.1 joerg #include "llvm/ADT/ArrayRef.h" 34 1.1 joerg #include "llvm/ADT/FoldingSet.h" 35 1.1 joerg #include "llvm/ADT/None.h" 36 1.1 joerg #include "llvm/ADT/Optional.h" 37 1.1 joerg #include "llvm/ADT/STLExtras.h" 38 1.1 joerg #include "llvm/ADT/SmallString.h" 39 1.1 joerg #include "llvm/ADT/SmallVector.h" 40 1.1 joerg #include "llvm/ADT/StringExtras.h" 41 1.1 joerg #include "llvm/ADT/StringRef.h" 42 1.1 joerg #include "llvm/Support/Casting.h" 43 1.1 joerg #include "llvm/Support/ErrorHandling.h" 44 1.1 joerg #include "llvm/Support/raw_ostream.h" 45 1.1 joerg #include <cassert> 46 1.1 joerg #include <cstring> 47 1.1 joerg #include <memory> 48 1.1 joerg #include <utility> 49 1.1 joerg #include <vector> 50 1.1 joerg 51 1.1 joerg using namespace clang; 52 1.1 joerg using namespace ento; 53 1.1 joerg 54 1.1 joerg static StringRef StripTrailingDots(StringRef s) { 55 1.1 joerg for (StringRef::size_type i = s.size(); i != 0; --i) 56 1.1 joerg if (s[i - 1] != '.') 57 1.1 joerg return s.substr(0, i); 58 1.1 joerg return {}; 59 1.1 joerg } 60 1.1 joerg 61 1.1 joerg PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, 62 1.1 joerg Kind k, DisplayHint hint) 63 1.1 joerg : str(StripTrailingDots(s)), kind(k), Hint(hint) {} 64 1.1 joerg 65 1.1 joerg PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) 66 1.1 joerg : kind(k), Hint(hint) {} 67 1.1 joerg 68 1.1 joerg PathDiagnosticPiece::~PathDiagnosticPiece() = default; 69 1.1 joerg 70 1.1 joerg PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default; 71 1.1 joerg 72 1.1 joerg PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default; 73 1.1 joerg 74 1.1 joerg PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default; 75 1.1 joerg 76 1.1 joerg PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default; 77 1.1 joerg 78 1.1 joerg PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default; 79 1.1 joerg 80 1.1 joerg PathDiagnosticPopUpPiece::~PathDiagnosticPopUpPiece() = default; 81 1.1 joerg 82 1.1 joerg void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, 83 1.1 joerg bool ShouldFlattenMacros) const { 84 1.1 joerg for (auto &Piece : *this) { 85 1.1 joerg switch (Piece->getKind()) { 86 1.1 joerg case PathDiagnosticPiece::Call: { 87 1.1 joerg auto &Call = cast<PathDiagnosticCallPiece>(*Piece); 88 1.1 joerg if (auto CallEnter = Call.getCallEnterEvent()) 89 1.1 joerg Current.push_back(std::move(CallEnter)); 90 1.1 joerg Call.path.flattenTo(Primary, Primary, ShouldFlattenMacros); 91 1.1 joerg if (auto callExit = Call.getCallExitEvent()) 92 1.1 joerg Current.push_back(std::move(callExit)); 93 1.1 joerg break; 94 1.1 joerg } 95 1.1 joerg case PathDiagnosticPiece::Macro: { 96 1.1 joerg auto &Macro = cast<PathDiagnosticMacroPiece>(*Piece); 97 1.1 joerg if (ShouldFlattenMacros) { 98 1.1 joerg Macro.subPieces.flattenTo(Primary, Primary, ShouldFlattenMacros); 99 1.1 joerg } else { 100 1.1 joerg Current.push_back(Piece); 101 1.1 joerg PathPieces NewPath; 102 1.1 joerg Macro.subPieces.flattenTo(Primary, NewPath, ShouldFlattenMacros); 103 1.1 joerg // FIXME: This probably shouldn't mutate the original path piece. 104 1.1 joerg Macro.subPieces = NewPath; 105 1.1 joerg } 106 1.1 joerg break; 107 1.1 joerg } 108 1.1 joerg case PathDiagnosticPiece::Event: 109 1.1 joerg case PathDiagnosticPiece::ControlFlow: 110 1.1 joerg case PathDiagnosticPiece::Note: 111 1.1 joerg case PathDiagnosticPiece::PopUp: 112 1.1 joerg Current.push_back(Piece); 113 1.1 joerg break; 114 1.1 joerg } 115 1.1 joerg } 116 1.1 joerg } 117 1.1 joerg 118 1.1 joerg PathDiagnostic::~PathDiagnostic() = default; 119 1.1 joerg 120 1.1 joerg PathDiagnostic::PathDiagnostic( 121 1.1 joerg StringRef CheckerName, const Decl *declWithIssue, StringRef bugtype, 122 1.1 joerg StringRef verboseDesc, StringRef shortDesc, StringRef category, 123 1.1 joerg PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique, 124 1.1 joerg std::unique_ptr<FilesToLineNumsMap> ExecutedLines) 125 1.1 joerg : CheckerName(CheckerName), DeclWithIssue(declWithIssue), 126 1.1 joerg BugType(StripTrailingDots(bugtype)), 127 1.1 joerg VerboseDesc(StripTrailingDots(verboseDesc)), 128 1.1 joerg ShortDesc(StripTrailingDots(shortDesc)), 129 1.1 joerg Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique), 130 1.1 joerg UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)), 131 1.1 joerg path(pathImpl) {} 132 1.1 joerg 133 1.1 joerg void PathDiagnosticConsumer::anchor() {} 134 1.1 joerg 135 1.1 joerg PathDiagnosticConsumer::~PathDiagnosticConsumer() { 136 1.1 joerg // Delete the contents of the FoldingSet if it isn't empty already. 137 1.1 joerg for (auto &Diag : Diags) 138 1.1 joerg delete &Diag; 139 1.1 joerg } 140 1.1 joerg 141 1.1 joerg void PathDiagnosticConsumer::HandlePathDiagnostic( 142 1.1 joerg std::unique_ptr<PathDiagnostic> D) { 143 1.1 joerg if (!D || D->path.empty()) 144 1.1 joerg return; 145 1.1 joerg 146 1.1 joerg // We need to flatten the locations (convert Stmt* to locations) because 147 1.1 joerg // the referenced statements may be freed by the time the diagnostics 148 1.1 joerg // are emitted. 149 1.1 joerg D->flattenLocations(); 150 1.1 joerg 151 1.1 joerg // If the PathDiagnosticConsumer does not support diagnostics that 152 1.1 joerg // cross file boundaries, prune out such diagnostics now. 153 1.1 joerg if (!supportsCrossFileDiagnostics()) { 154 1.1 joerg // Verify that the entire path is from the same FileID. 155 1.1 joerg FileID FID; 156 1.1 joerg const SourceManager &SMgr = D->path.front()->getLocation().getManager(); 157 1.1 joerg SmallVector<const PathPieces *, 5> WorkList; 158 1.1 joerg WorkList.push_back(&D->path); 159 1.1 joerg SmallString<128> buf; 160 1.1 joerg llvm::raw_svector_ostream warning(buf); 161 1.1 joerg warning << "warning: Path diagnostic report is not generated. Current " 162 1.1 joerg << "output format does not support diagnostics that cross file " 163 1.1 joerg << "boundaries. Refer to --analyzer-output for valid output " 164 1.1 joerg << "formats\n"; 165 1.1 joerg 166 1.1 joerg while (!WorkList.empty()) { 167 1.1 joerg const PathPieces &path = *WorkList.pop_back_val(); 168 1.1 joerg 169 1.1 joerg for (const auto &I : path) { 170 1.1 joerg const PathDiagnosticPiece *piece = I.get(); 171 1.1 joerg FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); 172 1.1 joerg 173 1.1 joerg if (FID.isInvalid()) { 174 1.1 joerg FID = SMgr.getFileID(L); 175 1.1 joerg } else if (SMgr.getFileID(L) != FID) { 176 1.1 joerg llvm::errs() << warning.str(); 177 1.1 joerg return; 178 1.1 joerg } 179 1.1 joerg 180 1.1 joerg // Check the source ranges. 181 1.1 joerg ArrayRef<SourceRange> Ranges = piece->getRanges(); 182 1.1 joerg for (const auto &I : Ranges) { 183 1.1 joerg SourceLocation L = SMgr.getExpansionLoc(I.getBegin()); 184 1.1 joerg if (!L.isFileID() || SMgr.getFileID(L) != FID) { 185 1.1 joerg llvm::errs() << warning.str(); 186 1.1 joerg return; 187 1.1 joerg } 188 1.1 joerg L = SMgr.getExpansionLoc(I.getEnd()); 189 1.1 joerg if (!L.isFileID() || SMgr.getFileID(L) != FID) { 190 1.1 joerg llvm::errs() << warning.str(); 191 1.1 joerg return; 192 1.1 joerg } 193 1.1 joerg } 194 1.1 joerg 195 1.1 joerg if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece)) 196 1.1 joerg WorkList.push_back(&call->path); 197 1.1 joerg else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece)) 198 1.1 joerg WorkList.push_back(¯o->subPieces); 199 1.1 joerg } 200 1.1 joerg } 201 1.1 joerg 202 1.1 joerg if (FID.isInvalid()) 203 1.1 joerg return; // FIXME: Emit a warning? 204 1.1 joerg } 205 1.1 joerg 206 1.1 joerg // Profile the node to see if we already have something matching it 207 1.1 joerg llvm::FoldingSetNodeID profile; 208 1.1 joerg D->Profile(profile); 209 1.1 joerg void *InsertPos = nullptr; 210 1.1 joerg 211 1.1 joerg if (PathDiagnostic *orig = Diags.FindNodeOrInsertPos(profile, InsertPos)) { 212 1.1 joerg // Keep the PathDiagnostic with the shorter path. 213 1.1 joerg // Note, the enclosing routine is called in deterministic order, so the 214 1.1 joerg // results will be consistent between runs (no reason to break ties if the 215 1.1 joerg // size is the same). 216 1.1 joerg const unsigned orig_size = orig->full_size(); 217 1.1 joerg const unsigned new_size = D->full_size(); 218 1.1 joerg if (orig_size <= new_size) 219 1.1 joerg return; 220 1.1 joerg 221 1.1 joerg assert(orig != D.get()); 222 1.1 joerg Diags.RemoveNode(orig); 223 1.1 joerg delete orig; 224 1.1 joerg } 225 1.1 joerg 226 1.1 joerg Diags.InsertNode(D.release()); 227 1.1 joerg } 228 1.1 joerg 229 1.1 joerg static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); 230 1.1 joerg 231 1.1 joerg static Optional<bool> 232 1.1 joerg compareControlFlow(const PathDiagnosticControlFlowPiece &X, 233 1.1 joerg const PathDiagnosticControlFlowPiece &Y) { 234 1.1 joerg FullSourceLoc XSL = X.getStartLocation().asLocation(); 235 1.1 joerg FullSourceLoc YSL = Y.getStartLocation().asLocation(); 236 1.1 joerg if (XSL != YSL) 237 1.1 joerg return XSL.isBeforeInTranslationUnitThan(YSL); 238 1.1 joerg FullSourceLoc XEL = X.getEndLocation().asLocation(); 239 1.1 joerg FullSourceLoc YEL = Y.getEndLocation().asLocation(); 240 1.1 joerg if (XEL != YEL) 241 1.1 joerg return XEL.isBeforeInTranslationUnitThan(YEL); 242 1.1 joerg return None; 243 1.1 joerg } 244 1.1 joerg 245 1.1 joerg static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, 246 1.1 joerg const PathDiagnosticMacroPiece &Y) { 247 1.1 joerg return comparePath(X.subPieces, Y.subPieces); 248 1.1 joerg } 249 1.1 joerg 250 1.1 joerg static Optional<bool> compareCall(const PathDiagnosticCallPiece &X, 251 1.1 joerg const PathDiagnosticCallPiece &Y) { 252 1.1 joerg FullSourceLoc X_CEL = X.callEnter.asLocation(); 253 1.1 joerg FullSourceLoc Y_CEL = Y.callEnter.asLocation(); 254 1.1 joerg if (X_CEL != Y_CEL) 255 1.1 joerg return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); 256 1.1 joerg FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); 257 1.1 joerg FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); 258 1.1 joerg if (X_CEWL != Y_CEWL) 259 1.1 joerg return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); 260 1.1 joerg FullSourceLoc X_CRL = X.callReturn.asLocation(); 261 1.1 joerg FullSourceLoc Y_CRL = Y.callReturn.asLocation(); 262 1.1 joerg if (X_CRL != Y_CRL) 263 1.1 joerg return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); 264 1.1 joerg return comparePath(X.path, Y.path); 265 1.1 joerg } 266 1.1 joerg 267 1.1 joerg static Optional<bool> comparePiece(const PathDiagnosticPiece &X, 268 1.1 joerg const PathDiagnosticPiece &Y) { 269 1.1 joerg if (X.getKind() != Y.getKind()) 270 1.1 joerg return X.getKind() < Y.getKind(); 271 1.1 joerg 272 1.1 joerg FullSourceLoc XL = X.getLocation().asLocation(); 273 1.1 joerg FullSourceLoc YL = Y.getLocation().asLocation(); 274 1.1 joerg if (XL != YL) 275 1.1 joerg return XL.isBeforeInTranslationUnitThan(YL); 276 1.1 joerg 277 1.1 joerg if (X.getString() != Y.getString()) 278 1.1 joerg return X.getString() < Y.getString(); 279 1.1 joerg 280 1.1 joerg if (X.getRanges().size() != Y.getRanges().size()) 281 1.1 joerg return X.getRanges().size() < Y.getRanges().size(); 282 1.1 joerg 283 1.1 joerg const SourceManager &SM = XL.getManager(); 284 1.1 joerg 285 1.1 joerg for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { 286 1.1 joerg SourceRange XR = X.getRanges()[i]; 287 1.1 joerg SourceRange YR = Y.getRanges()[i]; 288 1.1 joerg if (XR != YR) { 289 1.1 joerg if (XR.getBegin() != YR.getBegin()) 290 1.1 joerg return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); 291 1.1 joerg return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); 292 1.1 joerg } 293 1.1 joerg } 294 1.1 joerg 295 1.1 joerg switch (X.getKind()) { 296 1.1 joerg case PathDiagnosticPiece::ControlFlow: 297 1.1 joerg return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), 298 1.1 joerg cast<PathDiagnosticControlFlowPiece>(Y)); 299 1.1 joerg case PathDiagnosticPiece::Macro: 300 1.1 joerg return compareMacro(cast<PathDiagnosticMacroPiece>(X), 301 1.1 joerg cast<PathDiagnosticMacroPiece>(Y)); 302 1.1 joerg case PathDiagnosticPiece::Call: 303 1.1 joerg return compareCall(cast<PathDiagnosticCallPiece>(X), 304 1.1 joerg cast<PathDiagnosticCallPiece>(Y)); 305 1.1 joerg case PathDiagnosticPiece::Event: 306 1.1 joerg case PathDiagnosticPiece::Note: 307 1.1 joerg case PathDiagnosticPiece::PopUp: 308 1.1 joerg return None; 309 1.1 joerg } 310 1.1 joerg llvm_unreachable("all cases handled"); 311 1.1 joerg } 312 1.1 joerg 313 1.1 joerg static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { 314 1.1 joerg if (X.size() != Y.size()) 315 1.1 joerg return X.size() < Y.size(); 316 1.1 joerg 317 1.1 joerg PathPieces::const_iterator X_I = X.begin(), X_end = X.end(); 318 1.1 joerg PathPieces::const_iterator Y_I = Y.begin(), Y_end = Y.end(); 319 1.1 joerg 320 1.1 joerg for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) { 321 1.1 joerg Optional<bool> b = comparePiece(**X_I, **Y_I); 322 1.1 joerg if (b.hasValue()) 323 1.1 joerg return b.getValue(); 324 1.1 joerg } 325 1.1 joerg 326 1.1 joerg return None; 327 1.1 joerg } 328 1.1 joerg 329 1.1 joerg static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) { 330 1.1.1.2 joerg if (XL.isInvalid() && YL.isValid()) 331 1.1.1.2 joerg return true; 332 1.1.1.2 joerg if (XL.isValid() && YL.isInvalid()) 333 1.1.1.2 joerg return false; 334 1.1 joerg std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc(); 335 1.1 joerg std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc(); 336 1.1 joerg const SourceManager &SM = XL.getManager(); 337 1.1 joerg std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs); 338 1.1 joerg if (InSameTU.first) 339 1.1 joerg return XL.isBeforeInTranslationUnitThan(YL); 340 1.1 joerg const FileEntry *XFE = SM.getFileEntryForID(XL.getSpellingLoc().getFileID()); 341 1.1 joerg const FileEntry *YFE = SM.getFileEntryForID(YL.getSpellingLoc().getFileID()); 342 1.1 joerg if (!XFE || !YFE) 343 1.1 joerg return XFE && !YFE; 344 1.1 joerg int NameCmp = XFE->getName().compare(YFE->getName()); 345 1.1 joerg if (NameCmp != 0) 346 1.1 joerg return NameCmp == -1; 347 1.1 joerg // Last resort: Compare raw file IDs that are possibly expansions. 348 1.1 joerg return XL.getFileID() < YL.getFileID(); 349 1.1 joerg } 350 1.1 joerg 351 1.1 joerg static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { 352 1.1 joerg FullSourceLoc XL = X.getLocation().asLocation(); 353 1.1 joerg FullSourceLoc YL = Y.getLocation().asLocation(); 354 1.1 joerg if (XL != YL) 355 1.1 joerg return compareCrossTUSourceLocs(XL, YL); 356 1.1.1.2 joerg FullSourceLoc XUL = X.getUniqueingLoc().asLocation(); 357 1.1.1.2 joerg FullSourceLoc YUL = Y.getUniqueingLoc().asLocation(); 358 1.1.1.2 joerg if (XUL != YUL) 359 1.1.1.2 joerg return compareCrossTUSourceLocs(XUL, YUL); 360 1.1 joerg if (X.getBugType() != Y.getBugType()) 361 1.1 joerg return X.getBugType() < Y.getBugType(); 362 1.1 joerg if (X.getCategory() != Y.getCategory()) 363 1.1 joerg return X.getCategory() < Y.getCategory(); 364 1.1 joerg if (X.getVerboseDescription() != Y.getVerboseDescription()) 365 1.1 joerg return X.getVerboseDescription() < Y.getVerboseDescription(); 366 1.1 joerg if (X.getShortDescription() != Y.getShortDescription()) 367 1.1 joerg return X.getShortDescription() < Y.getShortDescription(); 368 1.1.1.2 joerg auto CompareDecls = [&XL](const Decl *D1, const Decl *D2) -> Optional<bool> { 369 1.1.1.2 joerg if (D1 == D2) 370 1.1.1.2 joerg return None; 371 1.1.1.2 joerg if (!D1) 372 1.1 joerg return true; 373 1.1.1.2 joerg if (!D2) 374 1.1 joerg return false; 375 1.1.1.2 joerg SourceLocation D1L = D1->getLocation(); 376 1.1.1.2 joerg SourceLocation D2L = D2->getLocation(); 377 1.1.1.2 joerg if (D1L != D2L) { 378 1.1 joerg const SourceManager &SM = XL.getManager(); 379 1.1.1.2 joerg return compareCrossTUSourceLocs(FullSourceLoc(D1L, SM), 380 1.1.1.2 joerg FullSourceLoc(D2L, SM)); 381 1.1 joerg } 382 1.1.1.2 joerg return None; 383 1.1.1.2 joerg }; 384 1.1.1.2 joerg if (auto Result = CompareDecls(X.getDeclWithIssue(), Y.getDeclWithIssue())) 385 1.1.1.2 joerg return *Result; 386 1.1.1.2 joerg if (XUL.isValid()) { 387 1.1.1.2 joerg if (auto Result = CompareDecls(X.getUniqueingDecl(), Y.getUniqueingDecl())) 388 1.1.1.2 joerg return *Result; 389 1.1 joerg } 390 1.1 joerg PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); 391 1.1 joerg PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); 392 1.1 joerg if (XE - XI != YE - YI) 393 1.1 joerg return (XE - XI) < (YE - YI); 394 1.1 joerg for ( ; XI != XE ; ++XI, ++YI) { 395 1.1 joerg if (*XI != *YI) 396 1.1 joerg return (*XI) < (*YI); 397 1.1 joerg } 398 1.1 joerg Optional<bool> b = comparePath(X.path, Y.path); 399 1.1 joerg assert(b.hasValue()); 400 1.1 joerg return b.getValue(); 401 1.1 joerg } 402 1.1 joerg 403 1.1 joerg void PathDiagnosticConsumer::FlushDiagnostics( 404 1.1 joerg PathDiagnosticConsumer::FilesMade *Files) { 405 1.1 joerg if (flushed) 406 1.1 joerg return; 407 1.1 joerg 408 1.1 joerg flushed = true; 409 1.1 joerg 410 1.1 joerg std::vector<const PathDiagnostic *> BatchDiags; 411 1.1 joerg for (const auto &D : Diags) 412 1.1 joerg BatchDiags.push_back(&D); 413 1.1 joerg 414 1.1 joerg // Sort the diagnostics so that they are always emitted in a deterministic 415 1.1 joerg // order. 416 1.1 joerg int (*Comp)(const PathDiagnostic *const *, const PathDiagnostic *const *) = 417 1.1 joerg [](const PathDiagnostic *const *X, const PathDiagnostic *const *Y) { 418 1.1 joerg assert(*X != *Y && "PathDiagnostics not uniqued!"); 419 1.1 joerg if (compare(**X, **Y)) 420 1.1 joerg return -1; 421 1.1 joerg assert(compare(**Y, **X) && "Not a total order!"); 422 1.1 joerg return 1; 423 1.1 joerg }; 424 1.1 joerg array_pod_sort(BatchDiags.begin(), BatchDiags.end(), Comp); 425 1.1 joerg 426 1.1 joerg FlushDiagnosticsImpl(BatchDiags, Files); 427 1.1 joerg 428 1.1 joerg // Delete the flushed diagnostics. 429 1.1 joerg for (const auto D : BatchDiags) 430 1.1 joerg delete D; 431 1.1 joerg 432 1.1 joerg // Clear out the FoldingSet. 433 1.1 joerg Diags.clear(); 434 1.1 joerg } 435 1.1 joerg 436 1.1 joerg PathDiagnosticConsumer::FilesMade::~FilesMade() { 437 1.1 joerg for (PDFileEntry &Entry : Set) 438 1.1 joerg Entry.~PDFileEntry(); 439 1.1 joerg } 440 1.1 joerg 441 1.1 joerg void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, 442 1.1 joerg StringRef ConsumerName, 443 1.1 joerg StringRef FileName) { 444 1.1 joerg llvm::FoldingSetNodeID NodeID; 445 1.1 joerg NodeID.Add(PD); 446 1.1 joerg void *InsertPos; 447 1.1 joerg PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 448 1.1 joerg if (!Entry) { 449 1.1 joerg Entry = Alloc.Allocate<PDFileEntry>(); 450 1.1 joerg Entry = new (Entry) PDFileEntry(NodeID); 451 1.1 joerg Set.InsertNode(Entry, InsertPos); 452 1.1 joerg } 453 1.1 joerg 454 1.1 joerg // Allocate persistent storage for the file name. 455 1.1 joerg char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); 456 1.1 joerg memcpy(FileName_cstr, FileName.data(), FileName.size()); 457 1.1 joerg 458 1.1 joerg Entry->files.push_back(std::make_pair(ConsumerName, 459 1.1 joerg StringRef(FileName_cstr, 460 1.1 joerg FileName.size()))); 461 1.1 joerg } 462 1.1 joerg 463 1.1 joerg PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * 464 1.1 joerg PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { 465 1.1 joerg llvm::FoldingSetNodeID NodeID; 466 1.1 joerg NodeID.Add(PD); 467 1.1 joerg void *InsertPos; 468 1.1 joerg PDFileEntry *Entry = Set.FindNodeOrInsertPos(NodeID, InsertPos); 469 1.1 joerg if (!Entry) 470 1.1 joerg return nullptr; 471 1.1 joerg return &Entry->files; 472 1.1 joerg } 473 1.1 joerg 474 1.1 joerg //===----------------------------------------------------------------------===// 475 1.1 joerg // PathDiagnosticLocation methods. 476 1.1 joerg //===----------------------------------------------------------------------===// 477 1.1 joerg 478 1.1 joerg SourceLocation PathDiagnosticLocation::getValidSourceLocation( 479 1.1 joerg const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) { 480 1.1 joerg SourceLocation L = UseEndOfStatement ? S->getEndLoc() : S->getBeginLoc(); 481 1.1 joerg assert(!LAC.isNull() && 482 1.1 joerg "A valid LocationContext or AnalysisDeclContext should be passed to " 483 1.1 joerg "PathDiagnosticLocation upon creation."); 484 1.1 joerg 485 1.1 joerg // S might be a temporary statement that does not have a location in the 486 1.1 joerg // source code, so find an enclosing statement and use its location. 487 1.1 joerg if (!L.isValid()) { 488 1.1 joerg AnalysisDeclContext *ADC; 489 1.1 joerg if (LAC.is<const LocationContext*>()) 490 1.1 joerg ADC = LAC.get<const LocationContext*>()->getAnalysisDeclContext(); 491 1.1 joerg else 492 1.1 joerg ADC = LAC.get<AnalysisDeclContext*>(); 493 1.1 joerg 494 1.1 joerg ParentMap &PM = ADC->getParentMap(); 495 1.1 joerg 496 1.1 joerg const Stmt *Parent = S; 497 1.1 joerg do { 498 1.1 joerg Parent = PM.getParent(Parent); 499 1.1 joerg 500 1.1 joerg // In rare cases, we have implicit top-level expressions, 501 1.1 joerg // such as arguments for implicit member initializers. 502 1.1 joerg // In this case, fall back to the start of the body (even if we were 503 1.1 joerg // asked for the statement end location). 504 1.1 joerg if (!Parent) { 505 1.1 joerg const Stmt *Body = ADC->getBody(); 506 1.1 joerg if (Body) 507 1.1 joerg L = Body->getBeginLoc(); 508 1.1 joerg else 509 1.1 joerg L = ADC->getDecl()->getEndLoc(); 510 1.1 joerg break; 511 1.1 joerg } 512 1.1 joerg 513 1.1 joerg L = UseEndOfStatement ? Parent->getEndLoc() : Parent->getBeginLoc(); 514 1.1 joerg } while (!L.isValid()); 515 1.1 joerg } 516 1.1 joerg 517 1.1 joerg // FIXME: Ironically, this assert actually fails in some cases. 518 1.1 joerg //assert(L.isValid()); 519 1.1 joerg return L; 520 1.1 joerg } 521 1.1 joerg 522 1.1 joerg static PathDiagnosticLocation 523 1.1 joerg getLocationForCaller(const StackFrameContext *SFC, 524 1.1 joerg const LocationContext *CallerCtx, 525 1.1 joerg const SourceManager &SM) { 526 1.1 joerg const CFGBlock &Block = *SFC->getCallSiteBlock(); 527 1.1 joerg CFGElement Source = Block[SFC->getIndex()]; 528 1.1 joerg 529 1.1 joerg switch (Source.getKind()) { 530 1.1 joerg case CFGElement::Statement: 531 1.1 joerg case CFGElement::Constructor: 532 1.1 joerg case CFGElement::CXXRecordTypedCall: 533 1.1 joerg return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), 534 1.1 joerg SM, CallerCtx); 535 1.1 joerg case CFGElement::Initializer: { 536 1.1 joerg const CFGInitializer &Init = Source.castAs<CFGInitializer>(); 537 1.1 joerg return PathDiagnosticLocation(Init.getInitializer()->getInit(), 538 1.1 joerg SM, CallerCtx); 539 1.1 joerg } 540 1.1 joerg case CFGElement::AutomaticObjectDtor: { 541 1.1 joerg const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); 542 1.1 joerg return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), 543 1.1 joerg SM, CallerCtx); 544 1.1 joerg } 545 1.1 joerg case CFGElement::DeleteDtor: { 546 1.1 joerg const CFGDeleteDtor &Dtor = Source.castAs<CFGDeleteDtor>(); 547 1.1 joerg return PathDiagnosticLocation(Dtor.getDeleteExpr(), SM, CallerCtx); 548 1.1 joerg } 549 1.1 joerg case CFGElement::BaseDtor: 550 1.1 joerg case CFGElement::MemberDtor: { 551 1.1 joerg const AnalysisDeclContext *CallerInfo = CallerCtx->getAnalysisDeclContext(); 552 1.1 joerg if (const Stmt *CallerBody = CallerInfo->getBody()) 553 1.1 joerg return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); 554 1.1 joerg return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); 555 1.1 joerg } 556 1.1 joerg case CFGElement::NewAllocator: { 557 1.1 joerg const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>(); 558 1.1 joerg return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx); 559 1.1 joerg } 560 1.1 joerg case CFGElement::TemporaryDtor: { 561 1.1 joerg // Temporary destructors are for temporaries. They die immediately at around 562 1.1 joerg // the location of CXXBindTemporaryExpr. If they are lifetime-extended, 563 1.1 joerg // they'd be dealt with via an AutomaticObjectDtor instead. 564 1.1 joerg const auto &Dtor = Source.castAs<CFGTemporaryDtor>(); 565 1.1 joerg return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM, 566 1.1 joerg CallerCtx); 567 1.1 joerg } 568 1.1 joerg case CFGElement::ScopeBegin: 569 1.1 joerg case CFGElement::ScopeEnd: 570 1.1 joerg llvm_unreachable("not yet implemented!"); 571 1.1 joerg case CFGElement::LifetimeEnds: 572 1.1 joerg case CFGElement::LoopExit: 573 1.1 joerg llvm_unreachable("CFGElement kind should not be on callsite!"); 574 1.1 joerg } 575 1.1 joerg 576 1.1 joerg llvm_unreachable("Unknown CFGElement kind"); 577 1.1 joerg } 578 1.1 joerg 579 1.1 joerg PathDiagnosticLocation 580 1.1 joerg PathDiagnosticLocation::createBegin(const Decl *D, 581 1.1 joerg const SourceManager &SM) { 582 1.1 joerg return PathDiagnosticLocation(D->getBeginLoc(), SM, SingleLocK); 583 1.1 joerg } 584 1.1 joerg 585 1.1 joerg PathDiagnosticLocation 586 1.1 joerg PathDiagnosticLocation::createBegin(const Stmt *S, 587 1.1 joerg const SourceManager &SM, 588 1.1 joerg LocationOrAnalysisDeclContext LAC) { 589 1.1 joerg return PathDiagnosticLocation(getValidSourceLocation(S, LAC), 590 1.1 joerg SM, SingleLocK); 591 1.1 joerg } 592 1.1 joerg 593 1.1 joerg PathDiagnosticLocation 594 1.1 joerg PathDiagnosticLocation::createEnd(const Stmt *S, 595 1.1 joerg const SourceManager &SM, 596 1.1 joerg LocationOrAnalysisDeclContext LAC) { 597 1.1 joerg if (const auto *CS = dyn_cast<CompoundStmt>(S)) 598 1.1 joerg return createEndBrace(CS, SM); 599 1.1 joerg return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), 600 1.1 joerg SM, SingleLocK); 601 1.1 joerg } 602 1.1 joerg 603 1.1 joerg PathDiagnosticLocation 604 1.1 joerg PathDiagnosticLocation::createOperatorLoc(const BinaryOperator *BO, 605 1.1 joerg const SourceManager &SM) { 606 1.1 joerg return PathDiagnosticLocation(BO->getOperatorLoc(), SM, SingleLocK); 607 1.1 joerg } 608 1.1 joerg 609 1.1 joerg PathDiagnosticLocation 610 1.1 joerg PathDiagnosticLocation::createConditionalColonLoc( 611 1.1 joerg const ConditionalOperator *CO, 612 1.1 joerg const SourceManager &SM) { 613 1.1 joerg return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); 614 1.1 joerg } 615 1.1 joerg 616 1.1 joerg PathDiagnosticLocation 617 1.1 joerg PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, 618 1.1 joerg const SourceManager &SM) { 619 1.1 joerg 620 1.1 joerg assert(ME->getMemberLoc().isValid() || ME->getBeginLoc().isValid()); 621 1.1 joerg 622 1.1 joerg // In some cases, getMemberLoc isn't valid -- in this case we'll return with 623 1.1 joerg // some other related valid SourceLocation. 624 1.1 joerg if (ME->getMemberLoc().isValid()) 625 1.1 joerg return PathDiagnosticLocation(ME->getMemberLoc(), SM, SingleLocK); 626 1.1 joerg 627 1.1 joerg return PathDiagnosticLocation(ME->getBeginLoc(), SM, SingleLocK); 628 1.1 joerg } 629 1.1 joerg 630 1.1 joerg PathDiagnosticLocation 631 1.1 joerg PathDiagnosticLocation::createBeginBrace(const CompoundStmt *CS, 632 1.1 joerg const SourceManager &SM) { 633 1.1 joerg SourceLocation L = CS->getLBracLoc(); 634 1.1 joerg return PathDiagnosticLocation(L, SM, SingleLocK); 635 1.1 joerg } 636 1.1 joerg 637 1.1 joerg PathDiagnosticLocation 638 1.1 joerg PathDiagnosticLocation::createEndBrace(const CompoundStmt *CS, 639 1.1 joerg const SourceManager &SM) { 640 1.1 joerg SourceLocation L = CS->getRBracLoc(); 641 1.1 joerg return PathDiagnosticLocation(L, SM, SingleLocK); 642 1.1 joerg } 643 1.1 joerg 644 1.1 joerg PathDiagnosticLocation 645 1.1 joerg PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, 646 1.1 joerg const SourceManager &SM) { 647 1.1 joerg // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. 648 1.1 joerg if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) 649 1.1 joerg if (!CS->body_empty()) { 650 1.1 joerg SourceLocation Loc = (*CS->body_begin())->getBeginLoc(); 651 1.1 joerg return PathDiagnosticLocation(Loc, SM, SingleLocK); 652 1.1 joerg } 653 1.1 joerg 654 1.1 joerg return PathDiagnosticLocation(); 655 1.1 joerg } 656 1.1 joerg 657 1.1 joerg PathDiagnosticLocation 658 1.1 joerg PathDiagnosticLocation::createDeclEnd(const LocationContext *LC, 659 1.1 joerg const SourceManager &SM) { 660 1.1 joerg SourceLocation L = LC->getDecl()->getBodyRBrace(); 661 1.1 joerg return PathDiagnosticLocation(L, SM, SingleLocK); 662 1.1 joerg } 663 1.1 joerg 664 1.1 joerg PathDiagnosticLocation 665 1.1 joerg PathDiagnosticLocation::create(const ProgramPoint& P, 666 1.1 joerg const SourceManager &SMng) { 667 1.1 joerg const Stmt* S = nullptr; 668 1.1 joerg if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { 669 1.1 joerg const CFGBlock *BSrc = BE->getSrc(); 670 1.1 joerg if (BSrc->getTerminator().isVirtualBaseBranch()) { 671 1.1 joerg // TODO: VirtualBaseBranches should also appear for destructors. 672 1.1 joerg // In this case we should put the diagnostic at the end of decl. 673 1.1 joerg return PathDiagnosticLocation::createBegin( 674 1.1 joerg P.getLocationContext()->getDecl(), SMng); 675 1.1 joerg 676 1.1 joerg } else { 677 1.1 joerg S = BSrc->getTerminatorCondition(); 678 1.1 joerg if (!S) { 679 1.1 joerg // If the BlockEdge has no terminator condition statement but its 680 1.1 joerg // source is the entry of the CFG (e.g. a checker crated the branch at 681 1.1 joerg // the beginning of a function), use the function's declaration instead. 682 1.1 joerg assert(BSrc == &BSrc->getParent()->getEntry() && "CFGBlock has no " 683 1.1 joerg "TerminatorCondition and is not the enrty block of the CFG"); 684 1.1 joerg return PathDiagnosticLocation::createBegin( 685 1.1 joerg P.getLocationContext()->getDecl(), SMng); 686 1.1 joerg } 687 1.1 joerg } 688 1.1 joerg } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { 689 1.1 joerg S = SP->getStmt(); 690 1.1 joerg if (P.getAs<PostStmtPurgeDeadSymbols>()) 691 1.1 joerg return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); 692 1.1 joerg } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { 693 1.1 joerg return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), 694 1.1 joerg SMng); 695 1.1 joerg } else if (Optional<PreImplicitCall> PIC = P.getAs<PreImplicitCall>()) { 696 1.1 joerg return PathDiagnosticLocation(PIC->getLocation(), SMng); 697 1.1 joerg } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { 698 1.1 joerg return PathDiagnosticLocation(PIE->getLocation(), SMng); 699 1.1 joerg } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { 700 1.1 joerg return getLocationForCaller(CE->getCalleeContext(), 701 1.1 joerg CE->getLocationContext(), 702 1.1 joerg SMng); 703 1.1 joerg } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { 704 1.1 joerg return getLocationForCaller(CEE->getCalleeContext(), 705 1.1 joerg CEE->getLocationContext(), 706 1.1 joerg SMng); 707 1.1 joerg } else if (auto CEB = P.getAs<CallExitBegin>()) { 708 1.1 joerg if (const ReturnStmt *RS = CEB->getReturnStmt()) 709 1.1 joerg return PathDiagnosticLocation::createBegin(RS, SMng, 710 1.1 joerg CEB->getLocationContext()); 711 1.1 joerg return PathDiagnosticLocation( 712 1.1 joerg CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng); 713 1.1 joerg } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) { 714 1.1 joerg if (Optional<CFGElement> BlockFront = BE->getFirstElement()) { 715 1.1 joerg if (auto StmtElt = BlockFront->getAs<CFGStmt>()) { 716 1.1 joerg return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng); 717 1.1 joerg } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) { 718 1.1 joerg return PathDiagnosticLocation( 719 1.1 joerg NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng); 720 1.1 joerg } 721 1.1 joerg llvm_unreachable("Unexpected CFG element at front of block"); 722 1.1 joerg } 723 1.1 joerg 724 1.1 joerg return PathDiagnosticLocation( 725 1.1 joerg BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng); 726 1.1 joerg } else if (Optional<FunctionExitPoint> FE = P.getAs<FunctionExitPoint>()) { 727 1.1 joerg return PathDiagnosticLocation(FE->getStmt(), SMng, 728 1.1 joerg FE->getLocationContext()); 729 1.1 joerg } else { 730 1.1 joerg llvm_unreachable("Unexpected ProgramPoint"); 731 1.1 joerg } 732 1.1 joerg 733 1.1 joerg return PathDiagnosticLocation(S, SMng, P.getLocationContext()); 734 1.1 joerg } 735 1.1 joerg 736 1.1 joerg PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation( 737 1.1 joerg const PathDiagnosticLocation &PDL) { 738 1.1 joerg FullSourceLoc L = PDL.asLocation(); 739 1.1 joerg return PathDiagnosticLocation(L, L.getManager(), SingleLocK); 740 1.1 joerg } 741 1.1 joerg 742 1.1 joerg FullSourceLoc 743 1.1 joerg PathDiagnosticLocation::genLocation(SourceLocation L, 744 1.1 joerg LocationOrAnalysisDeclContext LAC) const { 745 1.1 joerg assert(isValid()); 746 1.1 joerg // Note that we want a 'switch' here so that the compiler can warn us in 747 1.1 joerg // case we add more cases. 748 1.1 joerg switch (K) { 749 1.1 joerg case SingleLocK: 750 1.1 joerg case RangeK: 751 1.1 joerg break; 752 1.1 joerg case StmtK: 753 1.1 joerg // Defensive checking. 754 1.1 joerg if (!S) 755 1.1 joerg break; 756 1.1 joerg return FullSourceLoc(getValidSourceLocation(S, LAC), 757 1.1 joerg const_cast<SourceManager&>(*SM)); 758 1.1 joerg case DeclK: 759 1.1 joerg // Defensive checking. 760 1.1 joerg if (!D) 761 1.1 joerg break; 762 1.1 joerg return FullSourceLoc(D->getLocation(), const_cast<SourceManager&>(*SM)); 763 1.1 joerg } 764 1.1 joerg 765 1.1 joerg return FullSourceLoc(L, const_cast<SourceManager&>(*SM)); 766 1.1 joerg } 767 1.1 joerg 768 1.1 joerg PathDiagnosticRange 769 1.1 joerg PathDiagnosticLocation::genRange(LocationOrAnalysisDeclContext LAC) const { 770 1.1 joerg assert(isValid()); 771 1.1 joerg // Note that we want a 'switch' here so that the compiler can warn us in 772 1.1 joerg // case we add more cases. 773 1.1 joerg switch (K) { 774 1.1 joerg case SingleLocK: 775 1.1 joerg return PathDiagnosticRange(SourceRange(Loc,Loc), true); 776 1.1 joerg case RangeK: 777 1.1 joerg break; 778 1.1 joerg case StmtK: { 779 1.1 joerg const Stmt *S = asStmt(); 780 1.1 joerg switch (S->getStmtClass()) { 781 1.1 joerg default: 782 1.1 joerg break; 783 1.1 joerg case Stmt::DeclStmtClass: { 784 1.1 joerg const auto *DS = cast<DeclStmt>(S); 785 1.1 joerg if (DS->isSingleDecl()) { 786 1.1 joerg // Should always be the case, but we'll be defensive. 787 1.1 joerg return SourceRange(DS->getBeginLoc(), 788 1.1 joerg DS->getSingleDecl()->getLocation()); 789 1.1 joerg } 790 1.1 joerg break; 791 1.1 joerg } 792 1.1 joerg // FIXME: Provide better range information for different 793 1.1 joerg // terminators. 794 1.1 joerg case Stmt::IfStmtClass: 795 1.1 joerg case Stmt::WhileStmtClass: 796 1.1 joerg case Stmt::DoStmtClass: 797 1.1 joerg case Stmt::ForStmtClass: 798 1.1 joerg case Stmt::ChooseExprClass: 799 1.1 joerg case Stmt::IndirectGotoStmtClass: 800 1.1 joerg case Stmt::SwitchStmtClass: 801 1.1 joerg case Stmt::BinaryConditionalOperatorClass: 802 1.1 joerg case Stmt::ConditionalOperatorClass: 803 1.1 joerg case Stmt::ObjCForCollectionStmtClass: { 804 1.1 joerg SourceLocation L = getValidSourceLocation(S, LAC); 805 1.1 joerg return SourceRange(L, L); 806 1.1 joerg } 807 1.1 joerg } 808 1.1 joerg SourceRange R = S->getSourceRange(); 809 1.1 joerg if (R.isValid()) 810 1.1 joerg return R; 811 1.1 joerg break; 812 1.1 joerg } 813 1.1 joerg case DeclK: 814 1.1 joerg if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) 815 1.1 joerg return MD->getSourceRange(); 816 1.1 joerg if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 817 1.1 joerg if (Stmt *Body = FD->getBody()) 818 1.1 joerg return Body->getSourceRange(); 819 1.1 joerg } 820 1.1 joerg else { 821 1.1 joerg SourceLocation L = D->getLocation(); 822 1.1 joerg return PathDiagnosticRange(SourceRange(L, L), true); 823 1.1 joerg } 824 1.1 joerg } 825 1.1 joerg 826 1.1 joerg return SourceRange(Loc, Loc); 827 1.1 joerg } 828 1.1 joerg 829 1.1 joerg void PathDiagnosticLocation::flatten() { 830 1.1 joerg if (K == StmtK) { 831 1.1 joerg K = RangeK; 832 1.1 joerg S = nullptr; 833 1.1 joerg D = nullptr; 834 1.1 joerg } 835 1.1 joerg else if (K == DeclK) { 836 1.1 joerg K = SingleLocK; 837 1.1 joerg S = nullptr; 838 1.1 joerg D = nullptr; 839 1.1 joerg } 840 1.1 joerg } 841 1.1 joerg 842 1.1 joerg //===----------------------------------------------------------------------===// 843 1.1 joerg // Manipulation of PathDiagnosticCallPieces. 844 1.1 joerg //===----------------------------------------------------------------------===// 845 1.1 joerg 846 1.1 joerg std::shared_ptr<PathDiagnosticCallPiece> 847 1.1 joerg PathDiagnosticCallPiece::construct(const CallExitEnd &CE, 848 1.1 joerg const SourceManager &SM) { 849 1.1 joerg const Decl *caller = CE.getLocationContext()->getDecl(); 850 1.1 joerg PathDiagnosticLocation pos = getLocationForCaller(CE.getCalleeContext(), 851 1.1 joerg CE.getLocationContext(), 852 1.1 joerg SM); 853 1.1 joerg return std::shared_ptr<PathDiagnosticCallPiece>( 854 1.1 joerg new PathDiagnosticCallPiece(caller, pos)); 855 1.1 joerg } 856 1.1 joerg 857 1.1 joerg PathDiagnosticCallPiece * 858 1.1 joerg PathDiagnosticCallPiece::construct(PathPieces &path, 859 1.1 joerg const Decl *caller) { 860 1.1 joerg std::shared_ptr<PathDiagnosticCallPiece> C( 861 1.1 joerg new PathDiagnosticCallPiece(path, caller)); 862 1.1 joerg path.clear(); 863 1.1 joerg auto *R = C.get(); 864 1.1 joerg path.push_front(std::move(C)); 865 1.1 joerg return R; 866 1.1 joerg } 867 1.1 joerg 868 1.1 joerg void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, 869 1.1 joerg const SourceManager &SM) { 870 1.1 joerg const StackFrameContext *CalleeCtx = CE.getCalleeContext(); 871 1.1 joerg Callee = CalleeCtx->getDecl(); 872 1.1 joerg 873 1.1 joerg callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); 874 1.1 joerg callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); 875 1.1 joerg 876 1.1 joerg // Autosynthesized property accessors are special because we'd never 877 1.1 joerg // pop back up to non-autosynthesized code until we leave them. 878 1.1 joerg // This is not generally true for autosynthesized callees, which may call 879 1.1 joerg // non-autosynthesized callbacks. 880 1.1 joerg // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag 881 1.1 joerg // defaults to false. 882 1.1 joerg if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee)) 883 1.1 joerg IsCalleeAnAutosynthesizedPropertyAccessor = ( 884 1.1 joerg MD->isPropertyAccessor() && 885 1.1 joerg CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized()); 886 1.1 joerg } 887 1.1 joerg 888 1.1 joerg static void describeTemplateParameters(raw_ostream &Out, 889 1.1 joerg const ArrayRef<TemplateArgument> TAList, 890 1.1 joerg const LangOptions &LO, 891 1.1 joerg StringRef Prefix = StringRef(), 892 1.1 joerg StringRef Postfix = StringRef()); 893 1.1 joerg 894 1.1 joerg static void describeTemplateParameter(raw_ostream &Out, 895 1.1 joerg const TemplateArgument &TArg, 896 1.1 joerg const LangOptions &LO) { 897 1.1 joerg 898 1.1 joerg if (TArg.getKind() == TemplateArgument::ArgKind::Pack) { 899 1.1 joerg describeTemplateParameters(Out, TArg.getPackAsArray(), LO); 900 1.1 joerg } else { 901 1.1.1.2 joerg TArg.print(PrintingPolicy(LO), Out, /*IncludeType*/ true); 902 1.1 joerg } 903 1.1 joerg } 904 1.1 joerg 905 1.1 joerg static void describeTemplateParameters(raw_ostream &Out, 906 1.1 joerg const ArrayRef<TemplateArgument> TAList, 907 1.1 joerg const LangOptions &LO, 908 1.1 joerg StringRef Prefix, StringRef Postfix) { 909 1.1 joerg if (TAList.empty()) 910 1.1 joerg return; 911 1.1 joerg 912 1.1 joerg Out << Prefix; 913 1.1 joerg for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) { 914 1.1 joerg describeTemplateParameter(Out, TAList[I], LO); 915 1.1 joerg Out << ", "; 916 1.1 joerg } 917 1.1 joerg describeTemplateParameter(Out, TAList[TAList.size() - 1], LO); 918 1.1 joerg Out << Postfix; 919 1.1 joerg } 920 1.1 joerg 921 1.1 joerg static void describeClass(raw_ostream &Out, const CXXRecordDecl *D, 922 1.1 joerg StringRef Prefix = StringRef()) { 923 1.1 joerg if (!D->getIdentifier()) 924 1.1 joerg return; 925 1.1 joerg Out << Prefix << '\'' << *D; 926 1.1 joerg if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D)) 927 1.1 joerg describeTemplateParameters(Out, T->getTemplateArgs().asArray(), 928 1.1.1.2 joerg D->getLangOpts(), "<", ">"); 929 1.1 joerg 930 1.1 joerg Out << '\''; 931 1.1 joerg } 932 1.1 joerg 933 1.1 joerg static bool describeCodeDecl(raw_ostream &Out, const Decl *D, 934 1.1 joerg bool ExtendedDescription, 935 1.1 joerg StringRef Prefix = StringRef()) { 936 1.1 joerg if (!D) 937 1.1 joerg return false; 938 1.1 joerg 939 1.1 joerg if (isa<BlockDecl>(D)) { 940 1.1 joerg if (ExtendedDescription) 941 1.1 joerg Out << Prefix << "anonymous block"; 942 1.1 joerg return ExtendedDescription; 943 1.1 joerg } 944 1.1 joerg 945 1.1 joerg if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { 946 1.1 joerg Out << Prefix; 947 1.1 joerg if (ExtendedDescription && !MD->isUserProvided()) { 948 1.1 joerg if (MD->isExplicitlyDefaulted()) 949 1.1 joerg Out << "defaulted "; 950 1.1 joerg else 951 1.1 joerg Out << "implicit "; 952 1.1 joerg } 953 1.1 joerg 954 1.1 joerg if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { 955 1.1 joerg if (CD->isDefaultConstructor()) 956 1.1 joerg Out << "default "; 957 1.1 joerg else if (CD->isCopyConstructor()) 958 1.1 joerg Out << "copy "; 959 1.1 joerg else if (CD->isMoveConstructor()) 960 1.1 joerg Out << "move "; 961 1.1 joerg 962 1.1 joerg Out << "constructor"; 963 1.1 joerg describeClass(Out, MD->getParent(), " for "); 964 1.1 joerg } else if (isa<CXXDestructorDecl>(MD)) { 965 1.1 joerg if (!MD->isUserProvided()) { 966 1.1 joerg Out << "destructor"; 967 1.1 joerg describeClass(Out, MD->getParent(), " for "); 968 1.1 joerg } else { 969 1.1 joerg // Use ~Foo for explicitly-written destructors. 970 1.1 joerg Out << "'" << *MD << "'"; 971 1.1 joerg } 972 1.1 joerg } else if (MD->isCopyAssignmentOperator()) { 973 1.1 joerg Out << "copy assignment operator"; 974 1.1 joerg describeClass(Out, MD->getParent(), " for "); 975 1.1 joerg } else if (MD->isMoveAssignmentOperator()) { 976 1.1 joerg Out << "move assignment operator"; 977 1.1 joerg describeClass(Out, MD->getParent(), " for "); 978 1.1 joerg } else { 979 1.1 joerg if (MD->getParent()->getIdentifier()) 980 1.1 joerg Out << "'" << *MD->getParent() << "::" << *MD << "'"; 981 1.1 joerg else 982 1.1 joerg Out << "'" << *MD << "'"; 983 1.1 joerg } 984 1.1 joerg 985 1.1 joerg return true; 986 1.1 joerg } 987 1.1 joerg 988 1.1 joerg Out << Prefix << '\'' << cast<NamedDecl>(*D); 989 1.1 joerg 990 1.1 joerg // Adding template parameters. 991 1.1 joerg if (const auto FD = dyn_cast<FunctionDecl>(D)) 992 1.1 joerg if (const TemplateArgumentList *TAList = 993 1.1 joerg FD->getTemplateSpecializationArgs()) 994 1.1.1.2 joerg describeTemplateParameters(Out, TAList->asArray(), FD->getLangOpts(), "<", 995 1.1.1.2 joerg ">"); 996 1.1 joerg 997 1.1 joerg Out << '\''; 998 1.1 joerg return true; 999 1.1 joerg } 1000 1.1 joerg 1001 1.1 joerg std::shared_ptr<PathDiagnosticEventPiece> 1002 1.1 joerg PathDiagnosticCallPiece::getCallEnterEvent() const { 1003 1.1 joerg // We do not produce call enters and call exits for autosynthesized property 1004 1.1 joerg // accessors. We do generally produce them for other functions coming from 1005 1.1 joerg // the body farm because they may call callbacks that bring us back into 1006 1.1 joerg // visible code. 1007 1.1 joerg if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor) 1008 1.1 joerg return nullptr; 1009 1.1 joerg 1010 1.1 joerg SmallString<256> buf; 1011 1.1 joerg llvm::raw_svector_ostream Out(buf); 1012 1.1 joerg 1013 1.1 joerg Out << "Calling "; 1014 1.1 joerg describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); 1015 1.1 joerg 1016 1.1 joerg assert(callEnter.asLocation().isValid()); 1017 1.1 joerg return std::make_shared<PathDiagnosticEventPiece>(callEnter, Out.str()); 1018 1.1 joerg } 1019 1.1 joerg 1020 1.1 joerg std::shared_ptr<PathDiagnosticEventPiece> 1021 1.1 joerg PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { 1022 1.1 joerg if (!callEnterWithin.asLocation().isValid()) 1023 1.1 joerg return nullptr; 1024 1.1 joerg if (Callee->isImplicit() || !Callee->hasBody()) 1025 1.1 joerg return nullptr; 1026 1.1 joerg if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee)) 1027 1.1 joerg if (MD->isDefaulted()) 1028 1.1 joerg return nullptr; 1029 1.1 joerg 1030 1.1 joerg SmallString<256> buf; 1031 1.1 joerg llvm::raw_svector_ostream Out(buf); 1032 1.1 joerg 1033 1.1 joerg Out << "Entered call"; 1034 1.1 joerg describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); 1035 1.1 joerg 1036 1.1 joerg return std::make_shared<PathDiagnosticEventPiece>(callEnterWithin, Out.str()); 1037 1.1 joerg } 1038 1.1 joerg 1039 1.1 joerg std::shared_ptr<PathDiagnosticEventPiece> 1040 1.1 joerg PathDiagnosticCallPiece::getCallExitEvent() const { 1041 1.1 joerg // We do not produce call enters and call exits for autosynthesized property 1042 1.1 joerg // accessors. We do generally produce them for other functions coming from 1043 1.1 joerg // the body farm because they may call callbacks that bring us back into 1044 1.1 joerg // visible code. 1045 1.1 joerg if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor) 1046 1.1 joerg return nullptr; 1047 1.1 joerg 1048 1.1 joerg SmallString<256> buf; 1049 1.1 joerg llvm::raw_svector_ostream Out(buf); 1050 1.1 joerg 1051 1.1 joerg if (!CallStackMessage.empty()) { 1052 1.1 joerg Out << CallStackMessage; 1053 1.1 joerg } else { 1054 1.1 joerg bool DidDescribe = describeCodeDecl(Out, Callee, 1055 1.1 joerg /*ExtendedDescription=*/false, 1056 1.1 joerg "Returning from "); 1057 1.1 joerg if (!DidDescribe) 1058 1.1 joerg Out << "Returning to caller"; 1059 1.1 joerg } 1060 1.1 joerg 1061 1.1 joerg assert(callReturn.asLocation().isValid()); 1062 1.1 joerg return std::make_shared<PathDiagnosticEventPiece>(callReturn, Out.str()); 1063 1.1 joerg } 1064 1.1 joerg 1065 1.1 joerg static void compute_path_size(const PathPieces &pieces, unsigned &size) { 1066 1.1 joerg for (const auto &I : pieces) { 1067 1.1 joerg const PathDiagnosticPiece *piece = I.get(); 1068 1.1 joerg if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece)) 1069 1.1 joerg compute_path_size(cp->path, size); 1070 1.1 joerg else 1071 1.1 joerg ++size; 1072 1.1 joerg } 1073 1.1 joerg } 1074 1.1 joerg 1075 1.1 joerg unsigned PathDiagnostic::full_size() { 1076 1.1 joerg unsigned size = 0; 1077 1.1 joerg compute_path_size(path, size); 1078 1.1 joerg return size; 1079 1.1 joerg } 1080 1.1 joerg 1081 1.1 joerg //===----------------------------------------------------------------------===// 1082 1.1 joerg // FoldingSet profiling methods. 1083 1.1 joerg //===----------------------------------------------------------------------===// 1084 1.1 joerg 1085 1.1 joerg void PathDiagnosticLocation::Profile(llvm::FoldingSetNodeID &ID) const { 1086 1.1.1.2 joerg ID.Add(Range.getBegin()); 1087 1.1.1.2 joerg ID.Add(Range.getEnd()); 1088 1.1.1.2 joerg ID.Add(static_cast<const SourceLocation &>(Loc)); 1089 1.1 joerg } 1090 1.1 joerg 1091 1.1 joerg void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1092 1.1 joerg ID.AddInteger((unsigned) getKind()); 1093 1.1 joerg ID.AddString(str); 1094 1.1 joerg // FIXME: Add profiling support for code hints. 1095 1.1 joerg ID.AddInteger((unsigned) getDisplayHint()); 1096 1.1 joerg ArrayRef<SourceRange> Ranges = getRanges(); 1097 1.1 joerg for (const auto &I : Ranges) { 1098 1.1.1.2 joerg ID.Add(I.getBegin()); 1099 1.1.1.2 joerg ID.Add(I.getEnd()); 1100 1.1 joerg } 1101 1.1 joerg } 1102 1.1 joerg 1103 1.1 joerg void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1104 1.1 joerg PathDiagnosticPiece::Profile(ID); 1105 1.1 joerg for (const auto &I : path) 1106 1.1 joerg ID.Add(*I); 1107 1.1 joerg } 1108 1.1 joerg 1109 1.1 joerg void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1110 1.1 joerg PathDiagnosticPiece::Profile(ID); 1111 1.1 joerg ID.Add(Pos); 1112 1.1 joerg } 1113 1.1 joerg 1114 1.1 joerg void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1115 1.1 joerg PathDiagnosticPiece::Profile(ID); 1116 1.1 joerg for (const auto &I : *this) 1117 1.1 joerg ID.Add(I); 1118 1.1 joerg } 1119 1.1 joerg 1120 1.1 joerg void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1121 1.1 joerg PathDiagnosticSpotPiece::Profile(ID); 1122 1.1 joerg for (const auto &I : subPieces) 1123 1.1 joerg ID.Add(*I); 1124 1.1 joerg } 1125 1.1 joerg 1126 1.1 joerg void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const { 1127 1.1 joerg PathDiagnosticSpotPiece::Profile(ID); 1128 1.1 joerg } 1129 1.1 joerg 1130 1.1 joerg void PathDiagnosticPopUpPiece::Profile(llvm::FoldingSetNodeID &ID) const { 1131 1.1 joerg PathDiagnosticSpotPiece::Profile(ID); 1132 1.1 joerg } 1133 1.1 joerg 1134 1.1 joerg void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { 1135 1.1 joerg ID.Add(getLocation()); 1136 1.1.1.2 joerg ID.Add(getUniqueingLoc()); 1137 1.1 joerg ID.AddString(BugType); 1138 1.1 joerg ID.AddString(VerboseDesc); 1139 1.1 joerg ID.AddString(Category); 1140 1.1 joerg } 1141 1.1 joerg 1142 1.1 joerg void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { 1143 1.1 joerg Profile(ID); 1144 1.1 joerg for (const auto &I : path) 1145 1.1 joerg ID.Add(*I); 1146 1.1 joerg for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) 1147 1.1 joerg ID.AddString(*I); 1148 1.1 joerg } 1149 1.1 joerg 1150 1.1 joerg LLVM_DUMP_METHOD void PathPieces::dump() const { 1151 1.1 joerg unsigned index = 0; 1152 1.1 joerg for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { 1153 1.1 joerg llvm::errs() << "[" << index++ << "] "; 1154 1.1 joerg (*I)->dump(); 1155 1.1 joerg llvm::errs() << "\n"; 1156 1.1 joerg } 1157 1.1 joerg } 1158 1.1 joerg 1159 1.1 joerg LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const { 1160 1.1 joerg llvm::errs() << "CALL\n--------------\n"; 1161 1.1 joerg 1162 1.1 joerg if (const Stmt *SLoc = getLocation().getStmtOrNull()) 1163 1.1 joerg SLoc->dump(); 1164 1.1 joerg else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee())) 1165 1.1 joerg llvm::errs() << *ND << "\n"; 1166 1.1 joerg else 1167 1.1 joerg getLocation().dump(); 1168 1.1 joerg } 1169 1.1 joerg 1170 1.1 joerg LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const { 1171 1.1 joerg llvm::errs() << "EVENT\n--------------\n"; 1172 1.1 joerg llvm::errs() << getString() << "\n"; 1173 1.1 joerg llvm::errs() << " ---- at ----\n"; 1174 1.1 joerg getLocation().dump(); 1175 1.1 joerg } 1176 1.1 joerg 1177 1.1 joerg LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const { 1178 1.1 joerg llvm::errs() << "CONTROL\n--------------\n"; 1179 1.1 joerg getStartLocation().dump(); 1180 1.1 joerg llvm::errs() << " ---- to ----\n"; 1181 1.1 joerg getEndLocation().dump(); 1182 1.1 joerg } 1183 1.1 joerg 1184 1.1 joerg LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const { 1185 1.1 joerg llvm::errs() << "MACRO\n--------------\n"; 1186 1.1 joerg // FIXME: Print which macro is being invoked. 1187 1.1 joerg } 1188 1.1 joerg 1189 1.1 joerg LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const { 1190 1.1 joerg llvm::errs() << "NOTE\n--------------\n"; 1191 1.1 joerg llvm::errs() << getString() << "\n"; 1192 1.1 joerg llvm::errs() << " ---- at ----\n"; 1193 1.1 joerg getLocation().dump(); 1194 1.1 joerg } 1195 1.1 joerg 1196 1.1 joerg LLVM_DUMP_METHOD void PathDiagnosticPopUpPiece::dump() const { 1197 1.1 joerg llvm::errs() << "POP-UP\n--------------\n"; 1198 1.1 joerg llvm::errs() << getString() << "\n"; 1199 1.1 joerg llvm::errs() << " ---- at ----\n"; 1200 1.1 joerg getLocation().dump(); 1201 1.1 joerg } 1202 1.1 joerg 1203 1.1 joerg LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const { 1204 1.1 joerg if (!isValid()) { 1205 1.1 joerg llvm::errs() << "<INVALID>\n"; 1206 1.1 joerg return; 1207 1.1 joerg } 1208 1.1 joerg 1209 1.1 joerg switch (K) { 1210 1.1 joerg case RangeK: 1211 1.1 joerg // FIXME: actually print the range. 1212 1.1 joerg llvm::errs() << "<range>\n"; 1213 1.1 joerg break; 1214 1.1 joerg case SingleLocK: 1215 1.1 joerg asLocation().dump(); 1216 1.1 joerg llvm::errs() << "\n"; 1217 1.1 joerg break; 1218 1.1 joerg case StmtK: 1219 1.1 joerg if (S) 1220 1.1 joerg S->dump(); 1221 1.1 joerg else 1222 1.1 joerg llvm::errs() << "<NULL STMT>\n"; 1223 1.1 joerg break; 1224 1.1 joerg case DeclK: 1225 1.1 joerg if (const auto *ND = dyn_cast_or_null<NamedDecl>(D)) 1226 1.1 joerg llvm::errs() << *ND << "\n"; 1227 1.1 joerg else if (isa<BlockDecl>(D)) 1228 1.1 joerg // FIXME: Make this nicer. 1229 1.1 joerg llvm::errs() << "<block>\n"; 1230 1.1 joerg else if (D) 1231 1.1 joerg llvm::errs() << "<unknown decl>\n"; 1232 1.1 joerg else 1233 1.1 joerg llvm::errs() << "<NULL DECL>\n"; 1234 1.1 joerg break; 1235 1.1 joerg } 1236 1.1 joerg } 1237