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