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