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