1717#include " clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
1818#include " clang/StaticAnalyzer/Core/Checker.h"
1919#include < string>
20+ #include < variant>
2021
2122namespace clang {
2223
@@ -26,36 +27,53 @@ class BugReporter;
2627
2728class BugType {
2829private:
29- const CheckerNameRef CheckerName;
30+ struct CheckerPartRef {
31+ const CheckerBase *Checker;
32+ CheckerPartIdx Idx;
33+ };
34+ using CheckerNameInfo = std::variant<CheckerNameRef, CheckerPartRef>;
35+
36+ const CheckerNameInfo CheckerName;
3037 const std::string Description;
3138 const std::string Category;
32- const CheckerBase *Checker;
3339 bool SuppressOnSink;
3440
3541 virtual void anchor ();
3642
3743public:
44+ // Straightforward constructor where the checker name is specified directly.
45+ // TODO: As far as I know all applications of this constructor involve ugly
46+ // hacks that could be avoided by switching to a different constructor.
47+ // When those are all eliminated, this constructor should be removed to
48+ // eliminate the `variant` and simplify this class.
3849 BugType (CheckerNameRef CheckerName, StringRef Desc,
3950 StringRef Cat = categories::LogicError, bool SuppressOnSink = false )
4051 : CheckerName(CheckerName), Description(Desc), Category(Cat),
41- Checker (nullptr ), SuppressOnSink(SuppressOnSink) {}
52+ SuppressOnSink (SuppressOnSink) {}
53+ // Constructor that can be called from the constructor of a checker object.
54+ // At that point the checker name is not yet available, but we can save a
55+ // pointer to the checker and later use that to query the name.
4256 BugType (const CheckerBase *Checker, StringRef Desc,
4357 StringRef Cat = categories::LogicError, bool SuppressOnSink = false )
44- : CheckerName(), Description(Desc), Category(Cat), Checker(Checker),
45- SuppressOnSink(SuppressOnSink) {}
58+ : CheckerName(CheckerPartRef{Checker, DefaultPart}), Description(Desc),
59+ Category(Cat), SuppressOnSink(SuppressOnSink) {}
60+ // Constructor that can be called from the constructor of a checker object
61+ // when it has multiple parts with separate names. We save the name and the
62+ // part index to be able to query the name of that part later.
63+ BugType (const CheckerBase *Checker, CheckerPartIdx Idx, StringRef Desc,
64+ StringRef Cat = categories::LogicError, bool SuppressOnSink = false )
65+ : CheckerName(CheckerPartRef{Checker, Idx}), Description(Desc),
66+ Category(Cat), SuppressOnSink(SuppressOnSink) {}
4667 virtual ~BugType () = default ;
4768
4869 StringRef getDescription () const { return Description; }
4970 StringRef getCategory () const { return Category; }
5071 StringRef getCheckerName () const {
51- // FIXME: This is a workaround to ensure that the correct checker name is
52- // used. The checker names are set after the constructors are run.
53- // In case the BugType object is initialized in the checker's ctor
54- // the CheckerName field will be empty. To circumvent this problem we use
55- // CheckerBase whenever it is possible.
56- StringRef Ret = Checker ? Checker->getName () : CheckerName;
57- assert (!Ret.empty () && " Checker name is not set properly." );
58- return Ret;
72+ if (const auto *CNR = std::get_if<CheckerNameRef>(&CheckerName))
73+ return *CNR;
74+
75+ auto [Checker, Idx] = std::get<CheckerPartRef>(CheckerName);
76+ return Checker->getName (Idx);
5977 }
6078
6179 // / isSuppressOnSink - Returns true if bug reports associated with this bug
0 commit comments