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