From b52f4a65849ab4262f1ded6b48ed30eec0e9724d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= Date: Tue, 17 Jun 2025 15:56:54 +0200 Subject: [PATCH 1/2] [analyzer] Conversion to CheckerFamily: DynamicTypePropagation This commit converts the class DynamicTypePropagation to a very simple checker family, which has only one checker frontend -- but also supports enabling the backend ("modeling checker") without the frontend. As a tangentially related change, this commit adds the backend of DynamicTypePropagation as a dependency of alpha.core.DynamicTypeChecker, in Checkers.td, because the header comment of DynamicTypeChecker.cpp claims that it depends on DynamicTypePropagation and a cursory reading of the source code seems to confirm this. (The lack of this dependency relationship didn't cause problems, because 'core.DynamicTypePropagation' is in the group 'core', so it is practically always active. However, explicitly declaring the dependency clarifies the fact that the separate existence of the modeling checker is warranted.) --- .../clang/StaticAnalyzer/Checkers/Checkers.td | 10 ++-- .../Checkers/DynamicTypePropagation.cpp | 51 +++++++++---------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 2a96df80d1001..789a18ff11043 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -294,10 +294,12 @@ def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">, "Either the comparison is useless or there is division by zero.">, Documentation; -def DynamicTypeChecker : Checker<"DynamicTypeChecker">, - HelpText<"Check for cases where the dynamic and the static type of an object " - "are unrelated.">, - Documentation; +def DynamicTypeChecker + : Checker<"DynamicTypeChecker">, + HelpText<"Check for cases where the dynamic and the static type of an " + "object are unrelated.">, + Dependencies<[DynamicTypePropagation]>, + Documentation; def StackAddrAsyncEscapeChecker : Checker<"StackAddressAsyncEscape">, HelpText<"Check that addresses to stack memory do not escape the function">, diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 344be0b176c54..87fa233a94413 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -49,15 +49,19 @@ REGISTER_MAP_WITH_PROGRAMSTATE(MostSpecializedTypeArgsMap, SymbolRef, const ObjCObjectPointerType *) namespace { -class DynamicTypePropagation: - public Checker< check::PreCall, - check::PostCall, - check::DeadSymbols, - check::PostStmt, - check::PostStmt, - check::PreObjCMessage, - check::PostObjCMessage > { +class DynamicTypePropagation + : public CheckerFamily, + check::PostStmt, check::PreObjCMessage, + check::PostObjCMessage> { +public: + // This checker family implements only one frontend, but -- unlike a simple + // Checker -- its backend can be enabled (by the checker DynamicTypeChecker + // which depends on it) without enabling the frontend. + CheckerFrontendWithBugType ObjCGenericsChecker{ + "Generics", categories::CoreFoundationObjectiveC}; +private: /// Return a better dynamic type if one can be derived from the cast. const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, CheckerContext &C) const; @@ -66,13 +70,6 @@ class DynamicTypePropagation: ProgramStateRef &State, CheckerContext &C) const; - mutable std::unique_ptr ObjCGenericsBugType; - void initBugType() const { - if (!ObjCGenericsBugType) - ObjCGenericsBugType.reset(new BugType( - GenericCheckName, "Generics", categories::CoreFoundationObjectiveC)); - } - class GenericsBugVisitor : public BugReporterVisitor { public: GenericsBugVisitor(SymbolRef S) : Sym(S) {} @@ -106,9 +103,8 @@ class DynamicTypePropagation: void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; - /// This value is set to true, when the Generics checker is turned on. - bool CheckGenerics = false; - CheckerNameRef GenericCheckName; + /// Identifies this checker family for debugging purposes. + StringRef getDebugTag() const override { return "DynamicTypePropagation"; } }; bool isObjCClassType(QualType Type) { @@ -1026,10 +1022,9 @@ void DynamicTypePropagation::reportGenericsBug( const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, ExplodedNode *N, SymbolRef Sym, CheckerContext &C, const Stmt *ReportedNode) const { - if (!CheckGenerics) + if (!ObjCGenericsChecker.isEnabled()) return; - initBugType(); SmallString<192> Buf; llvm::raw_svector_ostream OS(Buf); OS << "Conversion from value of type '"; @@ -1037,7 +1032,7 @@ void DynamicTypePropagation::reportGenericsBug( OS << "' to incompatible type '"; QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); OS << "'"; - auto R = std::make_unique(*ObjCGenericsBugType, + auto R = std::make_unique(ObjCGenericsChecker, OS.str(), N); R->markInteresting(Sym); R->addVisitor(std::make_unique(Sym)); @@ -1102,18 +1097,20 @@ PathDiagnosticPieceRef DynamicTypePropagation::GenericsBugVisitor::VisitNode( } /// Register checkers. -void ento::registerObjCGenericsChecker(CheckerManager &mgr) { - DynamicTypePropagation *checker = mgr.getChecker(); - checker->CheckGenerics = true; - checker->GenericCheckName = mgr.getCurrentCheckerName(); +void ento::registerObjCGenericsChecker(CheckerManager &Mgr) { + Mgr.getChecker()->ObjCGenericsChecker.enable(Mgr); } bool ento::shouldRegisterObjCGenericsChecker(const CheckerManager &mgr) { return true; } -void ento::registerDynamicTypePropagation(CheckerManager &mgr) { - mgr.registerChecker(); +void ento::registerDynamicTypePropagation(CheckerManager &Mgr) { + // The checker 'core.DynamicTypeChecker' relies on the modeling implemented + // in the class 'DynamicTypePropagation', so this "modeling checker" can + // register the 'DynamicTypePropagation' backend for its callbacks without + // enabling its frontend. + Mgr.getChecker(); } bool ento::shouldRegisterDynamicTypePropagation(const CheckerManager &mgr) { From 4c0a6269bd8294eb2ecaa86fbafddc759a893139 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Don=C3=A1t=20Nagy?= Date: Thu, 19 Jun 2025 13:52:54 +0200 Subject: [PATCH 2/2] Get rid of two unused parameter names Just some drive-by prettification to get rid of the lowercase name. --- clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 87fa233a94413..4982cd59b0a4a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -1101,7 +1101,7 @@ void ento::registerObjCGenericsChecker(CheckerManager &Mgr) { Mgr.getChecker()->ObjCGenericsChecker.enable(Mgr); } -bool ento::shouldRegisterObjCGenericsChecker(const CheckerManager &mgr) { +bool ento::shouldRegisterObjCGenericsChecker(const CheckerManager &) { return true; } @@ -1113,6 +1113,6 @@ void ento::registerDynamicTypePropagation(CheckerManager &Mgr) { Mgr.getChecker(); } -bool ento::shouldRegisterDynamicTypePropagation(const CheckerManager &mgr) { +bool ento::shouldRegisterDynamicTypePropagation(const CheckerManager &) { return true; }