Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:26

0001 //===- PathDiagnostic.h - Path-Specific Diagnostic Handling -----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines the PathDiagnostic-related interfaces.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H
0014 #define LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H
0015 
0016 #include "clang/AST/Stmt.h"
0017 #include "clang/Analysis/AnalysisDeclContext.h"
0018 #include "clang/Basic/LLVM.h"
0019 #include "clang/Basic/SourceLocation.h"
0020 #include "llvm/ADT/ArrayRef.h"
0021 #include "llvm/ADT/FoldingSet.h"
0022 #include "llvm/ADT/PointerUnion.h"
0023 #include "llvm/ADT/SmallVector.h"
0024 #include "llvm/ADT/StringRef.h"
0025 #include "llvm/Support/Allocator.h"
0026 #include <cassert>
0027 #include <deque>
0028 #include <iterator>
0029 #include <list>
0030 #include <map>
0031 #include <memory>
0032 #include <optional>
0033 #include <set>
0034 #include <string>
0035 #include <utility>
0036 #include <vector>
0037 
0038 namespace clang {
0039 
0040 class AnalysisDeclContext;
0041 class BinaryOperator;
0042 class CallEnter;
0043 class CallExitEnd;
0044 class ConditionalOperator;
0045 class Decl;
0046 class LocationContext;
0047 class MemberExpr;
0048 class ProgramPoint;
0049 class SourceManager;
0050 
0051 namespace ento {
0052 
0053 //===----------------------------------------------------------------------===//
0054 // High-level interface for handlers of path-sensitive diagnostics.
0055 //===----------------------------------------------------------------------===//
0056 
0057 class PathDiagnostic;
0058 
0059 /// These options tweak the behavior of path diangostic consumers.
0060 /// Most of these options are currently supported by very few consumers.
0061 struct PathDiagnosticConsumerOptions {
0062   /// Run-line of the tool that produced the diagnostic.
0063   /// It can be included with the diagnostic for debugging purposes.
0064   std::string ToolInvocation;
0065 
0066   /// Whether to include additional information about macro expansions
0067   /// with the diagnostics, because otherwise they can be hard to obtain
0068   /// without re-compiling the program under analysis.
0069   bool ShouldDisplayMacroExpansions = false;
0070 
0071   /// Whether to include LLVM statistics of the process in the diagnostic.
0072   /// Useful for profiling the tool on large real-world codebases.
0073   bool ShouldSerializeStats = false;
0074 
0075   /// If the consumer intends to produce multiple output files, should it
0076   /// use a pseudo-random file name or a human-readable file name.
0077   bool ShouldWriteVerboseReportFilename = false;
0078 
0079   /// Whether the consumer should treat consumed diagnostics as hard errors.
0080   /// Useful for breaking your build when issues are found.
0081   bool ShouldDisplayWarningsAsErrors = false;
0082 
0083   /// Whether the consumer should attempt to rewrite the source file
0084   /// with fix-it hints attached to the diagnostics it consumes.
0085   bool ShouldApplyFixIts = false;
0086 
0087   /// Whether the consumer should present the name of the entity that emitted
0088   /// the diagnostic (eg., a checker) so that the user knew how to disable it.
0089   bool ShouldDisplayDiagnosticName = false;
0090 };
0091 
0092 class PathDiagnosticConsumer {
0093 public:
0094   class PDFileEntry : public llvm::FoldingSetNode {
0095   public:
0096     PDFileEntry(llvm::FoldingSetNodeID &NodeID) : NodeID(NodeID) {}
0097 
0098     using ConsumerFiles = std::vector<std::pair<StringRef, StringRef>>;
0099 
0100     /// A vector of <consumer,file> pairs.
0101     ConsumerFiles files;
0102 
0103     /// A precomputed hash tag used for uniquing PDFileEntry objects.
0104     const llvm::FoldingSetNodeID NodeID;
0105 
0106     /// Used for profiling in the FoldingSet.
0107     void Profile(llvm::FoldingSetNodeID &ID) { ID = NodeID; }
0108   };
0109 
0110   class FilesMade {
0111     llvm::BumpPtrAllocator Alloc;
0112     llvm::FoldingSet<PDFileEntry> Set;
0113 
0114   public:
0115     ~FilesMade();
0116 
0117     bool empty() const { return Set.empty(); }
0118 
0119     void addDiagnostic(const PathDiagnostic &PD,
0120                        StringRef ConsumerName,
0121                        StringRef fileName);
0122 
0123     PDFileEntry::ConsumerFiles *getFiles(const PathDiagnostic &PD);
0124   };
0125 
0126 private:
0127   virtual void anchor();
0128 
0129 public:
0130   PathDiagnosticConsumer() = default;
0131   virtual ~PathDiagnosticConsumer();
0132 
0133   void FlushDiagnostics(FilesMade *FilesMade);
0134 
0135   virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
0136                                     FilesMade *filesMade) = 0;
0137 
0138   virtual StringRef getName() const = 0;
0139 
0140   void HandlePathDiagnostic(std::unique_ptr<PathDiagnostic> D);
0141 
0142   enum PathGenerationScheme {
0143     /// Only runs visitors, no output generated.
0144     None,
0145 
0146     /// Used for SARIF and text output.
0147     Minimal,
0148 
0149     /// Used for plist output, used for "arrows" generation.
0150     Extensive,
0151 
0152     /// Used for HTML, shows both "arrows" and control notes.
0153     Everything
0154   };
0155 
0156   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
0157 
0158   bool shouldGenerateDiagnostics() const {
0159     return getGenerationScheme() != None;
0160   }
0161 
0162   bool shouldAddPathEdges() const { return getGenerationScheme() >= Extensive; }
0163   bool shouldAddControlNotes() const {
0164     return getGenerationScheme() == Minimal ||
0165            getGenerationScheme() == Everything;
0166   }
0167 
0168   virtual bool supportsLogicalOpControlFlow() const { return false; }
0169 
0170   /// Return true if the PathDiagnosticConsumer supports individual
0171   /// PathDiagnostics that span multiple files.
0172   virtual bool supportsCrossFileDiagnostics() const { return false; }
0173 
0174 protected:
0175   bool flushed = false;
0176   llvm::FoldingSet<PathDiagnostic> Diags;
0177 };
0178 
0179 //===----------------------------------------------------------------------===//
0180 // Path-sensitive diagnostics.
0181 //===----------------------------------------------------------------------===//
0182 
0183 class PathDiagnosticRange : public SourceRange {
0184 public:
0185   bool isPoint = false;
0186 
0187   PathDiagnosticRange(SourceRange R, bool isP = false)
0188       : SourceRange(R), isPoint(isP) {}
0189   PathDiagnosticRange() = default;
0190 };
0191 
0192 using LocationOrAnalysisDeclContext =
0193     llvm::PointerUnion<const LocationContext *, AnalysisDeclContext *>;
0194 
0195 class PathDiagnosticLocation {
0196 private:
0197   enum Kind { RangeK, SingleLocK, StmtK, DeclK } K = SingleLocK;
0198 
0199   const Stmt *S = nullptr;
0200   const Decl *D = nullptr;
0201   const SourceManager *SM = nullptr;
0202   FullSourceLoc Loc;
0203   PathDiagnosticRange Range;
0204 
0205   PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, Kind kind)
0206       : K(kind), SM(&sm), Loc(genLocation(L)), Range(genRange()) {}
0207 
0208   FullSourceLoc genLocation(
0209       SourceLocation L = SourceLocation(),
0210       LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
0211 
0212   PathDiagnosticRange genRange(
0213       LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext *)nullptr) const;
0214 
0215 public:
0216   /// Create an invalid location.
0217   PathDiagnosticLocation() = default;
0218 
0219   /// Create a location corresponding to the given statement.
0220   PathDiagnosticLocation(const Stmt *s, const SourceManager &sm,
0221                          LocationOrAnalysisDeclContext lac)
0222       : K(s->getBeginLoc().isValid() ? StmtK : SingleLocK),
0223         S(K == StmtK ? s : nullptr), SM(&sm),
0224         Loc(genLocation(SourceLocation(), lac)), Range(genRange(lac)) {
0225     assert(K == SingleLocK || S);
0226     assert(K == SingleLocK || Loc.isValid());
0227     assert(K == SingleLocK || Range.isValid());
0228   }
0229 
0230   /// Create a location corresponding to the given declaration.
0231   PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
0232       : K(DeclK), D(d), SM(&sm), Loc(genLocation()), Range(genRange()) {
0233     assert(D);
0234     assert(Loc.isValid());
0235     assert(Range.isValid());
0236   }
0237 
0238   /// Create a location at an explicit offset in the source.
0239   ///
0240   /// This should only be used if there are no more appropriate constructors.
0241   PathDiagnosticLocation(SourceLocation loc, const SourceManager &sm)
0242       : SM(&sm), Loc(loc, sm), Range(genRange()) {
0243     assert(Loc.isValid());
0244     assert(Range.isValid());
0245   }
0246 
0247   /// Create a location corresponding to the given declaration.
0248   static PathDiagnosticLocation create(const Decl *D,
0249                                        const SourceManager &SM) {
0250     return PathDiagnosticLocation(D, SM);
0251   }
0252 
0253   /// Create a location for the beginning of the declaration.
0254   static PathDiagnosticLocation createBegin(const Decl *D,
0255                                             const SourceManager &SM);
0256 
0257   /// Create a location for the beginning of the declaration.
0258   /// The third argument is ignored, useful for generic treatment
0259   /// of statements and declarations.
0260   static PathDiagnosticLocation
0261   createBegin(const Decl *D, const SourceManager &SM,
0262               const LocationOrAnalysisDeclContext LAC) {
0263     return createBegin(D, SM);
0264   }
0265 
0266   /// Create a location for the beginning of the statement.
0267   static PathDiagnosticLocation createBegin(const Stmt *S,
0268                                             const SourceManager &SM,
0269                                             const LocationOrAnalysisDeclContext LAC);
0270 
0271   /// Create a location for the end of the statement.
0272   ///
0273   /// If the statement is a CompoundStatement, the location will point to the
0274   /// closing brace instead of following it.
0275   static PathDiagnosticLocation createEnd(const Stmt *S,
0276                                           const SourceManager &SM,
0277                                        const LocationOrAnalysisDeclContext LAC);
0278 
0279   /// Create the location for the operator of the binary expression.
0280   /// Assumes the statement has a valid location.
0281   static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
0282                                                   const SourceManager &SM);
0283   static PathDiagnosticLocation createConditionalColonLoc(
0284                                                   const ConditionalOperator *CO,
0285                                                   const SourceManager &SM);
0286 
0287   /// For member expressions, return the location of the '.' or '->'.
0288   /// Assumes the statement has a valid location.
0289   static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
0290                                                 const SourceManager &SM);
0291 
0292   /// Create a location for the beginning of the compound statement.
0293   /// Assumes the statement has a valid location.
0294   static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
0295                                                  const SourceManager &SM);
0296 
0297   /// Create a location for the end of the compound statement.
0298   /// Assumes the statement has a valid location.
0299   static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
0300                                                const SourceManager &SM);
0301 
0302   /// Create a location for the beginning of the enclosing declaration body.
0303   /// Defaults to the beginning of the first statement in the declaration body.
0304   static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
0305                                                 const SourceManager &SM);
0306 
0307   /// Constructs a location for the end of the enclosing declaration body.
0308   /// Defaults to the end of brace.
0309   static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
0310                                                    const SourceManager &SM);
0311 
0312   /// Create a location corresponding to the given valid ProgramPoint.
0313   static PathDiagnosticLocation create(const ProgramPoint &P,
0314                                        const SourceManager &SMng);
0315 
0316   /// Convert the given location into a single kind location.
0317   static PathDiagnosticLocation createSingleLocation(
0318                                              const PathDiagnosticLocation &PDL);
0319 
0320   /// Construct a source location that corresponds to either the beginning
0321   /// or the end of the given statement, or a nearby valid source location
0322   /// if the statement does not have a valid source location of its own.
0323   static SourceLocation
0324   getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC,
0325                          bool UseEndOfStatement = false);
0326 
0327   bool operator==(const PathDiagnosticLocation &X) const {
0328     return K == X.K && Loc == X.Loc && Range == X.Range;
0329   }
0330 
0331   bool operator!=(const PathDiagnosticLocation &X) const {
0332     return !(*this == X);
0333   }
0334 
0335   bool isValid() const {
0336     return SM != nullptr;
0337   }
0338 
0339   FullSourceLoc asLocation() const {
0340     return Loc;
0341   }
0342 
0343   PathDiagnosticRange asRange() const {
0344     return Range;
0345   }
0346 
0347   const Stmt *asStmt() const { assert(isValid()); return S; }
0348   const Stmt *getStmtOrNull() const {
0349     if (!isValid())
0350       return nullptr;
0351     return asStmt();
0352   }
0353 
0354   const Decl *asDecl() const { assert(isValid()); return D; }
0355 
0356   bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
0357 
0358   bool hasValidLocation() const { return asLocation().isValid(); }
0359 
0360   void invalidate() {
0361     *this = PathDiagnosticLocation();
0362   }
0363 
0364   void flatten();
0365 
0366   const SourceManager& getManager() const { assert(isValid()); return *SM; }
0367 
0368   void Profile(llvm::FoldingSetNodeID &ID) const;
0369 
0370   void dump() const;
0371 };
0372 
0373 class PathDiagnosticLocationPair {
0374 private:
0375   PathDiagnosticLocation Start, End;
0376 
0377 public:
0378   PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
0379                              const PathDiagnosticLocation &end)
0380       : Start(start), End(end) {}
0381 
0382   const PathDiagnosticLocation &getStart() const { return Start; }
0383   const PathDiagnosticLocation &getEnd() const { return End; }
0384 
0385   void setStart(const PathDiagnosticLocation &L) { Start = L; }
0386   void setEnd(const PathDiagnosticLocation &L) { End = L; }
0387 
0388   void flatten() {
0389     Start.flatten();
0390     End.flatten();
0391   }
0392 
0393   void Profile(llvm::FoldingSetNodeID &ID) const {
0394     Start.Profile(ID);
0395     End.Profile(ID);
0396   }
0397 };
0398 
0399 //===----------------------------------------------------------------------===//
0400 // Path "pieces" for path-sensitive diagnostics.
0401 //===----------------------------------------------------------------------===//
0402 
0403 class PathDiagnosticPiece: public llvm::FoldingSetNode {
0404 public:
0405   enum Kind { ControlFlow, Event, Macro, Call, Note, PopUp };
0406   enum DisplayHint { Above, Below };
0407 
0408 private:
0409   const std::string str;
0410   const Kind kind;
0411   const DisplayHint Hint;
0412 
0413   /// In the containing bug report, this piece is the last piece from
0414   /// the main source file.
0415   bool LastInMainSourceFile = false;
0416 
0417   /// A constant string that can be used to tag the PathDiagnosticPiece,
0418   /// typically with the identification of the creator.  The actual pointer
0419   /// value is meant to be an identifier; the string itself is useful for
0420   /// debugging.
0421   StringRef Tag;
0422 
0423   std::vector<SourceRange> ranges;
0424   std::vector<FixItHint> fixits;
0425 
0426 protected:
0427   PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
0428   PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
0429 
0430 public:
0431   PathDiagnosticPiece() = delete;
0432   PathDiagnosticPiece(const PathDiagnosticPiece &) = delete;
0433   PathDiagnosticPiece &operator=(const PathDiagnosticPiece &) = delete;
0434   virtual ~PathDiagnosticPiece();
0435 
0436   StringRef getString() const { return str; }
0437 
0438   /// Tag this PathDiagnosticPiece with the given C-string.
0439   void setTag(const char *tag) { Tag = tag; }
0440 
0441   /// Return the opaque tag (if any) on the PathDiagnosticPiece.
0442   const void *getTag() const { return Tag.data(); }
0443 
0444   /// Return the string representation of the tag.  This is useful
0445   /// for debugging.
0446   StringRef getTagStr() const { return Tag; }
0447 
0448   /// getDisplayHint - Return a hint indicating where the diagnostic should
0449   ///  be displayed by the PathDiagnosticConsumer.
0450   DisplayHint getDisplayHint() const { return Hint; }
0451 
0452   virtual PathDiagnosticLocation getLocation() const = 0;
0453   virtual void flattenLocations() = 0;
0454 
0455   Kind getKind() const { return kind; }
0456 
0457   void addRange(SourceRange R) {
0458     if (!R.isValid())
0459       return;
0460     ranges.push_back(R);
0461   }
0462 
0463   void addRange(SourceLocation B, SourceLocation E) {
0464     if (!B.isValid() || !E.isValid())
0465       return;
0466     ranges.push_back(SourceRange(B,E));
0467   }
0468 
0469   void addFixit(FixItHint F) {
0470     fixits.push_back(F);
0471   }
0472 
0473   /// Return the SourceRanges associated with this PathDiagnosticPiece.
0474   ArrayRef<SourceRange> getRanges() const { return ranges; }
0475 
0476   /// Return the fix-it hints associated with this PathDiagnosticPiece.
0477   ArrayRef<FixItHint> getFixits() const { return fixits; }
0478 
0479   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
0480 
0481   void setAsLastInMainSourceFile() {
0482     LastInMainSourceFile = true;
0483   }
0484 
0485   bool isLastInMainSourceFile() const {
0486     return LastInMainSourceFile;
0487   }
0488 
0489   virtual void dump() const = 0;
0490 };
0491 
0492 using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
0493 
0494 class PathPieces : public std::list<PathDiagnosticPieceRef> {
0495   void flattenTo(PathPieces &Primary, PathPieces &Current,
0496                  bool ShouldFlattenMacros) const;
0497 
0498 public:
0499   PathPieces flatten(bool ShouldFlattenMacros) const {
0500     PathPieces Result;
0501     flattenTo(Result, Result, ShouldFlattenMacros);
0502     return Result;
0503   }
0504 
0505   void dump() const;
0506 };
0507 
0508 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
0509 private:
0510   PathDiagnosticLocation Pos;
0511 
0512 public:
0513   PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
0514                           StringRef s,
0515                           PathDiagnosticPiece::Kind k,
0516                           bool addPosRange = true)
0517       : PathDiagnosticPiece(s, k), Pos(pos) {
0518     assert(Pos.isValid() && Pos.hasValidLocation() &&
0519            "PathDiagnosticSpotPiece's must have a valid location.");
0520     if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
0521   }
0522 
0523   PathDiagnosticLocation getLocation() const override { return Pos; }
0524   void flattenLocations() override { Pos.flatten(); }
0525 
0526   void Profile(llvm::FoldingSetNodeID &ID) const override;
0527 
0528   static bool classof(const PathDiagnosticPiece *P) {
0529     return P->getKind() == Event || P->getKind() == Macro ||
0530            P->getKind() == Note || P->getKind() == PopUp;
0531   }
0532 };
0533 
0534 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
0535   std::optional<bool> IsPrunable;
0536 
0537 public:
0538   PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
0539                            StringRef s, bool addPosRange = true)
0540       : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
0541   ~PathDiagnosticEventPiece() override;
0542 
0543   /// Mark the diagnostic piece as being potentially prunable.  This
0544   /// flag may have been previously set, at which point it will not
0545   /// be reset unless one specifies to do so.
0546   void setPrunable(bool isPrunable, bool override = false) {
0547     if (IsPrunable && !override)
0548       return;
0549     IsPrunable = isPrunable;
0550   }
0551 
0552   /// Return true if the diagnostic piece is prunable.
0553   bool isPrunable() const { return IsPrunable.value_or(false); }
0554 
0555   void dump() const override;
0556 
0557   static bool classof(const PathDiagnosticPiece *P) {
0558     return P->getKind() == Event;
0559   }
0560 };
0561 
0562 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
0563   const Decl *Caller;
0564   const Decl *Callee = nullptr;
0565 
0566   // Flag signifying that this diagnostic has only call enter and no matching
0567   // call exit.
0568   bool NoExit;
0569 
0570   // Flag signifying that the callee function is an Objective-C autosynthesized
0571   // property getter or setter.
0572   bool IsCalleeAnAutosynthesizedPropertyAccessor = false;
0573 
0574   // The custom string, which should appear after the call Return Diagnostic.
0575   // TODO: Should we allow multiple diagnostics?
0576   std::string CallStackMessage;
0577 
0578   PathDiagnosticCallPiece(const Decl *callerD,
0579                           const PathDiagnosticLocation &callReturnPos)
0580       : PathDiagnosticPiece(Call), Caller(callerD), NoExit(false),
0581         callReturn(callReturnPos) {}
0582   PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
0583       : PathDiagnosticPiece(Call), Caller(caller), NoExit(true),
0584         path(oldPath) {}
0585 
0586 public:
0587   PathDiagnosticLocation callEnter;
0588   PathDiagnosticLocation callEnterWithin;
0589   PathDiagnosticLocation callReturn;
0590   PathPieces path;
0591 
0592   ~PathDiagnosticCallPiece() override;
0593 
0594   const Decl *getCaller() const { return Caller; }
0595 
0596   const Decl *getCallee() const { return Callee; }
0597   void setCallee(const CallEnter &CE, const SourceManager &SM);
0598 
0599   bool hasCallStackMessage() { return !CallStackMessage.empty(); }
0600   void setCallStackMessage(StringRef st) { CallStackMessage = std::string(st); }
0601 
0602   PathDiagnosticLocation getLocation() const override { return callEnter; }
0603 
0604   std::shared_ptr<PathDiagnosticEventPiece> getCallEnterEvent() const;
0605   std::shared_ptr<PathDiagnosticEventPiece>
0606   getCallEnterWithinCallerEvent() const;
0607   std::shared_ptr<PathDiagnosticEventPiece> getCallExitEvent() const;
0608 
0609   void flattenLocations() override {
0610     callEnter.flatten();
0611     callReturn.flatten();
0612     for (const auto &I : path)
0613       I->flattenLocations();
0614   }
0615 
0616   static std::shared_ptr<PathDiagnosticCallPiece>
0617   construct(const CallExitEnd &CE,
0618             const SourceManager &SM);
0619 
0620   static PathDiagnosticCallPiece *construct(PathPieces &pieces,
0621                                             const Decl *caller);
0622 
0623   void dump() const override;
0624 
0625   void Profile(llvm::FoldingSetNodeID &ID) const override;
0626 
0627   static bool classof(const PathDiagnosticPiece *P) {
0628     return P->getKind() == Call;
0629   }
0630 };
0631 
0632 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
0633   std::vector<PathDiagnosticLocationPair> LPairs;
0634 
0635 public:
0636   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
0637                                  const PathDiagnosticLocation &endPos,
0638                                  StringRef s)
0639       : PathDiagnosticPiece(s, ControlFlow) {
0640     LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
0641   }
0642 
0643   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
0644                                  const PathDiagnosticLocation &endPos)
0645       : PathDiagnosticPiece(ControlFlow) {
0646     LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
0647   }
0648 
0649   ~PathDiagnosticControlFlowPiece() override;
0650 
0651   PathDiagnosticLocation getStartLocation() const {
0652     assert(!LPairs.empty() &&
0653            "PathDiagnosticControlFlowPiece needs at least one location.");
0654     return LPairs[0].getStart();
0655   }
0656 
0657   PathDiagnosticLocation getEndLocation() const {
0658     assert(!LPairs.empty() &&
0659            "PathDiagnosticControlFlowPiece needs at least one location.");
0660     return LPairs[0].getEnd();
0661   }
0662 
0663   void setStartLocation(const PathDiagnosticLocation &L) {
0664     LPairs[0].setStart(L);
0665   }
0666 
0667   void setEndLocation(const PathDiagnosticLocation &L) {
0668     LPairs[0].setEnd(L);
0669   }
0670 
0671   void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
0672 
0673   PathDiagnosticLocation getLocation() const override {
0674     return getStartLocation();
0675   }
0676 
0677   using iterator = std::vector<PathDiagnosticLocationPair>::iterator;
0678 
0679   iterator begin() { return LPairs.begin(); }
0680   iterator end() { return LPairs.end(); }
0681 
0682   void flattenLocations() override {
0683     for (auto &I : *this)
0684       I.flatten();
0685   }
0686 
0687   using const_iterator =
0688       std::vector<PathDiagnosticLocationPair>::const_iterator;
0689 
0690   const_iterator begin() const { return LPairs.begin(); }
0691   const_iterator end() const { return LPairs.end(); }
0692 
0693   static bool classof(const PathDiagnosticPiece *P) {
0694     return P->getKind() == ControlFlow;
0695   }
0696 
0697   void dump() const override;
0698 
0699   void Profile(llvm::FoldingSetNodeID &ID) const override;
0700 };
0701 
0702 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
0703 public:
0704   PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
0705       : PathDiagnosticSpotPiece(pos, "", Macro) {}
0706   ~PathDiagnosticMacroPiece() override;
0707 
0708   PathPieces subPieces;
0709 
0710   void flattenLocations() override {
0711     PathDiagnosticSpotPiece::flattenLocations();
0712     for (const auto &I : subPieces)
0713       I->flattenLocations();
0714   }
0715 
0716   static bool classof(const PathDiagnosticPiece *P) {
0717     return P->getKind() == Macro;
0718   }
0719 
0720   void dump() const override;
0721 
0722   void Profile(llvm::FoldingSetNodeID &ID) const override;
0723 };
0724 
0725 class PathDiagnosticNotePiece: public PathDiagnosticSpotPiece {
0726 public:
0727   PathDiagnosticNotePiece(const PathDiagnosticLocation &Pos, StringRef S,
0728                           bool AddPosRange = true)
0729       : PathDiagnosticSpotPiece(Pos, S, Note, AddPosRange) {}
0730   ~PathDiagnosticNotePiece() override;
0731 
0732   static bool classof(const PathDiagnosticPiece *P) {
0733     return P->getKind() == Note;
0734   }
0735 
0736   void dump() const override;
0737 
0738   void Profile(llvm::FoldingSetNodeID &ID) const override;
0739 };
0740 
0741 class PathDiagnosticPopUpPiece: public PathDiagnosticSpotPiece {
0742 public:
0743   PathDiagnosticPopUpPiece(const PathDiagnosticLocation &Pos, StringRef S,
0744                            bool AddPosRange = true)
0745       : PathDiagnosticSpotPiece(Pos, S, PopUp, AddPosRange) {}
0746   ~PathDiagnosticPopUpPiece() override;
0747 
0748   static bool classof(const PathDiagnosticPiece *P) {
0749     return P->getKind() == PopUp;
0750   }
0751 
0752   void dump() const override;
0753 
0754   void Profile(llvm::FoldingSetNodeID &ID) const override;
0755 };
0756 
0757 /// File IDs mapped to sets of line numbers.
0758 using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
0759 
0760 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
0761 ///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
0762 ///  each which represent the pieces of the path.
0763 class PathDiagnostic : public llvm::FoldingSetNode {
0764   std::string CheckerName;
0765   const Decl *DeclWithIssue;
0766   std::string BugType;
0767   std::string VerboseDesc;
0768   std::string ShortDesc;
0769   std::string Category;
0770   std::deque<std::string> OtherDesc;
0771 
0772   /// Loc The location of the path diagnostic report.
0773   PathDiagnosticLocation Loc;
0774 
0775   PathPieces pathImpl;
0776   SmallVector<PathPieces *, 3> pathStack;
0777 
0778   /// Important bug uniqueing location.
0779   /// The location info is useful to differentiate between bugs.
0780   PathDiagnosticLocation UniqueingLoc;
0781   const Decl *UniqueingDecl;
0782 
0783   /// The top-level entry point from which this issue was discovered.
0784   const Decl *AnalysisEntryPoint = nullptr;
0785 
0786   /// Lines executed in the path.
0787   std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
0788 
0789 public:
0790   PathDiagnostic() = delete;
0791   PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
0792                  StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
0793                  StringRef category, PathDiagnosticLocation LocationToUnique,
0794                  const Decl *DeclToUnique, const Decl *AnalysisEntryPoint,
0795                  std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
0796   ~PathDiagnostic();
0797 
0798   const PathPieces &path;
0799 
0800   /// Return the path currently used by builders for constructing the
0801   /// PathDiagnostic.
0802   PathPieces &getActivePath() {
0803     if (pathStack.empty())
0804       return pathImpl;
0805     return *pathStack.back();
0806   }
0807 
0808   /// Return a mutable version of 'path'.
0809   PathPieces &getMutablePieces() {
0810     return pathImpl;
0811   }
0812 
0813   /// Return the unrolled size of the path.
0814   unsigned full_size();
0815 
0816   void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
0817   void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
0818 
0819   bool isWithinCall() const { return !pathStack.empty(); }
0820 
0821   void setEndOfPath(PathDiagnosticPieceRef EndPiece) {
0822     assert(!Loc.isValid() && "End location already set!");
0823     Loc = EndPiece->getLocation();
0824     assert(Loc.isValid() && "Invalid location for end-of-path piece");
0825     getActivePath().push_back(std::move(EndPiece));
0826   }
0827 
0828   void appendToDesc(StringRef S) {
0829     if (!ShortDesc.empty())
0830       ShortDesc += S;
0831     VerboseDesc += S;
0832   }
0833 
0834   StringRef getVerboseDescription() const { return VerboseDesc; }
0835 
0836   StringRef getShortDescription() const {
0837     return ShortDesc.empty() ? VerboseDesc : ShortDesc;
0838   }
0839 
0840   StringRef getCheckerName() const { return CheckerName; }
0841   StringRef getBugType() const { return BugType; }
0842   StringRef getCategory() const { return Category; }
0843 
0844   using meta_iterator = std::deque<std::string>::const_iterator;
0845 
0846   meta_iterator meta_begin() const { return OtherDesc.begin(); }
0847   meta_iterator meta_end() const { return OtherDesc.end(); }
0848   void addMeta(StringRef s) { OtherDesc.push_back(std::string(s)); }
0849 
0850   const FilesToLineNumsMap &getExecutedLines() const {
0851     return *ExecutedLines;
0852   }
0853 
0854   FilesToLineNumsMap &getExecutedLines() {
0855     return *ExecutedLines;
0856   }
0857 
0858   /// Get the top-level entry point from which this issue was discovered.
0859   const Decl *getAnalysisEntryPoint() const { return AnalysisEntryPoint; }
0860 
0861   /// Return the semantic context where an issue occurred.  If the
0862   /// issue occurs along a path, this represents the "central" area
0863   /// where the bug manifests.
0864   const Decl *getDeclWithIssue() const { return DeclWithIssue; }
0865 
0866   void setDeclWithIssue(const Decl *D) {
0867     DeclWithIssue = D;
0868   }
0869 
0870   PathDiagnosticLocation getLocation() const {
0871     return Loc;
0872   }
0873 
0874   void setLocation(PathDiagnosticLocation NewLoc) {
0875     Loc = NewLoc;
0876   }
0877 
0878   /// Get the location on which the report should be uniqued.
0879   PathDiagnosticLocation getUniqueingLoc() const {
0880     return UniqueingLoc;
0881   }
0882 
0883   /// Get the declaration containing the uniqueing location.
0884   const Decl *getUniqueingDecl() const {
0885     return UniqueingDecl;
0886   }
0887 
0888   void flattenLocations() {
0889     Loc.flatten();
0890     for (const auto &I : pathImpl)
0891       I->flattenLocations();
0892   }
0893 
0894   /// Profiles the diagnostic, independent of the path it references.
0895   ///
0896   /// This can be used to merge diagnostics that refer to the same issue
0897   /// along different paths.
0898   void Profile(llvm::FoldingSetNodeID &ID) const;
0899 
0900   /// Profiles the diagnostic, including its path.
0901   ///
0902   /// Two diagnostics with the same issue along different paths will generate
0903   /// different profiles.
0904   void FullProfile(llvm::FoldingSetNodeID &ID) const;
0905 };
0906 
0907 } // namespace ento
0908 } // namespace clang
0909 
0910 #endif // LLVM_CLANG_ANALYSIS_PATHDIAGNOSTIC_H