r343035 - [analyzer] NFC: Legalize state manager factory injection.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 25 15:10:12 PDT 2018


Author: dergachev
Date: Tue Sep 25 15:10:12 2018
New Revision: 343035

URL: http://llvm.org/viewvc/llvm-project?rev=343035&view=rev
Log:
[analyzer] NFC: Legalize state manager factory injection.

When a checker maintains a program state trait that isn't a simple list/set/map, but is a combination of multiple lists/sets/maps (eg., a multimap - which may be implemented as a map from something to set of something), ProgramStateManager only contains the factory for the trait itself. All auxiliary lists/sets/maps need a factory to be provided by the checker, which is annoying.

So far two checkers wanted a multimap, and both decided to trick the
ProgramStateManager into keeping the auxiliary factory within itself
by pretending that it's some sort of trait they're interested in,
but then never using this trait but only using the factory.

Make this trick legal. Define a convenient macro.

One thing that becomes apparent once all pieces are put together is that
these two checkers are in fact using the same factory, because the type that
identifies it, ImmutableMap<const MemRegion *, ImmutableSet<SymbolRef>>,
is the same. This situation is different from two checkers registering similar
primitive traits.

Differential Revision: https://reviews.llvm.org/D51388

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h?rev=343035&r1=343034&r2=343035&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h Tue Sep 25 15:10:12 2018
@@ -21,52 +21,6 @@
 namespace clang {
 namespace ento {
 
-  /// Declares an immutable map of type \p NameTy, suitable for placement into
-  /// the ProgramState. This is implementing using llvm::ImmutableMap.
-  ///
-  /// \code
-  /// State = State->set<Name>(K, V);
-  /// const Value *V = State->get<Name>(K); // Returns NULL if not in the map.
-  /// State = State->remove<Name>(K);
-  /// NameTy Map = State->get<Name>();
-  /// \endcode
-  ///
-  /// The macro should not be used inside namespaces, or for traits that must
-  /// be accessible from more than one translation unit.
-  #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \
-    REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \
-                                     CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value))
-
-  /// Declares an immutable set of type \p NameTy, suitable for placement into
-  /// the ProgramState. This is implementing using llvm::ImmutableSet.
-  ///
-  /// \code
-  /// State = State->add<Name>(E);
-  /// State = State->remove<Name>(E);
-  /// bool Present = State->contains<Name>(E);
-  /// NameTy Set = State->get<Name>();
-  /// \endcode
-  ///
-  /// The macro should not be used inside namespaces, or for traits that must
-  /// be accessible from more than one translation unit.
-  #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem) \
-    REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>)
-
-  /// Declares an immutable list of type \p NameTy, suitable for placement into
-  /// the ProgramState. This is implementing using llvm::ImmutableList.
-  ///
-  /// \code
-  /// State = State->add<Name>(E); // Adds to the /end/ of the list.
-  /// bool Present = State->contains<Name>(E);
-  /// NameTy List = State->get<Name>();
-  /// \endcode
-  ///
-  /// The macro should not be used inside namespaces, or for traits that must
-  /// be accessible from more than one translation unit.
-  #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \
-    REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)
-
-
 class CheckerContext {
   ExprEngine &Eng;
   /// The current exploded(symbolic execution) graph node.

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h?rev=343035&r1=343034&r2=343035&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h Tue Sep 25 15:10:12 2018
@@ -30,8 +30,7 @@ namespace ento {
 
   /// Declares a program state trait for type \p Type called \p Name, and
   /// introduce a type named \c NameTy.
-  /// The macro should not be used inside namespaces, or for traits that must
-  /// be accessible from more than one translation unit.
+  /// The macro should not be used inside namespaces.
   #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type) \
     namespace { \
       class Name {}; \
@@ -47,6 +46,102 @@ namespace ento {
     } \
     }
 
+  /// Declares a factory for objects of type \p Type in the program state
+  /// manager. The type must provide a ::Factory sub-class. Commonly used for
+  /// ImmutableMap, ImmutableSet, ImmutableList. The macro should not be used
+  /// inside namespaces.
+  #define REGISTER_FACTORY_WITH_PROGRAMSTATE(Type) \
+    namespace clang { \
+    namespace ento { \
+      template <> \
+      struct ProgramStateTrait<Type> \
+        : public ProgramStatePartialTrait<Type> { \
+        static void *GDMIndex() { static int Index; return &Index; } \
+      }; \
+    } \
+    }
+
+  /// Helper for registering a map trait.
+  ///
+  /// If the map type were written directly in the invocation of
+  /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments
+  /// would be treated as a macro argument separator, which is wrong.
+  /// This allows the user to specify a map type in a way that the preprocessor
+  /// can deal with.
+  #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value>
+
+  /// Declares an immutable map of type \p NameTy, suitable for placement into
+  /// the ProgramState. This is implementing using llvm::ImmutableMap.
+  ///
+  /// \code
+  /// State = State->set<Name>(K, V);
+  /// const Value *V = State->get<Name>(K); // Returns NULL if not in the map.
+  /// State = State->remove<Name>(K);
+  /// NameTy Map = State->get<Name>();
+  /// \endcode
+  ///
+  /// The macro should not be used inside namespaces, or for traits that must
+  /// be accessible from more than one translation unit.
+  #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \
+    REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \
+                                     CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value))
+
+  /// Declares an immutable map type \p Name and registers the factory
+  /// for such maps in the program state, but does not add the map itself
+  /// to the program state. Useful for managing lifetime of maps that are used
+  /// as elements of other program state data structures.
+  #define REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(Name, Key, Value) \
+    using Name = llvm::ImmutableMap<Key, Value>; \
+    REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
+
+
+  /// Declares an immutable set of type \p NameTy, suitable for placement into
+  /// the ProgramState. This is implementing using llvm::ImmutableSet.
+  ///
+  /// \code
+  /// State = State->add<Name>(E);
+  /// State = State->remove<Name>(E);
+  /// bool Present = State->contains<Name>(E);
+  /// NameTy Set = State->get<Name>();
+  /// \endcode
+  ///
+  /// The macro should not be used inside namespaces, or for traits that must
+  /// be accessible from more than one translation unit.
+  #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem) \
+    REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>)
+
+  /// Declares an immutable set type \p Name and registers the factory
+  /// for such sets in the program state, but does not add the set itself
+  /// to the program state. Useful for managing lifetime of sets that are used
+  /// as elements of other program state data structures.
+  #define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem) \
+    using Name = llvm::ImmutableSet<Elem>; \
+    REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
+
+
+  /// Declares an immutable list type \p NameTy, suitable for placement into
+  /// the ProgramState. This is implementing using llvm::ImmutableList.
+  ///
+  /// \code
+  /// State = State->add<Name>(E); // Adds to the /end/ of the list.
+  /// bool Present = State->contains<Name>(E);
+  /// NameTy List = State->get<Name>();
+  /// \endcode
+  ///
+  /// The macro should not be used inside namespaces, or for traits that must
+  /// be accessible from more than one translation unit.
+  #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \
+    REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)
+
+  /// Declares an immutable list of type \p Name and registers the factory
+  /// for such lists in the program state, but does not add the list itself
+  /// to the program state. Useful for managing lifetime of lists that are used
+  /// as elements of other program state data structures.
+  #define REGISTER_LIST_FACTORY_WITH_PROGRAMSTATE(Name, Elem) \
+    using Name = llvm::ImmutableList<Elem>; \
+    REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
+
+
   // Partial-specialization for ImmutableMap.
   template <typename Key, typename Data, typename Info>
   struct ProgramStatePartialTrait<llvm::ImmutableMap<Key, Data, Info>> {
@@ -95,15 +190,6 @@ namespace ento {
     }
   };
 
-  /// Helper for registering a map trait.
-  ///
-  /// If the map type were written directly in the invocation of
-  /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments
-  /// would be treated as a macro argument separator, which is wrong.
-  /// This allows the user to specify a map type in a way that the preprocessor
-  /// can deal with.
-  #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value>
-
   // Partial-specialization for ImmutableSet.
   template <typename Key, typename Info>
   struct ProgramStatePartialTrait<llvm::ImmutableSet<Key, Info>> {

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp?rev=343035&r1=343034&r2=343035&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp Tue Sep 25 15:10:12 2018
@@ -178,20 +178,12 @@ private:
 };
 } // End anonymous namespace.
 
-typedef llvm::ImmutableSet<SymbolRef> SymbolSet;
 
 /// Maps from the symbol for a class instance to the set of
 /// symbols remaining that must be released in -dealloc.
+REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(SymbolSet, SymbolRef)
 REGISTER_MAP_WITH_PROGRAMSTATE(UnreleasedIvarMap, SymbolRef, SymbolSet)
 
-namespace clang {
-namespace ento {
-template<> struct ProgramStateTrait<SymbolSet>
-:  public ProgramStatePartialTrait<SymbolSet> {
-  static void *GDMIndex() { static int index = 0; return &index; }
-};
-}
-}
 
 /// An AST check that diagnose when the class requires a -dealloc method and
 /// is missing one.

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp?rev=343035&r1=343034&r2=343035&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp Tue Sep 25 15:10:12 2018
@@ -25,23 +25,10 @@
 using namespace clang;
 using namespace ento;
 
-using PtrSet = llvm::ImmutableSet<SymbolRef>;
-
 // Associate container objects with a set of raw pointer symbols.
+REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(PtrSet, SymbolRef);
 REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, PtrSet)
 
-// This is a trick to gain access to PtrSet's Factory.
-namespace clang {
-namespace ento {
-template <>
-struct ProgramStateTrait<PtrSet> : public ProgramStatePartialTrait<PtrSet> {
-  static void *GDMIndex() {
-    static int Index = 0;
-    return &Index;
-  }
-};
-} // end namespace ento
-} // end namespace clang
 
 namespace {
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=343035&r1=343034&r2=343035&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Tue Sep 25 15:10:12 2018
@@ -406,9 +406,8 @@ namespace {
   };
 } // end anonymous namespace
 
-REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap,
-                                 CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *,
-                                                             unsigned))
+REGISTER_MAP_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap,
+                               const MemRegion *, unsigned)
 
 bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
                             NodeBuilder &Bldr, ExplodedNode *Pred,




More information about the cfe-commits mailing list