1 /*
2     SPDX-FileCopyrightText: 2006 Roberto Raggi <roberto@kdevelop.org>
3     SPDX-FileCopyrightText: 2006-2008 Hamish Rodda <rodda@kde.org>
4     SPDX-FileCopyrightText: 2007-2008 David Nolden <david.nolden.kdevelop@art-master.de>
5 
6     SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #ifndef KDEVPLATFORM_ABSTRACTTYPE_H
10 #define KDEVPLATFORM_ABSTRACTTYPE_H
11 
12 #include "typepointer.h"
13 #include <language/languageexport.h>
14 
15 class QString;
16 
17 namespace KDevelop {
18 class AbstractTypeData;
19 
20 class IndexedType;
21 
22 class TypeVisitor;
23 class TypeExchanger;
24 
25 /// This macro is used to declare type-specific data-access functions within subclasses of AbstractType
26 #define TYPE_DECLARE_DATA(Class) \
27     inline Class ## Data * d_func_dynamic() { makeDynamic(); return reinterpret_cast<Class ## Data*>(d_ptr); } \
28     inline const Class ## Data* d_func() const { return reinterpret_cast<const Class ## Data*>(d_ptr); }
29 
30 /// This function creates a local variable named 'd' pointing to the data type (as shortcut)
31 #define TYPE_D(Class) const Class ## Data * const d = d_func()
32 #define TYPE_D_DYNAMIC(Class) Class ## Data * const d = d_func_dynamic()
33 
34 /**
35  * \brief Base class for all types.
36  *
37  * The AbstractType class is a base class from which all types derive.  It features:
38  * - mechanisms for visiting types
39  * - toString() feature
40  * - equivalence feature
41  * - cloning of types, and
42  * - hashing and indexing
43  * - efficient, persistent, and reference-counted storage of types using IndexedType
44  *
45  *  Type classes are created in a way that allows storing them in memory or on disk
46  *  efficiently.  They are classes which can store arbitrary lists immediately after their
47  *  private data structures in memory (thus enabling them to be mmapped or memcopied),
48  *  or being "dynamic" where you use exactly the same class and same access functions,
49  *  but the list data is stored in a temporary KDevVarLengthArray from a central repository,
50  *  until we save it back to the static memory-region again.
51  *
52  * When creating an own (sub-) type, you must:
53  * - Override equals(..), hash().
54  *   - The functions should _fully_ distinguish all types,
55  *     in regard to all stored information, and regarding their identity.
56  *   - This can be skipped if you're overriding a base-type which already incorporates
57  *     all of your own types status within its equals/hash functions (eg. you don't add own data).
58  * - Implement a copy-constructor in which you copy the data from the source using copyData<YourType>()
59  * - Override the clone() function in which you use the copy-constructor to clone the type
60  * - Add an enumerator "Identity" that contains an arbitrary unique identity value of the type
61  * - Register your type in a source-file using REGISTER_TYPE(..), @see typeregister.h
62  * - Add a typedef "Data", that contains the actual data of the type using the mechanisms described in appendedlist.h.
63  *   That data type must follow the same inheritance chain as the type itself, so it must be based on the Data object
64  *   of the base class. See AbstractTypeData.
65  * - Use createData<YourType>() to create the data-object in a constructor (which you then reach to the parent constructor)
66  * - Use TYPE_DECLARE_DATA(YourType) to declare the data access functions d_func and d_func_dynamic,
67  *   and  then use d_func()->.. and d_func_dynamic()->.. to access your type data
68  * - Create a constructor that only takes a reference to the type data, and passes it to the parent type
69  *
70  *   Every type can have only one other type as base-type,
71  *   but it can have additional base-classes that are not a direct part of the type-system(@see IdentifiedType).
72  *
73  *  \sa appendedlist.h
74  */
75 class KDEVPLATFORMLANGUAGE_EXPORT AbstractType
76     : public QSharedData
77 {
78 public:
79     using Ptr = TypePtr<AbstractType>;
80 
81     /**
82      * An enumeration of common modifiers for data types.
83      * If you have any language-specific modifiers that don't belong here,
84      * you can add them at/after LanguageSpecificModifier
85      * @warning Think twice what information you store into the type-system.
86      *          The type-system should store information that is shared among many declarations,
87      *          and attributes of specific Declarations like public/private should be stored in
88      *          the Declarations themselves, not in the type-system.
89      */
90     enum CommonModifiers : quint32 {
91         NoModifiers                 = 0,
92 
93         ConstModifier               = 1 << 0,
94         VolatileModifier            = 1 << 1,
95         TransientModifier           = 1 << 2,
96         NewModifier                 = 1 << 3,
97         SealedModifier              = 1 << 4,
98         UnsafeModifier              = 1 << 5,
99         FixedModifier               = 1 << 6,
100         ShortModifier               = 1 << 7,
101         LongModifier                = 1 << 8,
102         LongLongModifier            = 1 << 9,
103         SignedModifier              = 1 << 10,
104         UnsignedModifier            = 1 << 11,
105 
106         LanguageSpecificModifier    = 1 << 12
107     };
108 
109     /// Constructor.
110     AbstractType();
111     /// Constructor from data.
112     explicit AbstractType(AbstractTypeData& dd);
113     /// Destructor.
114     virtual ~AbstractType ();
115 
116     AbstractType(const AbstractType& rhs) = delete;
117     AbstractType& operator=(const AbstractType& rhs) = delete;
118 
119     /**
120      * Access the type modifiers
121      *
122      * \returns the type's modifiers.
123      */
124     quint32 modifiers() const;
125 
126     /**
127      * Set the type's modifiers.
128      *
129      * \param modifiers modifiers of this type.
130      */
131     void setModifiers(quint32 modifiers);
132 
133     /**
134      * \returns The size in bytes or -1 if unknown.
135      */
136     int64_t sizeOf() const;
137 
138     /**
139      * Set the size to given number of bytes. Use -1 to represent unknown size.
140      */
141     void setSizeOf(int64_t sizeOf);
142 
143     /**
144      * \returns The alignment in bytes or -1 if unknown.
145      */
146     int64_t alignOf() const;
147 
148     /**
149      * Set the alignment to given number of bytes.
150      *
151      * The value must be non-negative power of 2 or -1 to represent unknown alignment.
152      */
153     void setAlignOf(int64_t alignedTo);
154 
155     /**
156      * Visitor method.  Called by TypeVisitor to visit the type hierarchy.
157      * Do not reimplement this, reimplement accept0 instead.
158      *
159      * \param v visitor which is calling this function.
160      */
161     void accept(TypeVisitor* v) const;
162 
163     /**
164      * Convenience visitor method which can be called with a null type.
165      *
166      * \param type type to visit, may be null.
167      * \param v visitor which is visiting the given \a type
168      */
169     static void acceptType(AbstractType::Ptr type, TypeVisitor* v);
170 
171     /**
172      * Returns this type as a string, preferably the same as it is expressed in the code.
173      *
174      * \return this type as a string
175      */
176     virtual QString toString() const;
177 
178     ///Must always be called before anything in the data pointer is changed!
179     ///If it's not called beforehand, the type-repository gets corrupted
180     void makeDynamic();
181 
182     ///Should return whether this type's content equals the given one
183     ///Since this is used by the type-repository, it must compare ALL members of the data type.
184     virtual bool equals(const AbstractType* rhs) const;
185 
186     /**
187      * Should create a clone of the source-type, with as much data copied as possible without breaking the du-chain.
188      * */
189     virtual AbstractType* clone() const = 0;
190 
191     /**
192      * A hash-value that should have the following properties:
193      * - When two types match on equals(), it should be same.
194      * - When two types don't match on equals(), it should be different with a high probability.
195      * */
196     virtual uint hash() const;
197 
198     ///This can also be called on zero types, those can then be reconstructed from the zero index
199     IndexedType indexed() const;
200 
201     /// Enumeration of major data types.
202     enum WhichType : quint8 {
203         TypeAbstract /**< an abstract type */,
204         TypeIntegral /**< an integral */,
205         TypePointer /**< a pointer*/,
206         TypeReference /**< a reference */,
207         TypeFunction /**< a function */,
208         TypeStructure /**< a structure */,
209         TypeArray /**< an array */,
210         TypeDelayed /**< a delayed type */,
211         TypeEnumeration /**< an enumeration type */,
212         TypeEnumerator /**< an enumerator type */,
213         TypeAlias /**< a type-alias type */,
214         TypeUnsure /**< may represent multiple different types */
215     };
216 
217     /**
218      * Determine which data type this abstract type represents.
219      *
220      * \returns the data type represented by this type.
221      */
222     virtual WhichType whichType() const;
223 
224     enum {
225         Identity = 1
226     };
227 
228     /**
229      * Should, like accept0, be implemented by all types that hold references to other types.
230      *
231      * If this is called on one type, that type should call exchangeTypes(..) with all its referenced sub-types.
232      * The type itself does not recurse into the sub-types, that can be done by the exchanger itself if desired.
233      * */
234     virtual void exchangeTypes(TypeExchanger* exchanger);
235 
236     /**
237      * Method to create copies of internal type data. You must use this to create the internal
238      * data instances in copy constructors. It is needed, because it may need to allocate more memory
239      * for appended lists.
240      *
241      * \param rhs data to copy
242      * \returns copy of the data
243      */
244 
245     template <class Type>
copyData(const typename Type::Data & rhs)246     static typename Type::Data& copyData(const typename Type::Data& rhs)
247     {
248         uint size;
249         if (!rhs.m_dynamic)
250             size = sizeof(typename Type::Data); //Create a dynamic data instance
251         else
252             size = rhs.dynamicSize(); //Create a constant data instance, that holds all the data embedded.
253 
254         typename Type::Data& ret(*new (new char[size]) typename Type::Data(rhs));
255         ret.template setTypeClassId<Type>();
256         return ret;
257     }
258 
259     /**
260      * As above, but does not support copying data into a lower class(Should not be used while cloning)
261      */
262     template <class DataType>
copyDataDirectly(const DataType & rhs)263     static DataType& copyDataDirectly(const DataType& rhs)
264     {
265         uint size;
266         if (!rhs.m_dynamic)
267             size = sizeof(DataType); //Create a dynamic data instance
268         else
269             size = rhs.dynamicSize(); //Create a constant data instance, that holds all the data embedded.
270 
271         return *new (new char[size]) DataType(rhs);
272     }
273 
274     /**
275      * Method to create internal data structures. Use this in normal constructors.
276      *
277      * \returns the internal data structure
278      */
279     template <class Type>
createData()280     static typename Type::Data& createData()
281     {
282         typename Type::Data& ret(*new (new char[sizeof(typename Type::Data)]) typename Type::Data());
283         ret.template setTypeClassId<Type>();
284         return ret;
285     }
286 
287     using Data = AbstractTypeData;
288 
289 protected:
290     /**
291      * Visitor method, reimplement to allow visiting of types.
292      *
293      * \param v visitor which is visiting.
294      */
295     virtual void accept0 (TypeVisitor* v) const = 0;
296 
297     /// toString() function which can provide \a spaceOnLeft rather than on right if desired.
298     QString toString(bool spaceOnLeft) const;
299 
300     AbstractTypeData* d_ptr;
301 
302     TYPE_DECLARE_DATA(AbstractType)
303 
304     friend class AbstractTypeDataRequest;
305 };
306 
307 /**
308  * You can use these instead of dynamic_cast, for basic types it has better performance because it checks the whichType() member
309  */
310 template <class To>
311 inline To fastCast(AbstractType* from)
312 {
313     return dynamic_cast<To>(from);
314 }
315 
316 template <class To>
317 inline const To fastCast(const AbstractType* from)
318 {
319     return const_cast<const To>(fastCast<To>(const_cast<AbstractType*>(from))); //Hack so we don't need to define the functions twice, once for const, and once for not const
320 }
321 }
322 
323 #endif
324