]> granicus.if.org Git - clang/commitdiff
[analyzer] NFC: Legalize state manager factory injection.
authorArtem Dergachev <artem.dergachev@gmail.com>
Tue, 25 Sep 2018 22:10:12 +0000 (22:10 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Tue, 25 Sep 2018 22:10:12 +0000 (22:10 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@343035 91177308-0d34-0410-b5e6-96231b3b80d8

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

index e342dd6bb7cc952602d15b27876b7250c5203edd..6ee75b73846597318f1a59174b020085e5d487cf 100644 (file)
 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.
index 5555b292534c54d621973a0e6898efaec2d71f04..64de736c7e9f2bc10397c00e1ca80cda37a8846d 100644 (file)
@@ -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>> {
index f4d2e32cef1114c855e2412451e407d2e7ac55d1..c330d7504b9489f58a68139dbd458b4e70051395 100644 (file)
@@ -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.
index b3638d0b9cfcf91a4cd1c32a6dc3d0b661a6eb32..716a89972a9a5f71203be4b60154114de306df71 100644 (file)
 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 {
 
index 202deb0d4fc9a9f71951fd76ea0cb871ac5b7f44..66cbebad1c26d58739f3000cc212e0705fecfb20 100644 (file)
@@ -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,