https://github.com/NagyDonat updated https://github.com/llvm/llvm-project/pull/139256
From 3bead14691a29482705c76951eaed176bfbfc996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Thu, 8 May 2025 18:46:41 +0200 Subject: [PATCH 01/12] [analyzer][NFC] Introduce framework for checker families The checker classes (i.e. classes derived from `CheckerBase` via the utility template `Checker<...>`) act as intermediates between the user and the analyzer engine, so they have two interfaces: - On the frontend side, they have a public name, can be enabled or disabled, can accept checker options and can be reported as the source of bug reports. - On the backend side, they can handle various checker callbacks and they "leave a mark" on the `ExplodedNode`s that are created by them. (These `ProgramPointTag` marks are internal: they appear in debug logs and can be queried by checker logic; but the user doesn't see them.) In a significant majority of the checkers there is 1:1 correspondence between these sides, but there are also many checker classes where several related user-facing checkers share the same backend class. Historically each of these "multi-part checker" classes had its own hacks to juggle its multiple names, which led to lots of ugliness like lazy initialization of `mutable std::unique_ptr<BugType>` members and redundant data members (when a checker used its custom `CheckNames` array and ignored the inherited single `Name`). My recent commit 27099982da2f5a6c2d282d6b385e79d080669546 tried to unify and standardize these existing solutions to get rid of some of the technical debt, but it still used enum values to identify the checker parts within a "multi-part" checker class, which led to some ugliness. This commit introduces a new framework which takes a more direct, object-oriented approach: instead of identifying checker parts with `{parent checker object, index of part}` pairs, the parts of a multi-part checker become stand-alone objects that store their own name (and enabled/disabled status) as a data member. This is implemented by separating the functionality of `CheckerBase` into two new classes: `CheckerFrontend` and `CheckerBackend`. The name `CheckerBase` is kept (as a class derived from both `CheckerFrontend` and `CheckerBackend`), so "simple" checkers that use `CheckerBase` and `Checker<...>` continues to work without changes. However we also get first-class support for the "many frontends - one backend" situation: - The class `CheckerFamily<...>` works exactly like `Checker<...>` but inherits from `CheckerBackend` instead of `CheckerBase`, so it won't have a superfluous single `Name` member. - Classes deriving from `CheckerFamily` can freely own multiple `CheckerFrontend` data members, which are enabled within the registration methods corresponding to their name and can be used to initialize the `BugType`s that they can emit. In this scheme each `CheckerFamily` needs to override the pure virtual method `ProgramPointTag::getTagDescription()` which returns a string which represents that class for debugging purposes. (Previously this used the name of one arbitrary sub-checker, which was passable for debugging purposes, but not too elegant.) I'm planning to implement follow-up commits that convert all the "multi-part" checkers to this `CheckerFamily` framework. --- clang/include/clang/Analysis/ProgramPoint.h | 4 +- .../Core/BugReporter/BugReporter.h | 7 +- .../StaticAnalyzer/Core/BugReporter/BugType.h | 44 +++--- .../clang/StaticAnalyzer/Core/Checker.h | 132 ++++++++++-------- .../StaticAnalyzer/Core/CheckerManager.h | 80 ++++------- .../Checkers/DivZeroChecker.cpp | 34 +++-- .../Checkers/ObjCSelfInitChecker.cpp | 2 +- .../Checkers/VirtualCallChecker.cpp | 29 ++-- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 4 +- clang/lib/StaticAnalyzer/Core/Checker.cpp | 14 +- .../StaticAnalyzer/Core/CheckerManager.cpp | 22 +-- 11 files changed, 180 insertions(+), 192 deletions(-) diff --git a/clang/include/clang/Analysis/ProgramPoint.h b/clang/include/clang/Analysis/ProgramPoint.h index c40aa3d8ffb72..d81b8e845cb48 100644 --- a/clang/include/clang/Analysis/ProgramPoint.h +++ b/clang/include/clang/Analysis/ProgramPoint.h @@ -40,8 +40,8 @@ class ProgramPointTag { ProgramPointTag(void *tagKind = nullptr) : TagKind(tagKind) {} virtual ~ProgramPointTag(); - /// The description of this program point which will be displayed when the - /// ExplodedGraph is dumped in DOT format for debugging. + /// The description of this program point which will be dumped for debugging + /// purposes. Do not use in user-facing output! virtual StringRef getTagDescription() const = 0; /// Used to implement 'isKind' in subclasses. diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 8e1d25b3eefa1..33d37febc7327 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -643,9 +643,10 @@ class BugReporter { /// reports. virtual void emitReport(std::unique_ptr<BugReport> R); - void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, - StringRef BugName, StringRef BugCategory, - StringRef BugStr, PathDiagnosticLocation Loc, + void EmitBasicReport(const Decl *DeclWithIssue, + const CheckerFrontend *Checker, StringRef BugName, + StringRef BugCategory, StringRef BugStr, + PathDiagnosticLocation Loc, ArrayRef<SourceRange> Ranges = {}, ArrayRef<FixItHint> Fixits = {}); diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h index 3a635e0d0125a..b05360904f86d 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -27,11 +27,7 @@ class BugReporter; class BugType { private: - struct CheckerPartRef { - const CheckerBase *Checker; - CheckerPartIdx Idx; - }; - using CheckerNameInfo = std::variant<CheckerNameRef, CheckerPartRef>; + using CheckerNameInfo = std::variant<CheckerNameRef, const CheckerFrontend *>; const CheckerNameInfo CheckerName; const std::string Description; @@ -43,7 +39,7 @@ class BugType { public: // Straightforward constructor where the checker name is specified directly. // TODO: As far as I know all applications of this constructor involve ugly - // hacks that could be avoided by switching to a different constructor. + // hacks that could be avoided by switching to the other constructor. // When those are all eliminated, this constructor should be removed to // eliminate the `variant` and simplify this class. BugType(CheckerNameRef CheckerName, StringRef Desc, @@ -52,18 +48,11 @@ class BugType { SuppressOnSink(SuppressOnSink) {} // Constructor that can be called from the constructor of a checker object. // At that point the checker name is not yet available, but we can save a - // pointer to the checker and later use that to query the name. - BugType(const CheckerBase *Checker, StringRef Desc, + // pointer to the checker and use that to query the name. + BugType(const CheckerFrontend *CF, StringRef Desc, StringRef Cat = categories::LogicError, bool SuppressOnSink = false) - : CheckerName(CheckerPartRef{Checker, DefaultPart}), Description(Desc), - Category(Cat), SuppressOnSink(SuppressOnSink) {} - // Constructor that can be called from the constructor of a checker object - // when it has multiple parts with separate names. We save the name and the - // part index to be able to query the name of that part later. - BugType(const CheckerBase *Checker, CheckerPartIdx Idx, StringRef Desc, - StringRef Cat = categories::LogicError, bool SuppressOnSink = false) - : CheckerName(CheckerPartRef{Checker, Idx}), Description(Desc), - Category(Cat), SuppressOnSink(SuppressOnSink) {} + : CheckerName(CF), Description(Desc), Category(Cat), + SuppressOnSink(SuppressOnSink) {} virtual ~BugType() = default; StringRef getDescription() const { return Description; } @@ -72,8 +61,7 @@ class BugType { if (const auto *CNR = std::get_if<CheckerNameRef>(&CheckerName)) return *CNR; - auto [Checker, Idx] = std::get<CheckerPartRef>(CheckerName); - return Checker->getName(Idx); + return std::get<const CheckerFrontend *>(CheckerName)->getName(); } /// isSuppressOnSink - Returns true if bug reports associated with this bug @@ -82,6 +70,24 @@ class BugType { bool isSuppressOnSink() const { return SuppressOnSink; } }; +/// Trivial convenience class for the common case when a certain checker +/// frontend always uses the same bug type. This way instead of writing +/// ``` +/// CheckerFrontend LongCheckerFrontendName; +/// BugType LongCheckerFrontendNameBug{LongCheckerFrontendName, "..."}; +/// ``` +/// we can use `CheckerFrontendWithBugType LongCheckerFrontendName{"..."}`. +class CheckerFrontendWithBugType : public CheckerFrontend { + BugType BT; + +public: + CheckerFrontendWithBugType(StringRef Desc, + StringRef Cat = categories::LogicError, + bool SuppressOnSink = false) + : BT(this, Desc, Cat, SuppressOnSink) {} + const BugType &getBT() const { return BT; } +}; + } // namespace ento } // end clang namespace diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h index a54c5bee612f6..45b0398f3aca5 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Checker.h +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -484,83 +484,87 @@ class Call { } // end eval namespace -class CheckerBase : public ProgramPointTag { - /// A single checker class (i.e. a subclass of `CheckerBase`) can implement - /// multiple user-facing checkers that have separate names and can be enabled - /// separately, but are backed by the same singleton checker object. - SmallVector<std::optional<CheckerNameRef>, 1> RegisteredNames; - - friend class ::clang::ento::CheckerManager; +/// A `CheckerFrontend` instance is what the user recognizes as "one checker": +/// it has a public canonical name (injected from the `CheckerManager`), can be +/// enabled or disabled, can have associated checker options and can be printed +/// as the "source" of bug reports. +/// The singleton instance of a simple `Checker<...>` is-a `CheckerFrontend` +/// (for historical reasons, to preserve old straightforward code), while the +/// singleton instance of a `CheckerFamily<...>` class owns multiple +/// `CheckerFrontend` instances as data members. +/// Modeling checkers that are hidden from the user but can be enabled or +/// disabled separately (as dependencies of other checkers) are also considered +/// to be `CheckerFrontend`s. +class CheckerFrontend { + /// The `Name` is nullopt if and only if the checker is disabled. + std::optional<CheckerNameRef> Name; public: - CheckerNameRef getName(CheckerPartIdx Idx = DefaultPart) const { - assert(Idx < RegisteredNames.size() && "Checker part index is too large!"); - std::optional<CheckerNameRef> Name = RegisteredNames[Idx]; - assert(Name && "Requested checker part is not registered!"); - return *Name; - } - - bool isPartEnabled(CheckerPartIdx Idx) const { - return Idx < RegisteredNames.size() && RegisteredNames[Idx].has_value(); - } - - void registerCheckerPart(CheckerPartIdx Idx, CheckerNameRef Name) { - // Paranoia: notice if e.g. UINT_MAX is passed as a checker part index. - assert(Idx < 256 && "Checker part identifiers should be small integers."); - - if (Idx >= RegisteredNames.size()) - RegisteredNames.resize(Idx + 1, std::nullopt); - - assert(!RegisteredNames[Idx] && "Repeated registration of checker a part!"); - RegisteredNames[Idx] = Name; - } - - StringRef getTagDescription() const override { - // When the ExplodedGraph is dumped for debugging (in DOT format), this - // method is called to attach a description to nodes created by this - // checker _class_. Ideally this should be recognizable identifier of the - // whole class, but for this debugging purpose it's sufficient to use the - // name of the first registered checker part. - for (const auto &OptName : RegisteredNames) - if (OptName) - return *OptName; - - return "Unregistered checker"; + void enable(CheckerManager &Mgr) { + assert(!Name && "Checker part registered twice!"); + Name = Mgr.getCurrentCheckerName(); } + bool isEnabled() const { return static_cast<bool>(Name); } + CheckerNameRef getName() const { return *Name; } +}; +/// `CheckerBackend` is an abstract base class that serves as the common +/// ancestor of all the `Checker<...>` and `CheckerFamily<...>` classes which +/// can create `ExplodedNode`s (by acting as a `ProgramPointTag`) and can be +/// registered to handle various checker callbacks. (Moreover the debug +/// callback `printState` is also introduced here.) +class CheckerBackend : public ProgramPointTag { +public: /// Debug state dump callback, see CheckerManager::runCheckersForPrintState. /// Default implementation does nothing. virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const; }; -/// Dump checker name to stream. -raw_ostream& operator<<(raw_ostream &Out, const CheckerBase &Checker); - -/// Tag that can use a checker name as a message provider -/// (see SimpleProgramPointTag). -class CheckerProgramPointTag : public SimpleProgramPointTag { +/// The non-templated common ancestor of all the simple `Checker<...>` classes. +class CheckerBase : public CheckerFrontend, public CheckerBackend { public: - CheckerProgramPointTag(StringRef CheckerName, StringRef Msg); - CheckerProgramPointTag(const CheckerBase *Checker, StringRef Msg); + /// Attached to nodes created by this checker class when the ExplodedGraph is + /// dumped for debugging. + StringRef getTagDescription() const override; }; -template <typename CHECK1, typename... CHECKs> -class Checker : public CHECK1, public CHECKs..., public CheckerBase { +// Template magic to implement the static method `_register()` which registers +// the `Checker` or `CheckerFamily` for all the implemented callbacks. +template <typename CHECKER, typename CHECK1, typename... CHECKs> +static void registerImpl(CHECKER *Chk, CheckerManager &Mgr) { + CHECK1::_register(Chk, Mgr); + registerImpl<CHECKER, CHECKs...>(Chk, Mgr); +} + +template <typename CHECKER> +static void registerImpl(CHECKER *Chk, CheckerManager &Mgr) {} + +/// Simple checker classes that implement one frontend (i.e. checker name) +/// should derive from this template and specify all the implemented callbacks +/// (i.e. classes like `check::PreStmt` or `eval::Call`) as template arguments +/// of `Checker`. +template <typename... CHECKs> +class Checker : public CheckerBase, public CHECKs... { public: template <typename CHECKER> - static void _register(CHECKER *checker, CheckerManager &mgr) { - CHECK1::_register(checker, mgr); - Checker<CHECKs...>::_register(checker, mgr); + static void _register(CHECKER *Chk, CheckerManager &Mgr) { + registerImpl<CHECKER, CHECKs...>(Chk, Mgr); } }; -template <typename CHECK1> -class Checker<CHECK1> : public CHECK1, public CheckerBase { +/// Checker families (where a single backend class implements multiple related +/// frontends) should derive from this template, specify all the implemented +/// callbacks (i.e. classes like `check::PreStmt` or `eval::Call`) as template +/// arguments of `FamilyChecker` and implement the pure virtual method +/// `StringRef getTagDescription()` which is inherited from `ProgramPointTag` +/// and should return a string identifying the class for debugging purposes. +template <typename... CHECKs> +class CheckerFamily : public CheckerBackend, public CHECKs... { public: template <typename CHECKER> - static void _register(CHECKER *checker, CheckerManager &mgr) { - CHECK1::_register(checker, mgr); + static void _register(CHECKER *Chk, CheckerManager &Mgr) { + registerImpl<CHECKER, CHECKs...>(Chk, Mgr); } }; @@ -581,6 +585,20 @@ class EventDispatcher { } }; +/// Tag that can use a checker name as a message provider +/// (see SimpleProgramPointTag). +/// FIXME: This is a cargo cult class which is copied into several checkers but +/// does not provide anything useful. +/// The only added functionality provided by this class (compared to +/// SimpleProgramPointTag) is that it composes the tag description string from +/// two arguments -- but tag descriptions only appear in debug output so there +/// is no reason to bother with this. +class CheckerProgramPointTag : public SimpleProgramPointTag { +public: + CheckerProgramPointTag(StringRef CheckerName, StringRef Msg); + CheckerProgramPointTag(const CheckerBase *Checker, StringRef Msg); +}; + /// We dereferenced a location that may be null. struct ImplicitNullDerefEvent { SVal Location; diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 03ffadd346d0b..8fa122f004bfe 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -39,7 +39,8 @@ class AnalysisManager; class CXXAllocatorCall; class BugReporter; class CallEvent; -class CheckerBase; +class CheckerFrontend; +class CheckerBackend; class CheckerContext; class CheckerRegistry; struct CheckerRegistryData; @@ -64,9 +65,9 @@ class CheckerFn<RET(Ps...)> { Func Fn; public: - CheckerBase *Checker; + CheckerBackend *Checker; - CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) {} + CheckerFn(CheckerBackend *checker, Func fn) : Fn(fn), Checker(checker) {} RET operator()(Ps... ps) const { return Fn(Checker, ps...); @@ -116,19 +117,6 @@ class CheckerNameRef { operator StringRef() const { return Name; } }; -/// A single checker class (and its singleton instance) can act as the -/// implementation of several (user-facing or modeling) checker parts that -/// have shared state and logic, but have their own names and can be enabled or -/// disabled separately. -/// Each checker class that implement multiple parts introduces its own enum -/// type to assign small numerical indices (0, 1, 2 ...) to their parts. The -/// type alias 'CheckerPartIdx' is conceptually the union of these enum types. -using CheckerPartIdx = unsigned; - -/// If a checker doesn't have multiple parts, then its single part is -/// represented by this index. -constexpr inline CheckerPartIdx DefaultPart = 0; - enum class ObjCMessageVisitKind { Pre, Post, @@ -193,14 +181,7 @@ class CheckerManager { /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. - void reportInvalidCheckerOptionValue(const CheckerBase *C, - StringRef OptionName, - StringRef ExpectedValueDesc) const { - reportInvalidCheckerOptionValue(C, DefaultPart, OptionName, - ExpectedValueDesc); - } - - void reportInvalidCheckerOptionValue(const CheckerBase *C, CheckerPartIdx Idx, + void reportInvalidCheckerOptionValue(const CheckerFrontend *CP, StringRef OptionName, StringRef ExpectedValueDesc) const; @@ -210,28 +191,15 @@ class CheckerManager { // Checker registration. //===--------------------------------------------------------------------===// - /// Construct the singleton instance of a checker, register it for the - /// supported callbacks and record its name with `registerCheckerPart()`. - /// Arguments passed to this function are forwarded to the constructor of the - /// checker. - /// - /// If `CHECKER` has multiple parts, then the constructor call and the - /// callback registration only happen within the first `registerChecker()` - /// call; while the subsequent calls only enable additional parts of the - /// existing checker object (while registering their names). - /// - /// \returns a pointer to the checker object. - template <typename CHECKER, CheckerPartIdx Idx = DefaultPart, typename... AT> - CHECKER *registerChecker(AT &&...Args) { - // This assert could be removed but then we need to make sure that calls - // registering different parts of the same checker pass the same arguments. - static_assert( - Idx == DefaultPart || !sizeof...(AT), - "Argument forwarding isn't supported with multi-part checkers!"); - + /// If the the singleton instance of a checker class is not yet constructed, + /// then construct it (with the supplied arguments), register it for the + /// callbacks that are supported by it, and return it. Otherwise, just return + /// a pointer to the existing instance. + template <typename CHECKER, typename... AT> + CHECKER *getChecker(AT &&...Args) { CheckerTag Tag = getTag<CHECKER>(); - std::unique_ptr<CheckerBase> &Ref = CheckerTags[Tag]; + std::unique_ptr<CheckerBackend> &Ref = CheckerTags[Tag]; if (!Ref) { std::unique_ptr<CHECKER> Checker = std::make_unique<CHECKER>(std::forward<AT>(Args)...); @@ -239,18 +207,18 @@ class CheckerManager { Ref = std::move(Checker); } - CHECKER *Result = static_cast<CHECKER *>(Ref.get()); - Result->registerCheckerPart(Idx, CurrentCheckerName); - return Result; + return static_cast<CHECKER *>(Ref.get()); } - template <typename CHECKER> - CHECKER *getChecker() { - CheckerTag Tag = getTag<CHECKER>(); - std::unique_ptr<CheckerBase> &Ref = CheckerTags[Tag]; - assert(Ref && "Requested checker is not registered! Maybe you should add it" - " as a dependency in Checkers.td?"); - return static_cast<CHECKER *>(Ref.get()); + /// Register a single-part checker (derived from `Checker`): construct its + /// singleton instance, register it for the supported callbacks and record + /// its name (with `CheckerFrontend::enable`). Calling this multiple times + /// triggers an assertion failure. + template <typename CHECKER, typename... AT> + CHECKER *registerChecker(AT &&...Args) { + CHECKER *Chk = getChecker<CHECKER>(std::forward<AT>(Args)...); + Chk->enable(*this); + return Chk; } template <typename CHECKER> bool isRegisteredChecker() { @@ -482,7 +450,7 @@ class CheckerManager { /// Run checkers for debug-printing a ProgramState. /// /// Unlike most other callbacks, any checker can simply implement the virtual - /// method CheckerBase::printState if it has custom data to print. + /// method CheckerBackend::printState if it has custom data to print. /// /// \param Out The output stream /// \param State The state being printed @@ -651,7 +619,7 @@ class CheckerManager { template <typename T> static void *getTag() { static int tag; return &tag; } - llvm::DenseMap<CheckerTag, std::unique_ptr<CheckerBase>> CheckerTags; + llvm::DenseMap<CheckerTag, std::unique_ptr<CheckerBackend>> CheckerTags; struct DeclCheckerInfo { CheckDeclFunc CheckFn; diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 3dd57732305b2..7672c63a646e4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -25,7 +25,7 @@ using namespace ento; using namespace taint; namespace { -class DivZeroChecker : public Checker<check::PreStmt<BinaryOperator>> { +class DivZeroChecker : public CheckerFamily<check::PreStmt<BinaryOperator>> { void reportBug(StringRef Msg, ProgramStateRef StateZero, CheckerContext &C) const; void reportTaintBug(StringRef Msg, ProgramStateRef StateZero, @@ -33,17 +33,15 @@ class DivZeroChecker : public Checker<check::PreStmt<BinaryOperator>> { llvm::ArrayRef<SymbolRef> TaintedSyms) const; public: - /// This checker class implements several user facing checkers - enum : CheckerPartIdx { - DivideZeroChecker, - TaintedDivChecker, - NumCheckerParts - }; - BugType BugTypes[NumCheckerParts] = { - {this, DivideZeroChecker, "Division by zero"}, - {this, TaintedDivChecker, "Division by zero", categories::TaintedData}}; + /// This checker family implements two user-facing checker parts. + CheckerFrontendWithBugType DivideZeroChecker{"Division by zero"}, + TaintedDivChecker{"Division by zero", categories::TaintedData}; void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; + + /// Identifies this checker family for debugging purposes. For backwards + /// compatibility, this is the name of the older sub-checker. + StringRef getTagDescription() const override { return "core.DivideZero"; } }; } // end anonymous namespace @@ -56,11 +54,11 @@ static const Expr *getDenomExpr(const ExplodedNode *N) { void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero, CheckerContext &C) const { - if (!isPartEnabled(DivideZeroChecker)) + if (!DivideZeroChecker.isEnabled()) return; if (ExplodedNode *N = C.generateErrorNode(StateZero)) { - auto R = std::make_unique<PathSensitiveBugReport>( - BugTypes[DivideZeroChecker], Msg, N); + auto R = std::make_unique<PathSensitiveBugReport>(DivideZeroChecker.getBT(), + Msg, N); bugreporter::trackExpressionValue(N, getDenomExpr(N), *R); C.emitReport(std::move(R)); } @@ -69,11 +67,11 @@ void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero, void DivZeroChecker::reportTaintBug( StringRef Msg, ProgramStateRef StateZero, CheckerContext &C, llvm::ArrayRef<SymbolRef> TaintedSyms) const { - if (!isPartEnabled(TaintedDivChecker)) + if (!TaintedDivChecker.isEnabled()) return; if (ExplodedNode *N = C.generateNonFatalErrorNode(StateZero)) { - auto R = std::make_unique<PathSensitiveBugReport>( - BugTypes[TaintedDivChecker], Msg, N); + auto R = std::make_unique<PathSensitiveBugReport>(TaintedDivChecker.getBT(), + Msg, N); bugreporter::trackExpressionValue(N, getDenomExpr(N), *R); for (auto Sym : TaintedSyms) R->markInteresting(Sym); @@ -127,13 +125,13 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B, } void ento::registerDivZeroChecker(CheckerManager &Mgr) { - Mgr.registerChecker<DivZeroChecker, DivZeroChecker::DivideZeroChecker>(); + Mgr.getChecker<DivZeroChecker>()->DivideZeroChecker.enable(Mgr); } bool ento::shouldRegisterDivZeroChecker(const CheckerManager &) { return true; } void ento::registerTaintedDivChecker(CheckerManager &Mgr) { - Mgr.registerChecker<DivZeroChecker, DivZeroChecker::TaintedDivChecker>(); + Mgr.getChecker<DivZeroChecker>()->TaintedDivChecker.enable(Mgr); } bool ento::shouldRegisterTaintedDivChecker(const CheckerManager &) { diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 217c46451f80f..ace3426387568 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -342,7 +342,7 @@ void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State, if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags) return; - Out << Sep << NL << *this << " :" << NL; + Out << Sep << NL << "ObjCSelfInitChecker:" << NL; if (DidCallInit) Out << " An init method has been called." << NL; diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 5b0d303ee5bbc..b73c25b95245a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -40,15 +40,13 @@ template <> struct FoldingSetTrait<ObjectState> { namespace { class VirtualCallChecker - : public Checker<check::BeginFunction, check::EndFunction, check::PreCall> { + : public CheckerFamily<check::BeginFunction, check::EndFunction, + check::PreCall> { public: - enum : CheckerPartIdx { PureChecker, ImpureChecker, NumCheckerParts }; - - BugType BugTypes[NumCheckerParts] = { - {this, PureChecker, "Pure virtual method call", - categories::CXXObjectLifecycle}, - {this, ImpureChecker, "Unexpected loss of virtual dispatch", - categories::CXXObjectLifecycle}}; + CheckerFrontendWithBugType PureChecker{"Pure virtual method call", + categories::CXXObjectLifecycle}, + ImpureChecker{"Unexpected loss of virtual dispatch", + categories::CXXObjectLifecycle}; bool ShowFixIts = false; @@ -56,6 +54,9 @@ class VirtualCallChecker void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + /// Identifies this checker family for debugging purposes. + StringRef getTagDescription() const override { return "VirtualCallChecker"; } + private: void registerCtorDtorCallInState(bool IsBeginFunction, CheckerContext &C) const; @@ -147,15 +148,15 @@ void VirtualCallChecker::checkPreCall(const CallEvent &Call, if (!N) return; - const CheckerPartIdx Part = IsPure ? PureChecker : ImpureChecker; + const CheckerFrontendWithBugType &Part = IsPure ? PureChecker : ImpureChecker; - if (!isPartEnabled(Part)) { + if (!Part.isEnabled()) { // The respective check is disabled. return; } auto Report = - std::make_unique<PathSensitiveBugReport>(BugTypes[Part], OS.str(), N); + std::make_unique<PathSensitiveBugReport>(Part.getBT(), OS.str(), N); if (ShowFixIts && !IsPure) { // FIXME: These hints are valid only when the virtual call is made @@ -210,7 +211,7 @@ void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction, } void ento::registerPureVirtualCallChecker(CheckerManager &Mgr) { - Mgr.registerChecker<VirtualCallChecker, VirtualCallChecker::PureChecker>(); + Mgr.getChecker<VirtualCallChecker>()->PureChecker.enable(Mgr); } bool ento::shouldRegisterPureVirtualCallChecker(const CheckerManager &Mgr) { @@ -218,8 +219,8 @@ bool ento::shouldRegisterPureVirtualCallChecker(const CheckerManager &Mgr) { } void ento::registerVirtualCallChecker(CheckerManager &Mgr) { - auto *Chk = Mgr.registerChecker<VirtualCallChecker, - VirtualCallChecker::ImpureChecker>(); + auto *Chk = Mgr.getChecker<VirtualCallChecker>(); + Chk->ImpureChecker.enable(Mgr); Chk->ShowFixIts = Mgr.getAnalyzerOptions().getCheckerBooleanOption( Mgr.getCurrentCheckerName(), "ShowFixIts"); } diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 28b96f2717210..39d9ad43fde29 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -3411,12 +3411,12 @@ PathSensitiveBugReporter::generateDiagnosticForConsumerMap( } void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, - const CheckerBase *Checker, StringRef Name, + const CheckerFrontend *CP, StringRef Name, StringRef Category, StringRef Str, PathDiagnosticLocation Loc, ArrayRef<SourceRange> Ranges, ArrayRef<FixItHint> Fixits) { - EmitBasicReport(DeclWithIssue, Checker->getName(), Name, Category, Str, Loc, + EmitBasicReport(DeclWithIssue, CP->getName(), Name, Category, Str, Loc, Ranges, Fixits); } diff --git a/clang/lib/StaticAnalyzer/Core/Checker.cpp b/clang/lib/StaticAnalyzer/Core/Checker.cpp index 2bbb7a541457b..f5a07f5d305c5 100644 --- a/clang/lib/StaticAnalyzer/Core/Checker.cpp +++ b/clang/lib/StaticAnalyzer/Core/Checker.cpp @@ -18,8 +18,10 @@ using namespace ento; int ImplicitNullDerefEvent::Tag; -void CheckerBase::printState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) const {} +StringRef CheckerBase::getTagDescription() const { return getName(); } + +void CheckerBackend::printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const {} CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName, StringRef Msg) @@ -27,10 +29,4 @@ CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName, CheckerProgramPointTag::CheckerProgramPointTag(const CheckerBase *Checker, StringRef Msg) - : SimpleProgramPointTag(Checker->getName(), Msg) {} - -raw_ostream& clang::ento::operator<<(raw_ostream &Out, - const CheckerBase &Checker) { - Out << Checker.getName(); - return Out; -} + : SimpleProgramPointTag(Checker->getTagDescription(), Msg) {} diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index 7ae86f133904b..705eedc106b4a 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -50,11 +50,11 @@ bool CheckerManager::hasPathSensitiveCheckers() const { } void CheckerManager::reportInvalidCheckerOptionValue( - const CheckerBase *C, CheckerPartIdx Idx, StringRef OptionName, + const CheckerFrontend *CP, StringRef OptionName, StringRef ExpectedValueDesc) const { getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input) - << (llvm::Twine(C->getName(Idx)) + ":" + OptionName).str() + << (llvm::Twine(CP->getName()) + ":" + OptionName).str() << ExpectedValueDesc; } @@ -135,12 +135,11 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx, namespace { -std::string checkerScopeName(StringRef Name, const CheckerBase *Checker) { +std::string checkerScopeName(StringRef Name, const CheckerBackend *Checker) { if (!llvm::timeTraceProfilerEnabled()) return ""; - StringRef CheckerName = - Checker ? static_cast<StringRef>(Checker->getName()) : "<unknown>"; - return (Name + ":" + CheckerName).str(); + StringRef CheckerTag = Checker ? Checker->getTagDescription() : "<unknown>"; + return (Name + ":" + CheckerTag).str(); } struct CheckStmtContext { @@ -690,7 +689,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, ExprEngine &Eng, const EvalCallOptions &CallOpts) { for (auto *const Pred : Src) { - std::optional<CheckerNameRef> evaluatorChecker; + std::optional<StringRef> evaluatorChecker; ExplodedNodeSet checkDst; NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); @@ -722,12 +721,12 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, "while the {2} checker also tried to evaluate the same call. At " "most one checker supposed to evaluate a call.", toString(Call), evaluatorChecker, - EvalCallChecker.Checker->getName()); + EvalCallChecker.Checker->getTagDescription()); llvm_unreachable(AssertionMessage.c_str()); } #endif if (evaluated) { - evaluatorChecker = EvalCallChecker.Checker->getName(); + evaluatorChecker = EvalCallChecker.Checker->getTagDescription(); Dst.insert(checkDst); #ifdef NDEBUG break; // on release don't check that no other checker also evals. @@ -798,8 +797,9 @@ void CheckerManager::runCheckersForPrintStateJson(raw_ostream &Out, if (TempBuf.empty()) continue; - Indent(Out, Space, IsDot) << "{ \"checker\": \"" << CT.second->getName() - << "\", \"messages\": [" << NL; + Indent(Out, Space, IsDot) + << "{ \"checker\": \"" << CT.second->getTagDescription() + << "\", \"messages\": [" << NL; Indent(Out, InnerSpace, IsDot) << '\"' << TempBuf.str().trim() << '\"' << NL; Indent(Out, Space, IsDot) << "]}"; From 23d128c05699489e3c06cd299ea1863e15720984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Fri, 9 May 2025 15:03:41 +0200 Subject: [PATCH 02/12] Fix abbreviation of 'CheckerFrontend' --- clang/include/clang/StaticAnalyzer/Core/CheckerManager.h | 2 +- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 4 ++-- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 8fa122f004bfe..b843a137ffff3 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -181,7 +181,7 @@ class CheckerManager { /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. - void reportInvalidCheckerOptionValue(const CheckerFrontend *CP, + void reportInvalidCheckerOptionValue(const CheckerFrontend *CF, StringRef OptionName, StringRef ExpectedValueDesc) const; diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 39d9ad43fde29..0165c1d85ffa3 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -3411,12 +3411,12 @@ PathSensitiveBugReporter::generateDiagnosticForConsumerMap( } void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, - const CheckerFrontend *CP, StringRef Name, + const CheckerFrontend *CF, StringRef Name, StringRef Category, StringRef Str, PathDiagnosticLocation Loc, ArrayRef<SourceRange> Ranges, ArrayRef<FixItHint> Fixits) { - EmitBasicReport(DeclWithIssue, CP->getName(), Name, Category, Str, Loc, + EmitBasicReport(DeclWithIssue, CF->getName(), Name, Category, Str, Loc, Ranges, Fixits); } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index 705eedc106b4a..dc87c7e92162e 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -50,11 +50,11 @@ bool CheckerManager::hasPathSensitiveCheckers() const { } void CheckerManager::reportInvalidCheckerOptionValue( - const CheckerFrontend *CP, StringRef OptionName, + const CheckerFrontend *CF, StringRef OptionName, StringRef ExpectedValueDesc) const { getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input) - << (llvm::Twine(CP->getName()) + ":" + OptionName).str() + << (llvm::Twine(CF->getName()) + ":" + OptionName).str() << ExpectedValueDesc; } From 8459b2f19139a6444d7a219c611bc085bced8e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Tue, 13 May 2025 15:02:03 +0200 Subject: [PATCH 03/12] Use class name as tag description of checker family --- clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp | 5 ++--- clang/test/Analysis/ftime-trace.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 7672c63a646e4..46db1857077b1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -39,9 +39,8 @@ class DivZeroChecker : public CheckerFamily<check::PreStmt<BinaryOperator>> { void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; - /// Identifies this checker family for debugging purposes. For backwards - /// compatibility, this is the name of the older sub-checker. - StringRef getTagDescription() const override { return "core.DivideZero"; } + /// Identifies this checker family for debugging purposes. + StringRef getTagDescription() const override { return "DivZeroChecker"; } }; } // end anonymous namespace diff --git a/clang/test/Analysis/ftime-trace.cpp b/clang/test/Analysis/ftime-trace.cpp index 2940ff2e02891..e349eab8b62ad 100644 --- a/clang/test/Analysis/ftime-trace.cpp +++ b/clang/test/Analysis/ftime-trace.cpp @@ -39,7 +39,7 @@ // Finally, each checker call back is also present: // -// CHECK: "name": "Total Stmt:core.DivideZero", +// CHECK: "name": "Total Stmt:DivZeroChecker", // CHECK-NEXT: "args": { // CHECK-NEXT: "count": {{[0-9]+}}, // CHECK-NEXT: "avg ms": {{[0-9]+}} From 76950c189d62f7f904653adcd30f09b3b96aa81f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Tue, 13 May 2025 15:26:28 +0200 Subject: [PATCH 04/12] Make CheckerFrontendWithBugType a subclass of BugType --- .../clang/StaticAnalyzer/Core/BugReporter/BugType.h | 7 ++----- clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp | 8 ++++---- clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp | 3 +-- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h index b05360904f86d..bdfc8384967a3 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -77,15 +77,12 @@ class BugType { /// BugType LongCheckerFrontendNameBug{LongCheckerFrontendName, "..."}; /// ``` /// we can use `CheckerFrontendWithBugType LongCheckerFrontendName{"..."}`. -class CheckerFrontendWithBugType : public CheckerFrontend { - BugType BT; - +class CheckerFrontendWithBugType : public CheckerFrontend, public BugType { public: CheckerFrontendWithBugType(StringRef Desc, StringRef Cat = categories::LogicError, bool SuppressOnSink = false) - : BT(this, Desc, Cat, SuppressOnSink) {} - const BugType &getBT() const { return BT; } + : BugType(this, Desc, Cat, SuppressOnSink) {} }; } // namespace ento diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 46db1857077b1..c42ea1811456e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -56,8 +56,8 @@ void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero, if (!DivideZeroChecker.isEnabled()) return; if (ExplodedNode *N = C.generateErrorNode(StateZero)) { - auto R = std::make_unique<PathSensitiveBugReport>(DivideZeroChecker.getBT(), - Msg, N); + auto R = + std::make_unique<PathSensitiveBugReport>(DivideZeroChecker, Msg, N); bugreporter::trackExpressionValue(N, getDenomExpr(N), *R); C.emitReport(std::move(R)); } @@ -69,8 +69,8 @@ void DivZeroChecker::reportTaintBug( if (!TaintedDivChecker.isEnabled()) return; if (ExplodedNode *N = C.generateNonFatalErrorNode(StateZero)) { - auto R = std::make_unique<PathSensitiveBugReport>(TaintedDivChecker.getBT(), - Msg, N); + auto R = + std::make_unique<PathSensitiveBugReport>(TaintedDivChecker, Msg, N); bugreporter::trackExpressionValue(N, getDenomExpr(N), *R); for (auto Sym : TaintedSyms) R->markInteresting(Sym); diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index b73c25b95245a..7ac4b133766aa 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -155,8 +155,7 @@ void VirtualCallChecker::checkPreCall(const CallEvent &Call, return; } - auto Report = - std::make_unique<PathSensitiveBugReport>(Part.getBT(), OS.str(), N); + auto Report = std::make_unique<PathSensitiveBugReport>(Part, OS.str(), N); if (ShowFixIts && !IsPure) { // FIXME: These hints are valid only when the virtual call is made From 1cbbc02a36a784514c601c52d62120e226d35e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Tue, 13 May 2025 15:30:33 +0200 Subject: [PATCH 05/12] Rename `CheckerFrontend *CF` to `Checker` --- .../clang/StaticAnalyzer/Core/BugReporter/BugType.h | 4 ++-- clang/include/clang/StaticAnalyzer/Core/CheckerManager.h | 2 +- clang/lib/StaticAnalyzer/Core/BugReporter.cpp | 8 ++++---- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h index bdfc8384967a3..73bece803cf15 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -49,9 +49,9 @@ class BugType { // Constructor that can be called from the constructor of a checker object. // At that point the checker name is not yet available, but we can save a // pointer to the checker and use that to query the name. - BugType(const CheckerFrontend *CF, StringRef Desc, + BugType(const CheckerFrontend *Checker, StringRef Desc, StringRef Cat = categories::LogicError, bool SuppressOnSink = false) - : CheckerName(CF), Description(Desc), Category(Cat), + : CheckerName(Checker), Description(Desc), Category(Cat), SuppressOnSink(SuppressOnSink) {} virtual ~BugType() = default; diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index b843a137ffff3..58f59f7ab049f 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -181,7 +181,7 @@ class CheckerManager { /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. - void reportInvalidCheckerOptionValue(const CheckerFrontend *CF, + void reportInvalidCheckerOptionValue(const CheckerFrontend *Checker, StringRef OptionName, StringRef ExpectedValueDesc) const; diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 0165c1d85ffa3..10901a2db0a69 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -3411,12 +3411,12 @@ PathSensitiveBugReporter::generateDiagnosticForConsumerMap( } void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, - const CheckerFrontend *CF, StringRef Name, - StringRef Category, StringRef Str, - PathDiagnosticLocation Loc, + const CheckerFrontend *Checker, + StringRef Name, StringRef Category, + StringRef Str, PathDiagnosticLocation Loc, ArrayRef<SourceRange> Ranges, ArrayRef<FixItHint> Fixits) { - EmitBasicReport(DeclWithIssue, CF->getName(), Name, Category, Str, Loc, + EmitBasicReport(DeclWithIssue, Checker->getName(), Name, Category, Str, Loc, Ranges, Fixits); } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index dc87c7e92162e..4c37b65ae5c68 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -50,11 +50,11 @@ bool CheckerManager::hasPathSensitiveCheckers() const { } void CheckerManager::reportInvalidCheckerOptionValue( - const CheckerFrontend *CF, StringRef OptionName, + const CheckerFrontend *Checker, StringRef OptionName, StringRef ExpectedValueDesc) const { getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input) - << (llvm::Twine(CF->getName()) + ":" + OptionName).str() + << (llvm::Twine(Checker->getName()) + ":" + OptionName).str() << ExpectedValueDesc; } From c7a96f204765315a6dfc532083e53c5d84970a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Tue, 13 May 2025 15:32:54 +0200 Subject: [PATCH 06/12] Declare data members in separate declarations --- clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp | 5 +++-- clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index c42ea1811456e..95a9582ecdcb1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -34,8 +34,9 @@ class DivZeroChecker : public CheckerFamily<check::PreStmt<BinaryOperator>> { public: /// This checker family implements two user-facing checker parts. - CheckerFrontendWithBugType DivideZeroChecker{"Division by zero"}, - TaintedDivChecker{"Division by zero", categories::TaintedData}; + CheckerFrontendWithBugType DivideZeroChecker{"Division by zero"}; + CheckerFrontendWithBugType TaintedDivChecker{"Division by zero", + categories::TaintedData}; void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 7ac4b133766aa..67429ee2c25f9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -44,9 +44,9 @@ class VirtualCallChecker check::PreCall> { public: CheckerFrontendWithBugType PureChecker{"Pure virtual method call", - categories::CXXObjectLifecycle}, - ImpureChecker{"Unexpected loss of virtual dispatch", - categories::CXXObjectLifecycle}; + categories::CXXObjectLifecycle}; + CheckerFrontendWithBugType ImpureChecker{ + "Unexpected loss of virtual dispatch", categories::CXXObjectLifecycle}; bool ShowFixIts = false; From 4e8035f7816b9d3bd9c53d2a9d1b4a4501d19803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Tue, 13 May 2025 15:40:37 +0200 Subject: [PATCH 07/12] Use fold expression over comma --- .../include/clang/StaticAnalyzer/Core/Checker.h | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h index 45b0398f3aca5..fc83cf68acfc1 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Checker.h +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -504,7 +504,7 @@ class CheckerFrontend { assert(!Name && "Checker part registered twice!"); Name = Mgr.getCurrentCheckerName(); } - bool isEnabled() const { return static_cast<bool>(Name); } + bool isEnabled() const { return Name.has_value(); } CheckerNameRef getName() const { return *Name; } }; @@ -529,17 +529,6 @@ class CheckerBase : public CheckerFrontend, public CheckerBackend { StringRef getTagDescription() const override; }; -// Template magic to implement the static method `_register()` which registers -// the `Checker` or `CheckerFamily` for all the implemented callbacks. -template <typename CHECKER, typename CHECK1, typename... CHECKs> -static void registerImpl(CHECKER *Chk, CheckerManager &Mgr) { - CHECK1::_register(Chk, Mgr); - registerImpl<CHECKER, CHECKs...>(Chk, Mgr); -} - -template <typename CHECKER> -static void registerImpl(CHECKER *Chk, CheckerManager &Mgr) {} - /// Simple checker classes that implement one frontend (i.e. checker name) /// should derive from this template and specify all the implemented callbacks /// (i.e. classes like `check::PreStmt` or `eval::Call`) as template arguments @@ -549,7 +538,7 @@ class Checker : public CheckerBase, public CHECKs... { public: template <typename CHECKER> static void _register(CHECKER *Chk, CheckerManager &Mgr) { - registerImpl<CHECKER, CHECKs...>(Chk, Mgr); + (CHECKs::_register(Chk, Mgr), ...); } }; @@ -564,7 +553,7 @@ class CheckerFamily : public CheckerBackend, public CHECKs... { public: template <typename CHECKER> static void _register(CHECKER *Chk, CheckerManager &Mgr) { - registerImpl<CHECKER, CHECKs...>(Chk, Mgr); + (CHECKs::_register(Chk, Mgr), ...); } }; From 7da3862e87c3e6e94b80e04bddbfd04848f6ce04 Mon Sep 17 00:00:00 2001 From: Balazs Benics <benicsbal...@gmail.com> Date: Thu, 15 May 2025 19:44:55 +0200 Subject: [PATCH 08/12] NFC Rename getTagDescription to getDebugName --- clang/include/clang/Analysis/ProgramPoint.h | 4 ++-- .../clang/StaticAnalyzer/Core/BugReporter/BugReporter.h | 4 ++-- clang/include/clang/StaticAnalyzer/Core/Checker.h | 4 ++-- clang/lib/Analysis/ProgramPoint.cpp | 4 +--- clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp | 2 +- clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp | 2 +- clang/lib/StaticAnalyzer/Core/Checker.cpp | 4 ++-- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp | 8 ++++---- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 2 +- 9 files changed, 16 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Analysis/ProgramPoint.h b/clang/include/clang/Analysis/ProgramPoint.h index d81b8e845cb48..8835127ecc503 100644 --- a/clang/include/clang/Analysis/ProgramPoint.h +++ b/clang/include/clang/Analysis/ProgramPoint.h @@ -42,7 +42,7 @@ class ProgramPointTag { /// The description of this program point which will be dumped for debugging /// purposes. Do not use in user-facing output! - virtual StringRef getTagDescription() const = 0; + virtual StringRef getDebugName() const = 0; /// Used to implement 'isKind' in subclasses. const void *getTagKind() const { return TagKind; } @@ -55,7 +55,7 @@ class SimpleProgramPointTag : public ProgramPointTag { std::string Desc; public: SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg); - StringRef getTagDescription() const override; + StringRef getDebugName() const override; }; class ProgramPoint { diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 33d37febc7327..42b242ada3489 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -758,7 +758,7 @@ class BugReporterContext { /// DataTag::Factory should be friend for every derived class. class DataTag : public ProgramPointTag { public: - StringRef getTagDescription() const override { return "Data Tag"; } + StringRef getDebugName() const override { return "Data Tag"; } // Manage memory for DataTag objects. class Factory { @@ -809,7 +809,7 @@ class NoteTag : public DataTag { return std::move(Msg); } - StringRef getTagDescription() const override { + StringRef getDebugName() const override { // TODO: Remember a few examples of generated messages // and display them in the ExplodedGraph dump by // returning them from this function. diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h index fc83cf68acfc1..89da9defc5f79 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Checker.h +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -526,7 +526,7 @@ class CheckerBase : public CheckerFrontend, public CheckerBackend { public: /// Attached to nodes created by this checker class when the ExplodedGraph is /// dumped for debugging. - StringRef getTagDescription() const override; + StringRef getDebugName() const override; }; /// Simple checker classes that implement one frontend (i.e. checker name) @@ -546,7 +546,7 @@ class Checker : public CheckerBase, public CHECKs... { /// frontends) should derive from this template, specify all the implemented /// callbacks (i.e. classes like `check::PreStmt` or `eval::Call`) as template /// arguments of `FamilyChecker` and implement the pure virtual method -/// `StringRef getTagDescription()` which is inherited from `ProgramPointTag` +/// `StringRef getDebugName()` which is inherited from `ProgramPointTag` /// and should return a string identifying the class for debugging purposes. template <typename... CHECKs> class CheckerFamily : public CheckerBackend, public CHECKs... { diff --git a/clang/lib/Analysis/ProgramPoint.cpp b/clang/lib/Analysis/ProgramPoint.cpp index e508681410b0b..337ee18b3e4c2 100644 --- a/clang/lib/Analysis/ProgramPoint.cpp +++ b/clang/lib/Analysis/ProgramPoint.cpp @@ -357,6 +357,4 @@ SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider, StringRef Msg) : Desc((MsgProvider + " : " + Msg).str()) {} -StringRef SimpleProgramPointTag::getTagDescription() const { - return Desc; -} +StringRef SimpleProgramPointTag::getDebugName() const { return Desc; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 95a9582ecdcb1..164e79a142545 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -41,7 +41,7 @@ class DivZeroChecker : public CheckerFamily<check::PreStmt<BinaryOperator>> { void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; /// Identifies this checker family for debugging purposes. - StringRef getTagDescription() const override { return "DivZeroChecker"; } + StringRef getDebugName() const override { return "DivZeroChecker"; } }; } // end anonymous namespace diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 67429ee2c25f9..29df35c6f8f8c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -55,7 +55,7 @@ class VirtualCallChecker void checkPreCall(const CallEvent &Call, CheckerContext &C) const; /// Identifies this checker family for debugging purposes. - StringRef getTagDescription() const override { return "VirtualCallChecker"; } + StringRef getDebugName() const override { return "VirtualCallChecker"; } private: void registerCtorDtorCallInState(bool IsBeginFunction, diff --git a/clang/lib/StaticAnalyzer/Core/Checker.cpp b/clang/lib/StaticAnalyzer/Core/Checker.cpp index f5a07f5d305c5..54f07e40ae139 100644 --- a/clang/lib/StaticAnalyzer/Core/Checker.cpp +++ b/clang/lib/StaticAnalyzer/Core/Checker.cpp @@ -18,7 +18,7 @@ using namespace ento; int ImplicitNullDerefEvent::Tag; -StringRef CheckerBase::getTagDescription() const { return getName(); } +StringRef CheckerBase::getDebugName() const { return getName(); } void CheckerBackend::printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const {} @@ -29,4 +29,4 @@ CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName, CheckerProgramPointTag::CheckerProgramPointTag(const CheckerBase *Checker, StringRef Msg) - : SimpleProgramPointTag(Checker->getTagDescription(), Msg) {} + : SimpleProgramPointTag(Checker->getDebugName(), Msg) {} diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index 4c37b65ae5c68..bcc7a7e6da22f 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -138,7 +138,7 @@ namespace { std::string checkerScopeName(StringRef Name, const CheckerBackend *Checker) { if (!llvm::timeTraceProfilerEnabled()) return ""; - StringRef CheckerTag = Checker ? Checker->getTagDescription() : "<unknown>"; + StringRef CheckerTag = Checker ? Checker->getDebugName() : "<unknown>"; return (Name + ":" + CheckerTag).str(); } @@ -721,12 +721,12 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, "while the {2} checker also tried to evaluate the same call. At " "most one checker supposed to evaluate a call.", toString(Call), evaluatorChecker, - EvalCallChecker.Checker->getTagDescription()); + EvalCallChecker.Checker->getDebugName()); llvm_unreachable(AssertionMessage.c_str()); } #endif if (evaluated) { - evaluatorChecker = EvalCallChecker.Checker->getTagDescription(); + evaluatorChecker = EvalCallChecker.Checker->getDebugName(); Dst.insert(checkDst); #ifdef NDEBUG break; // on release don't check that no other checker also evals. @@ -798,7 +798,7 @@ void CheckerManager::runCheckersForPrintStateJson(raw_ostream &Out, continue; Indent(Out, Space, IsDot) - << "{ \"checker\": \"" << CT.second->getTagDescription() + << "{ \"checker\": \"" << CT.second->getDebugName() << "\", \"messages\": [" << NL; Indent(Out, InnerSpace, IsDot) << '\"' << TempBuf.str().trim() << '\"' << NL; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 86e2e8f634bfd..d7901aaf92485 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -3992,7 +3992,7 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits { OtherNode->getLocation().printJson(Out, /*NL=*/"\\l"); Out << ", \"tag\": "; if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag()) - Out << '\"' << Tag->getTagDescription() << '\"'; + Out << '\"' << Tag->getDebugName() << '\"'; else Out << "null"; Out << ", \"node_id\": " << OtherNode->getID() << From 4becdebce0160f2dd941709110aa6a9bd9368dc2 Mon Sep 17 00:00:00 2001 From: Balazs Benics <benicsbal...@gmail.com> Date: Thu, 15 May 2025 19:49:27 +0200 Subject: [PATCH 09/12] HACK: Smuggle in the checker name into the CheckerFamily class --- clang/include/clang/StaticAnalyzer/Core/Checker.h | 14 ++++++++++---- .../lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp | 3 --- .../StaticAnalyzer/Checkers/VirtualCallChecker.cpp | 3 --- clang/test/Analysis/ftime-trace.cpp | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h index 89da9defc5f79..fad1c9f591927 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Checker.h +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -526,7 +526,7 @@ class CheckerBase : public CheckerFrontend, public CheckerBackend { public: /// Attached to nodes created by this checker class when the ExplodedGraph is /// dumped for debugging. - StringRef getDebugName() const override; + StringRef getDebugName() const final; }; /// Simple checker classes that implement one frontend (i.e. checker name) @@ -545,16 +545,22 @@ class Checker : public CheckerBase, public CHECKs... { /// Checker families (where a single backend class implements multiple related /// frontends) should derive from this template, specify all the implemented /// callbacks (i.e. classes like `check::PreStmt` or `eval::Call`) as template -/// arguments of `FamilyChecker` and implement the pure virtual method -/// `StringRef getDebugName()` which is inherited from `ProgramPointTag` -/// and should return a string identifying the class for debugging purposes. +/// arguments of `FamilyChecker`. template <typename... CHECKs> class CheckerFamily : public CheckerBackend, public CHECKs... { public: template <typename CHECKER> static void _register(CHECKER *Chk, CheckerManager &Mgr) { + Chk->CheckerBackendName = Mgr.getCurrentCheckerName(); (CHECKs::_register(Chk, Mgr), ...); } + + /// Attached to nodes created by this checker class when the ExplodedGraph is + /// dumped for debugging. + StringRef getDebugName() const final { return CheckerBackendName; } + +private: + CheckerNameRef CheckerBackendName; }; template <typename EVENT> diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 164e79a142545..1aa7705e06c0f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -39,9 +39,6 @@ class DivZeroChecker : public CheckerFamily<check::PreStmt<BinaryOperator>> { categories::TaintedData}; void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; - - /// Identifies this checker family for debugging purposes. - StringRef getDebugName() const override { return "DivZeroChecker"; } }; } // end anonymous namespace diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 29df35c6f8f8c..321fedfc4df1c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -54,9 +54,6 @@ class VirtualCallChecker void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; void checkPreCall(const CallEvent &Call, CheckerContext &C) const; - /// Identifies this checker family for debugging purposes. - StringRef getDebugName() const override { return "VirtualCallChecker"; } - private: void registerCtorDtorCallInState(bool IsBeginFunction, CheckerContext &C) const; diff --git a/clang/test/Analysis/ftime-trace.cpp b/clang/test/Analysis/ftime-trace.cpp index e349eab8b62ad..2940ff2e02891 100644 --- a/clang/test/Analysis/ftime-trace.cpp +++ b/clang/test/Analysis/ftime-trace.cpp @@ -39,7 +39,7 @@ // Finally, each checker call back is also present: // -// CHECK: "name": "Total Stmt:DivZeroChecker", +// CHECK: "name": "Total Stmt:core.DivideZero", // CHECK-NEXT: "args": { // CHECK-NEXT: "count": {{[0-9]+}}, // CHECK-NEXT: "avg ms": {{[0-9]+}} From 13f4a3011e76c5665ca295ef597eb130f356df68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Mon, 19 May 2025 17:10:54 +0200 Subject: [PATCH 10/12] Use registration function name fragment as checker family debug name This fragment is often the same as the class name. --- .../clang/StaticAnalyzer/Core/Checker.h | 3 ++- .../StaticAnalyzer/Core/CheckerManager.h | 10 ++++++++- .../StaticAnalyzer/Core/CheckerRegistryData.h | 7 ++++--- .../StaticAnalyzer/Frontend/CheckerRegistry.h | 21 +++++++++++++++---- .../Frontend/CheckerRegistry.cpp | 12 ++++++----- clang/test/Analysis/ftime-trace.cpp | 2 +- 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h index fad1c9f591927..2992ec54e9746 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Checker.h +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -551,7 +551,8 @@ class CheckerFamily : public CheckerBackend, public CHECKs... { public: template <typename CHECKER> static void _register(CHECKER *Chk, CheckerManager &Mgr) { - Chk->CheckerBackendName = Mgr.getCurrentCheckerName(); + if (Chk->getDebugName().empty()) + Chk->CheckerBackendName = Mgr.getCurrentCheckerDebugName(); (CHECKs::_register(Chk, Mgr), ...); } diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 58f59f7ab049f..14d904be16950 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -129,6 +129,7 @@ class CheckerManager { const AnalyzerOptions &AOptions; const Preprocessor *PP = nullptr; CheckerNameRef CurrentCheckerName; + CheckerNameRef CurrentCheckerDebugName; DiagnosticsEngine &Diags; std::unique_ptr<CheckerRegistryData> RegistryData; @@ -159,9 +160,16 @@ class CheckerManager { ~CheckerManager(); - void setCurrentCheckerName(CheckerNameRef name) { CurrentCheckerName = name; } + void setCurrentCheckerName(CheckerNameRef Name) { CurrentCheckerName = Name; } CheckerNameRef getCurrentCheckerName() const { return CurrentCheckerName; } + void setCurrentCheckerDebugName(CheckerNameRef Name) { + CurrentCheckerDebugName = Name; + } + CheckerNameRef getCurrentCheckerDebugName() const { + return CurrentCheckerDebugName; + } + bool hasPathSensitiveCheckers() const; const LangOptions &getLangOpts() const { return LangOpts; } diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerRegistryData.h b/clang/include/clang/StaticAnalyzer/Core/CheckerRegistryData.h index 43248d8e6bb8d..b51e639f7ba92 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerRegistryData.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerRegistryData.h @@ -104,6 +104,7 @@ struct CheckerInfo { RegisterCheckerFn Initialize = nullptr; ShouldRegisterFunction ShouldRegister = nullptr; StringRef FullName; + StringRef DebugName; StringRef Desc; StringRef DocumentationUri; CmdLineOptionList CmdLineOptions; @@ -128,9 +129,9 @@ struct CheckerInfo { } CheckerInfo(RegisterCheckerFn Fn, ShouldRegisterFunction sfn, StringRef Name, - StringRef Desc, StringRef DocsUri, bool IsHidden) - : Initialize(Fn), ShouldRegister(sfn), FullName(Name), Desc(Desc), - DocumentationUri(DocsUri), IsHidden(IsHidden) {} + StringRef DName, StringRef Desc, StringRef DocsUri, bool IsHidden) + : Initialize(Fn), ShouldRegister(sfn), FullName(Name), DebugName(DName), + Desc(Desc), DocumentationUri(DocsUri), IsHidden(IsHidden) {} // Used for lower_bound. explicit CheckerInfo(StringRef FullName) : FullName(FullName) {} diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h index 43dbfb1585151..49f0ed070b99f 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h @@ -50,8 +50,8 @@ // checker. // // The clang_registerCheckers function may add any number of checkers to the -// registry. If any checkers require additional initialization, use the three- -// argument form of CheckerRegistry::addChecker. +// registry. If any checkers require additional initialization, use the +// non-templated form of CheckerRegistry::addChecker. // // To load a checker plugin, specify the full path to the dynamic library as // the argument to the -load option in the cc1 frontend. You can then enable @@ -115,9 +115,22 @@ class CheckerRegistry { public: /// Adds a checker to the registry. Use this non-templated overload when your /// checker requires custom initialization. - void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction sfn, + void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn, + StringRef FullName, StringRef DebugName, StringRef Desc, + StringRef DocsUri, bool IsHidden); + + /// Adds a checker to the registry. This overload doesn't take a `DebugName` + /// (which usually looks like `DivZeroChecker`), so it uses the user-facing + /// `FullName` (which usually looks like ``core.DivideZero`) as a debug name. + /// THIS IS DEPRECATED and is only provided to preserve compatibility with + /// legacy plugins. + /// TODO: Eventually remove this from the codebase. + void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn, StringRef FullName, StringRef Desc, StringRef DocsUri, - bool IsHidden); + bool IsHidden) { + addChecker(Fn, Sfn, FullName, /*DebugName =*/FullName, Desc, DocsUri, + IsHidden); + } /// Adds a checker to the registry. Use this templated overload when your /// checker does not require any custom initialization. diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index 17af7bf0185d7..2e3eebf214def 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -56,8 +56,8 @@ CheckerRegistry::CheckerRegistry( // Register builtin checkers. #define GET_CHECKERS #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \ - addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \ - DOC_URI, IS_HIDDEN); + addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, #CLASS, \ + HELPTEXT, DOC_URI, IS_HIDDEN); #define GET_PACKAGES #define PACKAGE(FULLNAME) addPackage(FULLNAME); @@ -433,9 +433,10 @@ void CheckerRegistry::addPackageOption(StringRef OptionType, void CheckerRegistry::addChecker(RegisterCheckerFn Rfn, ShouldRegisterFunction Sfn, StringRef Name, - StringRef Desc, StringRef DocsUri, - bool IsHidden) { - Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden); + StringRef DebugName, StringRef Desc, + StringRef DocsUri, bool IsHidden) { + Data.Checkers.emplace_back(Rfn, Sfn, Name, DebugName, Desc, DocsUri, + IsHidden); // Record the presence of the checker in its packages. StringRef PackageName, LeafName; @@ -462,6 +463,7 @@ void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { // Initialize the CheckerManager with all enabled checkers. for (const auto *Checker : Data.EnabledCheckers) { CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName)); + CheckerMgr.setCurrentCheckerDebugName(CheckerNameRef(Checker->DebugName)); Checker->Initialize(CheckerMgr); } } diff --git a/clang/test/Analysis/ftime-trace.cpp b/clang/test/Analysis/ftime-trace.cpp index 2940ff2e02891..e349eab8b62ad 100644 --- a/clang/test/Analysis/ftime-trace.cpp +++ b/clang/test/Analysis/ftime-trace.cpp @@ -39,7 +39,7 @@ // Finally, each checker call back is also present: // -// CHECK: "name": "Total Stmt:core.DivideZero", +// CHECK: "name": "Total Stmt:DivZeroChecker", // CHECK-NEXT: "args": { // CHECK-NEXT: "count": {{[0-9]+}}, // CHECK-NEXT: "avg ms": {{[0-9]+}} From ffe6ac44f1959fcb0eb91ef3f8e80dfbb476d91a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Mon, 19 May 2025 17:13:41 +0200 Subject: [PATCH 11/12] s/FamilyChecker/CheckerFamily/ in comment --- clang/include/clang/StaticAnalyzer/Core/Checker.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h index 2992ec54e9746..613f8db517860 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Checker.h +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -545,7 +545,7 @@ class Checker : public CheckerBase, public CHECKs... { /// Checker families (where a single backend class implements multiple related /// frontends) should derive from this template, specify all the implemented /// callbacks (i.e. classes like `check::PreStmt` or `eval::Call`) as template -/// arguments of `FamilyChecker`. +/// arguments of `CheckerFamily`. template <typename... CHECKs> class CheckerFamily : public CheckerBackend, public CHECKs... { public: From 84eb5afa867f8f12db259053cb768919e0418ea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <donat.n...@ericsson.com> Date: Tue, 20 May 2025 15:51:48 +0200 Subject: [PATCH 12/12] Refactor use of CheckerRegistry::addChecker() --- .../StaticAnalyzer/Frontend/CheckerRegistry.h | 68 +++++++++---------- .../CheckerDependencyHandling.cpp | 12 ++-- .../CheckerOptionHandling.cpp | 13 ++-- .../SampleAnalyzer/MainCallChecker.cpp | 27 +++++--- .../BugReportInterestingnessTest.cpp | 4 +- .../StaticAnalyzer/CallDescriptionTest.cpp | 3 +- .../StaticAnalyzer/CallEventTest.cpp | 3 +- .../ConflictingEvalCallsTest.cpp | 6 +- .../StaticAnalyzer/ExprEngineVisitTest.cpp | 11 ++- .../FalsePositiveRefutationBRVisitorTest.cpp | 4 +- .../MemRegionDescriptiveNameTest.cpp | 3 +- .../NoStateChangeFuncVisitorTest.cpp | 11 +-- .../StaticAnalyzer/ObjcBug-124477.cpp | 4 +- .../RegisterCustomCheckersTest.cpp | 17 ++--- .../StaticAnalyzer/SValSimplifyerTest.cpp | 3 +- clang/unittests/StaticAnalyzer/SValTest.cpp | 5 +- .../TestReturnValueUnderConstruction.cpp | 6 +- 17 files changed, 101 insertions(+), 99 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h index 49f0ed070b99f..cca60b0b2df5f 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h @@ -38,20 +38,33 @@ // function clang_registerCheckers. For example: // // extern "C" -// void clang_registerCheckers (CheckerRegistry ®istry) { -// registry.addChecker<MainCallChecker>("example.MainCallChecker", -// "Disallows calls to functions called main"); +// void clang_registerCheckers(CheckerRegistry &Registry) { +// Registry.addChecker( +// registerMainCallChecker, +// shouldRegisterMainCallChecker, +// "example.MainCallChecker", +// "MainCallChecker", +// "Example Description", +// "example.mychecker.documentation.nonexistent.html", +// /*isHidden=*/ false); // } // -// The first method argument is the full name of the checker, including its -// enclosing package. By convention, the registered name of a checker is the -// name of the associated class (the template argument). -// The second method argument is a short human-readable description of the -// checker. +// The first two arguments are the registration handling functions, which +// in a simple case look like // -// The clang_registerCheckers function may add any number of checkers to the -// registry. If any checkers require additional initialization, use the -// non-templated form of CheckerRegistry::addChecker. +// void registerMainCallChecker(CheckerManager &Mgr) { +// Mgr.registerChecker<MainCallChecker>(); +// } +// +// bool shouldRegisterMainCallChecker(const CheckerManager &) { +// return true; +// } +// +// The third argument is the full name of the checker (including its package), +// the fourth name is the internal DebugName (by convention, the name of the +// class), the fifth argument is a short documentation, the sixth argument is +// an url to a documentation page, and the seventh argument should be false for +// normal user-facing checkers. // // To load a checker plugin, specify the full path to the dynamic library as // the argument to the -load option in the cc1 frontend. You can then enable @@ -60,7 +73,7 @@ // clang -cc1 -load </path/to/plugin.dylib> -analyze // -analyzer-checker=<example.MainCallChecker> // -// For a complete working example, see examples/analyzer-plugin. +// For a complete example, see clang/lib/Analysis/plugins/SampleAnalyzer #ifndef CLANG_ANALYZER_API_VERSION_STRING // FIXME: The Clang version string is not particularly granular; @@ -119,32 +132,13 @@ class CheckerRegistry { StringRef FullName, StringRef DebugName, StringRef Desc, StringRef DocsUri, bool IsHidden); - /// Adds a checker to the registry. This overload doesn't take a `DebugName` - /// (which usually looks like `DivZeroChecker`), so it uses the user-facing - /// `FullName` (which usually looks like ``core.DivideZero`) as a debug name. - /// THIS IS DEPRECATED and is only provided to preserve compatibility with - /// legacy plugins. - /// TODO: Eventually remove this from the codebase. - void addChecker(RegisterCheckerFn Fn, ShouldRegisterFunction Sfn, - StringRef FullName, StringRef Desc, StringRef DocsUri, - bool IsHidden) { - addChecker(Fn, Sfn, FullName, /*DebugName =*/FullName, Desc, DocsUri, - IsHidden); - } - - /// Adds a checker to the registry. Use this templated overload when your - /// checker does not require any custom initialization. - /// This function isn't really needed and probably causes more headaches than - /// the tiny convenience that it provides, but external plugins might use it, - /// and there isn't a strong incentive to remove it. - template <class T> - void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri, - bool IsHidden = false) { - // Avoid MSVC's Compiler Error C2276: - // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx + /// Add a mock checker to the registry for testing purposes, without + /// specifying metadata that is not relevant in simple tests. + template <class T> void addMockChecker(StringRef FullName) { addChecker(&CheckerRegistry::initializeManager<CheckerManager, T>, - &CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri, - IsHidden); + &CheckerRegistry::returnTrue<T>, FullName, + /*DebugName=*/"TestChecker", /*Desc=*/"", /*DocsUri=*/"", + /*IsHidden=*/false); } /// Makes the checker with the full name \p fullName depend on the checker diff --git a/clang/lib/Analysis/plugins/CheckerDependencyHandling/CheckerDependencyHandling.cpp b/clang/lib/Analysis/plugins/CheckerDependencyHandling/CheckerDependencyHandling.cpp index be8e1200d0bfd..77ba874578675 100644 --- a/clang/lib/Analysis/plugins/CheckerDependencyHandling/CheckerDependencyHandling.cpp +++ b/clang/lib/Analysis/plugins/CheckerDependencyHandling/CheckerDependencyHandling.cpp @@ -3,6 +3,9 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +// This barebones plugin is used by clang/test/Analysis/checker-plugins.c +// to test dependency handling among checkers loaded from plugins. + using namespace clang; using namespace ento; @@ -16,12 +19,11 @@ struct DependendentChecker : public Checker<check::BeginFunction> { } // end anonymous namespace // Register plugin! -extern "C" void clang_registerCheckers(CheckerRegistry ®istry) { - registry.addChecker<Dependency>("example.Dependency", "", ""); - registry.addChecker<DependendentChecker>("example.DependendentChecker", "", - ""); +extern "C" void clang_registerCheckers(CheckerRegistry &Registry) { + Registry.addMockChecker<Dependency>("example.Dependency"); + Registry.addMockChecker<DependendentChecker>("example.DependendentChecker"); - registry.addDependency("example.DependendentChecker", "example.Dependency"); + Registry.addDependency("example.DependendentChecker", "example.Dependency"); } extern "C" const char clang_analyzerAPIVersionString[] = diff --git a/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp b/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp index 32fba9c93752c..9cc641d23dc4b 100644 --- a/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp +++ b/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp @@ -6,6 +6,9 @@ using namespace clang; using namespace ento; +// This barebones plugin is used by clang/test/Analysis/checker-plugins.c +// to test option handling on checkers loaded from plugins. + namespace { struct MyChecker : public Checker<check::BeginFunction> { void checkBeginFunction(CheckerContext &Ctx) const {} @@ -26,13 +29,13 @@ bool shouldRegisterMyChecker(const CheckerManager &mgr) { return true; } } // end anonymous namespace // Register plugin! -extern "C" void clang_registerCheckers(CheckerRegistry ®istry) { - registry.addChecker(registerMyChecker, shouldRegisterMyChecker, - "example.MyChecker", "Example Description", +extern "C" void clang_registerCheckers(CheckerRegistry &Registry) { + Registry.addChecker(registerMyChecker, shouldRegisterMyChecker, + "example.MyChecker", "MyChecker", "Example Description", "example.mychecker.documentation.nonexistent.html", - /*isHidden*/false); + /*isHidden*/ false); - registry.addCheckerOption(/*OptionType*/ "bool", + Registry.addCheckerOption(/*OptionType*/ "bool", /*CheckerFullName*/ "example.MyChecker", /*OptionName*/ "ExampleOption", /*DefaultValStr*/ "false", diff --git a/clang/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp b/clang/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp index fd210d733fd0a..e9c6092fe0ac2 100644 --- a/clang/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp +++ b/clang/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp @@ -3,16 +3,26 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +// This simple plugin is used by clang/test/Analysis/checker-plugins.c +// to test use a checker that is defined in a plugin. + using namespace clang; using namespace ento; namespace { class MainCallChecker : public Checker<check::PreStmt<CallExpr>> { - mutable std::unique_ptr<BugType> BT; + + BugType BT{this, "call to main", "example analyzer plugin"}; public: void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; }; + +void registerMainCallChecker(CheckerManager &Mgr) { + Mgr.registerChecker<MainCallChecker>(); +} + +bool shouldRegisterMainCallChecker(const CheckerManager &) { return true; } } // end anonymous namespace void MainCallChecker::checkPreStmt(const CallExpr *CE, @@ -33,21 +43,20 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE, if (!N) return; - if (!BT) - BT.reset(new BugType(this, "call to main", "example analyzer plugin")); - auto report = - std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N); + std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N); report->addRange(Callee->getSourceRange()); C.emitReport(std::move(report)); } } // Register plugin! -extern "C" void clang_registerCheckers(CheckerRegistry ®istry) { - registry.addChecker<MainCallChecker>( - "example.MainCallChecker", "Disallows calls to functions called main", - ""); +extern "C" void clang_registerCheckers(CheckerRegistry &Registry) { + Registry.addChecker(registerMainCallChecker, shouldRegisterMainCallChecker, + "example.MainCallChecker", "MainCallChecker", + "Example Description", + "example.mychecker.documentation.nonexistent.html", + /*isHidden=*/false); } extern "C" const char clang_analyzerAPIVersionString[] = diff --git a/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp b/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp index 0ef63b049621e..5595363f669f9 100644 --- a/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp +++ b/clang/unittests/StaticAnalyzer/BugReportInterestingnessTest.cpp @@ -119,8 +119,8 @@ class TestAction : public ASTFrontendAction { std::make_unique<VerifyPathDiagnosticConsumer>( std::move(ExpectedDiags), Compiler.getSourceManager())); AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<InterestingnessTestChecker>("test.Interestingness", - "Description", ""); + Registry.addMockChecker<InterestingnessTestChecker>( + "test.Interestingness"); }); Compiler.getAnalyzerOpts().CheckersAndPackages = { {"test.Interestingness", true}}; diff --git a/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp b/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp index 434c1d1526a22..6dde8c2f50534 100644 --- a/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp +++ b/clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp @@ -620,8 +620,7 @@ void addCallDescChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"test.CallDescChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<CallDescChecker>("test.CallDescChecker", "Description", - ""); + Registry.addMockChecker<CallDescChecker>("test.CallDescChecker"); }); } diff --git a/clang/unittests/StaticAnalyzer/CallEventTest.cpp b/clang/unittests/StaticAnalyzer/CallEventTest.cpp index 2843572e5f800..22c50d168af99 100644 --- a/clang/unittests/StaticAnalyzer/CallEventTest.cpp +++ b/clang/unittests/StaticAnalyzer/CallEventTest.cpp @@ -55,8 +55,7 @@ void addCXXDeallocatorChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"test.CXXDeallocator", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<CXXDeallocatorChecker>("test.CXXDeallocator", - "Description", ""); + Registry.addMockChecker<CXXDeallocatorChecker>("test.CXXDeallocator"); }); } diff --git a/clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp b/clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp index e410cca076637..b11eeb1d290b6 100644 --- a/clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp +++ b/clang/unittests/StaticAnalyzer/ConflictingEvalCallsTest.cpp @@ -33,10 +33,8 @@ void addEvalFooCheckers(AnalysisASTConsumer &AnalysisConsumer, AnOpts.CheckersAndPackages = {{"test.EvalFoo1", true}, {"test.EvalFoo2", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<EvalCallFoo1>("test.EvalFoo1", "EmptyDescription", - "EmptyDocsUri"); - Registry.addChecker<EvalCallFoo2>("test.EvalFoo2", "EmptyDescription", - "EmptyDocsUri"); + Registry.addMockChecker<EvalCallFoo1>("test.EvalFoo1"); + Registry.addMockChecker<EvalCallFoo2>("test.EvalFoo2"); }); } } // namespace diff --git a/clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp b/clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp index b6eeb9ce37386..94ebbf878b92f 100644 --- a/clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp +++ b/clang/unittests/StaticAnalyzer/ExprEngineVisitTest.cpp @@ -77,8 +77,8 @@ void addExprEngineVisitPreChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"ExprEngineVisitPreChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<ExprEngineVisitPreChecker>("ExprEngineVisitPreChecker", - "Desc", "DocsURI"); + Registry.addMockChecker<ExprEngineVisitPreChecker>( + "ExprEngineVisitPreChecker"); }); } @@ -86,8 +86,8 @@ void addExprEngineVisitPostChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"ExprEngineVisitPostChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<ExprEngineVisitPostChecker>( - "ExprEngineVisitPostChecker", "Desc", "DocsURI"); + Registry.addMockChecker<ExprEngineVisitPostChecker>( + "ExprEngineVisitPostChecker"); }); } @@ -95,8 +95,7 @@ void addMemAccessChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"MemAccessChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<MemAccessChecker>("MemAccessChecker", "Desc", - "DocsURI"); + Registry.addMockChecker<MemAccessChecker>("MemAccessChecker"); }); } diff --git a/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp b/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp index 8f0a96d41e752..44bd9f2821608 100644 --- a/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp +++ b/clang/unittests/StaticAnalyzer/FalsePositiveRefutationBRVisitorTest.cpp @@ -92,8 +92,8 @@ void addFalsePositiveGenerator(AnalysisASTConsumer &AnalysisConsumer, AnOpts.CheckersAndPackages = {{"test.FalsePositiveGenerator", true}, {"debug.ViewExplodedGraph", false}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<FalsePositiveGenerator>( - "test.FalsePositiveGenerator", "EmptyDescription", "EmptyDocsUri"); + Registry.addMockChecker<FalsePositiveGenerator>( + "test.FalsePositiveGenerator"); }); } diff --git a/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp b/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp index 0f6e49bf42f4a..cfd0c8cf971c6 100644 --- a/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp +++ b/clang/unittests/StaticAnalyzer/MemRegionDescriptiveNameTest.cpp @@ -45,8 +45,7 @@ void addDescriptiveNameChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"DescriptiveNameChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<DescriptiveNameChecker>("DescriptiveNameChecker", - "Desc", "DocsURI"); + Registry.addMockChecker<DescriptiveNameChecker>("DescriptiveNameChecker"); }); } diff --git a/clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp b/clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp index a9033425dfb51..42f91af551aba 100644 --- a/clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp +++ b/clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp @@ -138,9 +138,9 @@ void addNonThoroughStatefulChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"test.StatefulChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry - .addChecker<StatefulChecker<NonThoroughErrorNotPreventedFuncVisitor>>( - "test.StatefulChecker", "Description", ""); + Registry.addMockChecker< + StatefulChecker<NonThoroughErrorNotPreventedFuncVisitor>>( + "test.StatefulChecker"); }); } @@ -232,8 +232,9 @@ void addThoroughStatefulChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"test.StatefulChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<StatefulChecker<ThoroughErrorNotPreventedFuncVisitor>>( - "test.StatefulChecker", "Description", ""); + Registry + .addMockChecker<StatefulChecker<ThoroughErrorNotPreventedFuncVisitor>>( + "test.StatefulChecker"); }); } diff --git a/clang/unittests/StaticAnalyzer/ObjcBug-124477.cpp b/clang/unittests/StaticAnalyzer/ObjcBug-124477.cpp index 51bd33210032c..7a6d74faec9aa 100644 --- a/clang/unittests/StaticAnalyzer/ObjcBug-124477.cpp +++ b/clang/unittests/StaticAnalyzer/ObjcBug-124477.cpp @@ -36,8 +36,8 @@ void addFlagFlipperChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"test.FlipFlagOnCheckLocation", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<FlipFlagOnCheckLocation>("test.FlipFlagOnCheckLocation", - "Description", ""); + Registry.addMockChecker<FlipFlagOnCheckLocation>( + "test.FlipFlagOnCheckLocation"); }); } diff --git a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp index 454eee9cf7e0a..abe7edad9c349 100644 --- a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp +++ b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp @@ -44,7 +44,7 @@ void addCustomChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"test.CustomChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<CustomChecker>("test.CustomChecker", "Description", ""); + Registry.addMockChecker<CustomChecker>("test.CustomChecker"); }); } @@ -73,8 +73,7 @@ void addLocIncDecChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"test.LocIncDecChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<CustomChecker>("test.LocIncDecChecker", "Description", - ""); + Registry.addMockChecker<CustomChecker>("test.LocIncDecChecker"); }); } @@ -117,9 +116,10 @@ bool shouldRegisterCheckerRegistrationOrderPrinter(const CheckerManager &mgr) { } void addCheckerRegistrationOrderPrinter(CheckerRegistry &Registry) { - Registry.addChecker(registerCheckerRegistrationOrderPrinter, - shouldRegisterCheckerRegistrationOrderPrinter, - "test.RegistrationOrder", "Description", "", false); + Registry.addChecker( + registerCheckerRegistrationOrderPrinter, + shouldRegisterCheckerRegistrationOrderPrinter, "test.RegistrationOrder", + "CheckerRegistrationOrderPrinter", "Description", "", false); } #define UNITTEST_CHECKER(CHECKER_NAME, DIAG_MSG) \ @@ -137,7 +137,8 @@ void addCheckerRegistrationOrderPrinter(CheckerRegistry &Registry) { } \ void add##CHECKER_NAME(CheckerRegistry &Registry) { \ Registry.addChecker(register##CHECKER_NAME, shouldRegister##CHECKER_NAME, \ - "test." #CHECKER_NAME, "Description", "", false); \ + "test." #CHECKER_NAME, #CHECKER_NAME, "Description", \ + "", false); \ } UNITTEST_CHECKER(StrongDep, "Strong") @@ -154,7 +155,7 @@ void addDep(AnalysisASTConsumer &AnalysisConsumer, {"test.RegistrationOrder", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { Registry.addChecker(registerStrongDep, shouldRegisterStrongFALSE, - "test.Strong", "Description", "", false); + "test.Strong", "StrongDep", "Description", "", false); addStrongDep(Registry); addDep(Registry); addCheckerRegistrationOrderPrinter(Registry); diff --git a/clang/unittests/StaticAnalyzer/SValSimplifyerTest.cpp b/clang/unittests/StaticAnalyzer/SValSimplifyerTest.cpp index 85cfe2c1965ac..3aefac1fd867c 100644 --- a/clang/unittests/StaticAnalyzer/SValSimplifyerTest.cpp +++ b/clang/unittests/StaticAnalyzer/SValSimplifyerTest.cpp @@ -68,8 +68,7 @@ static void addSimplifyChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"SimplifyChecker", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<SimplifyChecker>("SimplifyChecker", "EmptyDescription", - "EmptyDocsUri"); + Registry.addMockChecker<SimplifyChecker>("SimplifyChecker"); }); } diff --git a/clang/unittests/StaticAnalyzer/SValTest.cpp b/clang/unittests/StaticAnalyzer/SValTest.cpp index d8897b0f2183d..e36c9b2103495 100644 --- a/clang/unittests/StaticAnalyzer/SValTest.cpp +++ b/clang/unittests/StaticAnalyzer/SValTest.cpp @@ -139,10 +139,9 @@ class SValTest : public testing::TestWithParam<TestClangConfig> {}; \ void add##NAME##SValCollector(AnalysisASTConsumer &AnalysisConsumer, \ AnalyzerOptions &AnOpts) { \ - AnOpts.CheckersAndPackages = {{"test.##NAME##SValCollector", true}}; \ + AnOpts.CheckersAndPackages = {{"test.##NAME##SValColl", true}}; \ AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { \ - Registry.addChecker<NAME##SValCollector>("test.##NAME##SValCollector", \ - "Description", ""); \ + Registry.addMockChecker<NAME##SValCollector>("test.##NAME##SValColl"); \ }); \ } \ \ diff --git a/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp b/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp index 5fc084a48667c..1d56a24235556 100644 --- a/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp +++ b/clang/unittests/StaticAnalyzer/TestReturnValueUnderConstruction.cpp @@ -49,9 +49,9 @@ void addTestReturnValueUnderConstructionChecker( AnOpts.CheckersAndPackages = {{"test.TestReturnValueUnderConstruction", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker<TestReturnValueUnderConstructionChecker>( - "test.TestReturnValueUnderConstruction", "", ""); - }); + Registry.addMockChecker<TestReturnValueUnderConstructionChecker>( + "test.TestReturnValueUnderConstruction"); + }); } TEST(TestReturnValueUnderConstructionChecker, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits