1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt for Python.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #ifndef GENERATOR_H
30 #define GENERATOR_H
31 
32 #include "indentor.h"
33 #include <abstractmetalang_typedefs.h>
34 #include <typedatabase_typedefs.h>
35 #include <dependency.h>
36 #include <QtCore/QObject>
37 #include <QtCore/QSharedPointer>
38 #include <QtCore/QTextStream>
39 #include <QtCore/QVector>
40 
41 class ApiExtractor;
42 class AbstractMetaBuilder;
43 class AbstractMetaFunction;
44 class AbstractMetaClass;
45 class AbstractMetaEnum;
46 class TypeEntry;
47 class ComplexTypeEntry;
48 class AbstractMetaType;
49 class EnumTypeEntry;
50 class FlagsTypeEntry;
51 
52 QT_BEGIN_NAMESPACE
53 class QFile;
54 QT_END_NAMESPACE
55 
56 class PrimitiveTypeEntry;
57 class ContainerTypeEntry;
58 
59 QTextStream &formatCode(QTextStream &s, const QString &code, Indentor &indentor);
60 void verifyDirectoryFor(const QString &file);
61 
62 QString getClassTargetFullName(const AbstractMetaClass *metaClass, bool includePackageName = true);
63 QString getClassTargetFullName(const AbstractMetaEnum *metaEnum, bool includePackageName = true);
64 QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName = true);
65 QString getFilteredCppSignatureString(QString signature);
66 
67 /**
68  * PYSIDE-504: Handling the "protected hack"
69  *
70  * The problem: Creating wrappers when the class has private destructors.
71  * You can see an example on Windows in qclipboard_wrapper.h and others.
72  * Simply search for the text "// C++11: need to declare (unimplemented) destructor".
73  *
74  * The protected hack is the definition "#define protected public".
75  * For most compilers, this "hack" is enabled, because the problem of private
76  * destructors simply vanishes.
77  *
78  * If one does not want to use this hack, then a new problem arises:
79  * C++11 requires that a destructor is declared in a wrapper class when it is
80  * private in the base class. There is no implementation allowed!
81  *
82  * Unfortunately, MSVC in recent versions supports C++11, and due to restrictive
83  * rules, it is impossible to use the hack with this compiler.
84  * More unfortunate: Clang, when C++11 is enabled, also enforces a declaration
85  * of a private destructor, but it falsely then creates a linker error!
86  *
87  * Originally, we wanted to remove the protected hack. But due to the Clang
88  * problem, we gave up on removal of the protected hack and use it always
89  * when we can. This might change again when the Clang problem is solved.
90  */
91 
92 #ifdef Q_CC_MSVC
93 const int alwaysGenerateDestructor = 1;
94 #else
95 const int alwaysGenerateDestructor = 0;
96 #endif
97 
98 class DefaultValue
99 {
100 public:
101     enum Type
102     {
103         Error,
104         Boolean,
105         CppScalar, // A C++ scalar type (int,..) specified by value()
106         Custom, // A custom constructor/expression, uses value() as is
107         DefaultConstructor, // For classes named value()
108         DefaultConstructorWithDefaultValues, // as DefaultConstructor, but can't return {} though.
109         Enum, // Enum value as specified by value()
110         Pointer, // Pointer of type value()
111         Void  // "", for return values only
112     };
113 
114     explicit DefaultValue(Type t = Error, QString value = QString());
115     explicit DefaultValue(QString customValue);
116 
isValid()117     bool isValid() const { return m_type != Error; }
118 
119     QString returnValue() const;
120     QString initialization() const;
121     QString constructorParameter() const;
122 
value()123     QString value() const { return m_value; }
setValue(const QString & value)124     void setValue(const QString &value) { m_value = value; }
125 
type()126     Type type() const { return m_type; }
setType(Type type)127     void setType(Type type) { m_type = type; }
128 
129 private:
130     Type m_type;
131     QString m_value;
132 };
133 
134 /**
135  * A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
136  * AbstractMetaType, for which code is currently being generated.
137  *
138  * The main case is when the context contains only an AbstractMetaClass pointer, which is used
139  * by different methods to generate appropriate expressions, functions, type names, etc.
140  *
141  * The second case is for generation of code for smart pointers. In this case the m_metaClass member
142  * contains the generic template class of the smart pointer, and the m_preciseClassType member
143  * contains the instantiated template type, e.g. a concrete shared_ptr<int>. To
144  * distinguish this case, the member m_forSmartPointer is set to true.
145  *
146  * In the future the second case might be generalized for all template type instantiations.
147  */
148 class GeneratorContext {
149     friend class ShibokenGenerator;
150     friend class Generator;
151 public:
152     enum Type { Class, WrappedClass, SmartPointer };
153 
154     GeneratorContext() = default;
155 
metaClass()156     const AbstractMetaClass *metaClass() const { return m_metaClass; }
preciseType()157     const AbstractMetaType *preciseType() const { return m_preciseClassType; }
158 
forSmartPointer()159     bool forSmartPointer() const { return m_type == SmartPointer; }
useWrapper()160     bool useWrapper() const { return m_type ==  WrappedClass; }
161 
wrapperName()162     QString wrapperName() const
163     {
164         Q_ASSERT(m_type == WrappedClass);
165         return m_wrappername;
166     }
167 
168     QString smartPointerWrapperName() const;
169 
170 private:
171     const AbstractMetaClass *m_metaClass = nullptr;
172     const AbstractMetaType *m_preciseClassType = nullptr;
173     QString m_wrappername;
174     Type m_type = Class;
175 };
176 
177 /**
178  *   Base class for all generators. The default implementations does nothing,
179  *   you must subclass this to create your own generators.
180  */
181 class Generator
182 {
183 public:
184     using OptionDescription = QPair<QString, QString>;
185     using OptionDescriptions = QVector<OptionDescription>;
186 
187     /// Optiosn used around the generator code
188     enum Option {
189         NoOption                 = 0x00000000,
190         ExcludeConst             = 0x00000001,
191         ExcludeReference         = 0x00000002,
192 
193         EnumAsInts               = 0x00000004,
194         SkipName                 = 0x00000008,
195         SkipReturnType           = 0x00000010,
196         OriginalName             = 0x00000020,
197         VirtualCall              = 0x00000040,
198         OriginalTypeDescription  = 0x00000080,
199         SkipRemovedArguments     = 0x00000100,
200 
201         SkipDefaultValues        = 0x00000200,
202 
203         WriteSelf                = 0x00000400,
204         ExcludeMethodConst       = 0x00000800,
205 
206         ForceValueType           = ExcludeReference | ExcludeConst
207     };
208     Q_DECLARE_FLAGS(Options, Option)
209 
210     Generator();
211     virtual ~Generator();
212 
213     bool setup(const ApiExtractor &extractor);
214 
215     virtual OptionDescriptions options() const;
216     virtual bool handleOption(const QString &key, const QString &value);
217 
218     /// Returns the classes used to generate the binding code.
219     const AbstractMetaClassList &classes() const;
220 
221     /// Returns the top namespace made invisible
222     const AbstractMetaClassList &invisibleTopNamespaces() const;
223 
224     /// Returns the output directory
225     QString outputDirectory() const;
226 
227     /// Set the output directory
228     void setOutputDirectory(const QString &outDir);
229 
230     /**
231      *   Start the code generation, be sure to call setClasses before callign this method.
232      *   For each class it creates a QTextStream, call the write method with the current
233      *   class and the associated text stream, then write the text stream contents if needed.
234      *   \see #write
235      */
236     bool generate();
237 
238     /// Returns the license comment to be prepended to each source file generated.
239     QString licenseComment() const;
240 
241     /// Sets the license comment to be prepended to each source file generated.
242     void setLicenseComment(const QString &licenseComment);
243 
244     /// Returns the generator's name. Used for cosmetic purposes.
245     virtual const char *name() const = 0;
246 
247     /**
248      *  Retrieves the name of the currently processed module.
249      *  While package name is a complete package idetification, e.g. 'PySide.QtCore',
250      *  a module name represents the last part of the package, e.g. 'QtCore'.
251      *  If the target language separates the modules with characters other than
252      *  dots ('.') the generator subclass must overload this method.
253      *  \return a string representing the last part of a package name
254      */
255     QString moduleName() const;
256 
257     /**
258      *   Retrieves a list of constructors used in implicit conversions
259      *   available on the given type. The TypeEntry must be a value-type
260      *   or else it will return an empty list.
261      *   \param type a TypeEntry that is expected to be a value-type
262      *   \return a list of constructors that could be used as implicit converters
263      */
264     AbstractMetaFunctionList implicitConversions(const TypeEntry *type) const;
265 
266     /// Convenience function for implicitConversions(const TypeEntry *type).
267     AbstractMetaFunctionList implicitConversions(const AbstractMetaType *metaType) const;
268 
269     /// Check if type is a pointer.
270     static bool isPointer(const AbstractMetaType *type);
271 
272     /// Tells if the type or class is an Object (or QObject) Type.
273     static bool isObjectType(const TypeEntry *type);
274     static bool isObjectType(const ComplexTypeEntry *type);
275     static bool isObjectType(const AbstractMetaType *metaType);
276     static bool isObjectType(const AbstractMetaClass *metaClass);
277 
278     /// Returns true if the type is a C string (const char *).
279     static bool isCString(const AbstractMetaType *type);
280     /// Returns true if the type is a void pointer.
281     static bool isVoidPointer(const AbstractMetaType *type);
282 
283 protected:
284     /// Returns the classes, topologically ordered, used to generate the binding code.
285     ///
286     /// The classes are ordered such that derived classes appear later in the list than
287     /// their parent classes.
288     AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const;
289 
290     /// Returns all global functions found by APIExtractor
291     const AbstractMetaFunctionList &globalFunctions() const;
292 
293     /// Returns all global enums found by APIExtractor
294     const AbstractMetaEnumList &globalEnums() const;
295 
296     /// Returns all primitive types found by APIExtractor
297     PrimitiveTypeEntryList primitiveTypes() const;
298 
299     /// Returns all container types found by APIExtractor
300     ContainerTypeEntryList containerTypes() const;
301 
302     /// Returns an AbstractMetaEnum for a given TypeEntry that is an EnumTypeEntry, or nullptr if not found.
303     const AbstractMetaEnum *findAbstractMetaEnum(const TypeEntry *typeEntry) const;
304 
305     /// Returns an AbstractMetaEnum for a given AbstractMetaType that holds an EnumTypeEntry, or nullptr if not found.
306     const AbstractMetaEnum *findAbstractMetaEnum(const AbstractMetaType *metaType) const;
307 
308     virtual GeneratorContext contextForClass(const AbstractMetaClass *c) const;
309     GeneratorContext contextForSmartPointer(const AbstractMetaClass *c,
310                                             const AbstractMetaType *t) const;
311 
312     /// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case).
313     bool generateFileForContext(const GeneratorContext &context);
314 
315     /// Returns the file base name for a smart pointer.
316     QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
317                                            const AbstractMetaClass *smartPointerClass) const;
318 
319     /// Returns true if the generator should generate any code for the TypeEntry.
320     bool shouldGenerateTypeEntry(const TypeEntry *) const;
321 
322     /// Returns true if the generator should generate any code for the AbstractMetaClass.
323     virtual bool shouldGenerate(const AbstractMetaClass *) const;
324 
325     /// Returns the subdirectory used to write the binding code of an AbstractMetaClass.
326     virtual QString subDirectoryForClass(const AbstractMetaClass *clazz) const;
327 
328     /**
329     *   Translate metatypes to binding source format.
330     *   \param metatype a pointer to metatype
331     *   \param context the current meta class
332     *   \param option some extra options
333     *   \return the metatype translated to binding source format
334     */
335     QString translateType(const AbstractMetaType *metatype,
336                           const AbstractMetaClass *context,
337                           Options options = NoOption) const;
338 
339     /**
340     *   Function used to write the fucntion arguments on the class buffer.
341     *   \param s the class output buffer
342     *   \param metafunction the pointer to metafunction information
343     *   \param count the number of function arguments
344     *   \param options some extra options used during the parser
345     */
346     virtual void writeFunctionArguments(QTextStream &s,
347                                         const AbstractMetaFunction *metafunction,
348                                         Options options = NoOption) const = 0;
349 
350     virtual void writeArgumentNames(QTextStream &s,
351                                     const AbstractMetaFunction *metafunction,
352                                     Options options = NoOption) const = 0;
353 
354     void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func);
355 
356     /**
357      *   Returns the package name.
358      */
359     QString packageName() const;
360 
361     // Returns the full name of the type.
362     QString getFullTypeName(const TypeEntry *type) const;
363     QString getFullTypeName(const AbstractMetaType *type) const;
364     QString getFullTypeName(const AbstractMetaClass *metaClass) const;
365 
366     /**
367      *  Returns the full qualified C++ name for an AbstractMetaType, but removing modifiers
368      *  as 'const', '&', and '*' (except if the class is not derived from a template).
369      *  This is useful for instantiated templates.
370      */
371     QString getFullTypeNameWithoutModifiers(const AbstractMetaType *type) const;
372 
373     /**
374      *   Tries to build a minimal constructor for the type.
375      *   It will check first for a user defined default constructor.
376      *   Returns a null string if it fails.
377      */
378     DefaultValue minimalConstructor(const TypeEntry *type) const;
379     DefaultValue minimalConstructor(const AbstractMetaType *type) const;
380     DefaultValue minimalConstructor(const AbstractMetaClass *metaClass) const;
381 
382     /**
383      *   Returns the file name used to write the binding code of an AbstractMetaClass/Type.
384      *   \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType
385      *   for which the file name must be returned
386      *   \return the file name used to write the binding code for the class
387      */
388     virtual QString fileNameSuffix() const = 0;
389     virtual QString fileNameForContext(const GeneratorContext &context) const = 0;
390 
391 
392     virtual bool doSetup() = 0;
393 
394     /**
395      *   Write the bindding code for an AbstractMetaClass.
396      *   This is called by generate method.
397      *   \param  s   text stream to write the generated output
398      *   \param  metaClass  the class that should be generated
399      */
400     virtual void generateClass(QTextStream &s, const GeneratorContext &classContext) = 0;
401     virtual bool finishGeneration() = 0;
402 
403     /**
404     *    Returns the subdirectory path for a given package
405     *    (aka module, aka library) name.
406     *    If the target language separates the package modules with characters other
407     *    than dots ('.') the generator subclass must overload this method.
408     *    /param packageName complete package name for which to return the subdirectory path
409     *    or nothing the use the name of the currently processed package
410     *    /return a string representing the subdirectory path for the given package
411     */
412     virtual QString subDirectoryForPackage(QString packageName = QString()) const;
413 
414     QVector<const AbstractMetaType *> instantiatedContainers() const;
415     QVector<const AbstractMetaType *> instantiatedSmartPointers() const;
416 
417     static QString getSimplifiedContainerTypeName(const AbstractMetaType *type);
418     void addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type,
419                                                    const QString &context);
420 
421 private:
422     bool useEnumAsIntForProtectedHack(const AbstractMetaType *cType) const;
423 
424     struct GeneratorPrivate;
425     GeneratorPrivate *m_d;
426     void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction *func);
427     void collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass);
428     void collectInstantiatedContainersAndSmartPointers();
429 };
430 
431 Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options)
432 using GeneratorPtr = QSharedPointer<Generator>;
433 using Generators = QVector<GeneratorPtr>;
434 
435 #endif // GENERATOR_H
436 
437