llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balazs Benics (steakhal)

<details>
<summary>Changes</summary>

If we were to delay checker constructions after we have a filled ASTContext, 
then we could get rid of a bunch of "lazy initializers" in checkers.

Turns out in the register functions of the checkers we could transfer the 
ASTContext and all other things to checkers, so those could benefit from 
in-class initializers and const fields.

For example, if a checker would take the ASTContext as the first field, then 
the rest of the fields could use it in their in-class initializers, so the ctor 
of the checker would only need to set a single field!

This would open uup countless opportunities for cleaning up the asthetics of 
our checkers.

I attached a single use-case for the AST and the PP as demonstrating purposes. 
You can imagine the rest.

**FYI: This may be a breaking change** to some downstream users that may had 
some means to attach different listeners and what not to e.g. the Preprocessor 
inside their checker register functions. Since we delay the calls to these 
register fns after parsing is already done, they would of course miss the 
parsing Preprocessor events.

---
Full diff: https://github.com/llvm/llvm-project/pull/127409.diff


3 Files Affected:

- (modified) 
clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h (+17) 
- (modified) clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp (+32-29) 
- (modified) clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (+8-10) 


``````````diff
diff --git 
a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h 
b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
index b4afaaeec9a4b..f7635aa0342d1 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h
@@ -73,6 +73,23 @@ Nullability getNullabilityAnnotation(QualType Type);
 /// returned.
 std::optional<int> tryExpandAsInteger(StringRef Macro, const Preprocessor &PP);
 
+class CachedMacroValue {
+public:
+  CachedMacroValue(StringRef MacroSpelling, const Preprocessor &PP)
+      : MacroValueOrFailure(tryExpandAsInteger(MacroSpelling, PP)) {}
+  explicit CachedMacroValue(int ConcreteValue)
+      : MacroValueOrFailure(ConcreteValue) {}
+
+  int valueOr(int Default) const {
+    return MacroValueOrFailure.value_or(Default);
+  }
+  bool hasValue() const { return MacroValueOrFailure.has_value(); }
+  int value() const { return MacroValueOrFailure.value(); }
+
+private:
+  std::optional<int> MacroValueOrFailure;
+};
+
 class OperatorKind {
   union {
     BinaryOperatorKind Bin;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index da2d16ca9b5dd..0452e541e8d5c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -40,17 +40,28 @@ enum class OpenVariant {
   OpenAt
 };
 
+static CachedMacroValue getCreateFlagValue(const ASTContext &Ctx,
+                                           const Preprocessor &PP) {
+  CachedMacroValue MacroVal("O_CREAT", PP);
+  if (MacroVal.hasValue())
+    return MacroVal;
+
+  // If we failed, fall-back to known values.
+  if (Ctx.getTargetInfo().getTriple().getVendor() == llvm::Triple::Apple)
+    return CachedMacroValue{0x0200};
+  return MacroVal;
+}
+
 namespace {
 
-class UnixAPIMisuseChecker
-    : public Checker<check::PreCall, check::ASTDecl<TranslationUnitDecl>> {
+class UnixAPIMisuseChecker : public Checker<check::PreCall> {
   const BugType BT_open{this, "Improper use of 'open'", categories::UnixAPI};
   const BugType BT_getline{this, "Improper use of getdelim",
                            categories::UnixAPI};
   const BugType BT_pthreadOnce{this, "Improper use of 'pthread_once'",
                                categories::UnixAPI};
   const BugType BT_ArgumentNull{this, "NULL pointer", categories::UnixAPI};
-  mutable std::optional<uint64_t> Val_O_CREAT;
+  const CachedMacroValue Val_O_CREAT;
 
   ProgramStateRef
   EnsurePtrNotNull(SVal PtrVal, const Expr *PtrExpr, CheckerContext &C,
@@ -63,6 +74,9 @@ class UnixAPIMisuseChecker
       const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const;
 
 public:
+  UnixAPIMisuseChecker(const ASTContext &Ctx, const Preprocessor &PP)
+      : Val_O_CREAT(getCreateFlagValue(Ctx, PP)) {}
+
   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager &Mgr,
                     BugReporter &BR) const;
 
@@ -134,20 +148,6 @@ ProgramStateRef UnixAPIMisuseChecker::EnsurePtrNotNull(
   return PtrNotNull;
 }
 
-void UnixAPIMisuseChecker::checkASTDecl(const TranslationUnitDecl *TU,
-                                        AnalysisManager &Mgr,
-                                        BugReporter &) const {
-  // The definition of O_CREAT is platform specific.
-  // Try to get the macro value from the preprocessor.
-  Val_O_CREAT = tryExpandAsInteger("O_CREAT", Mgr.getPreprocessor());
-  // If we failed, fall-back to known values.
-  if (!Val_O_CREAT) {
-    if (TU->getASTContext().getTargetInfo().getTriple().getVendor() ==
-        llvm::Triple::Apple)
-      Val_O_CREAT = 0x0200;
-  }
-}
-
 
//===----------------------------------------------------------------------===//
 // "open" (man 2 open)
 //===----------------------------------------------------------------------===/
@@ -262,7 +262,7 @@ void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext 
&C,
     return;
   }
 
-  if (!Val_O_CREAT) {
+  if (!Val_O_CREAT.hasValue()) {
     return;
   }
 
@@ -276,7 +276,7 @@ void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext 
&C,
   }
   NonLoc oflags = V.castAs<NonLoc>();
   NonLoc ocreateFlag = C.getSValBuilder()
-                           .makeIntVal(*Val_O_CREAT, oflagsEx->getType())
+                           .makeIntVal(Val_O_CREAT.value(), 
oflagsEx->getType())
                            .castAs<NonLoc>();
   SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
                                                       oflags, ocreateFlag,
@@ -621,14 +621,17 @@ void UnixAPIPortabilityChecker::checkPreStmt(const 
CallExpr *CE,
 // Registration.
 
//===----------------------------------------------------------------------===//
 
-#define REGISTER_CHECKER(CHECKERNAME)                                          
\
-  void ento::register##CHECKERNAME(CheckerManager &mgr) {                      
\
-    mgr.registerChecker<CHECKERNAME>();                                        
\
-  }                                                                            
\
-                                                                               
\
-  bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) {          
\
-    return true;                                                               
\
-  }
+void ento::registerUnixAPIMisuseChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<UnixAPIMisuseChecker>(Mgr.getASTContext(),
+                                            Mgr.getPreprocessor());
+}
+bool ento::shouldRegisterUnixAPIMisuseChecker(const CheckerManager &Mgr) {
+  return true;
+}
 
-REGISTER_CHECKER(UnixAPIMisuseChecker)
-REGISTER_CHECKER(UnixAPIPortabilityChecker)
+void ento::registerUnixAPIPortabilityChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<UnixAPIPortabilityChecker>();
+}
+bool ento::shouldRegisterUnixAPIPortabilityChecker(const CheckerManager &Mgr) {
+  return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp 
b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 189d7d6bede8e..db177b584b4f5 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -224,16 +224,6 @@ class AnalysisConsumer : public AnalysisASTConsumer,
     }
   }
 
-  void Initialize(ASTContext &Context) override {
-    Ctx = &Context;
-    checkerMgr = std::make_unique<CheckerManager>(*Ctx, Opts, PP, Plugins,
-                                                  CheckerRegistrationFns);
-
-    Mgr = std::make_unique<AnalysisManager>(*Ctx, PP, PathConsumers,
-                                            CreateStoreMgr, 
CreateConstraintMgr,
-                                            checkerMgr.get(), Opts, Injector);
-  }
-
   /// Store the top level decls in the set to be processed later on.
   /// (Doing this pre-processing avoids deserialization of data from PCH.)
   bool HandleTopLevelDecl(DeclGroupRef D) override;
@@ -615,6 +605,14 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext 
&C) {
   if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
     return;
 
+  Ctx = &C;
+  checkerMgr = std::make_unique<CheckerManager>(*Ctx, Opts, PP, Plugins,
+                                                CheckerRegistrationFns);
+
+  Mgr = std::make_unique<AnalysisManager>(*Ctx, PP, PathConsumers,
+                                          CreateStoreMgr, CreateConstraintMgr,
+                                          checkerMgr.get(), Opts, Injector);
+
   // Explicitly destroy the PathDiagnosticConsumer.  This will flush its 
output.
   // FIXME: This should be replaced with something that doesn't rely on
   // side-effects in PathDiagnosticConsumer's destructor. This is required when

``````````

</details>


https://github.com/llvm/llvm-project/pull/127409
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to