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