| 1 |
/* |
| 2 |
* This file is part of the API Extractor project. |
| 3 |
* |
| 4 |
* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
| 5 |
* |
| 6 |
* Contact: PySide team <contact@pyside.org> |
| 7 |
* |
| 8 |
* This program is free software; you can redistribute it and/or |
| 9 |
* modify it under the terms of the GNU General Public License |
| 10 |
* version 2 as published by the Free Software Foundation. |
| 11 |
* |
| 12 |
* This program is distributed in the hope that it will be useful, but |
| 13 |
* WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 15 |
* General Public License for more details. |
| 16 |
* |
| 17 |
* You should have received a copy of the GNU General Public License |
| 18 |
* along with this program; if not, write to the Free Software |
| 19 |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
| 20 |
* 02110-1301 USA |
| 21 |
* |
| 22 |
*/ |
| 23 |
|
| 24 |
#include "generator.h" |
| 25 |
#include "reporthandler.h" |
| 26 |
#include "fileout.h" |
| 27 |
#include "apiextractor.h" |
| 28 |
|
| 29 |
#include <QtCore/QDir> |
| 30 |
#include <QtCore/QFile> |
| 31 |
#include <QtCore/QFileInfo> |
| 32 |
#include <QDebug> |
| 33 |
#include <typedatabase.h> |
| 34 |
|
| 35 |
struct Generator::GeneratorPrivate { |
| 36 |
const ApiExtractor* apiextractor; |
| 37 |
QString outDir; |
| 38 |
// License comment |
| 39 |
QString licenseComment; |
| 40 |
QString packageName; |
| 41 |
int numGenerated; |
| 42 |
int numGeneratedWritten; |
| 43 |
QStringList instantiatedContainersNames; |
| 44 |
QList<const AbstractMetaType*> instantiatedContainers; |
| 45 |
}; |
| 46 |
|
| 47 |
Generator::Generator() : m_d(new GeneratorPrivate) |
| 48 |
{ |
| 49 |
m_d->numGenerated = 0; |
| 50 |
m_d->numGeneratedWritten = 0; |
| 51 |
m_d->instantiatedContainers = QList<const AbstractMetaType*>(); |
| 52 |
m_d->instantiatedContainersNames = QStringList(); |
| 53 |
} |
| 54 |
|
| 55 |
Generator::~Generator() |
| 56 |
{ |
| 57 |
delete m_d; |
| 58 |
} |
| 59 |
|
| 60 |
bool Generator::setup(const ApiExtractor& extractor, const QMap< QString, QString > args) |
| 61 |
{ |
| 62 |
m_d->apiextractor = &extractor; |
| 63 |
TypeEntryHash allEntries = TypeDatabase::instance()->allEntries(); |
| 64 |
TypeEntry* entryFound = 0; |
| 65 |
foreach (QList<TypeEntry*> entryList, allEntries.values()) { |
| 66 |
foreach (TypeEntry* entry, entryList) { |
| 67 |
if (entry->type() == TypeEntry::TypeSystemType && entry->generateCode()) { |
| 68 |
entryFound = entry; |
| 69 |
break; |
| 70 |
} |
| 71 |
} |
| 72 |
if (entryFound) |
| 73 |
break; |
| 74 |
} |
| 75 |
if (entryFound) |
| 76 |
m_d->packageName = entryFound->name(); |
| 77 |
else |
| 78 |
ReportHandler::warning("Couldn't find the package name!!"); |
| 79 |
|
| 80 |
collectInstantiatedContainers(); |
| 81 |
|
| 82 |
return doSetup(args); |
| 83 |
} |
| 84 |
|
| 85 |
QString Generator::getSimplifiedContainerTypeName(const AbstractMetaType* type) |
| 86 |
{ |
| 87 |
if (!type->typeEntry()->isContainer()) |
| 88 |
return type->cppSignature(); |
| 89 |
QString typeName = type->cppSignature(); |
| 90 |
if (type->isConstant()) |
| 91 |
typeName.remove(0, sizeof("const ") / sizeof(char) - 1); |
| 92 |
if (type->isReference()) |
| 93 |
typeName.chop(1); |
| 94 |
while (typeName.endsWith('*') || typeName.endsWith(' ')) |
| 95 |
typeName.chop(1); |
| 96 |
return typeName; |
| 97 |
} |
| 98 |
|
| 99 |
void Generator::addInstantiatedContainers(const AbstractMetaType* type) |
| 100 |
{ |
| 101 |
if (!type) |
| 102 |
return; |
| 103 |
foreach (const AbstractMetaType* t, type->instantiations()) |
| 104 |
addInstantiatedContainers(t); |
| 105 |
if (!type->typeEntry()->isContainer()) |
| 106 |
return; |
| 107 |
QString typeName = getSimplifiedContainerTypeName(type); |
| 108 |
if (!m_d->instantiatedContainersNames.contains(typeName)) { |
| 109 |
m_d->instantiatedContainersNames.append(typeName); |
| 110 |
m_d->instantiatedContainers.append(type); |
| 111 |
} |
| 112 |
} |
| 113 |
|
| 114 |
void Generator::collectInstantiatedContainers(const AbstractMetaFunction* func) |
| 115 |
{ |
| 116 |
addInstantiatedContainers(func->type()); |
| 117 |
foreach (const AbstractMetaArgument* arg, func->arguments()) |
| 118 |
addInstantiatedContainers(arg->type()); |
| 119 |
} |
| 120 |
|
| 121 |
void Generator::collectInstantiatedContainers(const AbstractMetaClass* metaClass) |
| 122 |
{ |
| 123 |
if (!metaClass->typeEntry()->generateCode()) |
| 124 |
return; |
| 125 |
foreach (const AbstractMetaFunction* func, metaClass->functions()) |
| 126 |
collectInstantiatedContainers(func); |
| 127 |
foreach (const AbstractMetaField* field, metaClass->fields()) |
| 128 |
addInstantiatedContainers(field->type()); |
| 129 |
foreach (AbstractMetaClass* innerClass, metaClass->innerClasses()) |
| 130 |
collectInstantiatedContainers(innerClass); |
| 131 |
} |
| 132 |
|
| 133 |
void Generator::collectInstantiatedContainers() |
| 134 |
{ |
| 135 |
foreach (const AbstractMetaFunction* func, globalFunctions()) |
| 136 |
collectInstantiatedContainers(func); |
| 137 |
foreach (const AbstractMetaClass* metaClass, classes()) |
| 138 |
collectInstantiatedContainers(metaClass); |
| 139 |
} |
| 140 |
|
| 141 |
QList<const AbstractMetaType*> Generator::instantiatedContainers() const |
| 142 |
{ |
| 143 |
return m_d->instantiatedContainers; |
| 144 |
} |
| 145 |
|
| 146 |
QMap< QString, QString > Generator::options() const |
| 147 |
{ |
| 148 |
return QMap<QString, QString>(); |
| 149 |
} |
| 150 |
|
| 151 |
AbstractMetaClassList Generator::classes() const |
| 152 |
{ |
| 153 |
return m_d->apiextractor->classes(); |
| 154 |
} |
| 155 |
|
| 156 |
AbstractMetaFunctionList Generator::globalFunctions() const |
| 157 |
{ |
| 158 |
return m_d->apiextractor->globalFunctions(); |
| 159 |
} |
| 160 |
|
| 161 |
AbstractMetaEnumList Generator::globalEnums() const |
| 162 |
{ |
| 163 |
return m_d->apiextractor->globalEnums(); |
| 164 |
} |
| 165 |
|
| 166 |
QList<const PrimitiveTypeEntry*> Generator::primitiveTypes() const |
| 167 |
{ |
| 168 |
return m_d->apiextractor->primitiveTypes(); |
| 169 |
} |
| 170 |
|
| 171 |
QList<const ContainerTypeEntry*> Generator::containerTypes() const |
| 172 |
{ |
| 173 |
return m_d->apiextractor->containerTypes(); |
| 174 |
} |
| 175 |
|
| 176 |
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const |
| 177 |
{ |
| 178 |
return m_d->apiextractor->findAbstractMetaEnum(typeEntry); |
| 179 |
} |
| 180 |
|
| 181 |
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const TypeEntry* typeEntry) const |
| 182 |
{ |
| 183 |
return m_d->apiextractor->findAbstractMetaEnum(typeEntry); |
| 184 |
} |
| 185 |
|
| 186 |
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const |
| 187 |
{ |
| 188 |
return m_d->apiextractor->findAbstractMetaEnum(typeEntry); |
| 189 |
} |
| 190 |
|
| 191 |
const AbstractMetaEnum* Generator::findAbstractMetaEnum(const AbstractMetaType* metaType) const |
| 192 |
{ |
| 193 |
return m_d->apiextractor->findAbstractMetaEnum(metaType); |
| 194 |
} |
| 195 |
|
| 196 |
QSet< QString > Generator::qtMetaTypeDeclaredTypeNames() const |
| 197 |
{ |
| 198 |
return m_d->apiextractor->qtMetaTypeDeclaredTypeNames(); |
| 199 |
} |
| 200 |
|
| 201 |
QString Generator::licenseComment() const |
| 202 |
{ |
| 203 |
return m_d->licenseComment; |
| 204 |
} |
| 205 |
|
| 206 |
void Generator::setLicenseComment(const QString& licenseComment) |
| 207 |
{ |
| 208 |
m_d->licenseComment = licenseComment; |
| 209 |
} |
| 210 |
|
| 211 |
QString Generator::packageName() const |
| 212 |
{ |
| 213 |
return m_d->packageName; |
| 214 |
} |
| 215 |
|
| 216 |
QString Generator::moduleName() const |
| 217 |
{ |
| 218 |
QString& pkgName = m_d->packageName; |
| 219 |
return QString(pkgName).remove(0, pkgName.lastIndexOf('.') + 1); |
| 220 |
} |
| 221 |
|
| 222 |
QString Generator::outputDirectory() const |
| 223 |
{ |
| 224 |
return m_d->outDir; |
| 225 |
} |
| 226 |
|
| 227 |
void Generator::setOutputDirectory(const QString &outDir) |
| 228 |
{ |
| 229 |
m_d->outDir = outDir; |
| 230 |
} |
| 231 |
|
| 232 |
int Generator::numGenerated() const |
| 233 |
{ |
| 234 |
return m_d->numGenerated; |
| 235 |
} |
| 236 |
|
| 237 |
int Generator::numGeneratedAndWritten() const |
| 238 |
{ |
| 239 |
return m_d->numGeneratedWritten; |
| 240 |
} |
| 241 |
|
| 242 |
void Generator::generate() |
| 243 |
{ |
| 244 |
foreach (AbstractMetaClass *cls, m_d->apiextractor->classes()) { |
| 245 |
if (!shouldGenerate(cls)) |
| 246 |
continue; |
| 247 |
|
| 248 |
QString fileName = fileNameForClass(cls); |
| 249 |
if (fileName.isNull()) |
| 250 |
continue; |
| 251 |
ReportHandler::debugSparse(QString("generating: %1").arg(fileName)); |
| 252 |
|
| 253 |
FileOut fileOut(outputDirectory() + '/' + subDirectoryForClass(cls) + '/' + fileName); |
| 254 |
generateClass(fileOut.stream, cls); |
| 255 |
|
| 256 |
if (fileOut.done()) |
| 257 |
++m_d->numGeneratedWritten; |
| 258 |
++m_d->numGenerated; |
| 259 |
} |
| 260 |
finishGeneration(); |
| 261 |
} |
| 262 |
|
| 263 |
bool Generator::shouldGenerateTypeEntry(const TypeEntry* type) const |
| 264 |
{ |
| 265 |
return type->codeGeneration() & TypeEntry::GenerateTargetLang; |
| 266 |
} |
| 267 |
|
| 268 |
bool Generator::shouldGenerate(const AbstractMetaClass* metaClass) const |
| 269 |
{ |
| 270 |
return shouldGenerateTypeEntry(metaClass->typeEntry()); |
| 271 |
} |
| 272 |
|
| 273 |
void verifyDirectoryFor(const QFile &file) |
| 274 |
{ |
| 275 |
QDir dir = QFileInfo(file).dir(); |
| 276 |
if (!dir.exists()) { |
| 277 |
if (!dir.mkpath(dir.absolutePath())) |
| 278 |
ReportHandler::warning(QString("unable to create directory '%1'") |
| 279 |
.arg(dir.absolutePath())); |
| 280 |
} |
| 281 |
} |
| 282 |
|
| 283 |
void Generator::replaceTemplateVariables(QString &code, const AbstractMetaFunction *func) |
| 284 |
{ |
| 285 |
const AbstractMetaClass *cpp_class = func->ownerClass(); |
| 286 |
if (cpp_class) |
| 287 |
code.replace("%TYPE", cpp_class->name()); |
| 288 |
|
| 289 |
foreach (AbstractMetaArgument *arg, func->arguments()) |
| 290 |
code.replace("%" + QString::number(arg->argumentIndex() + 1), arg->name()); |
| 291 |
|
| 292 |
//template values |
| 293 |
code.replace("%RETURN_TYPE", translateType(func->type(), cpp_class)); |
| 294 |
code.replace("%FUNCTION_NAME", func->originalName()); |
| 295 |
|
| 296 |
if (code.contains("%ARGUMENT_NAMES")) { |
| 297 |
QString str; |
| 298 |
QTextStream aux_stream(&str); |
| 299 |
writeArgumentNames(aux_stream, func, Generator::SkipRemovedArguments); |
| 300 |
code.replace("%ARGUMENT_NAMES", str); |
| 301 |
} |
| 302 |
|
| 303 |
if (code.contains("%ARGUMENTS")) { |
| 304 |
QString str; |
| 305 |
QTextStream aux_stream(&str); |
| 306 |
writeFunctionArguments(aux_stream, func, Options(SkipDefaultValues) | SkipRemovedArguments); |
| 307 |
code.replace("%ARGUMENTS", str); |
| 308 |
} |
| 309 |
} |
| 310 |
|
| 311 |
QTextStream& formatCode(QTextStream &s, const QString& code, Indentor &indentor) |
| 312 |
{ |
| 313 |
// detect number of spaces before the first character |
| 314 |
QStringList lst(code.split("\n")); |
| 315 |
QRegExp nonSpaceRegex("[^\\s]"); |
| 316 |
int spacesToRemove = 0; |
| 317 |
foreach(QString line, lst) { |
| 318 |
if (!line.trimmed().isEmpty()) { |
| 319 |
spacesToRemove = line.indexOf(nonSpaceRegex); |
| 320 |
if (spacesToRemove == -1) |
| 321 |
spacesToRemove = 0; |
| 322 |
break; |
| 323 |
} |
| 324 |
} |
| 325 |
|
| 326 |
static QRegExp emptyLine("\\s*[\\r]?[\\n]?\\s*"); |
| 327 |
|
| 328 |
foreach(QString line, lst) { |
| 329 |
if (!line.isEmpty() && !emptyLine.exactMatch(line)) { |
| 330 |
while (line.end()->isSpace()) |
| 331 |
line.chop(1); |
| 332 |
int limit = 0; |
| 333 |
for(int i = 0; i < spacesToRemove; ++i) { |
| 334 |
if (!line[i].isSpace()) |
| 335 |
break; |
| 336 |
limit++; |
| 337 |
} |
| 338 |
|
| 339 |
s << indentor << line.remove(0, limit); |
| 340 |
} |
| 341 |
s << endl; |
| 342 |
} |
| 343 |
return s; |
| 344 |
} |
| 345 |
|
| 346 |
AbstractMetaFunctionList Generator::implicitConversions(const TypeEntry* type) const |
| 347 |
{ |
| 348 |
if (type->isValue()) { |
| 349 |
const AbstractMetaClass* metaClass = classes().findClass(type); |
| 350 |
if (metaClass) |
| 351 |
return metaClass->implicitConversions(); |
| 352 |
} |
| 353 |
return AbstractMetaFunctionList(); |
| 354 |
} |
| 355 |
|
| 356 |
AbstractMetaFunctionList Generator::implicitConversions(const AbstractMetaType* metaType) const |
| 357 |
{ |
| 358 |
return implicitConversions(metaType->typeEntry()); |
| 359 |
} |
| 360 |
|
| 361 |
bool Generator::isObjectType(const TypeEntry* type) |
| 362 |
{ |
| 363 |
if (type->isComplex()) |
| 364 |
return Generator::isObjectType((const ComplexTypeEntry*)type); |
| 365 |
return type->isObject(); |
| 366 |
} |
| 367 |
bool Generator::isObjectType(const ComplexTypeEntry* type) |
| 368 |
{ |
| 369 |
return type->isObject() || type->isQObject(); |
| 370 |
} |
| 371 |
bool Generator::isObjectType(const AbstractMetaClass* metaClass) |
| 372 |
{ |
| 373 |
return Generator::isObjectType(metaClass->typeEntry()); |
| 374 |
} |
| 375 |
bool Generator::isObjectType(const AbstractMetaType* metaType) |
| 376 |
{ |
| 377 |
return isObjectType(metaType->typeEntry()); |
| 378 |
} |
| 379 |
|
| 380 |
bool Generator::isPointer(const AbstractMetaType* type) |
| 381 |
{ |
| 382 |
return type->indirections() > 0 |
| 383 |
|| type->isNativePointer() |
| 384 |
|| type->isValuePointer(); |
| 385 |
} |
| 386 |
|
| 387 |
bool Generator::isCString(const AbstractMetaType* type) |
| 388 |
{ |
| 389 |
return type->isNativePointer() |
| 390 |
&& type->indirections() == 1 |
| 391 |
&& type->name() == "char"; |
| 392 |
} |
| 393 |
|
| 394 |
bool Generator::isVoidPointer(const AbstractMetaType* type) |
| 395 |
{ |
| 396 |
return type->isNativePointer() |
| 397 |
&& type->indirections() == 1 |
| 398 |
&& type->name() == "void"; |
| 399 |
} |
| 400 |
|
| 401 |
QString Generator::getFullTypeName(const TypeEntry* type) const |
| 402 |
{ |
| 403 |
return QString("%1%2").arg(type->isCppPrimitive() ? "" : "::").arg(type->qualifiedCppName()); |
| 404 |
} |
| 405 |
|
| 406 |
QString Generator::getFullTypeName(const AbstractMetaType* type) const |
| 407 |
{ |
| 408 |
if (isCString(type)) |
| 409 |
return "const char*"; |
| 410 |
if (isVoidPointer(type)) |
| 411 |
return "void*"; |
| 412 |
if (type->typeEntry()->isContainer()) |
| 413 |
return QString("::%1").arg(type->cppSignature()); |
| 414 |
QString typeName; |
| 415 |
if (type->typeEntry()->isComplex() && type->hasInstantiations()) |
| 416 |
typeName = getFullTypeNameWithoutModifiers(type); |
| 417 |
else |
| 418 |
typeName = getFullTypeName(type->typeEntry()); |
| 419 |
return typeName + QString("*").repeated(type->indirections()); |
| 420 |
} |
| 421 |
|
| 422 |
QString Generator::getFullTypeName(const AbstractMetaClass* metaClass) const |
| 423 |
{ |
| 424 |
return QString("::%1").arg(metaClass->qualifiedCppName()); |
| 425 |
} |
| 426 |
|
| 427 |
QString Generator::getFullTypeNameWithoutModifiers(const AbstractMetaType* type) const |
| 428 |
{ |
| 429 |
if (isCString(type)) |
| 430 |
return "const char*"; |
| 431 |
if (isVoidPointer(type)) |
| 432 |
return "void*"; |
| 433 |
if (!type->hasInstantiations()) |
| 434 |
return getFullTypeName(type->typeEntry()); |
| 435 |
QString typeName = type->cppSignature(); |
| 436 |
if (type->isConstant()) |
| 437 |
typeName.remove(0, sizeof("const ") / sizeof(char) - 1); |
| 438 |
if (type->isReference()) |
| 439 |
typeName.chop(1); |
| 440 |
while (typeName.endsWith('*') || typeName.endsWith(' ')) |
| 441 |
typeName.chop(1); |
| 442 |
return QString("::%1").arg(typeName); |
| 443 |
} |
| 444 |
|
| 445 |
QString Generator::minimalConstructor(const AbstractMetaType* type) const |
| 446 |
{ |
| 447 |
if (!type || (type->isReference() && Generator::isObjectType(type))) |
| 448 |
return QString(); |
| 449 |
|
| 450 |
if (type->isContainer()) { |
| 451 |
QString ctor = type->cppSignature(); |
| 452 |
if (ctor.endsWith("*")) |
| 453 |
return QString("0"); |
| 454 |
if (ctor.startsWith("const ")) |
| 455 |
ctor.remove(0, sizeof("const ") / sizeof(char) - 1); |
| 456 |
if (ctor.endsWith("&")) { |
| 457 |
ctor.chop(1); |
| 458 |
ctor = ctor.trimmed(); |
| 459 |
} |
| 460 |
return QString("::%1()").arg(ctor); |
| 461 |
} |
| 462 |
|
| 463 |
if (type->isNativePointer()) |
| 464 |
return QString("((%1*)0)").arg(type->typeEntry()->qualifiedCppName()); |
| 465 |
|
| 466 |
if (Generator::isPointer(type)) |
| 467 |
return QString("((::%1*)0)").arg(type->typeEntry()->qualifiedCppName()); |
| 468 |
|
| 469 |
if (type->typeEntry()->isComplex()) { |
| 470 |
const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(type->typeEntry()); |
| 471 |
QString ctor = cType->defaultConstructor(); |
| 472 |
if (!ctor.isEmpty()) |
| 473 |
return ctor; |
| 474 |
ctor = minimalConstructor(classes().findClass(cType)); |
| 475 |
if (type->hasInstantiations()) |
| 476 |
ctor = ctor.replace(getFullTypeName(cType), getFullTypeNameWithoutModifiers(type)); |
| 477 |
return ctor; |
| 478 |
} |
| 479 |
|
| 480 |
return minimalConstructor(type->typeEntry()); |
| 481 |
} |
| 482 |
|
| 483 |
QString Generator::minimalConstructor(const TypeEntry* type) const |
| 484 |
{ |
| 485 |
if (!type) |
| 486 |
return QString(); |
| 487 |
|
| 488 |
if (type->isCppPrimitive()) |
| 489 |
return QString("((%1)0)").arg(type->qualifiedCppName()); |
| 490 |
|
| 491 |
if (type->isEnum() || type->isFlags()) |
| 492 |
return QString("((::%1)0)").arg(type->qualifiedCppName()); |
| 493 |
|
| 494 |
if (type->isPrimitive()) { |
| 495 |
QString ctor = reinterpret_cast<const PrimitiveTypeEntry*>(type)->defaultConstructor(); |
| 496 |
// If a non-C++ (i.e. defined by the user) primitive type does not have |
| 497 |
// a default constructor defined by the user, the empty constructor is |
| 498 |
// heuristically returned. If this is wrong the build of the generated |
| 499 |
// bindings will tell. |
| 500 |
return (ctor.isEmpty()) ? QString("::%1()").arg(type->qualifiedCppName()) : ctor; |
| 501 |
} |
| 502 |
|
| 503 |
if (type->isComplex()) |
| 504 |
return minimalConstructor(classes().findClass(type)); |
| 505 |
|
| 506 |
return QString(); |
| 507 |
} |
| 508 |
|
| 509 |
QString Generator::minimalConstructor(const AbstractMetaClass* metaClass) const |
| 510 |
{ |
| 511 |
if (!metaClass) |
| 512 |
return QString(); |
| 513 |
|
| 514 |
const ComplexTypeEntry* cType = reinterpret_cast<const ComplexTypeEntry*>(metaClass->typeEntry()); |
| 515 |
if (cType->hasDefaultConstructor()) |
| 516 |
return cType->defaultConstructor(); |
| 517 |
|
| 518 |
AbstractMetaFunctionList constructors = metaClass->queryFunctions(AbstractMetaClass::Constructors); |
| 519 |
int maxArgs = 0; |
| 520 |
foreach (const AbstractMetaFunction* ctor, constructors) { |
| 521 |
if (ctor->isUserAdded() || ctor->isPrivate() || ctor->isCopyConstructor()) |
| 522 |
continue; |
| 523 |
int numArgs = ctor->arguments().size(); |
| 524 |
if (numArgs == 0) { |
| 525 |
maxArgs = 0; |
| 526 |
break; |
| 527 |
} |
| 528 |
if (numArgs > maxArgs) |
| 529 |
maxArgs = numArgs; |
| 530 |
} |
| 531 |
|
| 532 |
QString qualifiedCppName = metaClass->typeEntry()->qualifiedCppName(); |
| 533 |
QStringList templateTypes; |
| 534 |
foreach (TypeEntry* templateType, metaClass->templateArguments()) |
| 535 |
templateTypes << templateType->qualifiedCppName(); |
| 536 |
QString fixedTypeName = QString("%1<%2 >").arg(qualifiedCppName).arg(templateTypes.join(", ")); |
| 537 |
|
| 538 |
// Empty constructor. |
| 539 |
if (maxArgs == 0) |
| 540 |
return QString("::%1()").arg(qualifiedCppName); |
| 541 |
|
| 542 |
QList<const AbstractMetaFunction*> candidates; |
| 543 |
|
| 544 |
// Constructors with C++ primitive types, enums or pointers only. |
| 545 |
// Start with the ones with fewer arguments. |
| 546 |
for (int i = 1; i <= maxArgs; ++i) { |
| 547 |
foreach (const AbstractMetaFunction* ctor, constructors) { |
| 548 |
if (ctor->isUserAdded() || ctor->isPrivate() || ctor->isCopyConstructor()) |
| 549 |
continue; |
| 550 |
|
| 551 |
AbstractMetaArgumentList arguments = ctor->arguments(); |
| 552 |
if (arguments.size() != i) |
| 553 |
continue; |
| 554 |
|
| 555 |
QStringList args; |
| 556 |
foreach (const AbstractMetaArgument* arg, arguments) { |
| 557 |
const TypeEntry* type = arg->type()->typeEntry(); |
| 558 |
if (type == metaClass->typeEntry()) { |
| 559 |
args.clear(); |
| 560 |
break; |
| 561 |
} |
| 562 |
|
| 563 |
if (!arg->originalDefaultValueExpression().isEmpty()) { |
| 564 |
if (!arg->defaultValueExpression().isEmpty() |
| 565 |
&& arg->defaultValueExpression() != arg->originalDefaultValueExpression()) { |
| 566 |
args << arg->defaultValueExpression(); |
| 567 |
} |
| 568 |
break; |
| 569 |
} |
| 570 |
|
| 571 |
if (type->isCppPrimitive() || type->isEnum() || isPointer(arg->type())) { |
| 572 |
QString argValue = minimalConstructor(arg->type()); |
| 573 |
if (argValue.isEmpty()) { |
| 574 |
args.clear(); |
| 575 |
break; |
| 576 |
} |
| 577 |
args << argValue; |
| 578 |
} else { |
| 579 |
args.clear(); |
| 580 |
break; |
| 581 |
} |
| 582 |
} |
| 583 |
|
| 584 |
if (!args.isEmpty()) |
| 585 |
return QString("::%1(%2)").arg(qualifiedCppName).arg(args.join(", ")); |
| 586 |
|
| 587 |
candidates << ctor; |
| 588 |
} |
| 589 |
} |
| 590 |
|
| 591 |
// Constructors with C++ primitive types, enums, pointers, value types, |
| 592 |
// and user defined primitive types. |
| 593 |
// Builds the minimal constructor recursively. |
| 594 |
foreach (const AbstractMetaFunction* ctor, candidates) { |
| 595 |
QStringList args; |
| 596 |
foreach (const AbstractMetaArgument* arg, ctor->arguments()) { |
| 597 |
if (arg->type()->typeEntry() == metaClass->typeEntry()) { |
| 598 |
args.clear(); |
| 599 |
break; |
| 600 |
} |
| 601 |
QString argValue = minimalConstructor(arg->type()); |
| 602 |
if (argValue.isEmpty()) { |
| 603 |
args.clear(); |
| 604 |
break; |
| 605 |
} |
| 606 |
args << argValue; |
| 607 |
} |
| 608 |
if (!args.isEmpty()) { |
| 609 |
return QString("::%1(%2)").arg(qualifiedCppName) |
| 610 |
.arg(args.join(", ")); |
| 611 |
} |
| 612 |
} |
| 613 |
|
| 614 |
return QString(); |
| 615 |
} |
| 616 |
|
| 617 |
QString Generator::translateType(const AbstractMetaType *cType, |
| 618 |
const AbstractMetaClass *context, |
| 619 |
Options options) const |
| 620 |
{ |
| 621 |
QString s; |
| 622 |
static int constLen = strlen("const"); |
| 623 |
|
| 624 |
if (context && cType && |
| 625 |
context->typeEntry()->isGenericClass() && |
| 626 |
cType->originalTemplateType()) { |
| 627 |
cType = cType->originalTemplateType(); |
| 628 |
} |
| 629 |
|
| 630 |
if (!cType) { |
| 631 |
s = "void"; |
| 632 |
} else if (cType->isArray()) { |
| 633 |
s = translateType(cType->arrayElementType(), context, options) + "[]"; |
| 634 |
} else if (options & Generator::EnumAsInts && (cType->isEnum() || cType->isFlags())) { |
| 635 |
s = "int"; |
| 636 |
} else { |
| 637 |
if (options & Generator::OriginalName) { |
| 638 |
s = cType->originalTypeDescription().trimmed(); |
| 639 |
if ((options & Generator::ExcludeReference) && s.endsWith("&")) |
| 640 |
s = s.left(s.size()-1); |
| 641 |
|
| 642 |
// remove only the last const (avoid remove template const) |
| 643 |
if (options & Generator::ExcludeConst) { |
| 644 |
int index = s.lastIndexOf("const"); |
| 645 |
|
| 646 |
if (index >= (s.size() - (constLen + 1))) // (VarType const) or (VarType const[*|&]) |
| 647 |
s = s.remove(index, constLen); |
| 648 |
} |
| 649 |
} else if (options & Generator::ExcludeConst || options & Generator::ExcludeReference) { |
| 650 |
AbstractMetaType* copyType = cType->copy(); |
| 651 |
|
| 652 |
if (options & Generator::ExcludeConst) |
| 653 |
copyType->setConstant(false); |
| 654 |
|
| 655 |
if (options & Generator::ExcludeReference) |
| 656 |
copyType->setReference(false); |
| 657 |
|
| 658 |
s = copyType->cppSignature(); |
| 659 |
if (!copyType->typeEntry()->isVoid() && !copyType->typeEntry()->isCppPrimitive()) |
| 660 |
s.prepend("::"); |
| 661 |
delete copyType; |
| 662 |
} else { |
| 663 |
s = cType->cppSignature(); |
| 664 |
} |
| 665 |
} |
| 666 |
|
| 667 |
return s; |
| 668 |
} |
| 669 |
|
| 670 |
|
| 671 |
QString Generator::subDirectoryForClass(const AbstractMetaClass* clazz) const |
| 672 |
{ |
| 673 |
return subDirectoryForPackage(clazz->package()); |
| 674 |
} |
| 675 |
|
| 676 |
QString Generator::subDirectoryForPackage(QString packageName) const |
| 677 |
{ |
| 678 |
if (packageName.isEmpty()) |
| 679 |
packageName = m_d->packageName; |
| 680 |
return QString(packageName).replace(".", QDir::separator()); |
| 681 |
} |
| 682 |
|
| 683 |
template<typename T> |
| 684 |
static QString getClassTargetFullName_(const T* t, bool includePackageName) |
| 685 |
{ |
| 686 |
QString name = t->name(); |
| 687 |
const AbstractMetaClass* context = t->enclosingClass(); |
| 688 |
while (context) { |
| 689 |
name.prepend('.'); |
| 690 |
name.prepend(context->name()); |
| 691 |
context = context->enclosingClass(); |
| 692 |
} |
| 693 |
if (includePackageName) { |
| 694 |
name.prepend('.'); |
| 695 |
name.prepend(t->package()); |
| 696 |
} |
| 697 |
return name; |
| 698 |
} |
| 699 |
|
| 700 |
QString getClassTargetFullName(const AbstractMetaClass* metaClass, bool includePackageName) |
| 701 |
{ |
| 702 |
return getClassTargetFullName_(metaClass, includePackageName); |
| 703 |
} |
| 704 |
|
| 705 |
QString getClassTargetFullName(const AbstractMetaEnum* metaEnum, bool includePackageName) |
| 706 |
{ |
| 707 |
return getClassTargetFullName_(metaEnum, includePackageName); |
| 708 |
} |