clang  19.0.0git
BugReporter.cpp
Go to the documentation of this file.
1 //===- BugReporter.cpp - Generate PathDiagnostics for bugs ----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines BugReporter, a utility class for generating
10 // PathDiagnostics.
11 //
12 //===----------------------------------------------------------------------===//
13 
16 #include "clang/AST/Attr.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclBase.h"
19 #include "clang/AST/DeclObjC.h"
20 #include "clang/AST/Expr.h"
21 #include "clang/AST/ExprCXX.h"
22 #include "clang/AST/ParentMap.h"
24 #include "clang/AST/Stmt.h"
25 #include "clang/AST/StmtCXX.h"
26 #include "clang/AST/StmtObjC.h"
28 #include "clang/Analysis/CFG.h"
32 #include "clang/Basic/LLVM.h"
48 #include "llvm/ADT/ArrayRef.h"
49 #include "llvm/ADT/DenseMap.h"
50 #include "llvm/ADT/DenseSet.h"
51 #include "llvm/ADT/FoldingSet.h"
52 #include "llvm/ADT/STLExtras.h"
53 #include "llvm/ADT/SmallPtrSet.h"
54 #include "llvm/ADT/SmallString.h"
55 #include "llvm/ADT/SmallVector.h"
56 #include "llvm/ADT/Statistic.h"
57 #include "llvm/ADT/StringExtras.h"
58 #include "llvm/ADT/StringRef.h"
59 #include "llvm/ADT/iterator_range.h"
60 #include "llvm/Support/Casting.h"
61 #include "llvm/Support/Compiler.h"
62 #include "llvm/Support/ErrorHandling.h"
63 #include "llvm/Support/MemoryBuffer.h"
64 #include "llvm/Support/raw_ostream.h"
65 #include <algorithm>
66 #include <cassert>
67 #include <cstddef>
68 #include <iterator>
69 #include <memory>
70 #include <optional>
71 #include <queue>
72 #include <string>
73 #include <tuple>
74 #include <utility>
75 #include <vector>
76 
77 using namespace clang;
78 using namespace ento;
79 using namespace llvm;
80 
81 #define DEBUG_TYPE "BugReporter"
82 
83 STATISTIC(MaxBugClassSize,
84  "The maximum number of bug reports in the same equivalence class");
85 STATISTIC(MaxValidBugClassSize,
86  "The maximum number of bug reports in the same equivalence class "
87  "where at least one report is valid (not suppressed)");
88 
90 
91 void BugReporterContext::anchor() {}
92 
93 //===----------------------------------------------------------------------===//
94 // PathDiagnosticBuilder and its associated routines and helper objects.
95 //===----------------------------------------------------------------------===//
96 
97 namespace {
98 
99 /// A (CallPiece, node assiciated with its CallEnter) pair.
100 using CallWithEntry =
101  std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
102 using CallWithEntryStack = SmallVector<CallWithEntry, 6>;
103 
104 /// Map from each node to the diagnostic pieces visitors emit for them.
105 using VisitorsDiagnosticsTy =
106  llvm::DenseMap<const ExplodedNode *, std::vector<PathDiagnosticPieceRef>>;
107 
108 /// A map from PathDiagnosticPiece to the LocationContext of the inlined
109 /// function call it represents.
110 using LocationContextMap =
111  llvm::DenseMap<const PathPieces *, const LocationContext *>;
112 
113 /// A helper class that contains everything needed to construct a
114 /// PathDiagnostic object. It does no much more then providing convenient
115 /// getters and some well placed asserts for extra security.
116 class PathDiagnosticConstruct {
117  /// The consumer we're constructing the bug report for.
118  const PathDiagnosticConsumer *Consumer;
119  /// Our current position in the bug path, which is owned by
120  /// PathDiagnosticBuilder.
121  const ExplodedNode *CurrentNode;
122  /// A mapping from parts of the bug path (for example, a function call, which
123  /// would span backwards from a CallExit to a CallEnter with the nodes in
124  /// between them) with the location contexts it is associated with.
125  LocationContextMap LCM;
126  const SourceManager &SM;
127 
128 public:
129  /// We keep stack of calls to functions as we're ascending the bug path.
130  /// TODO: PathDiagnostic has a stack doing the same thing, shouldn't we use
131  /// that instead?
132  CallWithEntryStack CallStack;
133  /// The bug report we're constructing. For ease of use, this field is kept
134  /// public, though some "shortcut" getters are provided for commonly used
135  /// methods of PathDiagnostic.
136  std::unique_ptr<PathDiagnostic> PD;
137 
138 public:
139  PathDiagnosticConstruct(const PathDiagnosticConsumer *PDC,
140  const ExplodedNode *ErrorNode,
141  const PathSensitiveBugReport *R,
142  const Decl *AnalysisEntryPoint);
143 
144  /// \returns the location context associated with the current position in the
145  /// bug path.
146  const LocationContext *getCurrLocationContext() const {
147  assert(CurrentNode && "Already reached the root!");
148  return CurrentNode->getLocationContext();
149  }
150 
151  /// Same as getCurrLocationContext (they should always return the same
152  /// location context), but works after reaching the root of the bug path as
153  /// well.
154  const LocationContext *getLocationContextForActivePath() const {
155  return LCM.find(&PD->getActivePath())->getSecond();
156  }
157 
158  const ExplodedNode *getCurrentNode() const { return CurrentNode; }
159 
160  /// Steps the current node to its predecessor.
161  /// \returns whether we reached the root of the bug path.
162  bool ascendToPrevNode() {
163  CurrentNode = CurrentNode->getFirstPred();
164  return static_cast<bool>(CurrentNode);
165  }
166 
167  const ParentMap &getParentMap() const {
168  return getCurrLocationContext()->getParentMap();
169  }
170 
171  const SourceManager &getSourceManager() const { return SM; }
172 
173  const Stmt *getParent(const Stmt *S) const {
174  return getParentMap().getParent(S);
175  }
176 
177  void updateLocCtxMap(const PathPieces *Path, const LocationContext *LC) {
178  assert(Path && LC);
179  LCM[Path] = LC;
180  }
181 
182  const LocationContext *getLocationContextFor(const PathPieces *Path) const {
183  assert(LCM.count(Path) &&
184  "Failed to find the context associated with these pieces!");
185  return LCM.find(Path)->getSecond();
186  }
187 
188  bool isInLocCtxMap(const PathPieces *Path) const { return LCM.count(Path); }
189 
190  PathPieces &getActivePath() { return PD->getActivePath(); }
191  PathPieces &getMutablePieces() { return PD->getMutablePieces(); }
192 
193  bool shouldAddPathEdges() const { return Consumer->shouldAddPathEdges(); }
194  bool shouldAddControlNotes() const {
195  return Consumer->shouldAddControlNotes();
196  }
197  bool shouldGenerateDiagnostics() const {
198  return Consumer->shouldGenerateDiagnostics();
199  }
200  bool supportsLogicalOpControlFlow() const {
201  return Consumer->supportsLogicalOpControlFlow();
202  }
203 };
204 
205 /// Contains every contextual information needed for constructing a
206 /// PathDiagnostic object for a given bug report. This class and its fields are
207 /// immutable, and passes a BugReportConstruct object around during the
208 /// construction.
209 class PathDiagnosticBuilder : public BugReporterContext {
210  /// A linear path from the error node to the root.
211  std::unique_ptr<const ExplodedGraph> BugPath;
212  /// The bug report we're describing. Visitors create their diagnostics with
213  /// them being the last entities being able to modify it (for example,
214  /// changing interestingness here would cause inconsistencies as to how this
215  /// file and visitors construct diagnostics), hence its const.
216  const PathSensitiveBugReport *R;
217  /// The leaf of the bug path. This isn't the same as the bug reports error
218  /// node, which refers to the *original* graph, not the bug path.
219  const ExplodedNode *const ErrorNode;
220  /// The diagnostic pieces visitors emitted, which is expected to be collected
221  /// by the time this builder is constructed.
222  std::unique_ptr<const VisitorsDiagnosticsTy> VisitorsDiagnostics;
223 
224 public:
225  /// Find a non-invalidated report for a given equivalence class, and returns
226  /// a PathDiagnosticBuilder able to construct bug reports for different
227  /// consumers. Returns std::nullopt if no valid report is found.
228  static std::optional<PathDiagnosticBuilder>
229  findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports,
230  PathSensitiveBugReporter &Reporter);
231 
232  PathDiagnosticBuilder(
233  BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
234  PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,
235  std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics);
236 
237  /// This function is responsible for generating diagnostic pieces that are
238  /// *not* provided by bug report visitors.
239  /// These diagnostics may differ depending on the consumer's settings,
240  /// and are therefore constructed separately for each consumer.
241  ///
242  /// There are two path diagnostics generation modes: with adding edges (used
243  /// for plists) and without (used for HTML and text). When edges are added,
244  /// the path is modified to insert artificially generated edges.
245  /// Otherwise, more detailed diagnostics is emitted for block edges,
246  /// explaining the transitions in words.
247  std::unique_ptr<PathDiagnostic>
248  generate(const PathDiagnosticConsumer *PDC) const;
249 
250 private:
251  void updateStackPiecesWithMessage(PathDiagnosticPieceRef P,
252  const CallWithEntryStack &CallStack) const;
253  void generatePathDiagnosticsForNode(PathDiagnosticConstruct &C,
254  PathDiagnosticLocation &PrevLoc) const;
255 
256  void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &C,
257  BlockEdge BE) const;
258 
260  generateDiagForGotoOP(const PathDiagnosticConstruct &C, const Stmt *S,
261  PathDiagnosticLocation &Start) const;
262 
264  generateDiagForSwitchOP(const PathDiagnosticConstruct &C, const CFGBlock *Dst,
265  PathDiagnosticLocation &Start) const;
266 
268  generateDiagForBinaryOP(const PathDiagnosticConstruct &C, const Stmt *T,
269  const CFGBlock *Src, const CFGBlock *DstC) const;
270 
272  ExecutionContinues(const PathDiagnosticConstruct &C) const;
273 
275  ExecutionContinues(llvm::raw_string_ostream &os,
276  const PathDiagnosticConstruct &C) const;
277 
278  const PathSensitiveBugReport *getBugReport() const { return R; }
279 };
280 
281 } // namespace
282 
283 //===----------------------------------------------------------------------===//
284 // Base implementation of stack hint generators.
285 //===----------------------------------------------------------------------===//
286 
288 
290  if (!N)
291  return getMessageForSymbolNotFound();
292 
293  ProgramPoint P = N->getLocation();
294  CallExitEnd CExit = P.castAs<CallExitEnd>();
295 
296  // FIXME: Use CallEvent to abstract this over all calls.
297  const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
298  const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
299  if (!CE)
300  return {};
301 
302  // Check if one of the parameters are set to the interesting symbol.
303  for (auto [Idx, ArgExpr] : llvm::enumerate(CE->arguments())) {
304  SVal SV = N->getSVal(ArgExpr);
305 
306  // Check if the variable corresponding to the symbol is passed by value.
307  SymbolRef AS = SV.getAsLocSymbol();
308  if (AS == Sym) {
309  return getMessageForArg(ArgExpr, Idx);
310  }
311 
312  // Check if the parameter is a pointer to the symbol.
313  if (std::optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
314  // Do not attempt to dereference void*.
315  if (ArgExpr->getType()->isVoidPointerType())
316  continue;
317  SVal PSV = N->getState()->getSVal(Reg->getRegion());
318  SymbolRef AS = PSV.getAsLocSymbol();
319  if (AS == Sym) {
320  return getMessageForArg(ArgExpr, Idx);
321  }
322  }
323  }
324 
325  // Check if we are returning the interesting symbol.
326  SVal SV = N->getSVal(CE);
327  SymbolRef RetSym = SV.getAsLocSymbol();
328  if (RetSym == Sym) {
329  return getMessageForReturn(CE);
330  }
331 
332  return getMessageForSymbolNotFound();
333 }
334 
336  unsigned ArgIndex) {
337  // Printed parameters start at 1, not 0.
338  ++ArgIndex;
339 
340  return (llvm::Twine(Msg) + " via " + std::to_string(ArgIndex) +
341  llvm::getOrdinalSuffix(ArgIndex) + " parameter").str();
342 }
343 
344 //===----------------------------------------------------------------------===//
345 // Diagnostic cleanup.
346 //===----------------------------------------------------------------------===//
347 
351  // Prefer diagnostics that come from ConditionBRVisitor over
352  // those that came from TrackConstraintBRVisitor,
353  // unless the one from ConditionBRVisitor is
354  // its generic fallback diagnostic.
355  const void *tagPreferred = ConditionBRVisitor::getTag();
356  const void *tagLesser = TrackConstraintBRVisitor::getTag();
357 
358  if (X->getLocation() != Y->getLocation())
359  return nullptr;
360 
361  if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
363 
364  if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
366 
367  return nullptr;
368 }
369 
370 /// An optimization pass over PathPieces that removes redundant diagnostics
371 /// generated by both ConditionBRVisitor and TrackConstraintBRVisitor. Both
372 /// BugReporterVisitors use different methods to generate diagnostics, with
373 /// one capable of emitting diagnostics in some cases but not in others. This
374 /// can lead to redundant diagnostic pieces at the same point in a path.
375 static void removeRedundantMsgs(PathPieces &path) {
376  unsigned N = path.size();
377  if (N < 2)
378  return;
379  // NOTE: this loop intentionally is not using an iterator. Instead, we
380  // are streaming the path and modifying it in place. This is done by
381  // grabbing the front, processing it, and if we decide to keep it append
382  // it to the end of the path. The entire path is processed in this way.
383  for (unsigned i = 0; i < N; ++i) {
384  auto piece = std::move(path.front());
385  path.pop_front();
386 
387  switch (piece->getKind()) {
389  removeRedundantMsgs(cast<PathDiagnosticCallPiece>(*piece).path);
390  break;
392  removeRedundantMsgs(cast<PathDiagnosticMacroPiece>(*piece).subPieces);
393  break;
395  if (i == N-1)
396  break;
397 
398  if (auto *nextEvent =
399  dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
400  auto *event = cast<PathDiagnosticEventPiece>(piece.get());
401  // Check to see if we should keep one of the two pieces. If we
402  // come up with a preference, record which piece to keep, and consume
403  // another piece from the path.
404  if (auto *pieceToKeep =
405  eventsDescribeSameCondition(event, nextEvent)) {
406  piece = std::move(pieceToKeep == event ? piece : path.front());
407  path.pop_front();
408  ++i;
409  }
410  }
411  break;
412  }
416  break;
417  }
418  path.push_back(std::move(piece));
419  }
420 }
421 
422 /// Recursively scan through a path and prune out calls and macros pieces
423 /// that aren't needed. Return true if afterwards the path contains
424 /// "interesting stuff" which means it shouldn't be pruned from the parent path.
425 static bool removeUnneededCalls(const PathDiagnosticConstruct &C,
426  PathPieces &pieces,
427  const PathSensitiveBugReport *R,
428  bool IsInteresting = false) {
429  bool containsSomethingInteresting = IsInteresting;
430  const unsigned N = pieces.size();
431 
432  for (unsigned i = 0 ; i < N ; ++i) {
433  // Remove the front piece from the path. If it is still something we
434  // want to keep once we are done, we will push it back on the end.
435  auto piece = std::move(pieces.front());
436  pieces.pop_front();
437 
438  switch (piece->getKind()) {
440  auto &call = cast<PathDiagnosticCallPiece>(*piece);
441  // Check if the location context is interesting.
442  if (!removeUnneededCalls(
443  C, call.path, R,
444  R->isInteresting(C.getLocationContextFor(&call.path))))
445  continue;
446 
447  containsSomethingInteresting = true;
448  break;
449  }
451  auto &macro = cast<PathDiagnosticMacroPiece>(*piece);
452  if (!removeUnneededCalls(C, macro.subPieces, R, IsInteresting))
453  continue;
454  containsSomethingInteresting = true;
455  break;
456  }
458  auto &event = cast<PathDiagnosticEventPiece>(*piece);
459 
460  // We never throw away an event, but we do throw it away wholesale
461  // as part of a path if we throw the entire path away.
462  containsSomethingInteresting |= !event.isPrunable();
463  break;
464  }
468  break;
469  }
470 
471  pieces.push_back(std::move(piece));
472  }
473 
474  return containsSomethingInteresting;
475 }
476 
477 /// Same logic as above to remove extra pieces.
478 static void removePopUpNotes(PathPieces &Path) {
479  for (unsigned int i = 0; i < Path.size(); ++i) {
480  auto Piece = std::move(Path.front());
481  Path.pop_front();
482  if (!isa<PathDiagnosticPopUpPiece>(*Piece))
483  Path.push_back(std::move(Piece));
484  }
485 }
486 
487 /// Returns true if the given decl has been implicitly given a body, either by
488 /// the analyzer or by the compiler proper.
489 static bool hasImplicitBody(const Decl *D) {
490  assert(D);
491  return D->isImplicit() || !D->hasBody();
492 }
493 
494 /// Recursively scan through a path and make sure that all call pieces have
495 /// valid locations.
496 static void
498  PathDiagnosticLocation *LastCallLocation = nullptr) {
499  for (const auto &I : Pieces) {
500  auto *Call = dyn_cast<PathDiagnosticCallPiece>(I.get());
501 
502  if (!Call)
503  continue;
504 
505  if (LastCallLocation) {
506  bool CallerIsImplicit = hasImplicitBody(Call->getCaller());
507  if (CallerIsImplicit || !Call->callEnter.asLocation().isValid())
508  Call->callEnter = *LastCallLocation;
509  if (CallerIsImplicit || !Call->callReturn.asLocation().isValid())
510  Call->callReturn = *LastCallLocation;
511  }
512 
513  // Recursively clean out the subclass. Keep this call around if
514  // it contains any informative diagnostics.
515  PathDiagnosticLocation *ThisCallLocation;
516  if (Call->callEnterWithin.asLocation().isValid() &&
517  !hasImplicitBody(Call->getCallee()))
518  ThisCallLocation = &Call->callEnterWithin;
519  else
520  ThisCallLocation = &Call->callEnter;
521 
522  assert(ThisCallLocation && "Outermost call has an invalid location");
523  adjustCallLocations(Call->path, ThisCallLocation);
524  }
525 }
526 
527 /// Remove edges in and out of C++ default initializer expressions. These are
528 /// for fields that have in-class initializers, as opposed to being initialized
529 /// explicitly in a constructor or braced list.
531  for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
532  if (auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
534 
535  if (auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
536  removeEdgesToDefaultInitializers(M->subPieces);
537 
538  if (auto *CF = dyn_cast<PathDiagnosticControlFlowPiece>(I->get())) {
539  const Stmt *Start = CF->getStartLocation().asStmt();
540  const Stmt *End = CF->getEndLocation().asStmt();
541  if (isa_and_nonnull<CXXDefaultInitExpr>(Start)) {
542  I = Pieces.erase(I);
543  continue;
544  } else if (isa_and_nonnull<CXXDefaultInitExpr>(End)) {
545  PathPieces::iterator Next = std::next(I);
546  if (Next != E) {
547  if (auto *NextCF =
548  dyn_cast<PathDiagnosticControlFlowPiece>(Next->get())) {
549  NextCF->setStartLocation(CF->getStartLocation());
550  }
551  }
552  I = Pieces.erase(I);
553  continue;
554  }
555  }
556 
557  I++;
558  }
559 }
560 
561 /// Remove all pieces with invalid locations as these cannot be serialized.
562 /// We might have pieces with invalid locations as a result of inlining Body
563 /// Farm generated functions.
565  for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E;) {
566  if (auto *C = dyn_cast<PathDiagnosticCallPiece>(I->get()))
568 
569  if (auto *M = dyn_cast<PathDiagnosticMacroPiece>(I->get()))
570  removePiecesWithInvalidLocations(M->subPieces);
571 
572  if (!(*I)->getLocation().isValid() ||
573  !(*I)->getLocation().asLocation().isValid()) {
574  I = Pieces.erase(I);
575  continue;
576  }
577  I++;
578  }
579 }
580 
581 PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
582  const PathDiagnosticConstruct &C) const {
583  if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
584  return PathDiagnosticLocation(S, getSourceManager(),
585  C.getCurrLocationContext());
586 
587  return PathDiagnosticLocation::createDeclEnd(C.getCurrLocationContext(),
588  getSourceManager());
589 }
590 
591 PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
592  llvm::raw_string_ostream &os, const PathDiagnosticConstruct &C) const {
593  // Slow, but probably doesn't matter.
594  if (os.str().empty())
595  os << ' ';
596 
597  const PathDiagnosticLocation &Loc = ExecutionContinues(C);
598 
599  if (Loc.asStmt())
600  os << "Execution continues on line "
601  << getSourceManager().getExpansionLineNumber(Loc.asLocation())
602  << '.';
603  else {
604  os << "Execution jumps to the end of the ";
605  const Decl *D = C.getCurrLocationContext()->getDecl();
606  if (isa<ObjCMethodDecl>(D))
607  os << "method";
608  else if (isa<FunctionDecl>(D))
609  os << "function";
610  else {
611  assert(isa<BlockDecl>(D));
612  os << "anonymous block";
613  }
614  os << '.';
615  }
616 
617  return Loc;
618 }
619 
620 static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) {
621  if (isa<Expr>(S) && PM.isConsumedExpr(cast<Expr>(S)))
622  return PM.getParentIgnoreParens(S);
623 
624  const Stmt *Parent = PM.getParentIgnoreParens(S);
625  if (!Parent)
626  return nullptr;
627 
628  switch (Parent->getStmtClass()) {
629  case Stmt::ForStmtClass:
630  case Stmt::DoStmtClass:
631  case Stmt::WhileStmtClass:
632  case Stmt::ObjCForCollectionStmtClass:
633  case Stmt::CXXForRangeStmtClass:
634  return Parent;
635  default:
636  break;
637  }
638 
639  return nullptr;
640 }
641 
644  bool allowNestedContexts = false) {
645  if (!S)
646  return {};
647 
648  const SourceManager &SMgr = LC->getDecl()->getASTContext().getSourceManager();
649 
650  while (const Stmt *Parent = getEnclosingParent(S, LC->getParentMap())) {
651  switch (Parent->getStmtClass()) {
652  case Stmt::BinaryOperatorClass: {
653  const auto *B = cast<BinaryOperator>(Parent);
654  if (B->isLogicalOp())
655  return PathDiagnosticLocation(allowNestedContexts ? B : S, SMgr, LC);
656  break;
657  }
658  case Stmt::CompoundStmtClass:
659  case Stmt::StmtExprClass:
660  return PathDiagnosticLocation(S, SMgr, LC);
661  case Stmt::ChooseExprClass:
662  // Similar to '?' if we are referring to condition, just have the edge
663  // point to the entire choose expression.
664  if (allowNestedContexts || cast<ChooseExpr>(Parent)->getCond() == S)
665  return PathDiagnosticLocation(Parent, SMgr, LC);
666  else
667  return PathDiagnosticLocation(S, SMgr, LC);
668  case Stmt::BinaryConditionalOperatorClass:
669  case Stmt::ConditionalOperatorClass:
670  // For '?', if we are referring to condition, just have the edge point
671  // to the entire '?' expression.
672  if (allowNestedContexts ||
673  cast<AbstractConditionalOperator>(Parent)->getCond() == S)
674  return PathDiagnosticLocation(Parent, SMgr, LC);
675  else
676  return PathDiagnosticLocation(S, SMgr, LC);
677  case Stmt::CXXForRangeStmtClass:
678  if (cast<CXXForRangeStmt>(Parent)->getBody() == S)
679  return PathDiagnosticLocation(S, SMgr, LC);
680  break;
681  case Stmt::DoStmtClass:
682  return PathDiagnosticLocation(S, SMgr, LC);
683  case Stmt::ForStmtClass:
684  if (cast<ForStmt>(Parent)->getBody() == S)
685  return PathDiagnosticLocation(S, SMgr, LC);
686  break;
687  case Stmt::IfStmtClass:
688  if (cast<IfStmt>(Parent)->getCond() != S)
689  return PathDiagnosticLocation(S, SMgr, LC);
690  break;
691  case Stmt::ObjCForCollectionStmtClass:
692  if (cast<ObjCForCollectionStmt>(Parent)->getBody() == S)
693  return PathDiagnosticLocation(S, SMgr, LC);
694  break;
695  case Stmt::WhileStmtClass:
696  if (cast<WhileStmt>(Parent)->getCond() != S)
697  return PathDiagnosticLocation(S, SMgr, LC);
698  break;
699  default:
700  break;
701  }
702 
703  S = Parent;
704  }
705 
706  assert(S && "Cannot have null Stmt for PathDiagnosticLocation");
707 
708  return PathDiagnosticLocation(S, SMgr, LC);
709 }
710 
711 //===----------------------------------------------------------------------===//
712 // "Minimal" path diagnostic generation algorithm.
713 //===----------------------------------------------------------------------===//
714 
715 /// If the piece contains a special message, add it to all the call pieces on
716 /// the active stack. For example, my_malloc allocated memory, so MallocChecker
717 /// will construct an event at the call to malloc(), and add a stack hint that
718 /// an allocated memory was returned. We'll use this hint to construct a message
719 /// when returning from the call to my_malloc
720 ///
721 /// void *my_malloc() { return malloc(sizeof(int)); }
722 /// void fishy() {
723 /// void *ptr = my_malloc(); // returned allocated memory
724 /// } // leak
725 void PathDiagnosticBuilder::updateStackPiecesWithMessage(
726  PathDiagnosticPieceRef P, const CallWithEntryStack &CallStack) const {
727  if (R->hasCallStackHint(P))
728  for (const auto &I : CallStack) {
729  PathDiagnosticCallPiece *CP = I.first;
730  const ExplodedNode *N = I.second;
731  std::string stackMsg = R->getCallStackMessage(P, N);
732 
733  // The last message on the path to final bug is the most important
734  // one. Since we traverse the path backwards, do not add the message
735  // if one has been previously added.
736  if (!CP->hasCallStackMessage())
737  CP->setCallStackMessage(stackMsg);
738  }
739 }
740 
741 static void CompactMacroExpandedPieces(PathPieces &path,
742  const SourceManager& SM);
743 
744 PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForSwitchOP(
745  const PathDiagnosticConstruct &C, const CFGBlock *Dst,
746  PathDiagnosticLocation &Start) const {
747 
748  const SourceManager &SM = getSourceManager();
749  // Figure out what case arm we took.
750  std::string sbuf;
751  llvm::raw_string_ostream os(sbuf);
753 
754  if (const Stmt *S = Dst->getLabel()) {
755  End = PathDiagnosticLocation(S, SM, C.getCurrLocationContext());
756 
757  switch (S->getStmtClass()) {
758  default:
759  os << "No cases match in the switch statement. "
760  "Control jumps to line "
761  << End.asLocation().getExpansionLineNumber();
762  break;
763  case Stmt::DefaultStmtClass:
764  os << "Control jumps to the 'default' case at line "
765  << End.asLocation().getExpansionLineNumber();
766  break;
767 
768  case Stmt::CaseStmtClass: {
769  os << "Control jumps to 'case ";
770  const auto *Case = cast<CaseStmt>(S);
771  const Expr *LHS = Case->getLHS()->IgnoreParenImpCasts();
772 
773  // Determine if it is an enum.
774  bool GetRawInt = true;
775 
776  if (const auto *DR = dyn_cast<DeclRefExpr>(LHS)) {
777  // FIXME: Maybe this should be an assertion. Are there cases
778  // were it is not an EnumConstantDecl?
779  const auto *D = dyn_cast<EnumConstantDecl>(DR->getDecl());
780 
781  if (D) {
782  GetRawInt = false;
783  os << *D;
784  }
785  }
786 
787  if (GetRawInt)
788  os << LHS->EvaluateKnownConstInt(getASTContext());
789 
790  os << ":' at line " << End.asLocation().getExpansionLineNumber();
791  break;
792  }
793  }
794  } else {
795  os << "'Default' branch taken. ";
796  End = ExecutionContinues(os, C);
797  }
798  return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
799  os.str());
800 }
801 
802 PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForGotoOP(
803  const PathDiagnosticConstruct &C, const Stmt *S,
804  PathDiagnosticLocation &Start) const {
805  std::string sbuf;
806  llvm::raw_string_ostream os(sbuf);
807  const PathDiagnosticLocation &End =
808  getEnclosingStmtLocation(S, C.getCurrLocationContext());
809  os << "Control jumps to line " << End.asLocation().getExpansionLineNumber();
810  return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str());
811 }
812 
813 PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForBinaryOP(
814  const PathDiagnosticConstruct &C, const Stmt *T, const CFGBlock *Src,
815  const CFGBlock *Dst) const {
816 
817  const SourceManager &SM = getSourceManager();
818 
819  const auto *B = cast<BinaryOperator>(T);
820  std::string sbuf;
821  llvm::raw_string_ostream os(sbuf);
822  os << "Left side of '";
824 
825  if (B->getOpcode() == BO_LAnd) {
826  os << "&&"
827  << "' is ";
828 
829  if (*(Src->succ_begin() + 1) == Dst) {
830  os << "false";
831  End = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
832  Start =
834  } else {
835  os << "true";
836  Start =
837  PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
838  End = ExecutionContinues(C);
839  }
840  } else {
841  assert(B->getOpcode() == BO_LOr);
842  os << "||"
843  << "' is ";
844 
845  if (*(Src->succ_begin() + 1) == Dst) {
846  os << "false";
847  Start =
848  PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
849  End = ExecutionContinues(C);
850  } else {
851  os << "true";
852  End = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
853  Start =
855  }
856  }
857  return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
858  os.str());
859 }
860 
861 void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
862  PathDiagnosticConstruct &C, BlockEdge BE) const {
863  const SourceManager &SM = getSourceManager();
864  const LocationContext *LC = C.getCurrLocationContext();
865  const CFGBlock *Src = BE.getSrc();
866  const CFGBlock *Dst = BE.getDst();
867  const Stmt *T = Src->getTerminatorStmt();
868  if (!T)
869  return;
870 
871  auto Start = PathDiagnosticLocation::createBegin(T, SM, LC);
872  switch (T->getStmtClass()) {
873  default:
874  break;
875 
876  case Stmt::GotoStmtClass:
877  case Stmt::IndirectGotoStmtClass: {
878  if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
879  C.getActivePath().push_front(generateDiagForGotoOP(C, S, Start));
880  break;
881  }
882 
883  case Stmt::SwitchStmtClass: {
884  C.getActivePath().push_front(generateDiagForSwitchOP(C, Dst, Start));
885  break;
886  }
887 
888  case Stmt::BreakStmtClass:
889  case Stmt::ContinueStmtClass: {
890  std::string sbuf;
891  llvm::raw_string_ostream os(sbuf);
892  PathDiagnosticLocation End = ExecutionContinues(os, C);
893  C.getActivePath().push_front(
894  std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
895  break;
896  }
897 
898  // Determine control-flow for ternary '?'.
899  case Stmt::BinaryConditionalOperatorClass:
900  case Stmt::ConditionalOperatorClass: {
901  std::string sbuf;
902  llvm::raw_string_ostream os(sbuf);
903  os << "'?' condition is ";
904 
905  if (*(Src->succ_begin() + 1) == Dst)
906  os << "false";
907  else
908  os << "true";
909 
910  PathDiagnosticLocation End = ExecutionContinues(C);
911 
912  if (const Stmt *S = End.asStmt())
913  End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
914 
915  C.getActivePath().push_front(
916  std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
917  break;
918  }
919 
920  // Determine control-flow for short-circuited '&&' and '||'.
921  case Stmt::BinaryOperatorClass: {
922  if (!C.supportsLogicalOpControlFlow())
923  break;
924 
925  C.getActivePath().push_front(generateDiagForBinaryOP(C, T, Src, Dst));
926  break;
927  }
928 
929  case Stmt::DoStmtClass:
930  if (*(Src->succ_begin()) == Dst) {
931  std::string sbuf;
932  llvm::raw_string_ostream os(sbuf);
933 
934  os << "Loop condition is true. ";
935  PathDiagnosticLocation End = ExecutionContinues(os, C);
936 
937  if (const Stmt *S = End.asStmt())
938  End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
939 
940  C.getActivePath().push_front(
941  std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
942  os.str()));
943  } else {
944  PathDiagnosticLocation End = ExecutionContinues(C);
945 
946  if (const Stmt *S = End.asStmt())
947  End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
948 
949  C.getActivePath().push_front(
950  std::make_shared<PathDiagnosticControlFlowPiece>(
951  Start, End, "Loop condition is false. Exiting loop"));
952  }
953  break;
954 
955  case Stmt::WhileStmtClass:
956  case Stmt::ForStmtClass:
957  if (*(Src->succ_begin() + 1) == Dst) {
958  std::string sbuf;
959  llvm::raw_string_ostream os(sbuf);
960 
961  os << "Loop condition is false. ";
962  PathDiagnosticLocation End = ExecutionContinues(os, C);
963  if (const Stmt *S = End.asStmt())
964  End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
965 
966  C.getActivePath().push_front(
967  std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
968  os.str()));
969  } else {
970  PathDiagnosticLocation End = ExecutionContinues(C);
971  if (const Stmt *S = End.asStmt())
972  End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
973 
974  C.getActivePath().push_front(
975  std::make_shared<PathDiagnosticControlFlowPiece>(
976  Start, End, "Loop condition is true. Entering loop body"));
977  }
978 
979  break;
980 
981  case Stmt::IfStmtClass: {
982  PathDiagnosticLocation End = ExecutionContinues(C);
983 
984  if (const Stmt *S = End.asStmt())
985  End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
986 
987  if (*(Src->succ_begin() + 1) == Dst)
988  C.getActivePath().push_front(
989  std::make_shared<PathDiagnosticControlFlowPiece>(
990  Start, End, "Taking false branch"));
991  else
992  C.getActivePath().push_front(
993  std::make_shared<PathDiagnosticControlFlowPiece>(
994  Start, End, "Taking true branch"));
995 
996  break;
997  }
998  }
999 }
1000 
1001 //===----------------------------------------------------------------------===//
1002 // Functions for determining if a loop was executed 0 times.
1003 //===----------------------------------------------------------------------===//
1004 
1005 static bool isLoop(const Stmt *Term) {
1006  switch (Term->getStmtClass()) {
1007  case Stmt::ForStmtClass:
1008  case Stmt::WhileStmtClass:
1009  case Stmt::ObjCForCollectionStmtClass:
1010  case Stmt::CXXForRangeStmtClass:
1011  return true;
1012  default:
1013  // Note that we intentionally do not include do..while here.
1014  return false;
1015  }
1016 }
1017 
1018 static bool isJumpToFalseBranch(const BlockEdge *BE) {
1019  const CFGBlock *Src = BE->getSrc();
1020  assert(Src->succ_size() == 2);
1021  return (*(Src->succ_begin()+1) == BE->getDst());
1022 }
1023 
1024 static bool isContainedByStmt(const ParentMap &PM, const Stmt *S,
1025  const Stmt *SubS) {
1026  while (SubS) {
1027  if (SubS == S)
1028  return true;
1029  SubS = PM.getParent(SubS);
1030  }
1031  return false;
1032 }
1033 
1034 static const Stmt *getStmtBeforeCond(const ParentMap &PM, const Stmt *Term,
1035  const ExplodedNode *N) {
1036  while (N) {
1037  std::optional<StmtPoint> SP = N->getLocation().getAs<StmtPoint>();
1038  if (SP) {
1039  const Stmt *S = SP->getStmt();
1040  if (!isContainedByStmt(PM, Term, S))
1041  return S;
1042  }
1043  N = N->getFirstPred();
1044  }
1045  return nullptr;
1046 }
1047 
1048 static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term) {
1049  const Stmt *LoopBody = nullptr;
1050  switch (Term->getStmtClass()) {
1051  case Stmt::CXXForRangeStmtClass: {
1052  const auto *FR = cast<CXXForRangeStmt>(Term);
1053  if (isContainedByStmt(PM, FR->getInc(), S))
1054  return true;
1055  if (isContainedByStmt(PM, FR->getLoopVarStmt(), S))
1056  return true;
1057  LoopBody = FR->getBody();
1058  break;
1059  }
1060  case Stmt::ForStmtClass: {
1061  const auto *FS = cast<ForStmt>(Term);
1062  if (isContainedByStmt(PM, FS->getInc(), S))
1063  return true;
1064  LoopBody = FS->getBody();
1065  break;
1066  }
1067  case Stmt::ObjCForCollectionStmtClass: {
1068  const auto *FC = cast<ObjCForCollectionStmt>(Term);
1069  LoopBody = FC->getBody();
1070  break;
1071  }
1072  case Stmt::WhileStmtClass:
1073  LoopBody = cast<WhileStmt>(Term)->getBody();
1074  break;
1075  default:
1076  return false;
1077  }
1078  return isContainedByStmt(PM, LoopBody, S);
1079 }
1080 
1081 /// Adds a sanitized control-flow diagnostic edge to a path.
1082 static void addEdgeToPath(PathPieces &path,
1083  PathDiagnosticLocation &PrevLoc,
1084  PathDiagnosticLocation NewLoc) {
1085  if (!NewLoc.isValid())
1086  return;
1087 
1088  SourceLocation NewLocL = NewLoc.asLocation();
1089  if (NewLocL.isInvalid())
1090  return;
1091 
1092  if (!PrevLoc.isValid() || !PrevLoc.asLocation().isValid()) {
1093  PrevLoc = NewLoc;
1094  return;
1095  }
1096 
1097  // Ignore self-edges, which occur when there are multiple nodes at the same
1098  // statement.
1099  if (NewLoc.asStmt() && NewLoc.asStmt() == PrevLoc.asStmt())
1100  return;
1101 
1102  path.push_front(
1103  std::make_shared<PathDiagnosticControlFlowPiece>(NewLoc, PrevLoc));
1104  PrevLoc = NewLoc;
1105 }
1106 
1107 /// A customized wrapper for CFGBlock::getTerminatorCondition()
1108 /// which returns the element for ObjCForCollectionStmts.
1109 static const Stmt *getTerminatorCondition(const CFGBlock *B) {
1110  const Stmt *S = B->getTerminatorCondition();
1111  if (const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(S))
1112  return FS->getElement();
1113  return S;
1114 }
1115 
1116 constexpr llvm::StringLiteral StrEnteringLoop = "Entering loop body";
1117 constexpr llvm::StringLiteral StrLoopBodyZero = "Loop body executed 0 times";
1118 constexpr llvm::StringLiteral StrLoopRangeEmpty =
1119  "Loop body skipped when range is empty";
1120 constexpr llvm::StringLiteral StrLoopCollectionEmpty =
1121  "Loop body skipped when collection is empty";
1122 
1123 static std::unique_ptr<FilesToLineNumsMap>
1125 
1126 void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
1127  PathDiagnosticConstruct &C, PathDiagnosticLocation &PrevLoc) const {
1128  ProgramPoint P = C.getCurrentNode()->getLocation();
1129  const SourceManager &SM = getSourceManager();
1130 
1131  // Have we encountered an entrance to a call? It may be
1132  // the case that we have not encountered a matching
1133  // call exit before this point. This means that the path
1134  // terminated within the call itself.
1135  if (auto CE = P.getAs<CallEnter>()) {
1136 
1137  if (C.shouldAddPathEdges()) {
1138  // Add an edge to the start of the function.
1139  const StackFrameContext *CalleeLC = CE->getCalleeContext();
1140  const Decl *D = CalleeLC->getDecl();
1141  // Add the edge only when the callee has body. We jump to the beginning
1142  // of the *declaration*, however we expect it to be followed by the
1143  // body. This isn't the case for autosynthesized property accessors in
1144  // Objective-C. No need for a similar extra check for CallExit points
1145  // because the exit edge comes from a statement (i.e. return),
1146  // not from declaration.
1147  if (D->hasBody())
1148  addEdgeToPath(C.getActivePath(), PrevLoc,
1150  }
1151 
1152  // Did we visit an entire call?
1153  bool VisitedEntireCall = C.PD->isWithinCall();
1154  C.PD->popActivePath();
1155 
1157  if (VisitedEntireCall) {
1158  Call = cast<PathDiagnosticCallPiece>(C.getActivePath().front().get());
1159  } else {
1160  // The path terminated within a nested location context, create a new
1161  // call piece to encapsulate the rest of the path pieces.
1162  const Decl *Caller = CE->getLocationContext()->getDecl();
1163  Call = PathDiagnosticCallPiece::construct(C.getActivePath(), Caller);
1164  assert(C.getActivePath().size() == 1 &&
1165  C.getActivePath().front().get() == Call);
1166 
1167  // Since we just transferred the path over to the call piece, reset the
1168  // mapping of the active path to the current location context.
1169  assert(C.isInLocCtxMap(&C.getActivePath()) &&
1170  "When we ascend to a previously unvisited call, the active path's "
1171  "address shouldn't change, but rather should be compacted into "
1172  "a single CallEvent!");
1173  C.updateLocCtxMap(&C.getActivePath(), C.getCurrLocationContext());
1174 
1175  // Record the location context mapping for the path within the call.
1176  assert(!C.isInLocCtxMap(&Call->path) &&
1177  "When we ascend to a previously unvisited call, this must be the "
1178  "first time we encounter the caller context!");
1179  C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
1180  }
1181  Call->setCallee(*CE, SM);
1182 
1183  // Update the previous location in the active path.
1184  PrevLoc = Call->getLocation();
1185 
1186  if (!C.CallStack.empty()) {
1187  assert(C.CallStack.back().first == Call);
1188  C.CallStack.pop_back();
1189  }
1190  return;
1191  }
1192 
1193  assert(C.getCurrLocationContext() == C.getLocationContextForActivePath() &&
1194  "The current position in the bug path is out of sync with the "
1195  "location context associated with the active path!");
1196 
1197  // Have we encountered an exit from a function call?
1198  if (std::optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
1199 
1200  // We are descending into a call (backwards). Construct
1201  // a new call piece to contain the path pieces for that call.
1203  // Record the mapping from call piece to LocationContext.
1204  assert(!C.isInLocCtxMap(&Call->path) &&
1205  "We just entered a call, this must've been the first time we "
1206  "encounter its context!");
1207  C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
1208 
1209  if (C.shouldAddPathEdges()) {
1210  // Add the edge to the return site.
1211  addEdgeToPath(C.getActivePath(), PrevLoc, Call->callReturn);
1212  PrevLoc.invalidate();
1213  }
1214 
1215  auto *P = Call.get();
1216  C.getActivePath().push_front(std::move(Call));
1217 
1218  // Make the contents of the call the active path for now.
1219  C.PD->pushActivePath(&P->path);
1220  C.CallStack.push_back(CallWithEntry(P, C.getCurrentNode()));
1221  return;
1222  }
1223 
1224  if (auto PS = P.getAs<PostStmt>()) {
1225  if (!C.shouldAddPathEdges())
1226  return;
1227 
1228  // Add an edge. If this is an ObjCForCollectionStmt do
1229  // not add an edge here as it appears in the CFG both
1230  // as a terminator and as a terminator condition.
1231  if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
1233  PathDiagnosticLocation(PS->getStmt(), SM, C.getCurrLocationContext());
1234  addEdgeToPath(C.getActivePath(), PrevLoc, L);
1235  }
1236 
1237  } else if (auto BE = P.getAs<BlockEdge>()) {
1238 
1239  if (C.shouldAddControlNotes()) {
1240  generateMinimalDiagForBlockEdge(C, *BE);
1241  }
1242 
1243  if (!C.shouldAddPathEdges()) {
1244  return;
1245  }
1246 
1247  // Are we jumping to the head of a loop? Add a special diagnostic.
1248  if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
1249  PathDiagnosticLocation L(Loop, SM, C.getCurrLocationContext());
1250  const Stmt *Body = nullptr;
1251 
1252  if (const auto *FS = dyn_cast<ForStmt>(Loop))
1253  Body = FS->getBody();
1254  else if (const auto *WS = dyn_cast<WhileStmt>(Loop))
1255  Body = WS->getBody();
1256  else if (const auto *OFS = dyn_cast<ObjCForCollectionStmt>(Loop)) {
1257  Body = OFS->getBody();
1258  } else if (const auto *FRS = dyn_cast<CXXForRangeStmt>(Loop)) {
1259  Body = FRS->getBody();
1260  }
1261  // do-while statements are explicitly excluded here
1262 
1263  auto p = std::make_shared<PathDiagnosticEventPiece>(
1264  L, "Looping back to the head of the loop");
1265  p->setPrunable(true);
1266 
1267  addEdgeToPath(C.getActivePath(), PrevLoc, p->getLocation());
1268  // We might've added a very similar control node already
1269  if (!C.shouldAddControlNotes()) {
1270  C.getActivePath().push_front(std::move(p));
1271  }
1272 
1273  if (const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
1274  addEdgeToPath(C.getActivePath(), PrevLoc,
1276  }
1277  }
1278 
1279  const CFGBlock *BSrc = BE->getSrc();
1280  const ParentMap &PM = C.getParentMap();
1281 
1282  if (const Stmt *Term = BSrc->getTerminatorStmt()) {
1283  // Are we jumping past the loop body without ever executing the
1284  // loop (because the condition was false)?
1285  if (isLoop(Term)) {
1286  const Stmt *TermCond = getTerminatorCondition(BSrc);
1287  bool IsInLoopBody = isInLoopBody(
1288  PM, getStmtBeforeCond(PM, TermCond, C.getCurrentNode()), Term);
1289 
1290  StringRef str;
1291 
1292  if (isJumpToFalseBranch(&*BE)) {
1293  if (!IsInLoopBody) {
1294  if (isa<ObjCForCollectionStmt>(Term)) {
1295  str = StrLoopCollectionEmpty;
1296  } else if (isa<CXXForRangeStmt>(Term)) {
1297  str = StrLoopRangeEmpty;
1298  } else {
1299  str = StrLoopBodyZero;
1300  }
1301  }
1302  } else {
1303  str = StrEnteringLoop;
1304  }
1305 
1306  if (!str.empty()) {
1307  PathDiagnosticLocation L(TermCond ? TermCond : Term, SM,
1308  C.getCurrLocationContext());
1309  auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
1310  PE->setPrunable(true);
1311  addEdgeToPath(C.getActivePath(), PrevLoc, PE->getLocation());
1312 
1313  // We might've added a very similar control node already
1314  if (!C.shouldAddControlNotes()) {
1315  C.getActivePath().push_front(std::move(PE));
1316  }
1317  }
1318  } else if (isa<BreakStmt, ContinueStmt, GotoStmt>(Term)) {
1319  PathDiagnosticLocation L(Term, SM, C.getCurrLocationContext());
1320  addEdgeToPath(C.getActivePath(), PrevLoc, L);
1321  }
1322  }
1323  }
1324 }
1325 
1326 static std::unique_ptr<PathDiagnostic>
1328  const Decl *AnalysisEntryPoint) {
1329  const BugType &BT = R->getBugType();
1330  return std::make_unique<PathDiagnostic>(
1332  R->getDescription(), R->getShortDescription(/*UseFallback=*/false),
1334  AnalysisEntryPoint, std::make_unique<FilesToLineNumsMap>());
1335 }
1336 
1337 static std::unique_ptr<PathDiagnostic>
1339  const SourceManager &SM,
1340  const Decl *AnalysisEntryPoint) {
1341  const BugType &BT = R->getBugType();
1342  return std::make_unique<PathDiagnostic>(
1344  R->getDescription(), R->getShortDescription(/*UseFallback=*/false),
1346  AnalysisEntryPoint, findExecutedLines(SM, R->getErrorNode()));
1347 }
1348 
1349 static const Stmt *getStmtParent(const Stmt *S, const ParentMap &PM) {
1350  if (!S)
1351  return nullptr;
1352 
1353  while (true) {
1354  S = PM.getParentIgnoreParens(S);
1355 
1356  if (!S)
1357  break;
1358 
1359  if (isa<FullExpr, CXXBindTemporaryExpr, SubstNonTypeTemplateParmExpr>(S))
1360  continue;
1361 
1362  break;
1363  }
1364 
1365  return S;
1366 }
1367 
1368 static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond) {
1369  switch (S->getStmtClass()) {
1370  case Stmt::BinaryOperatorClass: {
1371  const auto *BO = cast<BinaryOperator>(S);
1372  if (!BO->isLogicalOp())
1373  return false;
1374  return BO->getLHS() == Cond || BO->getRHS() == Cond;
1375  }
1376  case Stmt::IfStmtClass:
1377  return cast<IfStmt>(S)->getCond() == Cond;
1378  case Stmt::ForStmtClass:
1379  return cast<ForStmt>(S)->getCond() == Cond;
1380  case Stmt::WhileStmtClass:
1381  return cast<WhileStmt>(S)->getCond() == Cond;
1382  case Stmt::DoStmtClass:
1383  return cast<DoStmt>(S)->getCond() == Cond;
1384  case Stmt::ChooseExprClass:
1385  return cast<ChooseExpr>(S)->getCond() == Cond;
1386  case Stmt::IndirectGotoStmtClass:
1387  return cast<IndirectGotoStmt>(S)->getTarget() == Cond;
1388  case Stmt::SwitchStmtClass:
1389  return cast<SwitchStmt>(S)->getCond() == Cond;
1390  case Stmt::BinaryConditionalOperatorClass:
1391  return cast<BinaryConditionalOperator>(S)->getCond() == Cond;
1392  case Stmt::ConditionalOperatorClass: {
1393  const auto *CO = cast<ConditionalOperator>(S);
1394  return CO->getCond() == Cond ||
1395  CO->getLHS() == Cond ||
1396  CO->getRHS() == Cond;
1397  }
1398  case Stmt::ObjCForCollectionStmtClass:
1399  return cast<ObjCForCollectionStmt>(S)->getElement() == Cond;
1400  case Stmt::CXXForRangeStmtClass: {
1401  const auto *FRS = cast<CXXForRangeStmt>(S);
1402  return FRS->getCond() == Cond || FRS->getRangeInit() == Cond;
1403  }
1404  default:
1405  return false;
1406  }
1407 }
1408 
1409 static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL) {
1410  if (const auto *FS = dyn_cast<ForStmt>(FL))
1411  return FS->getInc() == S || FS->getInit() == S;
1412  if (const auto *FRS = dyn_cast<CXXForRangeStmt>(FL))
1413  return FRS->getInc() == S || FRS->getRangeStmt() == S ||
1414  FRS->getLoopVarStmt() || FRS->getRangeInit() == S;
1415  return false;
1416 }
1417 
1419 
1420 /// Adds synthetic edges from top-level statements to their subexpressions.
1421 ///
1422 /// This avoids a "swoosh" effect, where an edge from a top-level statement A
1423 /// points to a sub-expression B.1 that's not at the start of B. In these cases,
1424 /// we'd like to see an edge from A to B, then another one from B to B.1.
1425 static void addContextEdges(PathPieces &pieces, const LocationContext *LC) {
1426  const ParentMap &PM = LC->getParentMap();
1427  PathPieces::iterator Prev = pieces.end();
1428  for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
1429  Prev = I, ++I) {
1430  auto *Piece = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1431 
1432  if (!Piece)
1433  continue;
1434 
1435  PathDiagnosticLocation SrcLoc = Piece->getStartLocation();
1437 
1438  PathDiagnosticLocation NextSrcContext = SrcLoc;
1439  const Stmt *InnerStmt = nullptr;
1440  while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
1441  SrcContexts.push_back(NextSrcContext);
1442  InnerStmt = NextSrcContext.asStmt();
1443  NextSrcContext = getEnclosingStmtLocation(InnerStmt, LC,
1444  /*allowNested=*/true);
1445  }
1446 
1447  // Repeatedly split the edge as necessary.
1448  // This is important for nested logical expressions (||, &&, ?:) where we
1449  // want to show all the levels of context.
1450  while (true) {
1451  const Stmt *Dst = Piece->getEndLocation().getStmtOrNull();
1452 
1453  // We are looking at an edge. Is the destination within a larger
1454  // expression?
1455  PathDiagnosticLocation DstContext =
1456  getEnclosingStmtLocation(Dst, LC, /*allowNested=*/true);
1457  if (!DstContext.isValid() || DstContext.asStmt() == Dst)
1458  break;
1459 
1460  // If the source is in the same context, we're already good.
1461  if (llvm::is_contained(SrcContexts, DstContext))
1462  break;
1463 
1464  // Update the subexpression node to point to the context edge.
1465  Piece->setStartLocation(DstContext);
1466 
1467  // Try to extend the previous edge if it's at the same level as the source
1468  // context.
1469  if (Prev != E) {
1470  auto *PrevPiece = dyn_cast<PathDiagnosticControlFlowPiece>(Prev->get());
1471 
1472  if (PrevPiece) {
1473  if (const Stmt *PrevSrc =
1474  PrevPiece->getStartLocation().getStmtOrNull()) {
1475  const Stmt *PrevSrcParent = getStmtParent(PrevSrc, PM);
1476  if (PrevSrcParent ==
1477  getStmtParent(DstContext.getStmtOrNull(), PM)) {
1478  PrevPiece->setEndLocation(DstContext);
1479  break;
1480  }
1481  }
1482  }
1483  }
1484 
1485  // Otherwise, split the current edge into a context edge and a
1486  // subexpression edge. Note that the context statement may itself have
1487  // context.
1488  auto P =
1489  std::make_shared<PathDiagnosticControlFlowPiece>(SrcLoc, DstContext);
1490  Piece = P.get();
1491  I = pieces.insert(I, std::move(P));
1492  }
1493  }
1494 }
1495 
1496 /// Move edges from a branch condition to a branch target
1497 /// when the condition is simple.
1498 ///
1499 /// This restructures some of the work of addContextEdges. That function
1500 /// creates edges this may destroy, but they work together to create a more
1501 /// aesthetically set of edges around branches. After the call to
1502 /// addContextEdges, we may have (1) an edge to the branch, (2) an edge from
1503 /// the branch to the branch condition, and (3) an edge from the branch
1504 /// condition to the branch target. We keep (1), but may wish to remove (2)
1505 /// and move the source of (3) to the branch if the branch condition is simple.
1506 static void simplifySimpleBranches(PathPieces &pieces) {
1507  for (PathPieces::iterator I = pieces.begin(), E = pieces.end(); I != E; ++I) {
1508  const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1509 
1510  if (!PieceI)
1511  continue;
1512 
1513  const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1514  const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1515 
1516  if (!s1Start || !s1End)
1517  continue;
1518 
1519  PathPieces::iterator NextI = I; ++NextI;
1520  if (NextI == E)
1521  break;
1522 
1523  PathDiagnosticControlFlowPiece *PieceNextI = nullptr;
1524 
1525  while (true) {
1526  if (NextI == E)
1527  break;
1528 
1529  const auto *EV = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1530  if (EV) {
1531  StringRef S = EV->getString();
1532  if (S == StrEnteringLoop || S == StrLoopBodyZero ||
1534  ++NextI;
1535  continue;
1536  }
1537  break;
1538  }
1539 
1540  PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1541  break;
1542  }
1543 
1544  if (!PieceNextI)
1545  continue;
1546 
1547  const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1548  const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1549 
1550  if (!s2Start || !s2End || s1End != s2Start)
1551  continue;
1552 
1553  // We only perform this transformation for specific branch kinds.
1554  // We don't want to do this for do..while, for example.
1556  CXXForRangeStmt>(s1Start))
1557  continue;
1558 
1559  // Is s1End the branch condition?
1560  if (!isConditionForTerminator(s1Start, s1End))
1561  continue;
1562 
1563  // Perform the hoisting by eliminating (2) and changing the start
1564  // location of (3).
1565  PieceNextI->setStartLocation(PieceI->getStartLocation());
1566  I = pieces.erase(I);
1567  }
1568 }
1569 
1570 /// Returns the number of bytes in the given (character-based) SourceRange.
1571 ///
1572 /// If the locations in the range are not on the same line, returns
1573 /// std::nullopt.
1574 ///
1575 /// Note that this does not do a precise user-visible character or column count.
1576 static std::optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
1577  SourceRange Range) {
1578  SourceRange ExpansionRange(SM.getExpansionLoc(Range.getBegin()),
1579  SM.getExpansionRange(Range.getEnd()).getEnd());
1580 
1581  FileID FID = SM.getFileID(ExpansionRange.getBegin());
1582  if (FID != SM.getFileID(ExpansionRange.getEnd()))
1583  return std::nullopt;
1584 
1585  std::optional<MemoryBufferRef> Buffer = SM.getBufferOrNone(FID);
1586  if (!Buffer)
1587  return std::nullopt;
1588 
1589  unsigned BeginOffset = SM.getFileOffset(ExpansionRange.getBegin());
1590  unsigned EndOffset = SM.getFileOffset(ExpansionRange.getEnd());
1591  StringRef Snippet = Buffer->getBuffer().slice(BeginOffset, EndOffset);
1592 
1593  // We're searching the raw bytes of the buffer here, which might include
1594  // escaped newlines and such. That's okay; we're trying to decide whether the
1595  // SourceRange is covering a large or small amount of space in the user's
1596  // editor.
1597  if (Snippet.find_first_of("\r\n") != StringRef::npos)
1598  return std::nullopt;
1599 
1600  // This isn't Unicode-aware, but it doesn't need to be.
1601  return Snippet.size();
1602 }
1603 
1604 /// \sa getLengthOnSingleLine(SourceManager, SourceRange)
1605 static std::optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
1606  const Stmt *S) {
1607  return getLengthOnSingleLine(SM, S->getSourceRange());
1608 }
1609 
1610 /// Eliminate two-edge cycles created by addContextEdges().
1611 ///
1612 /// Once all the context edges are in place, there are plenty of cases where
1613 /// there's a single edge from a top-level statement to a subexpression,
1614 /// followed by a single path note, and then a reverse edge to get back out to
1615 /// the top level. If the statement is simple enough, the subexpression edges
1616 /// just add noise and make it harder to understand what's going on.
1617 ///
1618 /// This function only removes edges in pairs, because removing only one edge
1619 /// might leave other edges dangling.
1620 ///
1621 /// This will not remove edges in more complicated situations:
1622 /// - if there is more than one "hop" leading to or from a subexpression.
1623 /// - if there is an inlined call between the edges instead of a single event.
1624 /// - if the whole statement is large enough that having subexpression arrows
1625 /// might be helpful.
1626 static void removeContextCycles(PathPieces &Path, const SourceManager &SM) {
1627  for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
1628  // Pattern match the current piece and its successor.
1629  const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1630 
1631  if (!PieceI) {
1632  ++I;
1633  continue;
1634  }
1635 
1636  const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1637  const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1638 
1639  PathPieces::iterator NextI = I; ++NextI;
1640  if (NextI == E)
1641  break;
1642 
1643  const auto *PieceNextI =
1644  dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1645 
1646  if (!PieceNextI) {
1647  if (isa<PathDiagnosticEventPiece>(NextI->get())) {
1648  ++NextI;
1649  if (NextI == E)
1650  break;
1651  PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1652  }
1653 
1654  if (!PieceNextI) {
1655  ++I;
1656  continue;
1657  }
1658  }
1659 
1660  const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1661  const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1662 
1663  if (s1Start && s2Start && s1Start == s2End && s2Start == s1End) {
1664  const size_t MAX_SHORT_LINE_LENGTH = 80;
1665  std::optional<size_t> s1Length = getLengthOnSingleLine(SM, s1Start);
1666  if (s1Length && *s1Length <= MAX_SHORT_LINE_LENGTH) {
1667  std::optional<size_t> s2Length = getLengthOnSingleLine(SM, s2Start);
1668  if (s2Length && *s2Length <= MAX_SHORT_LINE_LENGTH) {
1669  Path.erase(I);
1670  I = Path.erase(NextI);
1671  continue;
1672  }
1673  }
1674  }
1675 
1676  ++I;
1677  }
1678 }
1679 
1680 /// Return true if X is contained by Y.
1681 static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y) {
1682  while (X) {
1683  if (X == Y)
1684  return true;
1685  X = PM.getParent(X);
1686  }
1687  return false;
1688 }
1689 
1690 // Remove short edges on the same line less than 3 columns in difference.
1691 static void removePunyEdges(PathPieces &path, const SourceManager &SM,
1692  const ParentMap &PM) {
1693  bool erased = false;
1694 
1695  for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
1696  erased ? I : ++I) {
1697  erased = false;
1698 
1699  const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1700 
1701  if (!PieceI)
1702  continue;
1703 
1704  const Stmt *start = PieceI->getStartLocation().getStmtOrNull();
1705  const Stmt *end = PieceI->getEndLocation().getStmtOrNull();
1706 
1707  if (!start || !end)
1708  continue;
1709 
1710  const Stmt *endParent = PM.getParent(end);
1711  if (!endParent)
1712  continue;
1713 
1714  if (isConditionForTerminator(end, endParent))
1715  continue;
1716 
1717  SourceLocation FirstLoc = start->getBeginLoc();
1718  SourceLocation SecondLoc = end->getBeginLoc();
1719 
1720  if (!SM.isWrittenInSameFile(FirstLoc, SecondLoc))
1721  continue;
1722  if (SM.isBeforeInTranslationUnit(SecondLoc, FirstLoc))
1723  std::swap(SecondLoc, FirstLoc);
1724 
1725  SourceRange EdgeRange(FirstLoc, SecondLoc);
1726  std::optional<size_t> ByteWidth = getLengthOnSingleLine(SM, EdgeRange);
1727 
1728  // If the statements are on different lines, continue.
1729  if (!ByteWidth)
1730  continue;
1731 
1732  const size_t MAX_PUNY_EDGE_LENGTH = 2;
1733  if (*ByteWidth <= MAX_PUNY_EDGE_LENGTH) {
1734  // FIXME: There are enough /bytes/ between the endpoints of the edge, but
1735  // there might not be enough /columns/. A proper user-visible column count
1736  // is probably too expensive, though.
1737  I = path.erase(I);
1738  erased = true;
1739  continue;
1740  }
1741  }
1742 }
1743 
1744 static void removeIdenticalEvents(PathPieces &path) {
1745  for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ++I) {
1746  const auto *PieceI = dyn_cast<PathDiagnosticEventPiece>(I->get());
1747 
1748  if (!PieceI)
1749  continue;
1750 
1751  PathPieces::iterator NextI = I; ++NextI;
1752  if (NextI == E)
1753  return;
1754 
1755  const auto *PieceNextI = dyn_cast<PathDiagnosticEventPiece>(NextI->get());
1756 
1757  if (!PieceNextI)
1758  continue;
1759 
1760  // Erase the second piece if it has the same exact message text.
1761  if (PieceI->getString() == PieceNextI->getString()) {
1762  path.erase(NextI);
1763  }
1764  }
1765 }
1766 
1767 static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path,
1768  OptimizedCallsSet &OCS) {
1769  bool hasChanges = false;
1770  const LocationContext *LC = C.getLocationContextFor(&path);
1771  assert(LC);
1772  const ParentMap &PM = LC->getParentMap();
1773  const SourceManager &SM = C.getSourceManager();
1774 
1775  for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
1776  // Optimize subpaths.
1777  if (auto *CallI = dyn_cast<PathDiagnosticCallPiece>(I->get())) {
1778  // Record the fact that a call has been optimized so we only do the
1779  // effort once.
1780  if (!OCS.count(CallI)) {
1781  while (optimizeEdges(C, CallI->path, OCS)) {
1782  }
1783  OCS.insert(CallI);
1784  }
1785  ++I;
1786  continue;
1787  }
1788 
1789  // Pattern match the current piece and its successor.
1790  auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
1791 
1792  if (!PieceI) {
1793  ++I;
1794  continue;
1795  }
1796 
1797  const Stmt *s1Start = PieceI->getStartLocation().getStmtOrNull();
1798  const Stmt *s1End = PieceI->getEndLocation().getStmtOrNull();
1799  const Stmt *level1 = getStmtParent(s1Start, PM);
1800  const Stmt *level2 = getStmtParent(s1End, PM);
1801 
1802  PathPieces::iterator NextI = I; ++NextI;
1803  if (NextI == E)
1804  break;
1805 
1806  const auto *PieceNextI = dyn_cast<PathDiagnosticControlFlowPiece>(NextI->get());
1807 
1808  if (!PieceNextI) {
1809  ++I;
1810  continue;
1811  }
1812 
1813  const Stmt *s2Start = PieceNextI->getStartLocation().getStmtOrNull();
1814  const Stmt *s2End = PieceNextI->getEndLocation().getStmtOrNull();
1815  const Stmt *level3 = getStmtParent(s2Start, PM);
1816  const Stmt *level4 = getStmtParent(s2End, PM);
1817 
1818  // Rule I.
1819  //
1820  // If we have two consecutive control edges whose end/begin locations
1821  // are at the same level (e.g. statements or top-level expressions within
1822  // a compound statement, or siblings share a single ancestor expression),
1823  // then merge them if they have no interesting intermediate event.
1824  //
1825  // For example:
1826  //
1827  // (1.1 -> 1.2) -> (1.2 -> 1.3) becomes (1.1 -> 1.3) because the common
1828  // parent is '1'. Here 'x.y.z' represents the hierarchy of statements.
1829  //
1830  // NOTE: this will be limited later in cases where we add barriers
1831  // to prevent this optimization.
1832  if (level1 && level1 == level2 && level1 == level3 && level1 == level4) {
1833  PieceI->setEndLocation(PieceNextI->getEndLocation());
1834  path.erase(NextI);
1835  hasChanges = true;
1836  continue;
1837  }
1838 
1839  // Rule II.
1840  //
1841  // Eliminate edges between subexpressions and parent expressions
1842  // when the subexpression is consumed.
1843  //
1844  // NOTE: this will be limited later in cases where we add barriers
1845  // to prevent this optimization.
1846  if (s1End && s1End == s2Start && level2) {
1847  bool removeEdge = false;
1848  // Remove edges into the increment or initialization of a
1849  // loop that have no interleaving event. This means that
1850  // they aren't interesting.
1851  if (isIncrementOrInitInForLoop(s1End, level2))
1852  removeEdge = true;
1853  // Next only consider edges that are not anchored on
1854  // the condition of a terminator. This are intermediate edges
1855  // that we might want to trim.
1856  else if (!isConditionForTerminator(level2, s1End)) {
1857  // Trim edges on expressions that are consumed by
1858  // the parent expression.
1859  if (isa<Expr>(s1End) && PM.isConsumedExpr(cast<Expr>(s1End))) {
1860  removeEdge = true;
1861  }
1862  // Trim edges where a lexical containment doesn't exist.
1863  // For example:
1864  //
1865  // X -> Y -> Z
1866  //
1867  // If 'Z' lexically contains Y (it is an ancestor) and
1868  // 'X' does not lexically contain Y (it is a descendant OR
1869  // it has no lexical relationship at all) then trim.
1870  //
1871  // This can eliminate edges where we dive into a subexpression
1872  // and then pop back out, etc.
1873  else if (s1Start && s2End &&
1874  lexicalContains(PM, s2Start, s2End) &&
1875  !lexicalContains(PM, s1End, s1Start)) {
1876  removeEdge = true;
1877  }
1878  // Trim edges from a subexpression back to the top level if the
1879  // subexpression is on a different line.
1880  //
1881  // A.1 -> A -> B
1882  // becomes
1883  // A.1 -> B
1884  //
1885  // These edges just look ugly and don't usually add anything.
1886  else if (s1Start && s2End &&
1887  lexicalContains(PM, s1Start, s1End)) {
1888  SourceRange EdgeRange(PieceI->getEndLocation().asLocation(),
1889  PieceI->getStartLocation().asLocation());
1890  if (!getLengthOnSingleLine(SM, EdgeRange))
1891  removeEdge = true;
1892  }
1893  }
1894 
1895  if (removeEdge) {
1896  PieceI->setEndLocation(PieceNextI->getEndLocation());
1897  path.erase(NextI);
1898  hasChanges = true;
1899  continue;
1900  }
1901  }
1902 
1903  // Optimize edges for ObjC fast-enumeration loops.
1904  //
1905  // (X -> collection) -> (collection -> element)
1906  //
1907  // becomes:
1908  //
1909  // (X -> element)
1910  if (s1End == s2Start) {
1911  const auto *FS = dyn_cast_or_null<ObjCForCollectionStmt>(level3);
1912  if (FS && FS->getCollection()->IgnoreParens() == s2Start &&
1913  s2End == FS->getElement()) {
1914  PieceI->setEndLocation(PieceNextI->getEndLocation());
1915  path.erase(NextI);
1916  hasChanges = true;
1917  continue;
1918  }
1919  }
1920 
1921  // No changes at this index? Move to the next one.
1922  ++I;
1923  }
1924 
1925  if (!hasChanges) {
1926  // Adjust edges into subexpressions to make them more uniform
1927  // and aesthetically pleasing.
1928  addContextEdges(path, LC);
1929  // Remove "cyclical" edges that include one or more context edges.
1930  removeContextCycles(path, SM);
1931  // Hoist edges originating from branch conditions to branches
1932  // for simple branches.
1933  simplifySimpleBranches(path);
1934  // Remove any puny edges left over after primary optimization pass.
1935  removePunyEdges(path, SM, PM);
1936  // Remove identical events.
1937  removeIdenticalEvents(path);
1938  }
1939 
1940  return hasChanges;
1941 }
1942 
1943 /// Drop the very first edge in a path, which should be a function entry edge.
1944 ///
1945 /// If the first edge is not a function entry edge (say, because the first
1946 /// statement had an invalid source location), this function does nothing.
1947 // FIXME: We should just generate invalid edges anyway and have the optimizer
1948 // deal with them.
1949 static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C,
1950  PathPieces &Path) {
1951  const auto *FirstEdge =
1952  dyn_cast<PathDiagnosticControlFlowPiece>(Path.front().get());
1953  if (!FirstEdge)
1954  return;
1955 
1956  const Decl *D = C.getLocationContextFor(&Path)->getDecl();
1957  PathDiagnosticLocation EntryLoc =
1958  PathDiagnosticLocation::createBegin(D, C.getSourceManager());
1959  if (FirstEdge->getStartLocation() != EntryLoc)
1960  return;
1961 
1962  Path.pop_front();
1963 }
1964 
1965 /// Populate executes lines with lines containing at least one diagnostics.
1967 
1968  PathPieces path = PD.path.flatten(/*ShouldFlattenMacros=*/true);
1969  FilesToLineNumsMap &ExecutedLines = PD.getExecutedLines();
1970 
1971  for (const auto &P : path) {
1972  FullSourceLoc Loc = P->getLocation().asLocation().getExpansionLoc();
1973  FileID FID = Loc.getFileID();
1974  unsigned LineNo = Loc.getLineNumber();
1975  assert(FID.isValid());
1976  ExecutedLines[FID].insert(LineNo);
1977  }
1978 }
1979 
1980 PathDiagnosticConstruct::PathDiagnosticConstruct(
1981  const PathDiagnosticConsumer *PDC, const ExplodedNode *ErrorNode,
1982  const PathSensitiveBugReport *R, const Decl *AnalysisEntryPoint)
1983  : Consumer(PDC), CurrentNode(ErrorNode),
1984  SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
1985  PD(generateEmptyDiagnosticForReport(R, getSourceManager(),
1986  AnalysisEntryPoint)) {
1987  LCM[&PD->getActivePath()] = ErrorNode->getLocationContext();
1988 }
1989 
1990 PathDiagnosticBuilder::PathDiagnosticBuilder(
1991  BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
1992  PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,
1993  std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
1994  : BugReporterContext(BRC), BugPath(std::move(BugPath)), R(r),
1995  ErrorNode(ErrorNode),
1996  VisitorsDiagnostics(std::move(VisitorsDiagnostics)) {}
1997 
1998 std::unique_ptr<PathDiagnostic>
1999 PathDiagnosticBuilder::generate(const PathDiagnosticConsumer *PDC) const {
2000  const Decl *EntryPoint = getBugReporter().getAnalysisEntryPoint();
2001  PathDiagnosticConstruct Construct(PDC, ErrorNode, R, EntryPoint);
2002 
2003  const SourceManager &SM = getSourceManager();
2004  const AnalyzerOptions &Opts = getAnalyzerOptions();
2005 
2006  if (!PDC->shouldGenerateDiagnostics())
2007  return generateEmptyDiagnosticForReport(R, getSourceManager(), EntryPoint);
2008 
2009  // Construct the final (warning) event for the bug report.
2010  auto EndNotes = VisitorsDiagnostics->find(ErrorNode);
2011  PathDiagnosticPieceRef LastPiece;
2012  if (EndNotes != VisitorsDiagnostics->end()) {
2013  assert(!EndNotes->second.empty());
2014  LastPiece = EndNotes->second[0];
2015  } else {
2016  LastPiece = BugReporterVisitor::getDefaultEndPath(*this, ErrorNode,
2017  *getBugReport());
2018  }
2019  Construct.PD->setEndOfPath(LastPiece);
2020 
2021  PathDiagnosticLocation PrevLoc = Construct.PD->getLocation();
2022  // From the error node to the root, ascend the bug path and construct the bug
2023  // report.
2024  while (Construct.ascendToPrevNode()) {
2025  generatePathDiagnosticsForNode(Construct, PrevLoc);
2026 
2027  auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());
2028  if (VisitorNotes == VisitorsDiagnostics->end())
2029  continue;
2030 
2031  // This is a workaround due to inability to put shared PathDiagnosticPiece
2032  // into a FoldingSet.
2033  std::set<llvm::FoldingSetNodeID> DeduplicationSet;
2034 
2035  // Add pieces from custom visitors.
2036  for (const PathDiagnosticPieceRef &Note : VisitorNotes->second) {
2037  llvm::FoldingSetNodeID ID;
2038  Note->Profile(ID);
2039  if (!DeduplicationSet.insert(ID).second)
2040  continue;
2041 
2042  if (PDC->shouldAddPathEdges())
2043  addEdgeToPath(Construct.getActivePath(), PrevLoc, Note->getLocation());
2044  updateStackPiecesWithMessage(Note, Construct.CallStack);
2045  Construct.getActivePath().push_front(Note);
2046  }
2047  }
2048 
2049  if (PDC->shouldAddPathEdges()) {
2050  // Add an edge to the start of the function.
2051  // We'll prune it out later, but it helps make diagnostics more uniform.
2052  const StackFrameContext *CalleeLC =
2053  Construct.getLocationContextForActivePath()->getStackFrame();
2054  const Decl *D = CalleeLC->getDecl();
2055  addEdgeToPath(Construct.getActivePath(), PrevLoc,
2056  PathDiagnosticLocation::createBegin(D, SM));
2057  }
2058 
2059 
2060  // Finally, prune the diagnostic path of uninteresting stuff.
2061  if (!Construct.PD->path.empty()) {
2062  if (R->shouldPrunePath() && Opts.ShouldPrunePaths) {
2063  bool stillHasNotes =
2064  removeUnneededCalls(Construct, Construct.getMutablePieces(), R);
2065  assert(stillHasNotes);
2066  (void)stillHasNotes;
2067  }
2068 
2069  // Remove pop-up notes if needed.
2070  if (!Opts.ShouldAddPopUpNotes)
2071  removePopUpNotes(Construct.getMutablePieces());
2072 
2073  // Redirect all call pieces to have valid locations.
2074  adjustCallLocations(Construct.getMutablePieces());
2075  removePiecesWithInvalidLocations(Construct.getMutablePieces());
2076 
2077  if (PDC->shouldAddPathEdges()) {
2078 
2079  // Reduce the number of edges from a very conservative set
2080  // to an aesthetically pleasing subset that conveys the
2081  // necessary information.
2082  OptimizedCallsSet OCS;
2083  while (optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {
2084  }
2085 
2086  // Drop the very first function-entry edge. It's not really necessary
2087  // for top-level functions.
2088  dropFunctionEntryEdge(Construct, Construct.getMutablePieces());
2089  }
2090 
2091  // Remove messages that are basically the same, and edges that may not
2092  // make sense.
2093  // We have to do this after edge optimization in the Extensive mode.
2094  removeRedundantMsgs(Construct.getMutablePieces());
2095  removeEdgesToDefaultInitializers(Construct.getMutablePieces());
2096  }
2097 
2098  if (Opts.ShouldDisplayMacroExpansions)
2099  CompactMacroExpandedPieces(Construct.getMutablePieces(), SM);
2100 
2101  return std::move(Construct.PD);
2102 }
2103 
2104 //===----------------------------------------------------------------------===//
2105 // Methods for BugType and subclasses.
2106 //===----------------------------------------------------------------------===//
2107 
2108 void BugType::anchor() {}
2109 
2110 //===----------------------------------------------------------------------===//
2111 // Methods for BugReport and subclasses.
2112 //===----------------------------------------------------------------------===//
2113 
2114 LLVM_ATTRIBUTE_USED static bool
2115 isDependency(const CheckerRegistryData &Registry, StringRef CheckerName) {
2116  for (const std::pair<StringRef, StringRef> &Pair : Registry.Dependencies) {
2117  if (Pair.second == CheckerName)
2118  return true;
2119  }
2120  return false;
2121 }
2122 
2123 LLVM_ATTRIBUTE_USED static bool isHidden(const CheckerRegistryData &Registry,
2124  StringRef CheckerName) {
2125  for (const CheckerInfo &Checker : Registry.Checkers) {
2126  if (Checker.FullName == CheckerName)
2127  return Checker.IsHidden;
2128  }
2129  llvm_unreachable(
2130  "Checker name not found in CheckerRegistry -- did you retrieve it "
2131  "correctly from CheckerManager::getCurrentCheckerName?");
2132 }
2133 
2135  const BugType &bt, StringRef shortDesc, StringRef desc,
2136  const ExplodedNode *errorNode, PathDiagnosticLocation LocationToUnique,
2137  const Decl *DeclToUnique)
2138  : BugReport(Kind::PathSensitive, bt, shortDesc, desc), ErrorNode(errorNode),
2139  ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() : SourceRange()),
2140  UniqueingLocation(LocationToUnique), UniqueingDecl(DeclToUnique) {
2141  assert(!isDependency(ErrorNode->getState()
2142  ->getAnalysisManager()
2143  .getCheckerManager()
2144  ->getCheckerRegistryData(),
2145  bt.getCheckerName()) &&
2146  "Some checkers depend on this one! We don't allow dependency "
2147  "checkers to emit warnings, because checkers should depend on "
2148  "*modeling*, not *diagnostics*.");
2149 
2150  assert((bt.getCheckerName().starts_with("debug") ||
2152  ->getAnalysisManager()
2153  .getCheckerManager()
2154  ->getCheckerRegistryData(),
2155  bt.getCheckerName())) &&
2156  "Hidden checkers musn't emit diagnostics as they are by definition "
2157  "non-user facing!");
2158 }
2159 
2161  std::unique_ptr<BugReporterVisitor> visitor) {
2162  if (!visitor)
2163  return;
2164 
2165  llvm::FoldingSetNodeID ID;
2166  visitor->Profile(ID);
2167 
2168  void *InsertPos = nullptr;
2169  if (CallbacksSet.FindNodeOrInsertPos(ID, InsertPos)) {
2170  return;
2171  }
2172 
2173  Callbacks.push_back(std::move(visitor));
2174 }
2175 
2177  Callbacks.clear();
2178 }
2179 
2181  const ExplodedNode *N = getErrorNode();
2182  if (!N)
2183  return nullptr;
2184 
2185  const LocationContext *LC = N->getLocationContext();
2186  return LC->getStackFrame()->getDecl();
2187 }
2188 
2189 void BasicBugReport::Profile(llvm::FoldingSetNodeID& hash) const {
2190  hash.AddInteger(static_cast<int>(getKind()));
2191  hash.AddPointer(&BT);
2192  hash.AddString(Description);
2193  assert(Location.isValid());
2194  Location.Profile(hash);
2195 
2196  for (SourceRange range : Ranges) {
2197  if (!range.isValid())
2198  continue;
2199  hash.Add(range.getBegin());
2200  hash.Add(range.getEnd());
2201  }
2202 }
2203 
2204 void PathSensitiveBugReport::Profile(llvm::FoldingSetNodeID &hash) const {
2205  hash.AddInteger(static_cast<int>(getKind()));
2206  hash.AddPointer(&BT);
2207  hash.AddString(Description);
2209  if (UL.isValid()) {
2210  UL.Profile(hash);
2211  } else {
2212  // TODO: The statement may be null if the report was emitted before any
2213  // statements were executed. In particular, some checkers by design
2214  // occasionally emit their reports in empty functions (that have no
2215  // statements in their body). Do we profile correctly in this case?
2217  }
2218 
2219  for (SourceRange range : Ranges) {
2220  if (!range.isValid())
2221  continue;
2222  hash.Add(range.getBegin());
2223  hash.Add(range.getEnd());
2224  }
2225 }
2226 
2227 template <class T>
2229  llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap, T Val,
2230  bugreporter::TrackingKind TKind) {
2231  auto Result = InterestingnessMap.insert({Val, TKind});
2232 
2233  if (Result.second)
2234  return;
2235 
2236  // Even if this symbol/region was already marked as interesting as a
2237  // condition, if we later mark it as interesting again but with
2238  // thorough tracking, overwrite it. Entities marked with thorough
2239  // interestiness are the most important (or most interesting, if you will),
2240  // and we wouldn't like to downplay their importance.
2241 
2242  switch (TKind) {
2244  Result.first->getSecond() = bugreporter::TrackingKind::Thorough;
2245  return;
2247  return;
2248  }
2249 
2250  llvm_unreachable(
2251  "BugReport::markInteresting currently can only handle 2 different "
2252  "tracking kinds! Please define what tracking kind should this entitiy"
2253  "have, if it was already marked as interesting with a different kind!");
2254 }
2255 
2257  bugreporter::TrackingKind TKind) {
2258  if (!sym)
2259  return;
2260 
2262 
2263  // FIXME: No tests exist for this code and it is questionable:
2264  // How to handle multiple metadata for the same region?
2265  if (const auto *meta = dyn_cast<SymbolMetadata>(sym))
2266  markInteresting(meta->getRegion(), TKind);
2267 }
2268 
2270  if (!sym)
2271  return;
2272  InterestingSymbols.erase(sym);
2273 
2274  // The metadata part of markInteresting is not reversed here.
2275  // Just making the same region not interesting is incorrect
2276  // in specific cases.
2277  if (const auto *meta = dyn_cast<SymbolMetadata>(sym))
2278  markNotInteresting(meta->getRegion());
2279 }
2280 
2282  bugreporter::TrackingKind TKind) {
2283  if (!R)
2284  return;
2285 
2286  R = R->getBaseRegion();
2288 
2289  if (const auto *SR = dyn_cast<SymbolicRegion>(R))
2290  markInteresting(SR->getSymbol(), TKind);
2291 }
2292 
2294  if (!R)
2295  return;
2296 
2297  R = R->getBaseRegion();
2298  InterestingRegions.erase(R);
2299 
2300  if (const auto *SR = dyn_cast<SymbolicRegion>(R))
2301  markNotInteresting(SR->getSymbol());
2302 }
2303 
2305  bugreporter::TrackingKind TKind) {
2306  markInteresting(V.getAsRegion(), TKind);
2307  markInteresting(V.getAsSymbol(), TKind);
2308 }
2309 
2311  if (!LC)
2312  return;
2313  InterestingLocationContexts.insert(LC);
2314 }
2315 
2316 std::optional<bugreporter::TrackingKind>
2318  auto RKind = getInterestingnessKind(V.getAsRegion());
2319  auto SKind = getInterestingnessKind(V.getAsSymbol());
2320  if (!RKind)
2321  return SKind;
2322  if (!SKind)
2323  return RKind;
2324 
2325  // If either is marked with throrough tracking, return that, we wouldn't like
2326  // to downplay a note's importance by 'only' mentioning it as a condition.
2327  switch(*RKind) {
2329  return RKind;
2331  return SKind;
2332  }
2333 
2334  llvm_unreachable(
2335  "BugReport::getInterestingnessKind currently can only handle 2 different "
2336  "tracking kinds! Please define what tracking kind should we return here "
2337  "when the kind of getAsRegion() and getAsSymbol() is different!");
2338  return std::nullopt;
2339 }
2340 
2341 std::optional<bugreporter::TrackingKind>
2343  if (!sym)
2344  return std::nullopt;
2345  // We don't currently consider metadata symbols to be interesting
2346  // even if we know their region is interesting. Is that correct behavior?
2347  auto It = InterestingSymbols.find(sym);
2348  if (It == InterestingSymbols.end())
2349  return std::nullopt;
2350  return It->getSecond();
2351 }
2352 
2353 std::optional<bugreporter::TrackingKind>
2355  if (!R)
2356  return std::nullopt;
2357 
2358  R = R->getBaseRegion();
2359  auto It = InterestingRegions.find(R);
2360  if (It != InterestingRegions.end())
2361  return It->getSecond();
2362 
2363  if (const auto *SR = dyn_cast<SymbolicRegion>(R))
2364  return getInterestingnessKind(SR->getSymbol());
2365  return std::nullopt;
2366 }
2367 
2369  return getInterestingnessKind(V).has_value();
2370 }
2371 
2373  return getInterestingnessKind(sym).has_value();
2374 }
2375 
2377  return getInterestingnessKind(R).has_value();
2378 }
2379 
2381  if (!LC)
2382  return false;
2383  return InterestingLocationContexts.count(LC);
2384 }
2385 
2387  if (!ErrorNode)
2388  return nullptr;
2389 
2390  ProgramPoint ProgP = ErrorNode->getLocation();
2391  const Stmt *S = nullptr;
2392 
2393  if (std::optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
2394  CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
2395  if (BE->getBlock() == &Exit)
2397  }
2398  if (!S)
2400 
2401  return S;
2402 }
2403 
2406  // If no custom ranges, add the range of the statement corresponding to
2407  // the error node.
2408  if (Ranges.empty() && isa_and_nonnull<Expr>(getStmt()))
2409  return ErrorNodeRange;
2410 
2411  return Ranges;
2412 }
2413 
2416  assert(ErrorNode && "Cannot create a location with a null node.");
2417  const Stmt *S = ErrorNode->getStmtForDiagnostics();
2419  const LocationContext *LC = P.getLocationContext();
2420  SourceManager &SM =
2421  ErrorNode->getState()->getStateManager().getContext().getSourceManager();
2422 
2423  if (!S) {
2424  // If this is an implicit call, return the implicit call point location.
2425  if (std::optional<PreImplicitCall> PIE = P.getAs<PreImplicitCall>())
2426  return PathDiagnosticLocation(PIE->getLocation(), SM);
2427  if (auto FE = P.getAs<FunctionExitPoint>()) {
2428  if (const ReturnStmt *RS = FE->getStmt())
2429  return PathDiagnosticLocation::createBegin(RS, SM, LC);
2430  }
2432  }
2433 
2434  if (S) {
2435  // Attributed statements usually have corrupted begin locations,
2436  // it's OK to ignore attributes for our purposes and deal with
2437  // the actual annotated statement.
2438  if (const auto *AS = dyn_cast<AttributedStmt>(S))
2439  S = AS->getSubStmt();
2440 
2441  // For member expressions, return the location of the '.' or '->'.
2442  if (const auto *ME = dyn_cast<MemberExpr>(S))
2444 
2445  // For binary operators, return the location of the operator.
2446  if (const auto *B = dyn_cast<BinaryOperator>(S))
2448 
2449  if (P.getAs<PostStmtPurgeDeadSymbols>())
2450  return PathDiagnosticLocation::createEnd(S, SM, LC);
2451 
2452  if (S->getBeginLoc().isValid())
2453  return PathDiagnosticLocation(S, SM, LC);
2454 
2455  return PathDiagnosticLocation(
2457  }
2458 
2460  SM);
2461 }
2462 
2463 //===----------------------------------------------------------------------===//
2464 // Methods for BugReporter and subclasses.
2465 //===----------------------------------------------------------------------===//
2466 
2468  return Eng.getGraph();
2469 }
2470 
2472  return Eng.getStateManager();
2473 }
2474 
2476  : D(D), UserSuppressions(D.getASTContext()) {}
2477 
2479  // Make sure reports are flushed.
2480  assert(StrBugTypes.empty() &&
2481  "Destroying BugReporter before diagnostics are emitted!");
2482 
2483  // Free the bug reports we are tracking.
2484  for (const auto I : EQClassesVector)
2485  delete I;
2486 }
2487 
2489  // We need to flush reports in deterministic order to ensure the order
2490  // of the reports is consistent between runs.
2491  for (const auto EQ : EQClassesVector)
2492  FlushReport(*EQ);
2493 
2494  // BugReporter owns and deletes only BugTypes created implicitly through
2495  // EmitBasicReport.
2496  // FIXME: There are leaks from checkers that assume that the BugTypes they
2497  // create will be destroyed by the BugReporter.
2498  StrBugTypes.clear();
2499 }
2500 
2501 //===----------------------------------------------------------------------===//
2502 // PathDiagnostics generation.
2503 //===----------------------------------------------------------------------===//
2504 
2505 namespace {
2506 
2507 /// A wrapper around an ExplodedGraph that contains a single path from the root
2508 /// to the error node.
2509 class BugPathInfo {
2510 public:
2511  std::unique_ptr<ExplodedGraph> BugPath;
2512  PathSensitiveBugReport *Report;
2513  const ExplodedNode *ErrorNode;
2514 };
2515 
2516 /// A wrapper around an ExplodedGraph whose leafs are all error nodes. Can
2517 /// conveniently retrieve bug paths from a single error node to the root.
2518 class BugPathGetter {
2519  std::unique_ptr<ExplodedGraph> TrimmedGraph;
2520 
2521  using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
2522 
2523  /// Assign each node with its distance from the root.
2524  PriorityMapTy PriorityMap;
2525 
2526  /// Since the getErrorNode() or BugReport refers to the original ExplodedGraph,
2527  /// we need to pair it to the error node of the constructed trimmed graph.
2528  using ReportNewNodePair =
2529  std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
2531 
2532  BugPathInfo CurrentBugPath;
2533 
2534  /// A helper class for sorting ExplodedNodes by priority.
2535  template <bool Descending>
2536  class PriorityCompare {
2537  const PriorityMapTy &PriorityMap;
2538 
2539  public:
2540  PriorityCompare(const PriorityMapTy &M) : PriorityMap(M) {}
2541 
2542  bool operator()(const ExplodedNode *LHS, const ExplodedNode *RHS) const {
2543  PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
2544  PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
2545  PriorityMapTy::const_iterator E = PriorityMap.end();
2546 
2547  if (LI == E)
2548  return Descending;
2549  if (RI == E)
2550  return !Descending;
2551 
2552  return Descending ? LI->second > RI->second
2553  : LI->second < RI->second;
2554  }
2555 
2556  bool operator()(const ReportNewNodePair &LHS,
2557  const ReportNewNodePair &RHS) const {
2558  return (*this)(LHS.second, RHS.second);
2559  }
2560  };
2561 
2562 public:
2563  BugPathGetter(const ExplodedGraph *OriginalGraph,
2565 
2566  BugPathInfo *getNextBugPath();
2567 };
2568 
2569 } // namespace
2570 
2571 BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph,
2572  ArrayRef<PathSensitiveBugReport *> &bugReports) {
2574  for (const auto I : bugReports) {
2575  assert(I->isValid() &&
2576  "We only allow BugReporterVisitors and BugReporter itself to "
2577  "invalidate reports!");
2578  Nodes.emplace_back(I->getErrorNode());
2579  }
2580 
2581  // The trimmed graph is created in the body of the constructor to ensure
2582  // that the DenseMaps have been initialized already.
2583  InterExplodedGraphMap ForwardMap;
2584  TrimmedGraph = OriginalGraph->trim(Nodes, &ForwardMap);
2585 
2586  // Find the (first) error node in the trimmed graph. We just need to consult
2587  // the node map which maps from nodes in the original graph to nodes
2588  // in the new graph.
2590 
2591  for (PathSensitiveBugReport *Report : bugReports) {
2592  const ExplodedNode *NewNode = ForwardMap.lookup(Report->getErrorNode());
2593  assert(NewNode &&
2594  "Failed to construct a trimmed graph that contains this error "
2595  "node!");
2596  ReportNodes.emplace_back(Report, NewNode);
2597  RemainingNodes.insert(NewNode);
2598  }
2599 
2600  assert(!RemainingNodes.empty() && "No error node found in the trimmed graph");
2601 
2602  // Perform a forward BFS to find all the shortest paths.
2603  std::queue<const ExplodedNode *> WS;
2604 
2605  assert(TrimmedGraph->num_roots() == 1);
2606  WS.push(*TrimmedGraph->roots_begin());
2607  unsigned Priority = 0;
2608 
2609  while (!WS.empty()) {
2610  const ExplodedNode *Node = WS.front();
2611  WS.pop();
2612 
2613  PriorityMapTy::iterator PriorityEntry;
2614  bool IsNew;
2615  std::tie(PriorityEntry, IsNew) = PriorityMap.insert({Node, Priority});
2616  ++Priority;
2617 
2618  if (!IsNew) {
2619  assert(PriorityEntry->second <= Priority);
2620  continue;
2621  }
2622 
2623  if (RemainingNodes.erase(Node))
2624  if (RemainingNodes.empty())
2625  break;
2626 
2627  for (const ExplodedNode *Succ : Node->succs())
2628  WS.push(Succ);
2629  }
2630 
2631  // Sort the error paths from longest to shortest.
2632  llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
2633 }
2634 
2635 BugPathInfo *BugPathGetter::getNextBugPath() {
2636  if (ReportNodes.empty())
2637  return nullptr;
2638 
2639  const ExplodedNode *OrigN;
2640  std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
2641  assert(PriorityMap.contains(OrigN) && "error node not accessible from root");
2642 
2643  // Create a new graph with a single path. This is the graph that will be
2644  // returned to the caller.
2645  auto GNew = std::make_unique<ExplodedGraph>();
2646 
2647  // Now walk from the error node up the BFS path, always taking the
2648  // predeccessor with the lowest number.
2649  ExplodedNode *Succ = nullptr;
2650  while (true) {
2651  // Create the equivalent node in the new graph with the same state
2652  // and location.
2653  ExplodedNode *NewN = GNew->createUncachedNode(
2654  OrigN->getLocation(), OrigN->getState(),
2655  OrigN->getID(), OrigN->isSink());
2656 
2657  // Link up the new node with the previous node.
2658  if (Succ)
2659  Succ->addPredecessor(NewN, *GNew);
2660  else
2661  CurrentBugPath.ErrorNode = NewN;
2662 
2663  Succ = NewN;
2664 
2665  // Are we at the final node?
2666  if (OrigN->pred_empty()) {
2667  GNew->addRoot(NewN);
2668  break;
2669  }
2670 
2671  // Find the next predeccessor node. We choose the node that is marked
2672  // with the lowest BFS number.
2673  OrigN = *std::min_element(OrigN->pred_begin(), OrigN->pred_end(),
2674  PriorityCompare<false>(PriorityMap));
2675  }
2676 
2677  CurrentBugPath.BugPath = std::move(GNew);
2678 
2679  return &CurrentBugPath;
2680 }
2681 
2682 /// CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic
2683 /// object and collapses PathDiagosticPieces that are expanded by macros.
2685  const SourceManager& SM) {
2686  using MacroStackTy = std::vector<
2687  std::pair<std::shared_ptr<PathDiagnosticMacroPiece>, SourceLocation>>;
2688 
2689  using PiecesTy = std::vector<PathDiagnosticPieceRef>;
2690 
2691  MacroStackTy MacroStack;
2692  PiecesTy Pieces;
2693 
2694  for (PathPieces::const_iterator I = path.begin(), E = path.end();
2695  I != E; ++I) {
2696  const auto &piece = *I;
2697 
2698  // Recursively compact calls.
2699  if (auto *call = dyn_cast<PathDiagnosticCallPiece>(&*piece)) {
2700  CompactMacroExpandedPieces(call->path, SM);
2701  }
2702 
2703  // Get the location of the PathDiagnosticPiece.
2704  const FullSourceLoc Loc = piece->getLocation().asLocation();
2705 
2706  // Determine the instantiation location, which is the location we group
2707  // related PathDiagnosticPieces.
2708  SourceLocation InstantiationLoc = Loc.isMacroID() ?
2709  SM.getExpansionLoc(Loc) :
2710  SourceLocation();
2711 
2712  if (Loc.isFileID()) {
2713  MacroStack.clear();
2714  Pieces.push_back(piece);
2715  continue;
2716  }
2717 
2718  assert(Loc.isMacroID());
2719 
2720  // Is the PathDiagnosticPiece within the same macro group?
2721  if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
2722  MacroStack.back().first->subPieces.push_back(piece);
2723  continue;
2724  }
2725 
2726  // We aren't in the same group. Are we descending into a new macro
2727  // or are part of an old one?
2728  std::shared_ptr<PathDiagnosticMacroPiece> MacroGroup;
2729 
2730  SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ?
2731  SM.getExpansionLoc(Loc) :
2732  SourceLocation();
2733 
2734  // Walk the entire macro stack.
2735  while (!MacroStack.empty()) {
2736  if (InstantiationLoc == MacroStack.back().second) {
2737  MacroGroup = MacroStack.back().first;
2738  break;
2739  }
2740 
2741  if (ParentInstantiationLoc == MacroStack.back().second) {
2742  MacroGroup = MacroStack.back().first;
2743  break;
2744  }
2745 
2746  MacroStack.pop_back();
2747  }
2748 
2749  if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
2750  // Create a new macro group and add it to the stack.
2751  auto NewGroup = std::make_shared<PathDiagnosticMacroPiece>(
2752  PathDiagnosticLocation::createSingleLocation(piece->getLocation()));
2753 
2754  if (MacroGroup)
2755  MacroGroup->subPieces.push_back(NewGroup);
2756  else {
2757  assert(InstantiationLoc.isFileID());
2758  Pieces.push_back(NewGroup);
2759  }
2760 
2761  MacroGroup = NewGroup;
2762  MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
2763  }
2764 
2765  // Finally, add the PathDiagnosticPiece to the group.
2766  MacroGroup->subPieces.push_back(piece);
2767  }
2768 
2769  // Now take the pieces and construct a new PathDiagnostic.
2770  path.clear();
2771 
2772  path.insert(path.end(), Pieces.begin(), Pieces.end());
2773 }
2774 
2775 /// Generate notes from all visitors.
2776 /// Notes associated with @c ErrorNode are generated using
2777 /// @c getEndPath, and the rest are generated with @c VisitNode.
2778 static std::unique_ptr<VisitorsDiagnosticsTy>
2780  const ExplodedNode *ErrorNode,
2781  BugReporterContext &BRC) {
2782  std::unique_ptr<VisitorsDiagnosticsTy> Notes =
2783  std::make_unique<VisitorsDiagnosticsTy>();
2785 
2786  // Run visitors on all nodes starting from the node *before* the last one.
2787  // The last node is reserved for notes generated with @c getEndPath.
2788  const ExplodedNode *NextNode = ErrorNode->getFirstPred();
2789  while (NextNode) {
2790 
2791  // At each iteration, move all visitors from report to visitor list. This is
2792  // important, because the Profile() functions of the visitors make sure that
2793  // a visitor isn't added multiple times for the same node, but it's fine
2794  // to add the a visitor with Profile() for different nodes (e.g. tracking
2795  // a region at different points of the symbolic execution).
2796  for (std::unique_ptr<BugReporterVisitor> &Visitor : R->visitors())
2797  visitors.push_back(std::move(Visitor));
2798 
2799  R->clearVisitors();
2800 
2801  const ExplodedNode *Pred = NextNode->getFirstPred();
2802  if (!Pred) {
2803  PathDiagnosticPieceRef LastPiece;
2804  for (auto &V : visitors) {
2805  V->finalizeVisitor(BRC, ErrorNode, *R);
2806 
2807  if (auto Piece = V->getEndPath(BRC, ErrorNode, *R)) {
2808  assert(!LastPiece &&
2809  "There can only be one final piece in a diagnostic.");
2810  assert(Piece->getKind() == PathDiagnosticPiece::Kind::Event &&
2811  "The final piece must contain a message!");
2812  LastPiece = std::move(Piece);
2813  (*Notes)[ErrorNode].push_back(LastPiece);
2814  }
2815  }
2816  break;
2817  }
2818 
2819  for (auto &V : visitors) {
2820  auto P = V->VisitNode(NextNode, BRC, *R);
2821  if (P)
2822  (*Notes)[NextNode].push_back(std::move(P));
2823  }
2824 
2825  if (!R->isValid())
2826  break;
2827 
2828  NextNode = Pred;
2829  }
2830 
2831  return Notes;
2832 }
2833 
2834 std::optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
2836  PathSensitiveBugReporter &Reporter) {
2837 
2838  BugPathGetter BugGraph(&Reporter.getGraph(), bugReports);
2839 
2840  while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
2841  // Find the BugReport with the original location.
2842  PathSensitiveBugReport *R = BugPath->Report;
2843  assert(R && "No original report found for sliced graph.");
2844  assert(R->isValid() && "Report selected by trimmed graph marked invalid.");
2845  const ExplodedNode *ErrorNode = BugPath->ErrorNode;
2846 
2847  // Register refutation visitors first, if they mark the bug invalid no
2848  // further analysis is required
2850 
2851  // Register additional node visitors.
2854  R->addVisitor<TagVisitor>();
2855 
2856  BugReporterContext BRC(Reporter);
2857 
2858  // Run all visitors on a given graph, once.
2859  std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
2860  generateVisitorsDiagnostics(R, ErrorNode, BRC);
2861 
2862  if (R->isValid()) {
2863  if (Reporter.getAnalyzerOptions().ShouldCrosscheckWithZ3) {
2864  // If crosscheck is enabled, remove all visitors, add the refutation
2865  // visitor and check again
2866  R->clearVisitors();
2868 
2869  // We don't overwrite the notes inserted by other visitors because the
2870  // refutation manager does not add any new note to the path
2871  generateVisitorsDiagnostics(R, BugPath->ErrorNode, BRC);
2872  }
2873 
2874  // Check if the bug is still valid
2875  if (R->isValid())
2876  return PathDiagnosticBuilder(
2877  std::move(BRC), std::move(BugPath->BugPath), BugPath->Report,
2878  BugPath->ErrorNode, std::move(visitorNotes));
2879  }
2880  }
2881 
2882  return {};
2883 }
2884 
2885 std::unique_ptr<DiagnosticForConsumerMapTy>
2888  ArrayRef<PathSensitiveBugReport *> &bugReports) {
2889  assert(!bugReports.empty());
2890 
2891  auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
2892 
2893  std::optional<PathDiagnosticBuilder> PDB =
2894  PathDiagnosticBuilder::findValidReport(bugReports, *this);
2895 
2896  if (PDB) {
2897  for (PathDiagnosticConsumer *PC : consumers) {
2898  if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC)) {
2899  (*Out)[PC] = std::move(PD);
2900  }
2901  }
2902  }
2903 
2904  return Out;
2905 }
2906 
2907 void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
2908  bool ValidSourceLoc = R->getLocation().isValid();
2909  assert(ValidSourceLoc);
2910  // If we mess up in a release build, we'd still prefer to just drop the bug
2911  // instead of trying to go on.
2912  if (!ValidSourceLoc)
2913  return;
2914 
2915  // If the user asked to suppress this report, we should skip it.
2916  if (UserSuppressions.isSuppressed(*R))
2917  return;
2918 
2919  // Compute the bug report's hash to determine its equivalence class.
2920  llvm::FoldingSetNodeID ID;
2921  R->Profile(ID);
2922 
2923  // Lookup the equivance class. If there isn't one, create it.
2924  void *InsertPos;
2925  BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
2926 
2927  if (!EQ) {
2928  EQ = new BugReportEquivClass(std::move(R));
2929  EQClasses.InsertNode(EQ, InsertPos);
2930  EQClassesVector.push_back(EQ);
2931  } else
2932  EQ->AddReport(std::move(R));
2933 }
2934 
2935 void PathSensitiveBugReporter::emitReport(std::unique_ptr<BugReport> R) {
2936  if (auto PR = dyn_cast<PathSensitiveBugReport>(R.get()))
2937  if (const ExplodedNode *E = PR->getErrorNode()) {
2938  // An error node must either be a sink or have a tag, otherwise
2939  // it could get reclaimed before the path diagnostic is created.
2940  assert((E->isSink() || E->getLocation().getTag()) &&
2941  "Error node must either be a sink or have a tag");
2942 
2943  const AnalysisDeclContext *DeclCtx =
2944  E->getLocationContext()->getAnalysisDeclContext();
2945  // The source of autosynthesized body can be handcrafted AST or a model
2946  // file. The locations from handcrafted ASTs have no valid source
2947  // locations and have to be discarded. Locations from model files should
2948  // be preserved for processing and reporting.
2949  if (DeclCtx->isBodyAutosynthesized() &&
2951  return;
2952  }
2953 
2954  BugReporter::emitReport(std::move(R));
2955 }
2956 
2957 //===----------------------------------------------------------------------===//
2958 // Emitting reports in equivalence classes.
2959 //===----------------------------------------------------------------------===//
2960 
2961 namespace {
2962 
2963 struct FRIEC_WLItem {
2964  const ExplodedNode *N;
2966 
2967  FRIEC_WLItem(const ExplodedNode *n)
2968  : N(n), I(N->succ_begin()), E(N->succ_end()) {}
2969 };
2970 
2971 } // namespace
2972 
2973 BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
2975  // If we don't need to suppress any of the nodes because they are
2976  // post-dominated by a sink, simply add all the nodes in the equivalence class
2977  // to 'Nodes'. Any of the reports will serve as a "representative" report.
2978  assert(EQ.getReports().size() > 0);
2979  const BugType& BT = EQ.getReports()[0]->getBugType();
2980  if (!BT.isSuppressOnSink()) {
2981  BugReport *R = EQ.getReports()[0].get();
2982  for (auto &J : EQ.getReports()) {
2983  if (auto *PR = dyn_cast<PathSensitiveBugReport>(J.get())) {
2984  R = PR;
2985  bugReports.push_back(PR);
2986  }
2987  }
2988  return R;
2989  }
2990 
2991  // For bug reports that should be suppressed when all paths are post-dominated
2992  // by a sink node, iterate through the reports in the equivalence class
2993  // until we find one that isn't post-dominated (if one exists). We use a
2994  // DFS traversal of the ExplodedGraph to find a non-sink node. We could write
2995  // this as a recursive function, but we don't want to risk blowing out the
2996  // stack for very long paths.
2997  BugReport *exampleReport = nullptr;
2998 
2999  for (const auto &I: EQ.getReports()) {
3000  auto *R = dyn_cast<PathSensitiveBugReport>(I.get());
3001  if (!R)
3002  continue;
3003 
3004  const ExplodedNode *errorNode = R->getErrorNode();
3005  if (errorNode->isSink()) {
3006  llvm_unreachable(
3007  "BugType::isSuppressSink() should not be 'true' for sink end nodes");
3008  }
3009  // No successors? By definition this nodes isn't post-dominated by a sink.
3010  if (errorNode->succ_empty()) {
3011  bugReports.push_back(R);
3012  if (!exampleReport)
3013  exampleReport = R;
3014  continue;
3015  }
3016 
3017  // See if we are in a no-return CFG block. If so, treat this similarly
3018  // to being post-dominated by a sink. This works better when the analysis
3019  // is incomplete and we have never reached the no-return function call(s)
3020  // that we'd inevitably bump into on this path.
3021  if (const CFGBlock *ErrorB = errorNode->getCFGBlock())
3022  if (ErrorB->isInevitablySinking())
3023  continue;
3024 
3025  // At this point we know that 'N' is not a sink and it has at least one
3026  // successor. Use a DFS worklist to find a non-sink end-of-path node.
3027  using WLItem = FRIEC_WLItem;
3028  using DFSWorkList = SmallVector<WLItem, 10>;
3029 
3030  llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
3031 
3032  DFSWorkList WL;
3033  WL.push_back(errorNode);
3034  Visited[errorNode] = 1;
3035 
3036  while (!WL.empty()) {
3037  WLItem &WI = WL.back();
3038  assert(!WI.N->succ_empty());
3039 
3040  for (; WI.I != WI.E; ++WI.I) {
3041  const ExplodedNode *Succ = *WI.I;
3042  // End-of-path node?
3043  if (Succ->succ_empty()) {
3044  // If we found an end-of-path node that is not a sink.
3045  if (!Succ->isSink()) {
3046  bugReports.push_back(R);
3047  if (!exampleReport)
3048  exampleReport = R;
3049  WL.clear();
3050  break;
3051  }
3052  // Found a sink? Continue on to the next successor.
3053  continue;
3054  }
3055  // Mark the successor as visited. If it hasn't been explored,
3056  // enqueue it to the DFS worklist.
3057  unsigned &mark = Visited[Succ];
3058  if (!mark) {
3059  mark = 1;
3060  WL.push_back(Succ);
3061  break;
3062  }
3063  }
3064 
3065  // The worklist may have been cleared at this point. First
3066  // check if it is empty before checking the last item.
3067  if (!WL.empty() && &WL.back() == &WI)
3068  WL.pop_back();
3069  }
3070  }
3071 
3072  // ExampleReport will be NULL if all the nodes in the equivalence class
3073  // were post-dominated by sinks.
3074  return exampleReport;
3075 }
3076 
3077 void BugReporter::FlushReport(BugReportEquivClass& EQ) {
3078  SmallVector<BugReport*, 10> bugReports;
3079  BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
3080  if (!report)
3081  return;
3082 
3083  // See whether we need to silence the checker/package.
3084  for (const std::string &CheckerOrPackage :
3085  getAnalyzerOptions().SilencedCheckersAndPackages) {
3086  if (report->getBugType().getCheckerName().starts_with(CheckerOrPackage))
3087  return;
3088  }
3089 
3091  std::unique_ptr<DiagnosticForConsumerMapTy> Diagnostics =
3092  generateDiagnosticForConsumerMap(report, Consumers, bugReports);
3093 
3094  for (auto &P : *Diagnostics) {
3095  PathDiagnosticConsumer *Consumer = P.first;
3096  std::unique_ptr<PathDiagnostic> &PD = P.second;
3097 
3098  // If the path is empty, generate a single step path with the location
3099  // of the issue.
3100  if (PD->path.empty()) {
3101  PathDiagnosticLocation L = report->getLocation();
3102  auto piece = std::make_unique<PathDiagnosticEventPiece>(
3103  L, report->getDescription());
3104  for (SourceRange Range : report->getRanges())
3105  piece->addRange(Range);
3106  PD->setEndOfPath(std::move(piece));
3107  }
3108 
3109  PathPieces &Pieces = PD->getMutablePieces();
3110  if (getAnalyzerOptions().ShouldDisplayNotesAsEvents) {
3111  // For path diagnostic consumers that don't support extra notes,
3112  // we may optionally convert those to path notes.
3113  for (const auto &I : llvm::reverse(report->getNotes())) {
3114  PathDiagnosticNotePiece *Piece = I.get();
3115  auto ConvertedPiece = std::make_shared<PathDiagnosticEventPiece>(
3116  Piece->getLocation(), Piece->getString());
3117  for (const auto &R: Piece->getRanges())
3118  ConvertedPiece->addRange(R);
3119 
3120  Pieces.push_front(std::move(ConvertedPiece));
3121  }
3122  } else {
3123  for (const auto &I : llvm::reverse(report->getNotes()))
3124  Pieces.push_front(I);
3125  }
3126 
3127  for (const auto &I : report->getFixits())
3128  Pieces.back()->addFixit(I);
3129 
3131 
3132  // If we are debugging, let's have the entry point as the first note.
3133  if (getAnalyzerOptions().AnalyzerDisplayProgress ||
3134  getAnalyzerOptions().AnalyzerNoteAnalysisEntryPoints) {
3135  const Decl *EntryPoint = getAnalysisEntryPoint();
3136  Pieces.push_front(std::make_shared<PathDiagnosticEventPiece>(
3138  "[debug] analyzing from " +
3140  }
3141  Consumer->HandlePathDiagnostic(std::move(PD));
3142  }
3143 }
3144 
3145 /// Insert all lines participating in the function signature \p Signature
3146 /// into \p ExecutedLines.
3148  const Decl *Signature, const SourceManager &SM,
3149  FilesToLineNumsMap &ExecutedLines) {
3150  SourceRange SignatureSourceRange;
3151  const Stmt* Body = Signature->getBody();
3152  if (const auto FD = dyn_cast<FunctionDecl>(Signature)) {
3153  SignatureSourceRange = FD->getSourceRange();
3154  } else if (const auto OD = dyn_cast<ObjCMethodDecl>(Signature)) {
3155  SignatureSourceRange = OD->getSourceRange();
3156  } else {
3157  return;
3158  }
3159  SourceLocation Start = SignatureSourceRange.getBegin();
3160  SourceLocation End = Body ? Body->getSourceRange().getBegin()
3161  : SignatureSourceRange.getEnd();
3162  if (!Start.isValid() || !End.isValid())
3163  return;
3164  unsigned StartLine = SM.getExpansionLineNumber(Start);
3165  unsigned EndLine = SM.getExpansionLineNumber(End);
3166 
3167  FileID FID = SM.getFileID(SM.getExpansionLoc(Start));
3168  for (unsigned Line = StartLine; Line <= EndLine; Line++)
3169  ExecutedLines[FID].insert(Line);
3170 }
3171 
3173  const Stmt *S, const SourceManager &SM,
3174  FilesToLineNumsMap &ExecutedLines) {
3175  SourceLocation Loc = S->getSourceRange().getBegin();
3176  if (!Loc.isValid())
3177  return;
3178  SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
3179  FileID FID = SM.getFileID(ExpansionLoc);
3180  unsigned LineNo = SM.getExpansionLineNumber(ExpansionLoc);
3181  ExecutedLines[FID].insert(LineNo);
3182 }
3183 
3184 /// \return all executed lines including function signatures on the path
3185 /// starting from \p N.
3186 static std::unique_ptr<FilesToLineNumsMap>
3188  auto ExecutedLines = std::make_unique<FilesToLineNumsMap>();
3189 
3190  while (N) {
3191  if (N->getFirstPred() == nullptr) {
3192  // First node: show signature of the entrance point.
3193  const Decl *D = N->getLocationContext()->getDecl();
3194  populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
3195  } else if (auto CE = N->getLocationAs<CallEnter>()) {
3196  // Inlined function: show signature.
3197  const Decl* D = CE->getCalleeContext()->getDecl();
3198  populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
3199  } else if (const Stmt *S = N->getStmtForDiagnostics()) {
3200  populateExecutedLinesWithStmt(S, SM, *ExecutedLines);
3201 
3202  // Show extra context for some parent kinds.
3203  const Stmt *P = N->getParentMap().getParent(S);
3204 
3205  // The path exploration can die before the node with the associated
3206  // return statement is generated, but we do want to show the whole
3207  // return.
3208  if (const auto *RS = dyn_cast_or_null<ReturnStmt>(P)) {
3209  populateExecutedLinesWithStmt(RS, SM, *ExecutedLines);
3210  P = N->getParentMap().getParent(RS);
3211  }
3212 
3213  if (isa_and_nonnull<SwitchCase, LabelStmt>(P))
3214  populateExecutedLinesWithStmt(P, SM, *ExecutedLines);
3215  }
3216 
3217  N = N->getFirstPred();
3218  }
3219  return ExecutedLines;
3220 }
3221 
3222 std::unique_ptr<DiagnosticForConsumerMapTy>
3224  BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
3225  ArrayRef<BugReport *> bugReports) {
3226  auto *basicReport = cast<BasicBugReport>(exampleReport);
3227  auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
3228  for (auto *Consumer : consumers)
3229  (*Out)[Consumer] =
3230  generateDiagnosticForBasicReport(basicReport, AnalysisEntryPoint);
3231  return Out;
3232 }
3233 
3234 static PathDiagnosticCallPiece *
3236  const SourceManager &SMgr) {
3237  SourceLocation CallLoc = CP->callEnter.asLocation();
3238 
3239  // If the call is within a macro, don't do anything (for now).
3240  if (CallLoc.isMacroID())
3241  return nullptr;
3242 
3243  assert(AnalysisManager::isInCodeFile(CallLoc, SMgr) &&
3244  "The call piece should not be in a header file.");
3245 
3246  // Check if CP represents a path through a function outside of the main file.
3248  return CP;
3249 
3250  const PathPieces &Path = CP->path;
3251  if (Path.empty())
3252  return nullptr;
3253 
3254  // Check if the last piece in the callee path is a call to a function outside
3255  // of the main file.
3256  if (auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get()))
3257  return getFirstStackedCallToHeaderFile(CPInner, SMgr);
3258 
3259  // Otherwise, the last piece is in the main file.
3260  return nullptr;
3261 }
3262 
3264  if (PD.path.empty())
3265  return;
3266 
3267  PathDiagnosticPiece *LastP = PD.path.back().get();
3268  assert(LastP);
3269  const SourceManager &SMgr = LastP->getLocation().getManager();
3270 
3271  // We only need to check if the report ends inside headers, if the last piece
3272  // is a call piece.
3273  if (auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
3274  CP = getFirstStackedCallToHeaderFile(CP, SMgr);
3275  if (CP) {
3276  // Mark the piece.
3278 
3279  // Update the path diagnostic message.
3280  const auto *ND = dyn_cast<NamedDecl>(CP->getCallee());
3281  if (ND) {
3282  SmallString<200> buf;
3283  llvm::raw_svector_ostream os(buf);
3284  os << " (within a call to '" << ND->getDeclName() << "')";
3285  PD.appendToDesc(os.str());
3286  }
3287 
3288  // Reset the report containing declaration and location.
3289  PD.setDeclWithIssue(CP->getCaller());
3290  PD.setLocation(CP->getLocation());
3291 
3292  return;
3293  }
3294  }
3295 }
3296 
3297 
3298 
3299 std::unique_ptr<DiagnosticForConsumerMapTy>
3300 PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
3301  BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
3302  ArrayRef<BugReport *> bugReports) {
3303  std::vector<BasicBugReport *> BasicBugReports;
3304  std::vector<PathSensitiveBugReport *> PathSensitiveBugReports;
3305  if (isa<BasicBugReport>(exampleReport))
3306  return BugReporter::generateDiagnosticForConsumerMap(exampleReport,
3307  consumers, bugReports);
3308 
3309  // Generate the full path sensitive diagnostic, using the generation scheme
3310  // specified by the PathDiagnosticConsumer. Note that we have to generate
3311  // path diagnostics even for consumers which do not support paths, because
3312  // the BugReporterVisitors may mark this bug as a false positive.
3313  assert(!bugReports.empty());
3314  MaxBugClassSize.updateMax(bugReports.size());
3315 
3316  // Avoid copying the whole array because there may be a lot of reports.
3317  ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports(
3318  reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.begin()),
3319  reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.end()));
3320  std::unique_ptr<DiagnosticForConsumerMapTy> Out = generatePathDiagnostics(
3321  consumers, convertedArrayOfReports);
3322 
3323  if (Out->empty())
3324  return Out;
3325 
3326  MaxValidBugClassSize.updateMax(bugReports.size());
3327 
3328  // Examine the report and see if the last piece is in a header. Reset the
3329  // report location to the last piece in the main source file.
3330  const AnalyzerOptions &Opts = getAnalyzerOptions();
3331  for (auto const &P : *Out)
3332  if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.AnalyzeAll)
3334 
3335  return Out;
3336 }
3337 
3338 void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
3339  const CheckerBase *Checker, StringRef Name,
3340  StringRef Category, StringRef Str,
3342  ArrayRef<SourceRange> Ranges,
3343  ArrayRef<FixItHint> Fixits) {
3344  EmitBasicReport(DeclWithIssue, Checker->getCheckerName(), Name, Category, Str,
3345  Loc, Ranges, Fixits);
3346 }
3347 
3348 void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
3349  CheckerNameRef CheckName,
3350  StringRef name, StringRef category,
3351  StringRef str, PathDiagnosticLocation Loc,
3352  ArrayRef<SourceRange> Ranges,
3353  ArrayRef<FixItHint> Fixits) {
3354  // 'BT' is owned by BugReporter.
3355  BugType *BT = getBugTypeForName(CheckName, name, category);
3356  auto R = std::make_unique<BasicBugReport>(*BT, str, Loc);
3357  R->setDeclWithIssue(DeclWithIssue);
3358  for (const auto &SR : Ranges)
3359  R->addRange(SR);
3360  for (const auto &FH : Fixits)
3361  R->addFixItHint(FH);
3362  emitReport(std::move(R));
3363 }
3364 
3365 BugType *BugReporter::getBugTypeForName(CheckerNameRef CheckName,
3366  StringRef name, StringRef category) {
3367  SmallString<136> fullDesc;
3368  llvm::raw_svector_ostream(fullDesc) << CheckName.getName() << ":" << name
3369  << ":" << category;
3370  std::unique_ptr<BugType> &BT = StrBugTypes[fullDesc];
3371  if (!BT)
3372  BT = std::make_unique<BugType>(CheckName, name, category);
3373  return BT.get();
3374 }
#define V(N, I)
Definition: ASTContext.h:3299
NodeId Parent
Definition: ASTDiff.cpp:191
BoundNodesTreeBuilder Nodes
DynTypedNode Node
StringRef P
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static char ID
Definition: Arena.cpp:183
#define SM(sm)
Definition: Cuda.cpp:83
static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C, PathPieces &Path)
Drop the very first edge in a path, which should be a function entry edge.
constexpr llvm::StringLiteral StrLoopRangeEmpty
static PathDiagnosticCallPiece * getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, const SourceManager &SMgr)
static PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC, bool allowNestedContexts=false)
static std::unique_ptr< PathDiagnostic > generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R, const SourceManager &SM, const Decl *AnalysisEntryPoint)
static std::unique_ptr< FilesToLineNumsMap > findExecutedLines(const SourceManager &SM, const ExplodedNode *N)
static bool isConditionForTerminator(const Stmt *S, const Stmt *Cond)
static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD)
Populate executes lines with lines containing at least one diagnostics.
static void removeRedundantMsgs(PathPieces &path)
An optimization pass over PathPieces that removes redundant diagnostics generated by both ConditionBR...
constexpr llvm::StringLiteral StrLoopCollectionEmpty
static std::unique_ptr< VisitorsDiagnosticsTy > generateVisitorsDiagnostics(PathSensitiveBugReport *R, const ExplodedNode *ErrorNode, BugReporterContext &BRC)
Generate notes from all visitors.
static void adjustCallLocations(PathPieces &Pieces, PathDiagnosticLocation *LastCallLocation=nullptr)
Recursively scan through a path and make sure that all call pieces have valid locations.
static void removeIdenticalEvents(PathPieces &path)
static bool removeUnneededCalls(const PathDiagnosticConstruct &C, PathPieces &pieces, const PathSensitiveBugReport *R, bool IsInteresting=false)
Recursively scan through a path and prune out calls and macros pieces that aren't needed.
static const Stmt * getStmtParent(const Stmt *S, const ParentMap &PM)
static void populateExecutedLinesWithStmt(const Stmt *S, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
static bool isJumpToFalseBranch(const BlockEdge *BE)
static bool isLoop(const Stmt *Term)
static bool isContainedByStmt(const ParentMap &PM, const Stmt *S, const Stmt *SubS)
constexpr llvm::StringLiteral StrEnteringLoop
static std::unique_ptr< PathDiagnostic > generateDiagnosticForBasicReport(const BasicBugReport *R, const Decl *AnalysisEntryPoint)
static const Stmt * getTerminatorCondition(const CFGBlock *B)
A customized wrapper for CFGBlock::getTerminatorCondition() which returns the element for ObjCForColl...
static const Stmt * getStmtBeforeCond(const ParentMap &PM, const Stmt *Term, const ExplodedNode *N)
static void addEdgeToPath(PathPieces &path, PathDiagnosticLocation &PrevLoc, PathDiagnosticLocation NewLoc)
Adds a sanitized control-flow diagnostic edge to a path.
static bool isIncrementOrInitInForLoop(const Stmt *S, const Stmt *FL)
static PathDiagnosticEventPiece * eventsDescribeSameCondition(PathDiagnosticEventPiece *X, PathDiagnosticEventPiece *Y)
static void removeContextCycles(PathPieces &Path, const SourceManager &SM)
Eliminate two-edge cycles created by addContextEdges().
static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y)
Return true if X is contained by Y.
static void removePopUpNotes(PathPieces &Path)
Same logic as above to remove extra pieces.
STATISTIC(MaxBugClassSize, "The maximum number of bug reports in the same equivalence class")
static void insertToInterestingnessMap(llvm::DenseMap< T, bugreporter::TrackingKind > &InterestingnessMap, T Val, bugreporter::TrackingKind TKind)
constexpr llvm::StringLiteral StrLoopBodyZero
static void removePunyEdges(PathPieces &path, const SourceManager &SM, const ParentMap &PM)
static const Stmt * getEnclosingParent(const Stmt *S, const ParentMap &PM)
static std::optional< size_t > getLengthOnSingleLine(const SourceManager &SM, SourceRange Range)
Returns the number of bytes in the given (character-based) SourceRange.
static void CompactMacroExpandedPieces(PathPieces &path, const SourceManager &SM)
CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic object and collapses PathDi...
static void simplifySimpleBranches(PathPieces &pieces)
Move edges from a branch condition to a branch target when the condition is simple.
static void populateExecutedLinesWithFunctionSignature(const Decl *Signature, const SourceManager &SM, FilesToLineNumsMap &ExecutedLines)
Insert all lines participating in the function signature Signature into ExecutedLines.
static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD)
static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path, OptimizedCallsSet &OCS)
static bool hasImplicitBody(const Decl *D)
Returns true if the given decl has been implicitly given a body, either by the analyzer or by the com...
static void addContextEdges(PathPieces &pieces, const LocationContext *LC)
Adds synthetic edges from top-level statements to their subexpressions.
static LLVM_ATTRIBUTE_USED bool isDependency(const CheckerRegistryData &Registry, StringRef CheckerName)
static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term)
static void removeEdgesToDefaultInitializers(PathPieces &Pieces)
Remove edges in and out of C++ default initializer expressions.
static void removePiecesWithInvalidLocations(PathPieces &Pieces)
Remove all pieces with invalid locations as these cannot be serialized.
static LLVM_ATTRIBUTE_USED bool isHidden(const CheckerRegistryData &Registry, StringRef CheckerName)
Defines the clang::Expr interface and subclasses for C++ expressions.
int Priority
Definition: Format.cpp:2980
int Category
Definition: Format.cpp:2979
llvm::DenseSet< const void * > Visited
Definition: HTMLLogger.cpp:146
#define X(type, name)
Definition: Value.h:143
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
SourceLocation Loc
Definition: SemaObjC.cpp:755
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the Objective-C statement AST node classes.
SourceLocation End
SourceManager & getSourceManager()
Definition: ASTContext.h:708
AnalysisDeclContext contains the context data for the function, method or block under analysis.
static std::string getFunctionName(const Decl *D)
Stores options for the analyzer from the command line.
const CFGBlock * getDst() const
Definition: ProgramPoint.h:510
const CFGBlock * getSrc() const
Definition: ProgramPoint.h:506
Represents a single basic block in a source-level CFG.
Definition: CFG.h:604
Stmt * getLabel()
Definition: CFG.h:1100
Stmt * getTerminatorStmt()
Definition: CFG.h:1081
succ_iterator succ_begin()
Definition: CFG.h:984
const Stmt * getLoopTarget() const
Definition: CFG.h:1098
Stmt * getTerminatorCondition(bool StripParens=true)
Definition: CFG.cpp:6295
unsigned succ_size() const
Definition: CFG.h:1002
CFGBlock & getExit()
Definition: CFG.h:1324
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
Definition: StmtCXX.h:135
Represents a point when we begin processing an inlined call.
Definition: ProgramPoint.h:628
Represents a point when we finish the call exit sequence (for inlined call).
Definition: ProgramPoint.h:686
const StackFrameContext * getCalleeContext() const
Definition: ProgramPoint.h:693
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:501
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:599
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:1077
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
Definition: DeclBase.h:1083
SourceLocation getLocation() const
Definition: DeclBase.h:445
This represents one expression.
Definition: Expr.h:110
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx, SmallVectorImpl< PartialDiagnosticAt > *Diag=nullptr) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:3111
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isValid() const
ForStmt - This represents a 'for (init;cond;inc)' stmt.
Definition: Stmt.h:2781
A SourceLocation and its associated SourceManager.
IfStmt - This represents an if/then/else.
Definition: Stmt.h:2138
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
const ParentMap & getParentMap() const
const StackFrameContext * getStackFrame() const
Represents Objective-C's collection statement.
Definition: StmtObjC.h:23
bool isConsumedExpr(Expr *E) const
Definition: ParentMap.cpp:188
Stmt * getParent(Stmt *) const
Definition: ParentMap.cpp:152
Stmt * getParentIgnoreParens(Stmt *) const
Definition: ParentMap.cpp:157
Represents a point after we ran remove dead bindings AFTER processing the given statement.
Definition: ProgramPoint.h:484
Represents a program point just before an implicit call event.
Definition: ProgramPoint.h:579
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
Definition: ProgramPoint.h:147
const LocationContext * getLocationContext() const
Definition: ProgramPoint.h:175
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:3019
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
It represents a stack frame of the call stack (based on CallEvent).
const Stmt * getCallSite() const
Stmt - This represents one statement.
Definition: Stmt.h:84
StmtClass getStmtClass() const
Definition: Stmt.h:1358
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:326
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:338
WhileStmt - This represents a 'while' stmt.
Definition: Stmt.h:2584
static bool isInCodeFile(SourceLocation SL, const SourceManager &SM)
const Decl * getUniqueingDecl() const override
Get the declaration that corresponds to (usually contains) the uniqueing location.
Definition: BugReporter.h:276
PathDiagnosticLocation getUniqueingLocation() const override
Get the location on which the report should be uniqued.
Definition: BugReporter.h:272
void Profile(llvm::FoldingSetNodeID &hash) const override
Reports are uniqued to ensure that we do not emit multiple diagnostics for each bug.
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
Definition: BugReporter.h:268
This class provides an interface through which checkers can create individual bug reports.
Definition: BugReporter.h:119
ArrayRef< std::shared_ptr< PathDiagnosticNotePiece > > getNotes()
Definition: BugReporter.h:211
void addRange(SourceRange R)
Add a range to a bug report.
Definition: BugReporter.h:222
SmallVector< SourceRange, 4 > Ranges
Definition: BugReporter.h:132
virtual ArrayRef< SourceRange > getRanges() const
Get the SourceRanges associated with the report.
Definition: BugReporter.h:229
std::string Description
Definition: BugReporter.h:130
const BugType & getBugType() const
Definition: BugReporter.h:149
llvm::ArrayRef< FixItHint > getFixits() const
Definition: BugReporter.h:244
virtual PathDiagnosticLocation getLocation() const =0
The primary location of the bug report that points at the undesirable behavior in the code.
void addFixItHint(const FixItHint &F)
Add a fix-it hint to the bug report.
Definition: BugReporter.h:240
StringRef getDescription() const
A verbose warning message that is appropriate for displaying next to the source code that introduces ...
Definition: BugReporter.h:157
const BugType & BT
Definition: BugReporter.h:128
StringRef getShortDescription(bool UseFallback=true) const
A short general warning message that is appropriate for displaying in the list of all reported bugs.
Definition: BugReporter.h:163
Kind getKind() const
Definition: BugReporter.h:147
virtual std::unique_ptr< DiagnosticForConsumerMapTy > generateDiagnosticForConsumerMap(BugReport *exampleReport, ArrayRef< PathDiagnosticConsumer * > consumers, ArrayRef< BugReport * > bugReports)
Generate the diagnostics for the given bug report.
void FlushReports()
Generate and flush diagnostics for all bug reports.
BugReporter(BugReporterData &d)
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=std::nullopt, ArrayRef< FixItHint > Fixits=std::nullopt)
ArrayRef< PathDiagnosticConsumer * > getPathDiagnosticConsumers()
Definition: BugReporter.h:611
const SourceManager & getSourceManager()
Definition: BugReporter.h:623
const AnalyzerOptions & getAnalyzerOptions()
Definition: BugReporter.h:625
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
const Decl * getAnalysisEntryPoint() const
Get the top-level entry point for the issue to be reported.
Definition: BugReporter.h:630
bool isSuppressed(const BugReport &)
Return true if the given bug report was explicitly suppressed by the user.
bool isSuppressOnSink() const
isSuppressOnSink - Returns true if bug reports associated with this bug type should be suppressed if ...
Definition: BugType.h:64
StringRef getCategory() const
Definition: BugType.h:49
StringRef getDescription() const
Definition: BugType.h:48
StringRef getCheckerName() const
Definition: BugType.h:50
CheckerNameRef getCheckerName() const
Definition: Checker.cpp:25
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Visitor that tries to report interesting diagnostics from conditions.
static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece)
static const char * getTag()
Return the tag associated with this visitor.
bool isValid() const =delete
std::unique_ptr< ExplodedGraph > trim(ArrayRef< const NodeTy * > Nodes, InterExplodedGraphMap *ForwardMap=nullptr, InterExplodedGraphMap *InverseMap=nullptr) const
Creates a trimmed version of the graph that only contains paths leading to the given nodes.
ExplodedNode * getFirstPred()
const CFGBlock * getCFGBlock() const
const ProgramStateRef & getState() const
const ParentMap & getParentMap() const
const LocationContext * getLocationContext() const
pred_iterator pred_end()
pred_iterator pred_begin()
const Stmt * getStmtForDiagnostics() const
If the node's program point corresponds to a statement, retrieve that statement.
const Stmt * getPreviousStmtForDiagnostics() const
Find the statement that was executed immediately before this node.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
const Stmt * getNextStmtForDiagnostics() const
Find the next statement that was executed on this node's execution path.
SVal getSVal(const Stmt *S) const
Get the value of an arbitrary expression at this node.
const Stmt * getCurrentOrPreviousStmtForDiagnostics() const
Find the statement that was executed at or immediately before this node.
std::optional< T > getLocationAs() const &
const ExplodedNode *const * const_succ_iterator
ExplodedGraph & getGraph()
Definition: ExprEngine.h:256
ProgramStateManager & getStateManager()
Definition: ExprEngine.h:410
The bug visitor will walk all the nodes in a path and collect all the constraints.
Suppress reports that might lead to known false positives.
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:96
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
Definition: MemRegion.cpp:1343
Prints path notes when a message is sent to a nil receiver.
PathDiagnosticLocation getLocation() const override
static std::shared_ptr< PathDiagnosticCallPiece > construct(const CallExitEnd &CE, const SourceManager &SM)
PathDiagnosticLocation callEnterWithin
virtual bool supportsLogicalOpControlFlow() const
void HandlePathDiagnostic(std::unique_ptr< PathDiagnostic > D)
PathDiagnosticLocation getStartLocation() const
void setStartLocation(const PathDiagnosticLocation &L)
PathDiagnosticLocation getEndLocation() const
static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, const SourceManager &SM)
For member expressions, return the location of the '.
void Profile(llvm::FoldingSetNodeID &ID) const
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, const SourceManager &SM)
Create a location for the end of the compound statement.
static SourceLocation getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement=false)
Construct a source location that corresponds to either the beginning or the end of the given statemen...
static PathDiagnosticLocation createEnd(const Stmt *S, const SourceManager &SM, const LocationOrAnalysisDeclContext LAC)
Create a location for the end of the statement.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, const SourceManager &SM)
Constructs a location for the end of the enclosing declaration body.
const SourceManager & getManager() const
static PathDiagnosticLocation createSingleLocation(const PathDiagnosticLocation &PDL)
Convert the given location into a single kind location.
virtual PathDiagnosticLocation getLocation() const =0
const void * getTag() const
Return the opaque tag (if any) on the PathDiagnosticPiece.
ArrayRef< SourceRange > getRanges() const
Return the SourceRanges associated with this PathDiagnosticPiece.
PathDiagnosticLocation getLocation() const override
PathDiagnostic - PathDiagnostic objects represent a single path-sensitive diagnostic.
void setDeclWithIssue(const Decl *D)
void appendToDesc(StringRef S)
void setLocation(PathDiagnosticLocation NewLoc)
const FilesToLineNumsMap & getExecutedLines() const
PathPieces flatten(bool ShouldFlattenMacros) const
llvm::SmallSet< const LocationContext *, 2 > InterestingLocationContexts
A set of location contexts that correspoind to call sites which should be considered "interesting".
Definition: BugReporter.h:323
void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind=bugreporter::TrackingKind::Thorough)
Marks a symbol as interesting.
const Decl * getUniqueingDecl() const override
Get the declaration containing the uniqueing location.
Definition: BugReporter.h:417
PathDiagnosticLocation getUniqueingLocation() const override
Get the location on which the report should be uniqued.
Definition: BugReporter.h:412
VisitorList Callbacks
A set of custom visitors which generate "event" diagnostics at interesting points in the path.
Definition: BugReporter.h:327
PathDiagnosticLocation getLocation() const override
The primary location of the bug report that points at the undesirable behavior in the code.
const Decl * getDeclWithIssue() const override
The smallest declaration that contains the bug location.
bool shouldPrunePath() const
Indicates whether or not any path pruning should take place when generating a PathDiagnostic from thi...
Definition: BugReporter.h:406
ArrayRef< SourceRange > getRanges() const override
Get the SourceRanges associated with the report.
llvm::DenseMap< SymbolRef, bugreporter::TrackingKind > InterestingSymbols
Profile to identify equivalent bug reports for error report coalescing.
Definition: BugReporter.h:311
const ExplodedNode * getErrorNode() const
Definition: BugReporter.h:402
PathSensitiveBugReport(const BugType &bt, StringRef desc, const ExplodedNode *errorNode)
Definition: BugReporter.h:369
const ExplodedNode * ErrorNode
The ExplodedGraph node against which the report was thrown.
Definition: BugReporter.h:298
void Profile(llvm::FoldingSetNodeID &hash) const override
Profile to identify equivalent bug reports for error report coalescing.
void clearVisitors()
Remove all visitors attached to this bug report.
void addVisitor(std::unique_ptr< BugReporterVisitor > visitor)
Add custom or predefined bug report visitors to this report.
bool isValid() const
Returns whether or not this report should be considered valid.
Definition: BugReporter.h:468
std::optional< bugreporter::TrackingKind > getInterestingnessKind(SymbolRef sym) const
void markNotInteresting(SymbolRef sym)
llvm::DenseMap< const MemRegion *, bugreporter::TrackingKind > InterestingRegions
A (stack of) set of regions that are registered with this report as being "interesting",...
Definition: BugReporter.h:319
bool isInteresting(SymbolRef sym) const
const SourceRange ErrorNodeRange
The range that corresponds to ErrorNode's program point.
Definition: BugReporter.h:302
llvm::FoldingSet< BugReporterVisitor > CallbacksSet
Used for ensuring the visitors are only added once.
Definition: BugReporter.h:330
GRBugReporter is used for generating path-sensitive reports.
Definition: BugReporter.h:679
const ExplodedGraph & getGraph() const
getGraph - Get the exploded graph created by the analysis engine for the analyzed method or function.
std::unique_ptr< DiagnosticForConsumerMapTy > generatePathDiagnostics(ArrayRef< PathDiagnosticConsumer * > consumers, ArrayRef< PathSensitiveBugReport * > &bugReports)
bugReports A set of bug reports within a single equivalence class
void emitReport(std::unique_ptr< BugReport > R) override
Add the given report to the set of reports tracked by BugReporter.
ProgramStateManager & getStateManager() const
getStateManager - Return the state manager used by the analysis engine.
A Range represents the closed range [from, to].
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:55
SymbolRef getAsLocSymbol(bool IncludeBaseRegions=false) const
If this SVal is a location and wraps a symbol, return that SymbolRef.
Definition: SVals.cpp:68
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition: SVals.h:86
std::string getMessage(const ExplodedNode *N) override
Search the call expression for the symbol Sym and dispatch the 'getMessageForX()' methods to construc...
virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex)
Produces the message of the following form: 'Msg via Nth parameter'.
Symbolic value.
Definition: SymExpr.h:30
The visitor detects NoteTags and displays the event notes they contain.
static const char * getTag()
Return the tag associated with this visitor.
TrackingKind
Specifies the type of tracking for an expression.
@ Thorough
Default tracking kind – specifies that as much information should be gathered about the tracked expre...
@ Condition
Specifies that a more moderate tracking should be used for the expression value.
llvm::DenseMap< const ExplodedNode *, const ExplodedNode * > InterExplodedGraphMap
std::map< FileID, std::set< unsigned > > FilesToLineNumsMap
File IDs mapped to sets of line numbers.
@ CF
Indicates that the tracked object is a CF object.
std::shared_ptr< PathDiagnosticPiece > PathDiagnosticPieceRef
bool Call(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
Definition: Interp.h:2179
bool EQ(InterpState &S, CodePtr OpPC)
Definition: Interp.h:838
CharSourceRange getSourceRange(const SourceRange &Range)
Returns the token CharSourceRange corresponding to Range.
Definition: FixIt.h:32
RangeSelector range(RangeSelector Begin, RangeSelector End)
DEPRECATED. Use enclose.
Definition: RangeSelector.h:41
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition: Address.h:294
const FunctionProtoType * T
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
Definition: Format.h:5433
Specifies a checker.
llvm::SmallVector< std::pair< StringRef, StringRef >, 0 > Dependencies