File indexing completed on 2026-05-10 08:37:07
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
0015 #define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
0016
0017 #include "clang/Analysis/PathDiagnostic.h"
0018 #include "clang/Basic/LLVM.h"
0019 #include "clang/Basic/SourceLocation.h"
0020 #include "clang/Lex/Preprocessor.h"
0021 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
0022 #include "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h"
0023 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
0024 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
0025 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
0026 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
0027 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
0028 #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
0029 #include "llvm/ADT/ArrayRef.h"
0030 #include "llvm/ADT/FoldingSet.h"
0031 #include "llvm/ADT/ImmutableSet.h"
0032 #include "llvm/ADT/SmallSet.h"
0033 #include "llvm/ADT/SmallVector.h"
0034 #include "llvm/ADT/StringMap.h"
0035 #include "llvm/ADT/StringRef.h"
0036 #include "llvm/ADT/ilist.h"
0037 #include "llvm/ADT/ilist_node.h"
0038 #include "llvm/ADT/iterator_range.h"
0039 #include <cassert>
0040 #include <memory>
0041 #include <optional>
0042 #include <string>
0043 #include <utility>
0044 #include <vector>
0045
0046 namespace clang {
0047
0048 class AnalyzerOptions;
0049 class ASTContext;
0050 class Decl;
0051 class LocationContext;
0052 class SourceManager;
0053 class Stmt;
0054
0055 namespace ento {
0056
0057 class BugType;
0058 class CheckerBase;
0059 class ExplodedGraph;
0060 class ExplodedNode;
0061 class ExprEngine;
0062 class MemRegion;
0063
0064
0065
0066
0067
0068
0069
0070 using DiagnosticForConsumerMapTy =
0071 llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>;
0072
0073
0074
0075
0076
0077 class StackHintGenerator {
0078 public:
0079 virtual ~StackHintGenerator() = 0;
0080
0081
0082 virtual std::string getMessage(const ExplodedNode *N) = 0;
0083 };
0084
0085
0086
0087
0088
0089
0090
0091 class StackHintGeneratorForSymbol : public StackHintGenerator {
0092 private:
0093 SymbolRef Sym;
0094 std::string Msg;
0095
0096 public:
0097 StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
0098 ~StackHintGeneratorForSymbol() override = default;
0099
0100
0101
0102 std::string getMessage(const ExplodedNode *N) override;
0103
0104
0105
0106 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
0107
0108 virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
0109 return Msg;
0110 }
0111
0112 virtual std::string getMessageForSymbolNotFound() {
0113 return Msg;
0114 }
0115 };
0116
0117
0118
0119 class BugReport {
0120 public:
0121 enum class Kind { Basic, PathSensitive };
0122
0123 protected:
0124 friend class BugReportEquivClass;
0125 friend class BugReporter;
0126
0127 Kind K;
0128 const BugType& BT;
0129 std::string ShortDescription;
0130 std::string Description;
0131
0132 SmallVector<SourceRange, 4> Ranges;
0133 SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> Notes;
0134 SmallVector<FixItHint, 4> Fixits;
0135
0136 BugReport(Kind kind, const BugType &bt, StringRef desc)
0137 : BugReport(kind, bt, "", desc) {}
0138
0139 BugReport(Kind K, const BugType &BT, StringRef ShortDescription,
0140 StringRef Description)
0141 : K(K), BT(BT), ShortDescription(ShortDescription),
0142 Description(Description) {}
0143
0144 public:
0145 virtual ~BugReport() = default;
0146
0147 Kind getKind() const { return K; }
0148
0149 const BugType& getBugType() const { return BT; }
0150
0151
0152
0153
0154
0155
0156
0157 StringRef getDescription() const { return Description; }
0158
0159
0160
0161
0162
0163 StringRef getShortDescription(bool UseFallback = true) const {
0164 if (ShortDescription.empty() && UseFallback)
0165 return Description;
0166 return ShortDescription;
0167 }
0168
0169
0170
0171
0172
0173 virtual PathDiagnosticLocation getLocation() const = 0;
0174
0175
0176
0177
0178 virtual const Decl *getDeclWithIssue() const = 0;
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189 virtual PathDiagnosticLocation getUniqueingLocation() const = 0;
0190
0191
0192
0193
0194
0195 virtual const Decl *getUniqueingDecl() const = 0;
0196
0197
0198
0199
0200
0201 void addNote(StringRef Msg, const PathDiagnosticLocation &Pos,
0202 ArrayRef<SourceRange> Ranges = {}) {
0203 auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg);
0204
0205 for (const auto &R : Ranges)
0206 P->addRange(R);
0207
0208 Notes.push_back(std::move(P));
0209 }
0210
0211 ArrayRef<std::shared_ptr<PathDiagnosticNotePiece>> getNotes() {
0212 return Notes;
0213 }
0214
0215
0216
0217
0218
0219
0220
0221
0222 void addRange(SourceRange R) {
0223 assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
0224 "to specify that the report does not have a range.");
0225 Ranges.push_back(R);
0226 }
0227
0228
0229 virtual ArrayRef<SourceRange> getRanges() const {
0230 return Ranges;
0231 }
0232
0233
0234
0235
0236
0237
0238
0239
0240 void addFixItHint(const FixItHint &F) {
0241 Fixits.push_back(F);
0242 }
0243
0244 llvm::ArrayRef<FixItHint> getFixits() const { return Fixits; }
0245
0246
0247
0248 virtual void Profile(llvm::FoldingSetNodeID& hash) const = 0;
0249 };
0250
0251 class BasicBugReport : public BugReport {
0252 PathDiagnosticLocation Location;
0253 const Decl *DeclWithIssue = nullptr;
0254
0255 public:
0256 BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l)
0257 : BugReport(Kind::Basic, bt, desc), Location(l) {}
0258
0259 static bool classof(const BugReport *R) {
0260 return R->getKind() == Kind::Basic;
0261 }
0262
0263 PathDiagnosticLocation getLocation() const override {
0264 assert(Location.isValid());
0265 return Location;
0266 }
0267
0268 const Decl *getDeclWithIssue() const override {
0269 return DeclWithIssue;
0270 }
0271
0272 PathDiagnosticLocation getUniqueingLocation() const override {
0273 return getLocation();
0274 }
0275
0276 const Decl *getUniqueingDecl() const override {
0277 return getDeclWithIssue();
0278 }
0279
0280
0281
0282 void setDeclWithIssue(const Decl *declWithIssue) {
0283 DeclWithIssue = declWithIssue;
0284 }
0285
0286 void Profile(llvm::FoldingSetNodeID& hash) const override;
0287 };
0288
0289 class PathSensitiveBugReport : public BugReport {
0290 public:
0291 using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>;
0292 using visitor_iterator = VisitorList::iterator;
0293 using visitor_range = llvm::iterator_range<visitor_iterator>;
0294
0295 protected:
0296
0297
0298 const ExplodedNode *ErrorNode = nullptr;
0299
0300
0301
0302 const SourceRange ErrorNodeRange;
0303
0304
0305
0306
0307
0308
0309
0310
0311 llvm::DenseMap<SymbolRef, bugreporter::TrackingKind> InterestingSymbols;
0312
0313
0314
0315
0316
0317
0318 llvm::DenseMap<const MemRegion *, bugreporter::TrackingKind>
0319 InterestingRegions;
0320
0321
0322
0323 llvm::SmallSet<const LocationContext *, 2> InterestingLocationContexts;
0324
0325
0326
0327 VisitorList Callbacks;
0328
0329
0330 llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
0331
0332
0333
0334
0335 bool DoNotPrunePath = false;
0336
0337
0338
0339
0340
0341 using InvalidationRecord = std::pair<const void *, const void *>;
0342
0343
0344
0345
0346
0347
0348 llvm::SmallSet<InvalidationRecord, 4> Invalidations;
0349
0350
0351 llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions;
0352
0353
0354
0355 PathDiagnosticLocation UniqueingLocation;
0356 const Decl *UniqueingDecl;
0357
0358 const Stmt *getStmt() const;
0359
0360
0361
0362
0363
0364
0365 std::map<PathDiagnosticPieceRef, std::unique_ptr<StackHintGenerator>>
0366 StackHints;
0367
0368 public:
0369 PathSensitiveBugReport(const BugType &bt, StringRef desc,
0370 const ExplodedNode *errorNode)
0371 : PathSensitiveBugReport(bt, desc, desc, errorNode) {}
0372
0373 PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc,
0374 const ExplodedNode *errorNode)
0375 : PathSensitiveBugReport(bt, shortDesc, desc, errorNode,
0376 {},
0377 nullptr) {}
0378
0379
0380
0381
0382
0383
0384
0385
0386 PathSensitiveBugReport(const BugType &bt, StringRef desc,
0387 const ExplodedNode *errorNode,
0388 PathDiagnosticLocation LocationToUnique,
0389 const Decl *DeclToUnique)
0390 : PathSensitiveBugReport(bt, desc, desc, errorNode, LocationToUnique,
0391 DeclToUnique) {}
0392
0393 PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc,
0394 const ExplodedNode *errorNode,
0395 PathDiagnosticLocation LocationToUnique,
0396 const Decl *DeclToUnique);
0397
0398 static bool classof(const BugReport *R) {
0399 return R->getKind() == Kind::PathSensitive;
0400 }
0401
0402 const ExplodedNode *getErrorNode() const { return ErrorNode; }
0403
0404
0405
0406 bool shouldPrunePath() const { return !DoNotPrunePath; }
0407
0408
0409 void disablePathPruning() { DoNotPrunePath = true; }
0410
0411
0412 PathDiagnosticLocation getUniqueingLocation() const override {
0413 return UniqueingLocation;
0414 }
0415
0416
0417 const Decl *getUniqueingDecl() const override {
0418 return UniqueingDecl;
0419 }
0420
0421 const Decl *getDeclWithIssue() const override;
0422
0423 ArrayRef<SourceRange> getRanges() const override;
0424
0425 PathDiagnosticLocation getLocation() const override;
0426
0427
0428
0429
0430 void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind =
0431 bugreporter::TrackingKind::Thorough);
0432
0433 void markNotInteresting(SymbolRef sym);
0434
0435
0436
0437
0438 void markInteresting(
0439 const MemRegion *R,
0440 bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough);
0441
0442 void markNotInteresting(const MemRegion *R);
0443
0444
0445
0446
0447 void markInteresting(SVal V, bugreporter::TrackingKind TKind =
0448 bugreporter::TrackingKind::Thorough);
0449 void markInteresting(const LocationContext *LC);
0450
0451 bool isInteresting(SymbolRef sym) const;
0452 bool isInteresting(const MemRegion *R) const;
0453 bool isInteresting(SVal V) const;
0454 bool isInteresting(const LocationContext *LC) const;
0455
0456 std::optional<bugreporter::TrackingKind>
0457 getInterestingnessKind(SymbolRef sym) const;
0458
0459 std::optional<bugreporter::TrackingKind>
0460 getInterestingnessKind(const MemRegion *R) const;
0461
0462 std::optional<bugreporter::TrackingKind> getInterestingnessKind(SVal V) const;
0463
0464
0465
0466
0467
0468 bool isValid() const {
0469 return Invalidations.empty();
0470 }
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481 void markInvalid(const void *Tag, const void *Data) {
0482 Invalidations.insert(std::make_pair(Tag, Data));
0483 }
0484
0485
0486
0487
0488 void Profile(llvm::FoldingSetNodeID &hash) const override;
0489
0490
0491
0492
0493
0494
0495 void addVisitor(std::unique_ptr<BugReporterVisitor> visitor);
0496
0497 template <class VisitorType, class... Args>
0498 void addVisitor(Args &&... ConstructorArgs) {
0499 addVisitor(
0500 std::make_unique<VisitorType>(std::forward<Args>(ConstructorArgs)...));
0501 }
0502
0503
0504
0505 void clearVisitors();
0506
0507
0508 visitor_iterator visitor_begin() { return Callbacks.begin(); }
0509 visitor_iterator visitor_end() { return Callbacks.end(); }
0510 visitor_range visitors() { return {visitor_begin(), visitor_end()}; }
0511
0512
0513
0514
0515 bool addTrackedCondition(const ExplodedNode *Cond) {
0516 return TrackedConditions.insert(Cond).second;
0517 }
0518
0519 void addCallStackHint(PathDiagnosticPieceRef Piece,
0520 std::unique_ptr<StackHintGenerator> StackHint) {
0521 StackHints[Piece] = std::move(StackHint);
0522 }
0523
0524 bool hasCallStackHint(PathDiagnosticPieceRef Piece) const {
0525 return StackHints.count(Piece) > 0;
0526 }
0527
0528
0529
0530 std::string
0531 getCallStackMessage(PathDiagnosticPieceRef Piece,
0532 const ExplodedNode *N) const {
0533 auto I = StackHints.find(Piece);
0534 if (I != StackHints.end())
0535 return I->second->getMessage(N);
0536 return "";
0537 }
0538 };
0539
0540
0541
0542
0543
0544 class BugReportEquivClass : public llvm::FoldingSetNode {
0545 friend class BugReporter;
0546
0547
0548 llvm::SmallVector<std::unique_ptr<BugReport>, 4> Reports;
0549
0550 void AddReport(std::unique_ptr<BugReport> &&R) {
0551 Reports.push_back(std::move(R));
0552 }
0553
0554 public:
0555 BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); }
0556
0557 ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; }
0558
0559 void Profile(llvm::FoldingSetNodeID& ID) const {
0560 assert(!Reports.empty());
0561 Reports.front()->Profile(ID);
0562 }
0563 };
0564
0565
0566
0567
0568
0569 class BugReporterData {
0570 public:
0571 virtual ~BugReporterData() = default;
0572
0573 virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0;
0574 virtual ASTContext &getASTContext() = 0;
0575 virtual SourceManager &getSourceManager() = 0;
0576 virtual AnalyzerOptions &getAnalyzerOptions() = 0;
0577 virtual Preprocessor &getPreprocessor() = 0;
0578 };
0579
0580
0581
0582
0583
0584
0585 class BugReporter {
0586 private:
0587 BugReporterData& D;
0588
0589
0590 const Decl *AnalysisEntryPoint = nullptr;
0591
0592
0593 void FlushReport(BugReportEquivClass& EQ);
0594
0595
0596 llvm::FoldingSet<BugReportEquivClass> EQClasses;
0597
0598
0599 std::vector<BugReportEquivClass *> EQClassesVector;
0600
0601
0602 BugSuppression UserSuppressions;
0603
0604 public:
0605 BugReporter(BugReporterData &d);
0606 virtual ~BugReporter();
0607
0608
0609 void FlushReports();
0610
0611 ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() {
0612 return D.getPathDiagnosticConsumers();
0613 }
0614
0615
0616 using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator;
0617 llvm::iterator_range<EQClasses_iterator> equivalenceClasses() {
0618 return EQClasses;
0619 }
0620
0621 ASTContext &getContext() { return D.getASTContext(); }
0622
0623 const SourceManager &getSourceManager() { return D.getSourceManager(); }
0624
0625 const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
0626
0627 Preprocessor &getPreprocessor() { return D.getPreprocessor(); }
0628
0629
0630 const Decl *getAnalysisEntryPoint() const { return AnalysisEntryPoint; }
0631
0632 void setAnalysisEntryPoint(const Decl *EntryPoint) {
0633 assert(EntryPoint);
0634 AnalysisEntryPoint = EntryPoint;
0635 }
0636
0637
0638
0639
0640
0641
0642 virtual void emitReport(std::unique_ptr<BugReport> R);
0643
0644 void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker,
0645 StringRef BugName, StringRef BugCategory,
0646 StringRef BugStr, PathDiagnosticLocation Loc,
0647 ArrayRef<SourceRange> Ranges = {},
0648 ArrayRef<FixItHint> Fixits = {});
0649
0650 void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName,
0651 StringRef BugName, StringRef BugCategory,
0652 StringRef BugStr, PathDiagnosticLocation Loc,
0653 ArrayRef<SourceRange> Ranges = {},
0654 ArrayRef<FixItHint> Fixits = {});
0655
0656 private:
0657 llvm::StringMap<std::unique_ptr<BugType>> StrBugTypes;
0658
0659
0660
0661 BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name,
0662 StringRef category);
0663
0664 virtual BugReport *
0665 findReportInEquivalenceClass(BugReportEquivClass &eqClass,
0666 SmallVectorImpl<BugReport *> &bugReports) {
0667 return eqClass.getReports()[0].get();
0668 }
0669
0670 protected:
0671
0672 virtual std::unique_ptr<DiagnosticForConsumerMapTy>
0673 generateDiagnosticForConsumerMap(BugReport *exampleReport,
0674 ArrayRef<PathDiagnosticConsumer *> consumers,
0675 ArrayRef<BugReport *> bugReports);
0676 };
0677
0678
0679 class PathSensitiveBugReporter final : public BugReporter {
0680 ExprEngine& Eng;
0681
0682 BugReport *findReportInEquivalenceClass(
0683 BugReportEquivClass &eqClass,
0684 SmallVectorImpl<BugReport *> &bugReports) override;
0685
0686
0687 std::unique_ptr<DiagnosticForConsumerMapTy>
0688 generateDiagnosticForConsumerMap(BugReport *exampleReport,
0689 ArrayRef<PathDiagnosticConsumer *> consumers,
0690 ArrayRef<BugReport *> bugReports) override;
0691 public:
0692 PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng)
0693 : BugReporter(d), Eng(eng) {}
0694
0695
0696
0697 const ExplodedGraph &getGraph() const;
0698
0699
0700
0701 ProgramStateManager &getStateManager() const;
0702
0703
0704
0705
0706
0707
0708 std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics(
0709 ArrayRef<PathDiagnosticConsumer *> consumers,
0710 ArrayRef<PathSensitiveBugReport *> &bugReports);
0711
0712 void emitReport(std::unique_ptr<BugReport> R) override;
0713 };
0714
0715
0716 class BugReporterContext {
0717 PathSensitiveBugReporter &BR;
0718
0719 virtual void anchor();
0720
0721 public:
0722 BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {}
0723
0724 virtual ~BugReporterContext() = default;
0725
0726 PathSensitiveBugReporter& getBugReporter() { return BR; }
0727 const PathSensitiveBugReporter &getBugReporter() const { return BR; }
0728
0729 ProgramStateManager& getStateManager() const {
0730 return BR.getStateManager();
0731 }
0732
0733 ASTContext &getASTContext() const {
0734 return BR.getContext();
0735 }
0736
0737 const SourceManager& getSourceManager() const {
0738 return BR.getSourceManager();
0739 }
0740
0741 const AnalyzerOptions &getAnalyzerOptions() const {
0742 return BR.getAnalyzerOptions();
0743 }
0744 };
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754 class DataTag : public ProgramPointTag {
0755 public:
0756 StringRef getTagDescription() const override { return "Data Tag"; }
0757
0758
0759 class Factory {
0760 std::vector<std::unique_ptr<DataTag>> Tags;
0761
0762 public:
0763 template <class DataTagType, class... Args>
0764 const DataTagType *make(Args &&... ConstructorArgs) {
0765
0766
0767 Tags.emplace_back(
0768 new DataTagType(std::forward<Args>(ConstructorArgs)...));
0769 return static_cast<DataTagType *>(Tags.back().get());
0770 }
0771 };
0772
0773 protected:
0774 DataTag(void *TagKind) : ProgramPointTag(TagKind) {}
0775 };
0776
0777
0778
0779 class NoteTag : public DataTag {
0780 public:
0781 using Callback = std::function<std::string(BugReporterContext &,
0782 PathSensitiveBugReport &)>;
0783
0784 private:
0785 static int Kind;
0786
0787 const Callback Cb;
0788 const bool IsPrunable;
0789
0790 NoteTag(Callback &&Cb, bool IsPrunable)
0791 : DataTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {}
0792
0793 public:
0794 static bool classof(const ProgramPointTag *T) {
0795 return T->getTagKind() == &Kind;
0796 }
0797
0798 std::optional<std::string> generateMessage(BugReporterContext &BRC,
0799 PathSensitiveBugReport &R) const {
0800 std::string Msg = Cb(BRC, R);
0801 if (Msg.empty())
0802 return std::nullopt;
0803
0804 return std::move(Msg);
0805 }
0806
0807 StringRef getTagDescription() const override {
0808
0809
0810
0811 return "Note Tag";
0812 }
0813
0814 bool isPrunable() const { return IsPrunable; }
0815
0816 friend class Factory;
0817 friend class TagVisitor;
0818 };
0819
0820 }
0821
0822 }
0823
0824 #endif