Home | History | Annotate | Line # | Download | only in Support
      1 //===-- llvm/Support/ExtensibleRTTI.h - ExtensibleRTTI support --*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // \file
     11 //
     12 // Defines an extensible RTTI mechanism designed to work with Casting.h.
     13 //
     14 // Extensible RTTI differs from LLVM's primary RTTI mechanism (see
     15 // llvm.org/docs/HowToSetUpLLVMStyleRTTI.html) by supporting open type
     16 // hierarchies, where new types can be added from outside libraries without
     17 // needing to change existing code. LLVM's primary RTTI mechanism should be
     18 // preferred where possible, but where open hierarchies are needed this system
     19 // can be used.
     20 //
     21 // The RTTIRoot class defines methods for comparing type ids. Implementations
     22 // of these methods can be injected into new classes using the RTTIExtends
     23 // class template.
     24 //
     25 // E.g.
     26 //
     27 //   @code{.cpp}
     28 //   class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> {
     29 //   public:
     30 //     static char ID;
     31 //     virtual void foo() = 0;
     32 //   };
     33 //
     34 //   class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> {
     35 //   public:
     36 //     static char ID;
     37 //     void foo() override {}
     38 //   };
     39 //
     40 //   class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> {
     41 //   public:
     42 //     static char ID;
     43 //     void foo() override {}
     44 //   };
     45 //
     46 //   char MyBaseClass::ID = 0;
     47 //   char MyDerivedClass1::ID = 0;
     48 //   char MyDerivedClass2:: ID = 0;
     49 //
     50 //   void fn() {
     51 //     std::unique_ptr<MyBaseClass> B = llvm::make_unique<MyDerivedClass1>();
     52 //     llvm::outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1".
     53 //     llvm::outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1".
     54 //     llvm::outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'.
     55 //   }
     56 //
     57 //   @endcode
     58 //
     59 //===----------------------------------------------------------------------===//
     60 
     61 #ifndef LLVM_SUPPORT_EXTENSIBLERTTI_H
     62 #define LLVM_SUPPORT_EXTENSIBLERTTI_H
     63 
     64 namespace llvm {
     65 
     66 template <typename ThisT, typename ParentT> class RTTIExtends;
     67 
     68 /// Base class for the extensible RTTI hierarchy.
     69 ///
     70 /// This class defines virtual methods, dynamicClassID and isA, that enable
     71 /// type comparisons.
     72 class RTTIRoot {
     73 public:
     74   virtual ~RTTIRoot() = default;
     75 
     76   /// Returns the class ID for this type.
     77   static const void *classID() { return &ID; }
     78 
     79   /// Returns the class ID for the dynamic type of this RTTIRoot instance.
     80   virtual const void *dynamicClassID() const = 0;
     81 
     82   /// Returns true if this class's ID matches the given class ID.
     83   virtual bool isA(const void *const ClassID) const {
     84     return ClassID == classID();
     85   }
     86 
     87   /// Check whether this instance is a subclass of QueryT.
     88   template <typename QueryT>
     89   bool isA() const { return isA(QueryT::classID()); }
     90 
     91 private:
     92   virtual void anchor();
     93 
     94   static char ID;
     95 };
     96 
     97 /// Inheritance utility for extensible RTTI.
     98 ///
     99 /// Supports single inheritance only: A class can only have one
    100 /// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work),
    101 /// though it can have many non-ExtensibleRTTI parents.
    102 ///
    103 /// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
    104 /// newly introduced type, and the *second* argument is the parent class.
    105 ///
    106 /// class MyType : public RTTIExtends<MyType, RTTIRoot> {
    107 /// public:
    108 ///   static char ID;
    109 /// };
    110 ///
    111 /// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> {
    112 /// public:
    113 ///   static char ID;
    114 /// };
    115 ///
    116 template <typename ThisT, typename ParentT>
    117 class RTTIExtends : public ParentT {
    118 public:
    119   // Inherit constructors from ParentT.
    120   using ParentT::ParentT;
    121 
    122   static const void *classID() { return &ThisT::ID; }
    123 
    124   const void *dynamicClassID() const override { return &ThisT::ID; }
    125 
    126   bool isA(const void *const ClassID) const override {
    127     return ClassID == classID() || ParentT::isA(ClassID);
    128   }
    129 
    130   static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
    131 };
    132 
    133 } // end namespace llvm
    134 
    135 #endif // LLVM_SUPPORT_EXTENSIBLERTTI_H
    136