aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/generator/generator.h
blob: 04840427f0209c0ba84e60f39a49aed02d576fdb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt for Python.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#ifndef GENERATOR_H
#define GENERATOR_H

#include "indentor.h"
#include <abstractmetalang_typedefs.h>
#include <typedatabase_typedefs.h>
#include <dependency.h>
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
#include <QtCore/QTextStream>
#include <QtCore/QVector>

class ApiExtractor;
class AbstractMetaBuilder;
class AbstractMetaFunction;
class AbstractMetaClass;
class AbstractMetaEnum;
class TypeEntry;
class ComplexTypeEntry;
class AbstractMetaType;
class EnumTypeEntry;
class FlagsTypeEntry;

QT_BEGIN_NAMESPACE
class QFile;
QT_END_NAMESPACE

class PrimitiveTypeEntry;
class ContainerTypeEntry;

QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor);
void verifyDirectoryFor(const QString &file);

QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName = true);
QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName = true);
QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePackageName = true);
QString getFilteredCppSignatureString(QString signature);

/**
 * PYSIDE-504: Handling the "protected hack"
 *
 * The problem: Creating wrappers when the class has private destructors.
 * You can see an example on Windows in qclipboard_wrapper.h and others.
 * Simply search for the text "// C++11: need to declare (unimplemented) destructor".
 *
 * The protected hack is the definition "#define protected public".
 * For most compilers, this "hack" is enabled, because the problem of private
 * destructors simply vanishes.
 *
 * If one does not want to use this hack, then a new problem arises:
 * C++11 requires that a destructor is declared in a wrapper class when it is
 * private in the base class. There is no implementation allowed!
 *
 * Unfortunately, MSVC in recent versions supports C++11, and due to restrictive
 * rules, it is impossible to use the hack with this compiler.
 * More unfortunate: Clang, when C++11 is enabled, also enforces a declaration
 * of a private destructor, but it falsely then creates a linker error!
 *
 * Originally, we wanted to remove the protected hack. But due to the Clang
 * problem, we gave up on removal of the protected hack and use it always
 * when we can. This might change again when the Clang problem is solved.
 */

#ifdef Q_CC_MSVC
const int alwaysGenerateDestructor = 1;
#else
const int alwaysGenerateDestructor = 0;
#endif

class DefaultValue
{
public:
    enum Type
    {
        Error,
        Boolean,
        CppScalar, // A C++ scalar type (int,..) specified by value()
        Custom, // A custom constructor/expression, uses value() as is
        DefaultConstructor, // For classes named value()
        DefaultConstructorWithDefaultValues, // as DefaultConstructor, but can't return {} though.
        Enum, // Enum value as specified by value()
        Pointer, // Pointer of type value()
        Void  // "", for return values only
    };

    explicit DefaultValue(Type t = Error, QString value = QString());
    explicit DefaultValue(QString customValue);

    bool isValid() const { return m_type != Error; }

    QString returnValue() const;
    QString initialization() const;
    QString constructorParameter() const;

    QString value() const { return m_value; }
    void setValue(const QString &value) { m_value = value; }

    Type type() const { return m_type; }
    void setType(Type type) { m_type = type; }

private:
    Type m_type;
    QString m_value;
};

/**
 * A GeneratorContext object contains a pointer to an AbstractMetaClass and/or a specialized
 * AbstractMetaType, for which code is currently being generated.
 *
 * The main case is when the context contains only an AbstractMetaClass pointer, which is used
 * by different methods to generate appropriate expressions, functions, type names, etc.
 *
 * The second case is for generation of code for smart pointers. In this case the m_metaClass member
 * contains the generic template class of the smart pointer, and the m_preciseClassType member
 * contains the instantiated template type, e.g. a concrete shared_ptr<int>. To
 * distinguish this case, the member m_forSmartPointer is set to true.
 *
 * In the future the second case might be generalized for all template type instantiations.
 */
class GeneratorContext {
public:
    GeneratorContext() : m_metaClass(0), m_preciseClassType(0), m_forSmartPointer(false) {}
    GeneratorContext(AbstractMetaClass *metaClass,
                     const AbstractMetaType *preciseType = 0,
                     bool forSmartPointer = false)
        : m_metaClass(metaClass),
        m_preciseClassType(preciseType),
        m_forSmartPointer(forSmartPointer) {}


    AbstractMetaClass *metaClass() const { return m_metaClass; }
    bool forSmartPointer() const { return m_forSmartPointer; }
    const AbstractMetaType *preciseType() const { return m_preciseClassType; }

private:
    AbstractMetaClass *m_metaClass;
    const AbstractMetaType *m_preciseClassType;
    bool m_forSmartPointer;
};

/**
 *   Base class for all generators. The default implementations does nothing,
 *   you must subclass this to create your own generators.
 */
class Generator
{
public:
    typedef QPair<QString, QString> OptionDescription;
    typedef QVector<OptionDescription> OptionDescriptions;

    /// Optiosn used around the generator code
    enum Option {
        NoOption                 = 0x00000000,
        ExcludeConst             = 0x00000001,
        ExcludeReference         = 0x00000002,

        EnumAsInts               = 0x00000004,
        SkipName                 = 0x00000008,
        SkipReturnType           = 0x00000010,
        OriginalName             = 0x00000020,
        VirtualCall              = 0x00000040,
        OriginalTypeDescription  = 0x00000080,
        SkipRemovedArguments     = 0x00000100,

        SkipDefaultValues        = 0x00000200,

        WriteSelf                = 0x00000400,
        ExcludeMethodConst       = 0x00000800,

        ForceValueType           = ExcludeReference | ExcludeConst
    };
    Q_DECLARE_FLAGS(Options, Option)

    Generator();
    virtual ~Generator();

    bool setup(const ApiExtractor& extractor);

    virtual OptionDescriptions options() const;
    virtual bool handleOption(const QString &key, const QString &value);

    /// Returns the classes used to generate the binding code.
    AbstractMetaClassList classes() const;

    /// Returns the output directory
    QString outputDirectory() const;

    /// Set the output directory
    void setOutputDirectory(const QString &outDir);

    /**
     *   Start the code generation, be sure to call setClasses before callign this method.
     *   For each class it creates a QTextStream, call the write method with the current
     *   class and the associated text stream, then write the text stream contents if needed.
     *   \see #write
     */
    bool generate();

    /// Returns the license comment to be prepended to each source file generated.
    QString licenseComment() const;

    /// Sets the license comment to be prepended to each source file generated.
    void setLicenseComment(const QString &licenseComment);

    /// Returns the generator's name. Used for cosmetic purposes.
    virtual const char* name() const = 0;

    /**
     *  Retrieves the name of the currently processed module.
     *  While package name is a complete package idetification, e.g. 'PySide.QtCore',
     *  a module name represents the last part of the package, e.g. 'QtCore'.
     *  If the target language separates the modules with characters other than
     *  dots ('.') the generator subclass must overload this method.
     *  \return a string representing the last part of a package name
     */
    QString moduleName() const;

    /**
     *   Retrieves a list of constructors used in implicit conversions
     *   available on the given type. The TypeEntry must be a value-type
     *   or else it will return an empty list.
     *   \param type a TypeEntry that is expected to be a value-type
     *   \return a list of constructors that could be used as implicit converters
     */
    AbstractMetaFunctionList implicitConversions(const TypeEntry* type) const;

    /// Convenience function for implicitConversions(const TypeEntry* type).
    AbstractMetaFunctionList implicitConversions(const AbstractMetaType* metaType) const;

    /// Check if type is a pointer.
    static bool isPointer(const AbstractMetaType* type);

    /// Tells if the type or class is an Object (or QObject) Type.
    static bool isObjectType(const TypeEntry* type);
    static bool isObjectType(const ComplexTypeEntry* type);
    static bool isObjectType(const AbstractMetaType* metaType);
    static bool isObjectType(const AbstractMetaClass* metaClass);

    /// Returns true if the type is a C string (const char*).
    static bool isCString(const AbstractMetaType* type);
    /// Returns true if the type is a void pointer.
    static bool isVoidPointer(const AbstractMetaType* type);

protected:
    /// Returns the classes, topologically ordered, used to generate the binding code.
    ///
    /// The classes are ordered such that derived classes appear later in the list than
    /// their parent classes.
    AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const;

    /// Returns all global functions found by APIExtractor
    AbstractMetaFunctionList globalFunctions() const;

    /// Returns all global enums found by APIExtractor
    AbstractMetaEnumList globalEnums() const;

    /// Returns all primitive types found by APIExtractor
    PrimitiveTypeEntryList primitiveTypes() const;

    /// Returns all container types found by APIExtractor
    ContainerTypeEntryList containerTypes() const;

    /// Returns an AbstractMetaEnum for a given TypeEntry that is an EnumTypeEntry, or nullptr if not found.
    const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const;

    /// Returns an AbstractMetaEnum for a given AbstractMetaType that holds an EnumTypeEntry, or nullptr if not found.
    const AbstractMetaEnum* findAbstractMetaEnum(const AbstractMetaType* metaType) const;

    /// Generates a file for given AbstractMetaClass or AbstractMetaType (smart pointer case).
    bool generateFileForContext(GeneratorContext &context);

    /// Returns the file base name for a smart pointer.
    QString getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
                                           const AbstractMetaClass *smartPointerClass) const;

    /// Returns true if the generator should generate any code for the TypeEntry.
    bool shouldGenerateTypeEntry(const TypeEntry*) const;

    /// Returns true if the generator should generate any code for the AbstractMetaClass.
    virtual bool shouldGenerate(const AbstractMetaClass *) const;

    /// Returns the subdirectory used to write the binding code of an AbstractMetaClass.
    virtual QString subDirectoryForClass(const AbstractMetaClass* clazz) const;

    /**
    *   Translate metatypes to binding source format.
    *   \param metatype a pointer to metatype
    *   \param context the current meta class
    *   \param option some extra options
    *   \return the metatype translated to binding source format
    */
    QString translateType(const AbstractMetaType *metatype,
                          const AbstractMetaClass *context,
                          Options options = NoOption) const;

    /**
    *   Function used to write the fucntion arguments on the class buffer.
    *   \param s the class output buffer
    *   \param metafunction the pointer to metafunction information
    *   \param count the number of function arguments
    *   \param options some extra options used during the parser
    */
    virtual void writeFunctionArguments(QTextStream &s,
                                        const AbstractMetaFunction *metafunction,
                                        Options options = NoOption) const = 0;

    virtual void writeArgumentNames(QTextStream &s,
                                    const AbstractMetaFunction *metafunction,
                                    Options options = NoOption) const = 0;

    void replaceTemplateVariables(QString &code, const AbstractMetaFunction *func);

    /**
     *   Returns the package name.
     */
    QString packageName() const;

    // Returns the full name of the type.
    QString getFullTypeName(const TypeEntry* type) const;
    QString getFullTypeName(const AbstractMetaType* type) const;
    QString getFullTypeName(const AbstractMetaClass* metaClass) const;

    /**
     *  Returns the full qualified C++ name for an AbstractMetaType, but removing modifiers
     *  as 'const', '&', and '*' (except if the class is not derived from a template).
     *  This is useful for instantiated templates.
     */
    QString getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const;

    /**
     *   Tries to build a minimal constructor for the type.
     *   It will check first for a user defined default constructor.
     *   Returns a null string if it fails.
     */
    DefaultValue minimalConstructor(const TypeEntry* type) const;
    DefaultValue minimalConstructor(const AbstractMetaType* type) const;
    DefaultValue minimalConstructor(const AbstractMetaClass* metaClass) const;

    /**
     *   Returns the file name used to write the binding code of an AbstractMetaClass/Type.
     *   \param context the GeneratorContext which contains an AbstractMetaClass or AbstractMetaType
     *   for which the file name must be returned
     *   \return the file name used to write the binding code for the class
     */
    virtual QString fileNameSuffix() const = 0;
    virtual QString fileNameForContext(GeneratorContext &context) const = 0;


    virtual bool doSetup() = 0;

    /**
     *   Write the bindding code for an AbstractMetaClass.
     *   This is called by generate method.
     *   \param  s   text stream to write the generated output
     *   \param  metaClass  the class that should be generated
     */
    virtual void generateClass(QTextStream& s, GeneratorContext &classContext) = 0;
    virtual bool finishGeneration() = 0;

    /**
    *    Returns the subdirectory path for a given package
    *    (aka module, aka library) name.
    *    If the target language separates the package modules with characters other
    *    than dots ('.') the generator subclass must overload this method.
    *    /param packageName complete package name for which to return the subdirectory path
    *    or nothing the use the name of the currently processed package
    *    /return a string representing the subdirectory path for the given package
    */
    virtual QString subDirectoryForPackage(QString packageName = QString()) const;

    QVector<const AbstractMetaType*> instantiatedContainers() const;
    QVector<const AbstractMetaType*> instantiatedSmartPointers() const;

    static QString getSimplifiedContainerTypeName(const AbstractMetaType *type);
    void addInstantiatedContainersAndSmartPointers(const AbstractMetaType *type,
                                                   const QString &context);

private:
    bool useEnumAsIntForProtectedHack(const AbstractMetaType *cType) const;

    struct GeneratorPrivate;
    GeneratorPrivate* m_d;
    void collectInstantiatedContainersAndSmartPointers(const AbstractMetaFunction* func);
    void collectInstantiatedContainersAndSmartPointers(const AbstractMetaClass *metaClass);
    void collectInstantiatedContainersAndSmartPointers();
};

Q_DECLARE_OPERATORS_FOR_FLAGS(Generator::Options)
typedef QSharedPointer<Generator> GeneratorPtr;
typedef QVector<GeneratorPtr> Generators;

#endif // GENERATOR_H