Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:37:09

0001 //ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- C++ -*-
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines partial implementations of template specializations of
0010 //  the class ProgramStateTrait<>.  ProgramStateTrait<> is used by ProgramState
0011 //  to implement set/get methods for manipulating a ProgramState's
0012 //  generic data map.
0013 //
0014 //===----------------------------------------------------------------------===//
0015 
0016 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
0017 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H
0018 
0019 #include "llvm/ADT/ImmutableList.h"
0020 #include "llvm/ADT/ImmutableMap.h"
0021 #include "llvm/ADT/ImmutableSet.h"
0022 #include "llvm/Support/Allocator.h"
0023 #include <cstdint>
0024 #include <type_traits>
0025 
0026 namespace clang {
0027 namespace ento {
0028 
0029 template <typename T, typename Enable = void> struct ProgramStatePartialTrait;
0030 
0031 /// Declares a program state trait for type \p Type called \p Name, and
0032 /// introduce a type named \c NameTy.
0033 /// The macro should not be used inside namespaces.
0034 #define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)                           \
0035   namespace {                                                                  \
0036   class Name {};                                                               \
0037   using Name##Ty = Type;                                                       \
0038   }                                                                            \
0039   namespace clang {                                                            \
0040   namespace ento {                                                             \
0041   template <>                                                                  \
0042   struct ProgramStateTrait<Name> : public ProgramStatePartialTrait<Name##Ty> { \
0043     static void *GDMIndex() {                                                  \
0044       static int Index;                                                        \
0045       return &Index;                                                           \
0046     }                                                                          \
0047   };                                                                           \
0048   }                                                                            \
0049   }
0050 
0051   /// Declares a factory for objects of type \p Type in the program state
0052   /// manager. The type must provide a ::Factory sub-class. Commonly used for
0053   /// ImmutableMap, ImmutableSet, ImmutableList. The macro should not be used
0054   /// inside namespaces.
0055   #define REGISTER_FACTORY_WITH_PROGRAMSTATE(Type) \
0056     namespace clang { \
0057     namespace ento { \
0058       template <> \
0059       struct ProgramStateTrait<Type> \
0060         : public ProgramStatePartialTrait<Type> { \
0061         static void *GDMIndex() { static int Index; return &Index; } \
0062       }; \
0063     } \
0064     }
0065 
0066   /// Helper for registering a map trait.
0067   ///
0068   /// If the map type were written directly in the invocation of
0069   /// REGISTER_TRAIT_WITH_PROGRAMSTATE, the comma in the template arguments
0070   /// would be treated as a macro argument separator, which is wrong.
0071   /// This allows the user to specify a map type in a way that the preprocessor
0072   /// can deal with.
0073   #define CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value) llvm::ImmutableMap<Key, Value>
0074 
0075   /// Declares an immutable map of type \p NameTy, suitable for placement into
0076   /// the ProgramState. This is implementing using llvm::ImmutableMap.
0077   ///
0078   /// \code
0079   /// State = State->set<Name>(K, V);
0080   /// const Value *V = State->get<Name>(K); // Returns NULL if not in the map.
0081   /// State = State->remove<Name>(K);
0082   /// NameTy Map = State->get<Name>();
0083   /// \endcode
0084   ///
0085   /// The macro should not be used inside namespaces, or for traits that must
0086   /// be accessible from more than one translation unit.
0087   #define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value) \
0088     REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, \
0089                                      CLANG_ENTO_PROGRAMSTATE_MAP(Key, Value))
0090 
0091   /// Declares an immutable map type \p Name and registers the factory
0092   /// for such maps in the program state, but does not add the map itself
0093   /// to the program state. Useful for managing lifetime of maps that are used
0094   /// as elements of other program state data structures.
0095   #define REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(Name, Key, Value) \
0096     using Name = llvm::ImmutableMap<Key, Value>; \
0097     REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
0098 
0099 
0100   /// Declares an immutable set of type \p NameTy, suitable for placement into
0101   /// the ProgramState. This is implementing using llvm::ImmutableSet.
0102   ///
0103   /// \code
0104   /// State = State->add<Name>(E);
0105   /// State = State->remove<Name>(E);
0106   /// bool Present = State->contains<Name>(E);
0107   /// NameTy Set = State->get<Name>();
0108   /// \endcode
0109   ///
0110   /// The macro should not be used inside namespaces, or for traits that must
0111   /// be accessible from more than one translation unit.
0112   #define REGISTER_SET_WITH_PROGRAMSTATE(Name, Elem) \
0113     REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableSet<Elem>)
0114 
0115   /// Declares an immutable set type \p Name and registers the factory
0116   /// for such sets in the program state, but does not add the set itself
0117   /// to the program state. Useful for managing lifetime of sets that are used
0118   /// as elements of other program state data structures.
0119   #define REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(Name, Elem) \
0120     using Name = llvm::ImmutableSet<Elem>; \
0121     REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
0122 
0123 
0124   /// Declares an immutable list type \p NameTy, suitable for placement into
0125   /// the ProgramState. This is implementing using llvm::ImmutableList.
0126   ///
0127   /// \code
0128   /// State = State->add<Name>(E); // Adds to the /end/ of the list.
0129   /// bool Present = State->contains<Name>(E);
0130   /// NameTy List = State->get<Name>();
0131   /// \endcode
0132   ///
0133   /// The macro should not be used inside namespaces, or for traits that must
0134   /// be accessible from more than one translation unit.
0135   #define REGISTER_LIST_WITH_PROGRAMSTATE(Name, Elem) \
0136     REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, llvm::ImmutableList<Elem>)
0137 
0138   /// Declares an immutable list of type \p Name and registers the factory
0139   /// for such lists in the program state, but does not add the list itself
0140   /// to the program state. Useful for managing lifetime of lists that are used
0141   /// as elements of other program state data structures.
0142   #define REGISTER_LIST_FACTORY_WITH_PROGRAMSTATE(Name, Elem) \
0143     using Name = llvm::ImmutableList<Elem>; \
0144     REGISTER_FACTORY_WITH_PROGRAMSTATE(Name)
0145 
0146 
0147   // Partial-specialization for ImmutableMap.
0148   template <typename Key, typename Data, typename Info>
0149   struct ProgramStatePartialTrait<llvm::ImmutableMap<Key, Data, Info>> {
0150     using data_type = llvm::ImmutableMap<Key, Data, Info>;
0151     using context_type = typename data_type::Factory &;
0152     using key_type = Key;
0153     using value_type = Data;
0154     using lookup_type = const value_type *;
0155 
0156     static data_type MakeData(void *const *p) {
0157       return p ? data_type((typename data_type::TreeTy *) *p)
0158                : data_type(nullptr);
0159     }
0160 
0161     static void *MakeVoidPtr(data_type B) {
0162       return B.getRoot();
0163     }
0164 
0165     static lookup_type Lookup(data_type B, key_type K) {
0166       return B.lookup(K);
0167     }
0168 
0169     static data_type Set(data_type B, key_type K, value_type E,
0170                          context_type F) {
0171       return F.add(B, K, E);
0172     }
0173 
0174     static data_type Remove(data_type B, key_type K, context_type F) {
0175       return F.remove(B, K);
0176     }
0177 
0178     static bool Contains(data_type B, key_type K) {
0179       return B.contains(K);
0180     }
0181 
0182     static context_type MakeContext(void *p) {
0183       return *((typename data_type::Factory *) p);
0184     }
0185 
0186     static void *CreateContext(llvm::BumpPtrAllocator& Alloc) {
0187       return new typename data_type::Factory(Alloc);
0188     }
0189 
0190     static void DeleteContext(void *Ctx) {
0191       delete (typename data_type::Factory *) Ctx;
0192     }
0193   };
0194 
0195   // Partial-specialization for ImmutableSet.
0196   template <typename Key, typename Info>
0197   struct ProgramStatePartialTrait<llvm::ImmutableSet<Key, Info>> {
0198     using data_type = llvm::ImmutableSet<Key, Info>;
0199     using context_type = typename data_type::Factory &;
0200     using key_type = Key;
0201 
0202     static data_type MakeData(void *const *p) {
0203       return p ? data_type((typename data_type::TreeTy *) *p)
0204                : data_type(nullptr);
0205     }
0206 
0207     static void *MakeVoidPtr(data_type B) {
0208       return B.getRoot();
0209     }
0210 
0211     static data_type Add(data_type B, key_type K, context_type F) {
0212       return F.add(B, K);
0213     }
0214 
0215     static data_type Remove(data_type B, key_type K, context_type F) {
0216       return F.remove(B, K);
0217     }
0218 
0219     static bool Contains(data_type B, key_type K) {
0220       return B.contains(K);
0221     }
0222 
0223     static context_type MakeContext(void *p) {
0224       return *((typename data_type::Factory *) p);
0225     }
0226 
0227     static void *CreateContext(llvm::BumpPtrAllocator &Alloc) {
0228       return new typename data_type::Factory(Alloc);
0229     }
0230 
0231     static void DeleteContext(void *Ctx) {
0232       delete (typename data_type::Factory *) Ctx;
0233     }
0234   };
0235 
0236   // Partial-specialization for ImmutableList.
0237   template <typename T>
0238   struct ProgramStatePartialTrait<llvm::ImmutableList<T>> {
0239     using data_type = llvm::ImmutableList<T>;
0240     using key_type = T;
0241     using context_type = typename data_type::Factory &;
0242 
0243     static data_type Add(data_type L, key_type K, context_type F) {
0244       return F.add(K, L);
0245     }
0246 
0247     static bool Contains(data_type L, key_type K) {
0248       return L.contains(K);
0249     }
0250 
0251     static data_type MakeData(void *const *p) {
0252       return p ? data_type((const llvm::ImmutableListImpl<T> *) *p)
0253                : data_type(nullptr);
0254     }
0255 
0256     static void *MakeVoidPtr(data_type D) {
0257       return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer());
0258     }
0259 
0260     static context_type MakeContext(void *p) {
0261       return *((typename data_type::Factory *) p);
0262     }
0263 
0264     static void *CreateContext(llvm::BumpPtrAllocator &Alloc) {
0265       return new typename data_type::Factory(Alloc);
0266     }
0267 
0268     static void DeleteContext(void *Ctx) {
0269       delete (typename data_type::Factory *) Ctx;
0270     }
0271   };
0272 
0273   template <typename T> struct DefaultProgramStatePartialTraitImpl {
0274     using data_type = T;
0275     static T MakeData(void *const *P) { return P ? (T)(uintptr_t)*P : T{}; }
0276     static void *MakeVoidPtr(T D) { return (void *)(uintptr_t)D; }
0277   };
0278 
0279   // Partial specialization for integral types.
0280   template <typename T>
0281   struct ProgramStatePartialTrait<T,
0282                                   std::enable_if_t<std::is_integral<T>::value>>
0283       : DefaultProgramStatePartialTraitImpl<T> {};
0284 
0285   // Partial specialization for enums.
0286   template <typename T>
0287   struct ProgramStatePartialTrait<T, std::enable_if_t<std::is_enum<T>::value>>
0288       : DefaultProgramStatePartialTraitImpl<T> {};
0289 
0290   // Partial specialization for pointers.
0291   template <typename T>
0292   struct ProgramStatePartialTrait<T *, void>
0293       : DefaultProgramStatePartialTraitImpl<T *> {};
0294 
0295 } // namespace ento
0296 } // namespace clang
0297 
0298 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATETRAIT_H