diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -725,14 +725,43 @@ } }; +/// The tag that carries some information with it. +/// +/// It can be valuable to produce tags with some bits of information and later +/// reuse them for a better diagnostic. +/// +/// Please make sure that derived class' constuctor is private and that the user +/// can only create objects using DataTag::Factory. This also means that +/// DataTag::Factory should be friend for every derived class. +class DataTag : public ProgramPointTag { +public: + StringRef getTagDescription() const override { return "Data Tag"; } + + // Manage memory for DataTag objects. + class Factory { + std::vector> Tags; + + public: + template + const DataTagType *make(Args &&... ConstructorArgs) { + // We cannot use std::make_unique because we cannot access the private + // constructor from inside it. + Tags.emplace_back( + new DataTagType(std::forward(ConstructorArgs)...)); + return static_cast(Tags.back().get()); + } + }; + +protected: + DataTag(void *TagKind) : ProgramPointTag(TagKind) {} +}; /// The tag upon which the TagVisitor reacts. Add these in order to display /// additional PathDiagnosticEventPieces along the path. -class NoteTag : public ProgramPointTag { +class NoteTag : public DataTag { public: - using Callback = - std::function; + using Callback = std::function; private: static int Kind; @@ -741,7 +770,7 @@ const bool IsPrunable; NoteTag(Callback &&Cb, bool IsPrunable) - : ProgramPointTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {} + : DataTag(&Kind), Cb(std::move(Cb)), IsPrunable(IsPrunable) {} public: static bool classof(const ProgramPointTag *T) { @@ -766,20 +795,7 @@ bool isPrunable() const { return IsPrunable; } - // Manage memory for NoteTag objects. - class Factory { - std::vector> Tags; - - public: - const NoteTag *makeNoteTag(Callback &&Cb, bool IsPrunable = false) { - // We cannot use std::make_unique because we cannot access the private - // constructor from inside it. - std::unique_ptr T(new NoteTag(std::move(Cb), IsPrunable)); - Tags.push_back(std::move(T)); - return Tags.back().get(); - } - }; - + friend class Factory; friend class TagVisitor; }; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -255,7 +255,7 @@ /// to omit the note from the report if it would make the displayed /// bug path significantly shorter. const NoteTag *getNoteTag(NoteTag::Callback &&Cb, bool IsPrunable = false) { - return Eng.getNoteTags().makeNoteTag(std::move(Cb), IsPrunable); + return Eng.getDataTags().make(std::move(Cb), IsPrunable); } /// A shorthand version of getNoteTag that doesn't require you to accept diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -96,9 +96,10 @@ /// (This data is owned by AnalysisConsumer.) FunctionSummariesTy *FunctionSummaries; - /// Add path note tags along the path when we see that something interesting - /// is happening. This field is the allocator for such tags. - NoteTag::Factory NoteTags; + /// Add path tags with some useful data along the path when we see that + /// something interesting is happening. This field is the allocator for such + /// tags. + DataTag::Factory DataTags; void generateNode(const ProgramPoint &Loc, ProgramStateRef State, @@ -200,7 +201,7 @@ /// Enqueue a single node created as a result of statement processing. void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx); - NoteTag::Factory &getNoteTags() { return NoteTags; } + DataTag::Factory &getDataTags() { return DataTags; } }; // TODO: Turn into a class. diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -428,8 +428,7 @@ SymbolManager &getSymbolManager() { return SymMgr; } MemRegionManager &getRegionManager() { return MRMgr; } - NoteTag::Factory &getNoteTags() { return Engine.getNoteTags(); } - + DataTag::Factory &getDataTags() { return Engine.getDataTags(); } // Functions for external checking of whether we have unfinished work bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); } diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -219,13 +219,14 @@ // and we're taking the path that skips virtual base constructors. if (L.getSrc()->getTerminator().isVirtualBaseBranch() && L.getDst() == *L.getSrc()->succ_begin()) { - ProgramPoint P = L.withTag(getNoteTags().makeNoteTag( + ProgramPoint P = L.withTag(getDataTags().make( [](BugReporterContext &, PathSensitiveBugReport &) -> std::string { // TODO: Just call out the name of the most derived class // when we know it. return "Virtual base initialization skipped because " "it has already been handled by the most derived class"; - }, /*IsPrunable=*/true)); + }, + /*IsPrunable=*/true)); // Perform the transition. ExplodedNodeSet Dst; NodeBuilder Bldr(Pred, Dst, BuilderCtx);