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