##// END OF EJS Templates
added return value conversion from reference to pointer to work around moc limitations, added toString method generation...
florianlink -
r70:dadaf215f719
parent child
Show More
@@ -1,2554 +1,2555
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
4 4 **
5 5 ** This file is part of the Qt Script Generator project on Trolltech Labs.
6 6 **
7 7 ** This file may be used under the terms of the GNU General Public
8 8 ** License version 2.0 as published by the Free Software Foundation
9 9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 10 ** this file. Please review the following information to ensure GNU
11 11 ** General Public Licensing requirements will be met:
12 12 ** http://www.trolltech.com/products/qt/opensource.html
13 13 **
14 14 ** If you are unsure which license is appropriate for your use, please
15 15 ** review the following information:
16 16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 17 ** sales department at sales@trolltech.com.
18 18 **
19 19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 21 **
22 22 ****************************************************************************/
23 23
24 24 #include "abstractmetabuilder.h"
25 25 #include "reporthandler.h"
26 26
27 27 #include "ast.h"
28 28 #include "binder.h"
29 29 #include "control.h"
30 30 #include "default_visitor.h"
31 31 #include "dumptree.h"
32 32 #include "lexer.h"
33 33 #include "parser.h"
34 34 #include "tokens.h"
35 35
36 36 #include <QtCore/QDebug>
37 37 #include <QtCore/QFile>
38 38 #include <QtCore/QFileInfo>
39 39 #include <QtCore/QTextCodec>
40 40 #include <QtCore/QTextStream>
41 41 #include <QtCore/QVariant>
42 42
43 43 static QString strip_template_args(const QString &name)
44 44 {
45 45 int pos = name.indexOf('<');
46 46 return pos < 0 ? name : name.left(pos);
47 47 }
48 48
49 49 static QHash<QString, QString> *operator_names;
50 50 QString rename_operator(const QString &oper)
51 51 {
52 52 QString op = oper.trimmed();
53 53 if (!operator_names) {
54 54 operator_names = new QHash<QString, QString>;
55 55
56 56 operator_names->insert("+", "add");
57 57 operator_names->insert("-", "subtract");
58 58 operator_names->insert("*", "multiply");
59 59 operator_names->insert("/", "divide");
60 60 operator_names->insert("%", "modulo");
61 61 operator_names->insert("&", "and");
62 62 operator_names->insert("|", "or");
63 63 operator_names->insert("^", "xor");
64 64 operator_names->insert("~", "negate");
65 65 operator_names->insert("<<", "shift_left");
66 66 operator_names->insert(">>", "shift_right");
67 67
68 68 // assigments
69 69 operator_names->insert("=", "assign");
70 70 operator_names->insert("+=", "add_assign");
71 71 operator_names->insert("-=", "subtract_assign");
72 72 operator_names->insert("*=", "multiply_assign");
73 73 operator_names->insert("/=", "divide_assign");
74 74 operator_names->insert("%=", "modulo_assign");
75 75 operator_names->insert("&=", "and_assign");
76 76 operator_names->insert("|=", "or_assign");
77 77 operator_names->insert("^=", "xor_assign");
78 78 operator_names->insert("<<=", "shift_left_assign");
79 79 operator_names->insert(">>=", "shift_right_assign");
80 80
81 81 // Logical
82 82 operator_names->insert("&&", "logical_and");
83 83 operator_names->insert("||", "logical_or");
84 84 operator_names->insert("!", "not");
85 85
86 86 // incr/decr
87 87 operator_names->insert("++", "increment");
88 88 operator_names->insert("--", "decrement");
89 89
90 90 // compare
91 91 operator_names->insert("<", "less");
92 92 operator_names->insert(">", "greater");
93 93 operator_names->insert("<=", "less_or_equal");
94 94 operator_names->insert(">=", "greater_or_equal");
95 95 operator_names->insert("!=", "not_equal");
96 96 operator_names->insert("==", "equal");
97 97
98 98 // other
99 99 operator_names->insert("[]", "subscript");
100 100 operator_names->insert("->", "pointer");
101 101 }
102 102
103 103 if (!operator_names->contains(op)) {
104 104 TypeDatabase *tb = TypeDatabase::instance();
105 105
106 106 TypeParser::Info typeInfo = TypeParser::parse(op);
107 107 QString cast_to_name = typeInfo.qualified_name.join("::");
108 108 TypeEntry *te = tb->findType(cast_to_name);
109 109 if ((te && te->codeGeneration() == TypeEntry::GenerateNothing)
110 110 || tb->isClassRejected(cast_to_name)) {
111 111 return QString();
112 112 } else if (te) {
113 113 return "operator_cast_" + typeInfo.qualified_name.join("_");
114 114 } else {
115 115 ReportHandler::warning(QString("unknown operator '%1'").arg(op));
116 116 return "operator " + op;
117 117 }
118 118 }
119 119
120 120 return "operator_" + operator_names->value(op);
121 121 }
122 122
123 123 AbstractMetaBuilder::AbstractMetaBuilder()
124 124 : m_current_class(0)
125 125 {
126 126 }
127 127
128 128 void AbstractMetaBuilder::checkFunctionModifications()
129 129 {
130 130 TypeDatabase *types = TypeDatabase::instance();
131 131 SingleTypeEntryHash entryHash = types->entries();
132 132 QList<TypeEntry *> entries = entryHash.values();
133 133 foreach (TypeEntry *entry, entries) {
134 134 if (entry == 0)
135 135 continue;
136 136 if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing)
137 137 continue;
138 138
139 139 ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(entry);
140 140 FunctionModificationList modifications = centry->functionModifications();
141 141
142 142 foreach (FunctionModification modification, modifications) {
143 143 QString signature = modification.signature;
144 144
145 145 QString name = signature.trimmed();
146 146 name = name.mid(0, signature.indexOf("("));
147 147
148 148 AbstractMetaClass *clazz = m_meta_classes.findClass(centry->qualifiedCppName());
149 149 if (clazz == 0)
150 150 continue;
151 151
152 152 AbstractMetaFunctionList functions = clazz->functions();
153 153 bool found = false;
154 154 QStringList possibleSignatures;
155 155 foreach (AbstractMetaFunction *function, functions) {
156 156 if (function->minimalSignature() == signature && function->implementingClass() == clazz) {
157 157 found = true;
158 158 break;
159 159 }
160 160
161 161 if (function->originalName() == name)
162 162 possibleSignatures.append(function->minimalSignature() + " in " + function->implementingClass()->name());
163 163 }
164 164
165 165 if (!found) {
166 166 QString warning
167 167 = QString("signature '%1' for function modification in '%2' not found. Possible candidates: %3")
168 168 .arg(signature)
169 169 .arg(clazz->qualifiedCppName())
170 170 .arg(possibleSignatures.join(", "));
171 171
172 172 ReportHandler::warning(warning);
173 173 }
174 174 }
175 175 }
176 176 }
177 177
178 178 AbstractMetaClass *AbstractMetaBuilder::argumentToClass(ArgumentModelItem argument)
179 179 {
180 180 AbstractMetaClass *returned = 0;
181 181 bool ok = false;
182 182 AbstractMetaType *type = translateType(argument->type(), &ok);
183 183 if (ok && type != 0 && type->typeEntry() != 0 && type->typeEntry()->isComplex()) {
184 184 const TypeEntry *entry = type->typeEntry();
185 185 returned = m_meta_classes.findClass(entry->name());
186 186 }
187 187 delete type;
188 188 return returned;
189 189 }
190 190
191 191 /**
192 192 * Checks the argument of a hash function and flags the type if it is a complex type
193 193 */
194 194 void AbstractMetaBuilder::registerHashFunction(FunctionModelItem function_item)
195 195 {
196 196 ArgumentList arguments = function_item->arguments();
197 197 if (arguments.size() == 1) {
198 198 if (AbstractMetaClass *cls = argumentToClass(arguments.at(0)))
199 199 cls->setHasHashFunction(true);
200 200 }
201 201 }
202 202
203 203 /**
204 204 * Check if a class has a debug stream operator that can be used as toString
205 205 */
206 206
207 207 void AbstractMetaBuilder::registerToStringCapability(FunctionModelItem function_item)
208 208 {
209 209 ArgumentList arguments = function_item->arguments();
210 210 if (arguments.size() == 2) {
211 211 if (arguments.at(0)->type().toString() == "QDebug"){
212 212 ArgumentModelItem arg = arguments.at(1);
213 213 if (AbstractMetaClass *cls = argumentToClass(arg)) {
214 214 if (arg->type().indirections() < 2) {
215 215 cls->setToStringCapability(function_item);
216 216 }
217 217 }
218 218 }
219 219 }
220 220 }
221 221
222 222 void AbstractMetaBuilder::traverseCompareOperator(FunctionModelItem item) {
223 223 ArgumentList arguments = item->arguments();
224 224 if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
225 225 AbstractMetaClass *comparer_class = argumentToClass(arguments.at(0));
226 226 AbstractMetaClass *compared_class = argumentToClass(arguments.at(1));
227 227 if (comparer_class != 0 && compared_class != 0) {
228 228 AbstractMetaClass *old_current_class = m_current_class;
229 229 m_current_class = comparer_class;
230 230
231 231 AbstractMetaFunction *meta_function = traverseFunction(item);
232 232 if (meta_function != 0 && !meta_function->isInvalid()) {
233 233 // Strip away first argument, since that is the containing object
234 234 AbstractMetaArgumentList arguments = meta_function->arguments();
235 235 arguments.pop_front();
236 236 meta_function->setArguments(arguments);
237 237
238 238 meta_function->setFunctionType(AbstractMetaFunction::GlobalScopeFunction);
239 239
240 240 meta_function->setOriginalAttributes(meta_function->attributes());
241 241 setupFunctionDefaults(meta_function, comparer_class);
242 242
243 243 comparer_class->addFunction(meta_function);
244 244 } else if (meta_function != 0) {
245 245 delete meta_function;
246 246 }
247 247
248 248 m_current_class = old_current_class;
249 249 }
250 250 }
251 251 }
252 252
253 253 void AbstractMetaBuilder::traverseStreamOperator(FunctionModelItem item)
254 254 {
255 255 ArgumentList arguments = item->arguments();
256 256 if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
257 257 AbstractMetaClass *streamClass = argumentToClass(arguments.at(0));
258 258 AbstractMetaClass *streamedClass = argumentToClass(arguments.at(1));
259 259
260 260 if (streamClass != 0 && streamedClass != 0
261 261 && (streamClass->name() == "QDataStream" || streamClass->name() == "QTextStream")) {
262 262 AbstractMetaClass *old_current_class = m_current_class;
263 263 m_current_class = streamedClass;
264 264 AbstractMetaFunction *streamFunction = traverseFunction(item);
265 265
266 266 if (streamFunction != 0 && !streamFunction->isInvalid()) {
267 267 QString name = item->name();
268 268 streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction);
269 269
270 270 if (name.endsWith("<<"))
271 271 streamFunction->setName("writeTo");
272 272 else
273 273 streamFunction->setName("readFrom");
274 274
275 275 // Strip away last argument, since that is the containing object
276 276 AbstractMetaArgumentList arguments = streamFunction->arguments();
277 277 arguments.pop_back();
278 278 streamFunction->setArguments(arguments);
279 279
280 280 *streamFunction += AbstractMetaAttributes::Final;
281 281 *streamFunction += AbstractMetaAttributes::Public;
282 282 streamFunction->setOriginalAttributes(streamFunction->attributes());
283 283
284 284 streamFunction->setType(0);
285 285
286 286 setupFunctionDefaults(streamFunction, streamedClass);
287 287
288 288 streamedClass->addFunction(streamFunction);
289 289 streamedClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include());
290 290
291 291 m_current_class = old_current_class;
292 292 }
293 293 }
294 294 }
295 295 }
296 296
297 297 void AbstractMetaBuilder::fixQObjectForScope(TypeDatabase *types,
298 298 NamespaceModelItem scope)
299 299 {
300 300 foreach (ClassModelItem item, scope->classes()) {
301 301 QString qualified_name = item->qualifiedName().join("::");
302 302 TypeEntry *entry = types->findType(qualified_name);
303 303 if (entry) {
304 304 if (isQObject(qualified_name) && entry->isComplex()) {
305 305 ((ComplexTypeEntry *) entry)->setQObject(true);
306 306 }
307 307 }
308 308 }
309 309
310 310 foreach (NamespaceModelItem item, scope->namespaceMap().values()) {
311 311 if (scope != item)
312 312 fixQObjectForScope(types, item);
313 313 }
314 314 }
315 315
316 316 static bool class_less_than(AbstractMetaClass *a, AbstractMetaClass *b)
317 317 {
318 318 return a->name() < b->name();
319 319 }
320 320
321 321
322 322 void AbstractMetaBuilder::sortLists()
323 323 {
324 324 qSort(m_meta_classes.begin(), m_meta_classes.end(), class_less_than);
325 325 foreach (AbstractMetaClass *cls, m_meta_classes) {
326 326 cls->sortFunctions();
327 327 }
328 328 }
329 329
330 330 bool AbstractMetaBuilder::build()
331 331 {
332 332 Q_ASSERT(!m_file_name.isEmpty());
333 333
334 334 QFile file(m_file_name);
335 335
336 336 if (!file.open(QFile::ReadOnly))
337 337 return false;
338 338
339 339 QTextStream stream(&file);
340 340 stream.setCodec(QTextCodec::codecForName("UTF-8"));
341 341 QByteArray contents = stream.readAll().toUtf8();
342 342 file.close();
343 343
344 344 Control control;
345 345 Parser p(&control);
346 346 pool __pool;
347 347
348 348 TranslationUnitAST *ast = p.parse(contents, contents.size(), &__pool);
349 349
350 350 CodeModel model;
351 351 Binder binder(&model, p.location());
352 352 m_dom = binder.run(ast);
353 353
354 354 pushScope(model_dynamic_cast<ScopeModelItem>(m_dom));
355 355
356 356 QHash<QString, ClassModelItem> typeMap = m_dom->classMap();
357 357
358 358
359 359 // fix up QObject's in the type system..
360 360 TypeDatabase *types = TypeDatabase::instance();
361 361 fixQObjectForScope(types, model_dynamic_cast<NamespaceModelItem>(m_dom));
362 362
363 363
364 364 // Start the generation...
365 365 foreach (ClassModelItem item, typeMap.values()) {
366 366 AbstractMetaClass *cls = traverseClass(item);
367 367 addAbstractMetaClass(cls);
368 368 }
369 369
370 370
371 371 QHash<QString, NamespaceModelItem> namespaceMap = m_dom->namespaceMap();
372 372 foreach (NamespaceModelItem item, namespaceMap.values()) {
373 373 AbstractMetaClass *meta_class = traverseNamespace(item);
374 374 if (meta_class)
375 375 m_meta_classes << meta_class;
376 376 }
377 377
378 378
379 379 // Some trickery to support global-namespace enums...
380 380 QHash<QString, EnumModelItem> enumMap = m_dom->enumMap();
381 381 m_current_class = 0;
382 382 foreach (EnumModelItem item, enumMap) {
383 383 AbstractMetaEnum *meta_enum = traverseEnum(item, 0, QSet<QString>());
384 384
385 385 if (meta_enum) {
386 386 QString package = meta_enum->typeEntry()->javaPackage();
387 387 QString globalName = TypeDatabase::globalNamespaceClassName(meta_enum->typeEntry());
388 388
389 389 AbstractMetaClass *global = m_meta_classes.findClass(package + "." + globalName);
390 390 if (!global) {
391 391 ComplexTypeEntry *gte = new ObjectTypeEntry(globalName);
392 392 gte->setTargetLangPackage(meta_enum->typeEntry()->javaPackage());
393 393 gte->setCodeGeneration(meta_enum->typeEntry()->codeGeneration());
394 394 global = createMetaClass();
395 395 global->setTypeEntry(gte);
396 396 *global += AbstractMetaAttributes::Final;
397 397 *global += AbstractMetaAttributes::Public;
398 398 *global += AbstractMetaAttributes::Fake;
399 399
400 400 m_meta_classes << global;
401 401 }
402 402
403 403 global->addEnum(meta_enum);
404 404 meta_enum->setEnclosingClass(global);
405 405 meta_enum->typeEntry()->setQualifier(globalName);
406 406 }
407 407
408 408
409 409 }
410 410
411 411
412 412 // Go through all typedefs to see if we have defined any
413 413 // specific typedefs to be used as classes.
414 414 TypeAliasList typeAliases = m_dom->typeAliases();
415 415 foreach (TypeAliasModelItem typeAlias, typeAliases) {
416 416 AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
417 417 addAbstractMetaClass(cls);
418 418 }
419 419
420 420
421 421
422 422
423 423 foreach (AbstractMetaClass *cls, m_meta_classes) {
424 424 if (!cls->isInterface() && !cls->isNamespace()) {
425 425 setupInheritance(cls);
426 426 }
427 427 }
428 428
429 429
430 430 foreach (AbstractMetaClass *cls, m_meta_classes) {
431 431 cls->fixFunctions();
432 432
433 433 if (cls->typeEntry() == 0) {
434 434 ReportHandler::warning(QString("class '%1' does not have an entry in the type system")
435 435 .arg(cls->name()));
436 436 } else {
437 437 if (!cls->hasConstructors() && !cls->isFinalInCpp() && !cls->isInterface() && !cls->isNamespace())
438 438 cls->addDefaultConstructor();
439 439 }
440 440
441 441 if (cls->isAbstract() && !cls->isInterface()) {
442 442 cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + "$ConcreteWrapper");
443 443 }
444 444 }
445 445
446 446 QList<TypeEntry *> entries = TypeDatabase::instance()->entries().values();
447 447 foreach (const TypeEntry *entry, entries) {
448 448 if (entry->isPrimitive())
449 449 continue;
450 450
451 451 if ((entry->isValue() || entry->isObject())
452 452 && !entry->isString()
453 453 && !entry->isChar()
454 454 && !entry->isContainer()
455 455 && !entry->isCustom()
456 456 && !entry->isVariant()
457 457 && !m_meta_classes.findClass(entry->qualifiedCppName())) {
458 458 ReportHandler::warning(QString("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.")
459 459 .arg(entry->qualifiedCppName()));
460 460 }
461 461
462 462 if (entry->isEnum()) {
463 463 QString pkg = entry->javaPackage();
464 464 QString name = (pkg.isEmpty() ? QString() : pkg + ".")
465 465 + ((EnumTypeEntry *) entry)->javaQualifier();
466 466 AbstractMetaClass *cls = m_meta_classes.findClass(name);
467 467
468 468 if (!cls) {
469 469 ReportHandler::warning(QString("namespace '%1' for enum '%2' is not declared")
470 470 .arg(name).arg(entry->targetLangName()));
471 471 } else {
472 472 AbstractMetaEnum *e = cls->findEnum(entry->targetLangName());
473 473 if (!e)
474 474 ReportHandler::warning(QString("enum '%1' is specified in typesystem, "
475 475 "but not declared")
476 476 .arg(entry->qualifiedCppName()));
477 477 }
478 478 }
479 479 }
480 480
481 481 {
482 482 FunctionList hash_functions = m_dom->findFunctions("qHash");
483 483 foreach (FunctionModelItem item, hash_functions) {
484 484 registerHashFunction(item);
485 485 }
486 486 }
487 487
488 488 {
489 489 FunctionList hash_functions = m_dom->findFunctions("operator<<");
490 490 foreach (FunctionModelItem item, hash_functions) {
491 491 registerToStringCapability(item);
492 492 }
493 493 }
494 494
495 495 {
496 496 FunctionList compare_operators = m_dom->findFunctions("operator==")
497 497 + m_dom->findFunctions("operator<=")
498 498 + m_dom->findFunctions("operator>=")
499 499 + m_dom->findFunctions("operator<")
500 500 + m_dom->findFunctions("operator>");
501 501 foreach (FunctionModelItem item, compare_operators) {
502 502 traverseCompareOperator(item);
503 503 }
504 504 }
505 // TODO XXX search and add operator+ etc. to the classes here!
505 506
506 507 {
507 508 FunctionList stream_operators = m_dom->findFunctions("operator<<") + m_dom->findFunctions("operator>>");
508 509 foreach (FunctionModelItem item, stream_operators) {
509 510 traverseStreamOperator(item);
510 511 }
511 512 }
512 513
513 514 figureOutEnumValues();
514 515 figureOutDefaultEnumArguments();
515 516 checkFunctionModifications();
516 517
517 518 foreach (AbstractMetaClass *cls, m_meta_classes) {
518 519 setupEquals(cls);
519 520 setupComparable(cls);
520 521 setupClonable(cls);
521 522 }
522 523
523 524 dumpLog();
524 525
525 526 sortLists();
526 527
527 528 return true;
528 529 }
529 530
530 531
531 532 void AbstractMetaBuilder::addAbstractMetaClass(AbstractMetaClass *cls)
532 533 {
533 534 if (!cls)
534 535 return;
535 536
536 537 cls->setOriginalAttributes(cls->attributes());
537 538 if (cls->typeEntry()->isContainer()) {
538 539 m_templates << cls;
539 540 } else {
540 541 m_meta_classes << cls;
541 542 if (cls->typeEntry()->designatedInterface()) {
542 543 AbstractMetaClass *interface = cls->extractInterface();
543 544 m_meta_classes << interface;
544 545 ReportHandler::debugSparse(QString(" -> interface '%1'").arg(interface->name()));
545 546 }
546 547 }
547 548 }
548 549
549 550
550 551 AbstractMetaClass *AbstractMetaBuilder::traverseNamespace(NamespaceModelItem namespace_item)
551 552 {
552 553 QString namespace_name = (!m_namespace_prefix.isEmpty() ? m_namespace_prefix + "::" : QString()) + namespace_item->name();
553 554 NamespaceTypeEntry *type = TypeDatabase::instance()->findNamespaceType(namespace_name);
554 555
555 556 if (TypeDatabase::instance()->isClassRejected(namespace_name)) {
556 557 m_rejected_classes.insert(namespace_name, GenerationDisabled);
557 558 return 0;
558 559 }
559 560
560 561 if (!type) {
561 562 ReportHandler::warning(QString("namespace '%1' does not have a type entry")
562 563 .arg(namespace_name));
563 564 return 0;
564 565 }
565 566
566 567 AbstractMetaClass *meta_class = createMetaClass();
567 568 meta_class->setTypeEntry(type);
568 569
569 570 *meta_class += AbstractMetaAttributes::Public;
570 571
571 572 m_current_class = meta_class;
572 573
573 574 ReportHandler::debugSparse(QString("namespace '%1.%2'")
574 575 .arg(meta_class->package())
575 576 .arg(namespace_item->name()));
576 577
577 578 traverseEnums(model_dynamic_cast<ScopeModelItem>(namespace_item), meta_class, namespace_item->enumsDeclarations());
578 579 traverseFunctions(model_dynamic_cast<ScopeModelItem>(namespace_item), meta_class);
579 580 // traverseClasses(model_dynamic_cast<ScopeModelItem>(namespace_item));
580 581
581 582 pushScope(model_dynamic_cast<ScopeModelItem>(namespace_item));
582 583 m_namespace_prefix = currentScope()->qualifiedName().join("::");
583 584
584 585
585 586 ClassList classes = namespace_item->classes();
586 587 foreach (ClassModelItem cls, classes) {
587 588 AbstractMetaClass *mjc = traverseClass(cls);
588 589 addAbstractMetaClass(mjc);
589 590 }
590 591
591 592 // Go through all typedefs to see if we have defined any
592 593 // specific typedefs to be used as classes.
593 594 TypeAliasList typeAliases = namespace_item->typeAliases();
594 595 foreach (TypeAliasModelItem typeAlias, typeAliases) {
595 596 AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
596 597 addAbstractMetaClass(cls);
597 598 }
598 599
599 600
600 601
601 602 // Traverse namespaces recursively
602 603 QList<NamespaceModelItem> inner_namespaces = namespace_item->namespaceMap().values();
603 604 foreach (const NamespaceModelItem &ni, inner_namespaces) {
604 605 AbstractMetaClass *mjc = traverseNamespace(ni);
605 606 addAbstractMetaClass(mjc);
606 607 }
607 608
608 609 m_current_class = 0;
609 610
610 611
611 612 popScope();
612 613 m_namespace_prefix = currentScope()->qualifiedName().join("::");
613 614
614 615 if (!type->include().isValid()) {
615 616 QFileInfo info(namespace_item->fileName());
616 617 type->setInclude(Include(Include::IncludePath, info.fileName()));
617 618 }
618 619
619 620 return meta_class;
620 621 }
621 622
622 623 struct Operator
623 624 {
624 625 enum Type { Plus, ShiftLeft, None };
625 626
626 627 Operator() : type(None) { }
627 628
628 629 int calculate(int x) {
629 630 switch (type) {
630 631 case Plus: return x + value;
631 632 case ShiftLeft: return x << value;
632 633 case None: return x;
633 634 }
634 635 return x;
635 636 }
636 637
637 638 Type type;
638 639 int value;
639 640 };
640 641
641 642
642 643
643 644 Operator findOperator(QString *s) {
644 645 const char *names[] = {
645 646 "+",
646 647 "<<"
647 648 };
648 649
649 650 for (int i=0; i<Operator::None; ++i) {
650 651 QString name = QLatin1String(names[i]);
651 652 QString str = *s;
652 653 int splitPoint = str.indexOf(name);
653 654 if (splitPoint > 0) {
654 655 bool ok;
655 656 QString right = str.mid(splitPoint + name.length());
656 657 Operator op;
657 658 op.value = right.toInt(&ok);
658 659 if (ok) {
659 660 op.type = Operator::Type(i);
660 661 *s = str.left(splitPoint).trimmed();
661 662 return op;
662 663 }
663 664 }
664 665 }
665 666 return Operator();
666 667 }
667 668
668 669 int AbstractMetaBuilder::figureOutEnumValue(const QString &stringValue,
669 670 int oldValuevalue,
670 671 AbstractMetaEnum *meta_enum,
671 672 AbstractMetaFunction *meta_function)
672 673 {
673 674 if (stringValue.isEmpty())
674 675 return oldValuevalue;
675 676
676 677 QStringList stringValues = stringValue.split("|");
677 678
678 679 int returnValue = 0;
679 680
680 681 bool matched = false;
681 682
682 683 for (int i=0; i<stringValues.size(); ++i) {
683 684 QString s = stringValues.at(i).trimmed();
684 685
685 686 bool ok;
686 687 int v;
687 688
688 689 Operator op = findOperator(&s);
689 690
690 691 if (s.length() > 0 && s.at(0) == QLatin1Char('0'))
691 692 v = s.toUInt(&ok, 0);
692 693 else
693 694 v = s.toInt(&ok);
694 695
695 696 if (ok) {
696 697 matched = true;
697 698
698 699 } else if (m_enum_values.contains(s)) {
699 700 v = m_enum_values[s]->value();
700 701 matched = true;
701 702
702 703 } else {
703 704 AbstractMetaEnumValue *ev = 0;
704 705
705 706 if (meta_enum && (ev = meta_enum->values().find(s))) {
706 707 v = ev->value();
707 708 matched = true;
708 709
709 710 } else if (meta_enum && (ev = meta_enum->enclosingClass()->findEnumValue(s, meta_enum))) {
710 711 v = ev->value();
711 712 matched = true;
712 713
713 714 } else {
714 715 if (meta_enum)
715 716 ReportHandler::warning("unhandled enum value: " + s + " in "
716 717 + meta_enum->enclosingClass()->name() + "::"
717 718 + meta_enum->name());
718 719 else
719 720 ReportHandler::warning("unhandled enum value: Unknown enum");
720 721 }
721 722 }
722 723
723 724 if (matched)
724 725 returnValue |= op.calculate(v);
725 726 }
726 727
727 728 if (!matched) {
728 729 QString warn = QString("unmatched enum %1").arg(stringValue);
729 730
730 731 if (meta_function != 0) {
731 732 warn += QString(" when parsing default value of '%1' in class '%2'")
732 733 .arg(meta_function->name())
733 734 .arg(meta_function->implementingClass()->name());
734 735 }
735 736
736 737 ReportHandler::warning(warn);
737 738 returnValue = oldValuevalue;
738 739 }
739 740
740 741 return returnValue;
741 742 }
742 743
743 744 void AbstractMetaBuilder::figureOutEnumValuesForClass(AbstractMetaClass *meta_class,
744 745 QSet<AbstractMetaClass *> *classes)
745 746 {
746 747 AbstractMetaClass *base = meta_class->baseClass();
747 748
748 749 if (base != 0 && !classes->contains(base))
749 750 figureOutEnumValuesForClass(base, classes);
750 751
751 752 if (classes->contains(meta_class))
752 753 return;
753 754
754 755 AbstractMetaEnumList enums = meta_class->enums();
755 756 foreach (AbstractMetaEnum *e, enums) {
756 757 if (!e) {
757 758 ReportHandler::warning("bad enum in class " + meta_class->name());
758 759 continue;
759 760 }
760 761 AbstractMetaEnumValueList lst = e->values();
761 762 int value = 0;
762 763 for (int i=0; i<lst.size(); ++i) {
763 764 value = figureOutEnumValue(lst.at(i)->stringValue(), value, e);
764 765 lst.at(i)->setValue(value);
765 766 value++;
766 767 }
767 768
768 769 // Check for duplicate values...
769 770 EnumTypeEntry *ete = e->typeEntry();
770 771 if (!ete->forceInteger()) {
771 772 QHash<int, AbstractMetaEnumValue *> entries;
772 773 foreach (AbstractMetaEnumValue *v, lst) {
773 774
774 775 bool vRejected = ete->isEnumValueRejected(v->name());
775 776
776 777 AbstractMetaEnumValue *current = entries.value(v->value());
777 778 if (current) {
778 779 bool currentRejected = ete->isEnumValueRejected(current->name());
779 780 if (!currentRejected && !vRejected) {
780 781 ReportHandler::warning(
781 782 QString("duplicate enum values: %1::%2, %3 and %4 are %5, already rejected: (%6)")
782 783 .arg(meta_class->name())
783 784 .arg(e->name())
784 785 .arg(v->name())
785 786 .arg(entries[v->value()]->name())
786 787 .arg(v->value())
787 788 .arg(ete->enumValueRejections().join(", ")));
788 789 continue;
789 790 }
790 791 }
791 792
792 793 if (!vRejected)
793 794 entries[v->value()] = v;
794 795 }
795 796
796 797 // Entries now contain all the original entries, no
797 798 // rejected ones... Use this to generate the enumValueRedirection table.
798 799 foreach (AbstractMetaEnumValue *reject, lst) {
799 800 if (!ete->isEnumValueRejected(reject->name()))
800 801 continue;
801 802
802 803 AbstractMetaEnumValue *used = entries.value(reject->value());
803 804 if (!used) {
804 805 ReportHandler::warning(
805 806 QString::fromLatin1("Rejected enum has no alternative...: %1::%2")
806 807 .arg(meta_class->name())
807 808 .arg(reject->name()));
808 809 continue;
809 810 }
810 811 ete->addEnumValueRedirection(reject->name(), used->name());
811 812 }
812 813
813 814 }
814 815 }
815 816
816 817
817 818
818 819 *classes += meta_class;
819 820 }
820 821
821 822
822 823 void AbstractMetaBuilder::figureOutEnumValues()
823 824 {
824 825 // Keep a set of classes that we already traversed. We use this to
825 826 // enforce that we traverse base classes prior to subclasses.
826 827 QSet<AbstractMetaClass *> classes;
827 828 foreach (AbstractMetaClass *c, m_meta_classes) {
828 829 figureOutEnumValuesForClass(c, &classes);
829 830 }
830 831 }
831 832
832 833 void AbstractMetaBuilder::figureOutDefaultEnumArguments()
833 834 {
834 835 foreach (AbstractMetaClass *meta_class, m_meta_classes) {
835 836 foreach (AbstractMetaFunction *meta_function, meta_class->functions()) {
836 837 foreach (AbstractMetaArgument *arg, meta_function->arguments()) {
837 838
838 839 QString expr = arg->defaultValueExpression();
839 840 if (expr.isEmpty())
840 841 continue;
841 842
842 843 if (!meta_function->replacedDefaultExpression(meta_function->implementingClass(),
843 844 arg->argumentIndex()+1).isEmpty()) {
844 845 continue;
845 846 }
846 847
847 848 QString new_expr = expr;
848 849 if (arg->type()->isEnum()) {
849 850 QStringList lst = expr.split(QLatin1String("::"));
850 851 if (lst.size() == 1) {
851 852 QVector<AbstractMetaClass *> classes(1, meta_class);
852 853 AbstractMetaEnum *e = 0;
853 854 while (!classes.isEmpty() && e == 0) {
854 855 if (classes.front() != 0) {
855 856 classes << classes.front()->baseClass();
856 857
857 858 AbstractMetaClassList interfaces = classes.front()->interfaces();
858 859 foreach (AbstractMetaClass *interface, interfaces)
859 860 classes << interface->primaryInterfaceImplementor();
860 861
861 862 e = classes.front()->findEnumForValue(expr);
862 863 }
863 864
864 865 classes.pop_front();
865 866 }
866 867
867 868 if (e != 0) {
868 869 new_expr = QString("%1.%2")
869 870 .arg(e->typeEntry()->qualifiedTargetLangName())
870 871 .arg(expr);
871 872 } else {
872 873 ReportHandler::warning("Cannot find enum constant for value '" + expr + "' in '" + meta_class->name() + "' or any of its super classes");
873 874 }
874 875 } else if (lst.size() == 2) {
875 876 AbstractMetaClass *cl = m_meta_classes.findClass(lst.at(0));
876 877 if (!cl) {
877 878 ReportHandler::warning("missing required class for enums: " + lst.at(0));
878 879 continue;
879 880 }
880 881 new_expr = QString("%1.%2.%3")
881 882 .arg(cl->typeEntry()->qualifiedTargetLangName())
882 883 .arg(arg->type()->name())
883 884 .arg(lst.at(1));
884 885 } else {
885 886 ReportHandler::warning("bad default value passed to enum " + expr);
886 887 }
887 888
888 889 } else if(arg->type()->isFlags()) {
889 890 const FlagsTypeEntry *flagsEntry =
890 891 static_cast<const FlagsTypeEntry *>(arg->type()->typeEntry());
891 892 EnumTypeEntry *enumEntry = flagsEntry->originator();
892 893 AbstractMetaEnum *meta_enum = m_meta_classes.findEnum(enumEntry);
893 894 if (!meta_enum) {
894 895 ReportHandler::warning("unknown required enum " + enumEntry->qualifiedCppName());
895 896 continue;
896 897 }
897 898
898 899 int value = figureOutEnumValue(expr, 0, meta_enum, meta_function);
899 900 new_expr = QString::number(value);
900 901
901 902 } else if (arg->type()->isPrimitive()) {
902 903 AbstractMetaEnumValue *value = 0;
903 904 if (expr.contains("::"))
904 905 value = m_meta_classes.findEnumValue(expr);
905 906 if (!value)
906 907 value = meta_class->findEnumValue(expr, 0);
907 908
908 909 if (value) {
909 910 new_expr = QString::number(value->value());
910 911 } else if (expr.contains(QLatin1Char('+'))) {
911 912 new_expr = QString::number(figureOutEnumValue(expr, 0, 0));
912 913
913 914 }
914 915
915 916
916 917
917 918 }
918 919
919 920 arg->setDefaultValueExpression(new_expr);
920 921 }
921 922 }
922 923 }
923 924 }
924 925
925 926
926 927 AbstractMetaEnum *AbstractMetaBuilder::traverseEnum(EnumModelItem enum_item, AbstractMetaClass *enclosing, const QSet<QString> &enumsDeclarations)
927 928 {
928 929 // Skipping private enums.
929 930 if (enum_item->accessPolicy() == CodeModel::Private) {
930 931 return 0;
931 932 }
932 933
933 934 QString qualified_name = enum_item->qualifiedName().join("::");
934 935
935 936 TypeEntry *type_entry = TypeDatabase::instance()->findType(qualified_name);
936 937 QString enum_name = enum_item->name();
937 938
938 939 QString class_name;
939 940 if (m_current_class)
940 941 class_name = m_current_class->typeEntry()->qualifiedCppName();
941 942
942 943 if (TypeDatabase::instance()->isEnumRejected(class_name, enum_name)) {
943 944 m_rejected_enums.insert(qualified_name, GenerationDisabled);
944 945 return 0;
945 946 }
946 947
947 948 if (!type_entry || !type_entry->isEnum()) {
948 949 QString context = m_current_class ? m_current_class->name() : QLatin1String("");
949 950 ReportHandler::warning(QString("enum '%1' does not have a type entry or is not an enum")
950 951 .arg(qualified_name));
951 952 m_rejected_enums.insert(qualified_name, NotInTypeSystem);
952 953 return 0;
953 954 }
954 955
955 956 AbstractMetaEnum *meta_enum = createMetaEnum();
956 957 if ( enumsDeclarations.contains(qualified_name)
957 958 || enumsDeclarations.contains(enum_name)) {
958 959 meta_enum->setHasQEnumsDeclaration(true);
959 960 }
960 961
961 962 meta_enum->setTypeEntry((EnumTypeEntry *) type_entry);
962 963 switch (enum_item->accessPolicy()) {
963 964 case CodeModel::Public: *meta_enum += AbstractMetaAttributes::Public; break;
964 965 case CodeModel::Protected: *meta_enum += AbstractMetaAttributes::Protected; break;
965 966 // case CodeModel::Private: *meta_enum += AbstractMetaAttributes::Private; break;
966 967 default: break;
967 968 }
968 969
969 970 ReportHandler::debugMedium(QString(" - traversing enum %1").arg(meta_enum->fullName()));
970 971
971 972 foreach (EnumeratorModelItem value, enum_item->enumerators()) {
972 973
973 974 AbstractMetaEnumValue *meta_enum_value = createMetaEnumValue();
974 975 meta_enum_value->setName(value->name());
975 976 // Deciding the enum value...
976 977
977 978 meta_enum_value->setStringValue(value->value());
978 979 meta_enum->addEnumValue(meta_enum_value);
979 980
980 981 ReportHandler::debugFull(" - " + meta_enum_value->name() + " = "
981 982 + meta_enum_value->value());
982 983
983 984 // Add into global register...
984 985 if (enclosing)
985 986 m_enum_values[enclosing->name() + "::" + meta_enum_value->name()] = meta_enum_value;
986 987 else
987 988 m_enum_values[meta_enum_value->name()] = meta_enum_value;
988 989 }
989 990
990 991 m_enums << meta_enum;
991 992
992 993 return meta_enum;
993 994 }
994 995
995 996 AbstractMetaClass *AbstractMetaBuilder::traverseTypeAlias(TypeAliasModelItem typeAlias)
996 997 {
997 998 QString class_name = strip_template_args(typeAlias->name());
998 999
999 1000 QString full_class_name = class_name;
1000 1001 // we have an inner class
1001 1002 if (m_current_class) {
1002 1003 full_class_name = strip_template_args(m_current_class->typeEntry()->qualifiedCppName())
1003 1004 + "::" + full_class_name;
1004 1005 }
1005 1006
1006 1007 // If we haven't specified anything for the typedef, then we don't care
1007 1008 ComplexTypeEntry *type = TypeDatabase::instance()->findComplexType(full_class_name);
1008 1009 if (type == 0)
1009 1010 return 0;
1010 1011
1011 1012 if (type->isObject())
1012 1013 static_cast<ObjectTypeEntry *>(type)->setQObject(isQObject(strip_template_args(typeAlias->type().qualifiedName().join("::"))));
1013 1014
1014 1015 AbstractMetaClass *meta_class = createMetaClass();
1015 1016 meta_class->setTypeAlias(true);
1016 1017 meta_class->setTypeEntry(type);
1017 1018 meta_class->setBaseClassNames(QStringList() << typeAlias->type().qualifiedName().join("::"));
1018 1019 *meta_class += AbstractMetaAttributes::Public;
1019 1020
1020 1021 // Set the default include file name
1021 1022 if (!type->include().isValid()) {
1022 1023 QFileInfo info(typeAlias->fileName());
1023 1024 type->setInclude(Include(Include::IncludePath, info.fileName()));
1024 1025 }
1025 1026
1026 1027 return meta_class;
1027 1028 }
1028 1029
1029 1030 AbstractMetaClass *AbstractMetaBuilder::traverseClass(ClassModelItem class_item)
1030 1031 {
1031 1032 QString class_name = strip_template_args(class_item->name());
1032 1033 QString full_class_name = class_name;
1033 1034
1034 1035 // we have inner an class
1035 1036 if (m_current_class) {
1036 1037 full_class_name = strip_template_args(m_current_class->typeEntry()->qualifiedCppName())
1037 1038 + "::" + full_class_name;
1038 1039 }
1039 1040
1040 1041 ComplexTypeEntry *type = TypeDatabase::instance()->findComplexType(full_class_name);
1041 1042 RejectReason reason = NoReason;
1042 1043
1043 1044 if (full_class_name == "QMetaTypeId") {
1044 1045 // QtScript: record which types have been declared
1045 1046 int lpos = class_item->name().indexOf('<');
1046 1047 int rpos = class_item->name().lastIndexOf('>');
1047 1048 if ((lpos != -1) && (rpos != -1)) {
1048 1049 QString declared_typename = class_item->name().mid(lpos+1, rpos - lpos-1);
1049 1050 m_qmetatype_declared_typenames.insert(declared_typename);
1050 1051 }
1051 1052 }
1052 1053
1053 1054 if (TypeDatabase::instance()->isClassRejected(full_class_name)) {
1054 1055 reason = GenerationDisabled;
1055 1056 } else if (!type) {
1056 1057 TypeEntry *te = TypeDatabase::instance()->findType(full_class_name);
1057 1058 if (te && !te->isComplex())
1058 1059 reason = RedefinedToNotClass;
1059 1060 else
1060 1061 reason = NotInTypeSystem;
1061 1062 } else if (type->codeGeneration() == TypeEntry::GenerateNothing) {
1062 1063 reason = GenerationDisabled;
1063 1064 }
1064 1065
1065 1066 if (reason != NoReason) {
1066 1067 m_rejected_classes.insert(full_class_name, reason);
1067 1068 return 0;
1068 1069 }
1069 1070
1070 1071 if (type->isObject()) {
1071 1072 ((ObjectTypeEntry *)type)->setQObject(isQObject(full_class_name));
1072 1073 }
1073 1074
1074 1075 AbstractMetaClass *meta_class = createMetaClass();
1075 1076 meta_class->setTypeEntry(type);
1076 1077 meta_class->setBaseClassNames(class_item->baseClasses());
1077 1078 *meta_class += AbstractMetaAttributes::Public;
1078 1079
1079 1080 AbstractMetaClass *old_current_class = m_current_class;
1080 1081 m_current_class = meta_class;
1081 1082
1082 1083 if (type->isContainer()) {
1083 1084 ReportHandler::debugSparse(QString("container: '%1'").arg(full_class_name));
1084 1085 } else {
1085 1086 ReportHandler::debugSparse(QString("class: '%1'").arg(meta_class->fullName()));
1086 1087 }
1087 1088
1088 1089 TemplateParameterList template_parameters = class_item->templateParameters();
1089 1090 QList<TypeEntry *> template_args;
1090 1091 template_args.clear();
1091 1092 for (int i=0; i<template_parameters.size(); ++i) {
1092 1093 const TemplateParameterModelItem &param = template_parameters.at(i);
1093 1094 TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name());
1094 1095 param_type->setOrdinal(i);
1095 1096 template_args.append(param_type);
1096 1097 }
1097 1098 meta_class->setTemplateArguments(template_args);
1098 1099
1099 1100 parseQ_Property(meta_class, class_item->propertyDeclarations());
1100 1101
1101 1102 traverseFunctions(model_dynamic_cast<ScopeModelItem>(class_item), meta_class);
1102 1103 traverseEnums(model_dynamic_cast<ScopeModelItem>(class_item), meta_class, class_item->enumsDeclarations());
1103 1104 traverseFields(model_dynamic_cast<ScopeModelItem>(class_item), meta_class);
1104 1105
1105 1106 // Inner classes
1106 1107 {
1107 1108 QList<ClassModelItem> inner_classes = class_item->classMap().values();
1108 1109 foreach (const ClassModelItem &ci, inner_classes) {
1109 1110 AbstractMetaClass *cl = traverseClass(ci);
1110 1111 if (cl) {
1111 1112 cl->setEnclosingClass(meta_class);
1112 1113 m_meta_classes << cl;
1113 1114 }
1114 1115 }
1115 1116
1116 1117 }
1117 1118
1118 1119 // Go through all typedefs to see if we have defined any
1119 1120 // specific typedefs to be used as classes.
1120 1121 TypeAliasList typeAliases = class_item->typeAliases();
1121 1122 foreach (TypeAliasModelItem typeAlias, typeAliases) {
1122 1123 AbstractMetaClass *cls = traverseTypeAlias(typeAlias);
1123 1124 if (cls != 0) {
1124 1125 cls->setEnclosingClass(meta_class);
1125 1126 addAbstractMetaClass(cls);
1126 1127 }
1127 1128 }
1128 1129
1129 1130
1130 1131 m_current_class = old_current_class;
1131 1132
1132 1133 // Set the default include file name
1133 1134 if (!type->include().isValid()) {
1134 1135 QFileInfo info(class_item->fileName());
1135 1136 type->setInclude(Include(Include::IncludePath, info.fileName()));
1136 1137 }
1137 1138
1138 1139 return meta_class;
1139 1140 }
1140 1141
1141 1142 AbstractMetaField *AbstractMetaBuilder::traverseField(VariableModelItem field, const AbstractMetaClass *cls)
1142 1143 {
1143 1144 QString field_name = field->name();
1144 1145 QString class_name = m_current_class->typeEntry()->qualifiedCppName();
1145 1146
1146 1147 // Ignore friend decl.
1147 1148 if (field->isFriend())
1148 1149 return 0;
1149 1150
1150 1151 if (field->accessPolicy() == CodeModel::Private)
1151 1152 return 0;
1152 1153
1153 1154 if (TypeDatabase::instance()->isFieldRejected(class_name, field_name)) {
1154 1155 m_rejected_fields.insert(class_name + "::" + field_name, GenerationDisabled);
1155 1156 return 0;
1156 1157 }
1157 1158
1158 1159
1159 1160 AbstractMetaField *meta_field = createMetaField();
1160 1161 meta_field->setName(field_name);
1161 1162 meta_field->setEnclosingClass(cls);
1162 1163
1163 1164 bool ok;
1164 1165 TypeInfo field_type = field->type();
1165 1166 AbstractMetaType *meta_type = translateType(field_type, &ok);
1166 1167
1167 1168 if (!meta_type || !ok) {
1168 1169 ReportHandler::warning(QString("skipping field '%1::%2' with unmatched type '%3'")
1169 1170 .arg(m_current_class->name())
1170 1171 .arg(field_name)
1171 1172 .arg(TypeInfo::resolveType(field_type, currentScope()->toItem()).qualifiedName().join("::")));
1172 1173 delete meta_field;
1173 1174 return 0;
1174 1175 }
1175 1176
1176 1177 meta_field->setType(meta_type);
1177 1178
1178 1179 uint attr = 0;
1179 1180 if (field->isStatic())
1180 1181 attr |= AbstractMetaAttributes::Static;
1181 1182
1182 1183 CodeModel::AccessPolicy policy = field->accessPolicy();
1183 1184 if (policy == CodeModel::Public)
1184 1185 attr |= AbstractMetaAttributes::Public;
1185 1186 else if (policy == CodeModel::Protected)
1186 1187 attr |= AbstractMetaAttributes::Protected;
1187 1188 else
1188 1189 attr |= AbstractMetaAttributes::Private;
1189 1190 meta_field->setAttributes(attr);
1190 1191
1191 1192 return meta_field;
1192 1193 }
1193 1194
1194 1195 void AbstractMetaBuilder::traverseFields(ScopeModelItem scope_item, AbstractMetaClass *meta_class)
1195 1196 {
1196 1197 foreach (VariableModelItem field, scope_item->variables()) {
1197 1198 AbstractMetaField *meta_field = traverseField(field, meta_class);
1198 1199
1199 1200 if (meta_field) {
1200 1201 meta_field->setOriginalAttributes(meta_field->attributes());
1201 1202 meta_class->addField(meta_field);
1202 1203 }
1203 1204 }
1204 1205 }
1205 1206
1206 1207 void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction *meta_function, AbstractMetaClass *meta_class)
1207 1208 {
1208 1209 // Set the default value of the declaring class. This may be changed
1209 1210 // in fixFunctions later on
1210 1211 meta_function->setDeclaringClass(meta_class);
1211 1212
1212 1213 // Some of the queries below depend on the implementing class being set
1213 1214 // to function properly. Such as function modifications
1214 1215 meta_function->setImplementingClass(meta_class);
1215 1216
1216 1217 if (meta_function->name() == "operator_equal")
1217 1218 meta_class->setHasEqualsOperator(true);
1218 1219
1219 1220 if (!meta_function->isFinalInTargetLang()
1220 1221 && meta_function->isRemovedFrom(meta_class, TypeSystem::TargetLangCode)) {
1221 1222 *meta_function += AbstractMetaAttributes::FinalInCpp;
1222 1223 }
1223 1224 }
1224 1225
1225 1226 void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item, AbstractMetaClass *meta_class)
1226 1227 {
1227 1228 foreach (FunctionModelItem function, scope_item->functions()) {
1228 1229 AbstractMetaFunction *meta_function = traverseFunction(function);
1229 1230
1230 1231 if (meta_function) {
1231 1232 meta_function->setOriginalAttributes(meta_function->attributes());
1232 1233 if (meta_class->isNamespace())
1233 1234 *meta_function += AbstractMetaAttributes::Static;
1234 1235
1235 1236 if (QPropertySpec *read = meta_class->propertySpecForRead(meta_function->name())) {
1236 1237 if (read->type() == meta_function->type()->typeEntry()) {
1237 1238 *meta_function += AbstractMetaAttributes::PropertyReader;
1238 1239 meta_function->setPropertySpec(read);
1239 1240 // printf("%s is reader for %s\n",
1240 1241 // qPrintable(meta_function->name()),
1241 1242 // qPrintable(read->name()));
1242 1243 }
1243 1244 } else if (QPropertySpec *write =
1244 1245 meta_class->propertySpecForWrite(meta_function->name())) {
1245 1246 if (write->type() == meta_function->arguments().at(0)->type()->typeEntry()) {
1246 1247 *meta_function += AbstractMetaAttributes::PropertyWriter;
1247 1248 meta_function->setPropertySpec(write);
1248 1249 // printf("%s is writer for %s\n",
1249 1250 // qPrintable(meta_function->name()),
1250 1251 // qPrintable(write->name()));
1251 1252 }
1252 1253 } else if (QPropertySpec *reset =
1253 1254 meta_class->propertySpecForReset(meta_function->name())) {
1254 1255 *meta_function += AbstractMetaAttributes::PropertyResetter;
1255 1256 meta_function->setPropertySpec(reset);
1256 1257 // printf("%s is resetter for %s\n",
1257 1258 // qPrintable(meta_function->name()),
1258 1259 // qPrintable(reset->name()));
1259 1260 }
1260 1261
1261 1262
1262 1263 bool isInvalidDestructor = meta_function->isDestructor() && meta_function->isPrivate();
1263 1264 bool isInvalidConstructor = meta_function->isConstructor()
1264 1265 && (meta_function->isPrivate() || meta_function->isInvalid());
1265 1266 if ((isInvalidDestructor || isInvalidConstructor)
1266 1267 && !meta_class->hasNonPrivateConstructor()) {
1267 1268 *meta_class += AbstractMetaAttributes::Final;
1268 1269 } else if (meta_function->isConstructor() && !meta_function->isPrivate()) {
1269 1270 *meta_class -= AbstractMetaAttributes::Final;
1270 1271 meta_class->setHasNonPrivateConstructor(true);
1271 1272 }
1272 1273
1273 1274 // Classes with virtual destructors should always have a shell class
1274 1275 // (since we aren't registering the destructors, we need this extra check)
1275 1276 if (meta_function->isDestructor() && !meta_function->isFinal())
1276 1277 meta_class->setForceShellClass(true);
1277 1278
1278 1279 if (!meta_function->isDestructor()
1279 1280 && !meta_function->isInvalid()
1280 1281 && (!meta_function->isConstructor() || !meta_function->isPrivate())) {
1281 1282
1282 1283 if (meta_class->typeEntry()->designatedInterface() && !meta_function->isPublic()
1283 1284 && !meta_function->isPrivate()) {
1284 1285 QString warn = QString("non-public function '%1' in interface '%2'")
1285 1286 .arg(meta_function->name()).arg(meta_class->name());
1286 1287 ReportHandler::warning(warn);
1287 1288
1288 1289 meta_function->setVisibility(AbstractMetaClass::Public);
1289 1290 }
1290 1291
1291 1292 setupFunctionDefaults(meta_function, meta_class);
1292 1293
1293 1294 if (meta_function->isSignal() && meta_class->hasSignal(meta_function)) {
1294 1295 QString warn = QString("signal '%1' in class '%2' is overloaded.")
1295 1296 .arg(meta_function->name()).arg(meta_class->name());
1296 1297 ReportHandler::warning(warn);
1297 1298 }
1298 1299
1299 1300 if (meta_function->isSignal() && !meta_class->isQObject()) {
1300 1301 QString warn = QString("signal '%1' in non-QObject class '%2'")
1301 1302 .arg(meta_function->name()).arg(meta_class->name());
1302 1303 ReportHandler::warning(warn);
1303 1304 }
1304 1305
1305 1306 meta_class->addFunction(meta_function);
1306 1307 } else if (meta_function->isDestructor() && !meta_function->isPublic()) {
1307 1308 meta_class->setHasPublicDestructor(false);
1308 1309 }
1309 1310 }
1310 1311 }
1311 1312 }
1312 1313
1313 1314 bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass *meta_class)
1314 1315 {
1315 1316 Q_ASSERT(!meta_class->isInterface());
1316 1317
1317 1318 if (m_setup_inheritance_done.contains(meta_class))
1318 1319 return true;
1319 1320 m_setup_inheritance_done.insert(meta_class);
1320 1321
1321 1322 QStringList base_classes = meta_class->baseClassNames();
1322 1323
1323 1324 TypeDatabase *types = TypeDatabase::instance();
1324 1325
1325 1326 // we only support our own containers and ONLY if there is only one baseclass
1326 1327 if (base_classes.size() == 1 && base_classes.first().count('<') == 1) {
1327 1328 QStringList scope = meta_class->typeEntry()->qualifiedCppName().split("::");
1328 1329 scope.removeLast();
1329 1330 for (int i=scope.size(); i>=0; --i) {
1330 1331 QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join("::") + "::" : QString();
1331 1332 QString complete_name = prefix + base_classes.first();
1332 1333 TypeParser::Info info = TypeParser::parse(complete_name);
1333 1334 QString base_name = info.qualified_name.join("::");
1334 1335
1335 1336 AbstractMetaClass *templ = 0;
1336 1337 foreach (AbstractMetaClass *c, m_templates) {
1337 1338 if (c->typeEntry()->name() == base_name) {
1338 1339 templ = c;
1339 1340 break;
1340 1341 }
1341 1342 }
1342 1343
1343 1344 if (templ == 0)
1344 1345 templ = m_meta_classes.findClass(base_name);
1345 1346
1346 1347 if (templ) {
1347 1348 setupInheritance(templ);
1348 1349 inheritTemplate(meta_class, templ, info);
1349 1350 return true;
1350 1351 }
1351 1352 }
1352 1353
1353 1354 ReportHandler::warning(QString("template baseclass '%1' of '%2' is not known")
1354 1355 .arg(base_classes.first())
1355 1356 .arg(meta_class->name()));
1356 1357 return false;
1357 1358 }
1358 1359
1359 1360 int primary = -1;
1360 1361 int primaries = 0;
1361 1362 for (int i=0; i<base_classes.size(); ++i) {
1362 1363
1363 1364 if (types->isClassRejected(base_classes.at(i)))
1364 1365 continue;
1365 1366
1366 1367 TypeEntry *base_class_entry = types->findType(base_classes.at(i));
1367 1368 if (!base_class_entry) {
1368 1369 ReportHandler::warning(QString("class '%1' inherits from unknown base class '%2'")
1369 1370 .arg(meta_class->name()).arg(base_classes.at(i)));
1370 1371 }
1371 1372
1372 1373 // true for primary base class
1373 1374 else if (!base_class_entry->designatedInterface()) {
1374 1375 if (primaries > 0) {
1375 1376 ReportHandler::warning(QString("class '%1' has multiple primary base classes"
1376 1377 " '%2' and '%3'")
1377 1378 .arg(meta_class->name())
1378 1379 .arg(base_classes.at(primary))
1379 1380 .arg(base_class_entry->name()));
1380 1381 return false;
1381 1382 }
1382 1383 primaries++;
1383 1384 primary = i;
1384 1385 }
1385 1386 }
1386 1387
1387 1388 if (primary >= 0) {
1388 1389 AbstractMetaClass *base_class = m_meta_classes.findClass(base_classes.at(primary));
1389 1390 if (!base_class) {
1390 1391 ReportHandler::warning(QString("unknown baseclass for '%1': '%2'")
1391 1392 .arg(meta_class->name())
1392 1393 .arg(base_classes.at(primary)));
1393 1394 return false;
1394 1395 }
1395 1396 meta_class->setBaseClass(base_class);
1396 1397
1397 1398 if (meta_class->typeEntry()->designatedInterface() != 0 && meta_class->isQObject()) {
1398 1399 ReportHandler::warning(QString("QObject extended by interface type '%1'. This is not supported and the generated Java code will not compile.")
1399 1400 .arg(meta_class->name()));
1400 1401 } else if (meta_class->typeEntry()->designatedInterface() != 0 && base_class != 0 && !base_class->isInterface()) {
1401 1402 ReportHandler::warning(QString("object type '%1' extended by interface type '%2'. The resulting API will be less expressive than the original.")
1402 1403 .arg(base_class->name())
1403 1404 .arg(meta_class->name()));
1404 1405 }
1405 1406
1406 1407 }
1407 1408
1408 1409 for (int i=0; i<base_classes.size(); ++i) {
1409 1410 if (types->isClassRejected(base_classes.at(i)))
1410 1411 continue;
1411 1412
1412 1413 if (i != primary) {
1413 1414 AbstractMetaClass *base_class = m_meta_classes.findClass(base_classes.at(i));
1414 1415 if (base_class == 0) {
1415 1416 ReportHandler::warning(QString("class not found for setup inheritance '%1'").arg(base_classes.at(i)));
1416 1417 return false;
1417 1418 }
1418 1419
1419 1420 setupInheritance(base_class);
1420 1421
1421 1422 QString interface_name = InterfaceTypeEntry::interfaceName(base_class->name());
1422 1423 AbstractMetaClass *iface = m_meta_classes.findClass(interface_name);
1423 1424 if (!iface) {
1424 1425 ReportHandler::warning(QString("unknown interface for '%1': '%2'")
1425 1426 .arg(meta_class->name())
1426 1427 .arg(interface_name));
1427 1428 return false;
1428 1429 }
1429 1430 meta_class->addInterface(iface);
1430 1431
1431 1432 AbstractMetaClassList interfaces = iface->interfaces();
1432 1433 foreach (AbstractMetaClass *iface, interfaces)
1433 1434 meta_class->addInterface(iface);
1434 1435 }
1435 1436 }
1436 1437
1437 1438 return true;
1438 1439 }
1439 1440
1440 1441 void AbstractMetaBuilder::traverseEnums(ScopeModelItem scope_item, AbstractMetaClass *meta_class, const QStringList &enumsDeclarations)
1441 1442 {
1442 1443 EnumList enums = scope_item->enums();
1443 1444 foreach (EnumModelItem enum_item, enums) {
1444 1445 AbstractMetaEnum *meta_enum = traverseEnum(enum_item, meta_class, QSet<QString>::fromList(enumsDeclarations));
1445 1446 if (meta_enum) {
1446 1447 meta_enum->setOriginalAttributes(meta_enum->attributes());
1447 1448 meta_class->addEnum(meta_enum);
1448 1449 meta_enum->setEnclosingClass(meta_class);
1449 1450 }
1450 1451 }
1451 1452 }
1452 1453
1453 1454 AbstractMetaFunction *AbstractMetaBuilder::traverseFunction(FunctionModelItem function_item)
1454 1455 {
1455 1456 QString function_name = function_item->name();
1456 1457 QString class_name = m_current_class->typeEntry()->qualifiedCppName();
1457 1458
1458 1459 if (TypeDatabase::instance()->isFunctionRejected(class_name, function_name)) {
1459 1460 m_rejected_functions.insert(class_name + "::" + function_name, GenerationDisabled);
1460 1461 return 0;
1461 1462 }
1462 1463
1463 1464
1464 1465 Q_ASSERT(function_item->functionType() == CodeModel::Normal
1465 1466 || function_item->functionType() == CodeModel::Signal
1466 1467 || function_item->functionType() == CodeModel::Slot);
1467 1468
1468 1469 if (function_item->isFriend())
1469 1470 return 0;
1470 1471
1471 1472
1472 1473 QString cast_type;
1473 1474
1474 1475 if (function_name.startsWith("operator")) {
1475 1476 function_name = rename_operator(function_name.mid(8));
1476 1477 if (function_name.isEmpty()) {
1477 1478 m_rejected_functions.insert(class_name + "::" + function_name,
1478 1479 GenerationDisabled);
1479 1480 return 0;
1480 1481 }
1481 1482 if (function_name.contains("_cast_"))
1482 1483 cast_type = function_name.mid(14).trimmed();
1483 1484 }
1484 1485
1485 1486 AbstractMetaFunction *meta_function = createMetaFunction();
1486 1487 meta_function->setConstant(function_item->isConstant());
1487 1488
1488 1489 ReportHandler::debugMedium(QString(" - %2()").arg(function_name));
1489 1490
1490 1491 meta_function->setName(function_name);
1491 1492 meta_function->setOriginalName(function_item->name());
1492 1493
1493 1494 if (function_item->isAbstract())
1494 1495 *meta_function += AbstractMetaAttributes::Abstract;
1495 1496
1496 1497 if (!meta_function->isAbstract())
1497 1498 *meta_function += AbstractMetaAttributes::Native;
1498 1499
1499 1500 if (!function_item->isVirtual())
1500 1501 *meta_function += AbstractMetaAttributes::Final;
1501 1502
1502 1503 if (function_item->isInvokable())
1503 1504 *meta_function += AbstractMetaAttributes::Invokable;
1504 1505
1505 1506 if (function_item->isStatic()) {
1506 1507 *meta_function += AbstractMetaAttributes::Static;
1507 1508 *meta_function += AbstractMetaAttributes::Final;
1508 1509 }
1509 1510
1510 1511 // Access rights
1511 1512 if (function_item->accessPolicy() == CodeModel::Public)
1512 1513 *meta_function += AbstractMetaAttributes::Public;
1513 1514 else if (function_item->accessPolicy() == CodeModel::Private)
1514 1515 *meta_function += AbstractMetaAttributes::Private;
1515 1516 else
1516 1517 *meta_function += AbstractMetaAttributes::Protected;
1517 1518
1518 1519
1519 1520 QString stripped_class_name = class_name;
1520 1521 int cc_pos = stripped_class_name.lastIndexOf("::");
1521 1522 if (cc_pos > 0)
1522 1523 stripped_class_name = stripped_class_name.mid(cc_pos + 2);
1523 1524
1524 1525 TypeInfo function_type = function_item->type();
1525 1526 if (function_name.startsWith('~')) {
1526 1527 meta_function->setFunctionType(AbstractMetaFunction::DestructorFunction);
1527 1528 meta_function->setInvalid(true);
1528 1529 } else if (strip_template_args(function_name) == stripped_class_name) {
1529 1530 meta_function->setFunctionType(AbstractMetaFunction::ConstructorFunction);
1530 1531 meta_function->setName(m_current_class->name());
1531 1532 } else {
1532 1533 bool ok;
1533 1534 AbstractMetaType *type = 0;
1534 1535
1535 1536 if (!cast_type.isEmpty()) {
1536 1537 TypeInfo info;
1537 1538 info.setQualifiedName(QStringList(cast_type));
1538 1539 type = translateType(info, &ok);
1539 1540 } else {
1540 1541 type = translateType(function_type, &ok);
1541 1542 }
1542 1543
1543 1544 if (!ok) {
1544 1545 ReportHandler::warning(QString("skipping function '%1::%2', unmatched return type '%3'")
1545 1546 .arg(class_name)
1546 1547 .arg(function_item->name())
1547 1548 .arg(function_item->type().toString()));
1548 1549 m_rejected_functions[class_name + "::" + function_name] =
1549 1550 UnmatchedReturnType;
1550 1551 meta_function->setInvalid(true);
1551 1552 return meta_function;
1552 1553 }
1553 1554 meta_function->setType(type);
1554 1555
1555 1556 if (function_item->functionType() == CodeModel::Signal)
1556 1557 meta_function->setFunctionType(AbstractMetaFunction::SignalFunction);
1557 1558 else if (function_item->functionType() == CodeModel::Slot)
1558 1559 meta_function->setFunctionType(AbstractMetaFunction::SlotFunction);
1559 1560 }
1560 1561
1561 1562 ArgumentList arguments = function_item->arguments();
1562 1563 AbstractMetaArgumentList meta_arguments;
1563 1564
1564 1565 int first_default_argument = 0;
1565 1566 for (int i=0; i<arguments.size(); ++i) {
1566 1567 ArgumentModelItem arg = arguments.at(i);
1567 1568
1568 1569 bool ok;
1569 1570 AbstractMetaType *meta_type = translateType(arg->type(), &ok);
1570 1571 if (!meta_type || !ok) {
1571 1572 ReportHandler::warning(QString("skipping function '%1::%2', "
1572 1573 "unmatched parameter type '%3'")
1573 1574 .arg(class_name)
1574 1575 .arg(function_item->name())
1575 1576 .arg(arg->type().toString()));
1576 1577 m_rejected_functions[class_name + "::" + function_name] =
1577 1578 UnmatchedArgumentType;
1578 1579 meta_function->setInvalid(true);
1579 1580 return meta_function;
1580 1581 }
1581 1582 AbstractMetaArgument *meta_argument = createMetaArgument();
1582 1583 meta_argument->setType(meta_type);
1583 1584 meta_argument->setName(arg->name());
1584 1585 meta_argument->setArgumentIndex(i);
1585 1586 meta_arguments << meta_argument;
1586 1587 }
1587 1588
1588 1589 meta_function->setArguments(meta_arguments);
1589 1590
1590 1591 // Find the correct default values
1591 1592 for (int i=0; i<arguments.size(); ++i) {
1592 1593 ArgumentModelItem arg = arguments.at(i);
1593 1594 AbstractMetaArgument *meta_arg = meta_arguments.at(i);
1594 1595 if (arg->defaultValue()) {
1595 1596 QString expr = arg->defaultValueExpression();
1596 1597 if (!expr.isEmpty())
1597 1598 meta_arg->setOriginalDefaultValueExpression(expr);
1598 1599
1599 1600 expr = translateDefaultValue(arg, meta_arg->type(), meta_function, m_current_class, i);
1600 1601 if (expr.isEmpty()) {
1601 1602 first_default_argument = i;
1602 1603 } else {
1603 1604 meta_arg->setDefaultValueExpression(expr);
1604 1605 }
1605 1606
1606 1607 if (meta_arg->type()->isEnum() || meta_arg->type()->isFlags()) {
1607 1608 m_enum_default_arguments
1608 1609 << QPair<AbstractMetaArgument *, AbstractMetaFunction *>(meta_arg, meta_function);
1609 1610 }
1610 1611
1611 1612 }
1612 1613 }
1613 1614
1614 1615 // If we where not able to translate the default argument make it
1615 1616 // reset all default arguments before this one too.
1616 1617 for (int i=0; i<first_default_argument; ++i)
1617 1618 meta_arguments[i]->setDefaultValueExpression(QString());
1618 1619
1619 1620 if (ReportHandler::debugLevel() == ReportHandler::FullDebug)
1620 1621 foreach(AbstractMetaArgument *arg, meta_arguments)
1621 1622 ReportHandler::debugFull(" - " + arg->toString());
1622 1623
1623 1624 return meta_function;
1624 1625 }
1625 1626
1626 1627
1627 1628 AbstractMetaType *AbstractMetaBuilder::translateType(const TypeInfo &_typei, bool *ok, bool resolveType, bool resolveScope)
1628 1629 {
1629 1630 Q_ASSERT(ok);
1630 1631 *ok = true;
1631 1632
1632 1633 // 1. Test the type info without resolving typedefs in case this is present in the
1633 1634 // type system
1634 1635 TypeInfo typei;
1635 1636 if (resolveType) {
1636 1637 bool isok;
1637 1638 AbstractMetaType *t = translateType(_typei, &isok, false, resolveScope);
1638 1639 if (t != 0 && isok)
1639 1640 return t;
1640 1641 }
1641 1642
1642 1643 if (!resolveType)
1643 1644 typei = _typei;
1644 1645 else {
1645 1646 // Go through all parts of the current scope (including global namespace)
1646 1647 // to resolve typedefs. The parser does not properly resolve typedefs in
1647 1648 // the global scope when they are referenced from inside a namespace.
1648 1649 // This is a work around to fix this bug since fixing it in resolveType
1649 1650 // seemed non-trivial
1650 1651 int i = m_scopes.size() - 1;
1651 1652 while (i >= 0) {
1652 1653 typei = TypeInfo::resolveType(_typei, m_scopes.at(i--)->toItem());
1653 1654 if (typei.qualifiedName().join("::") != _typei.qualifiedName().join("::"))
1654 1655 break;
1655 1656 }
1656 1657
1657 1658 }
1658 1659
1659 1660 if (typei.isFunctionPointer()) {
1660 1661 *ok = false;
1661 1662 return 0;
1662 1663 }
1663 1664
1664 1665 TypeParser::Info typeInfo = TypeParser::parse(typei.toString());
1665 1666 if (typeInfo.is_busted) {
1666 1667 *ok = false;
1667 1668 return 0;
1668 1669 }
1669 1670
1670 1671 // 2. Handle pointers specified as arrays with unspecified size
1671 1672 bool array_of_unspecified_size = false;
1672 1673 if (typeInfo.arrays.size() > 0) {
1673 1674 array_of_unspecified_size = true;
1674 1675 for (int i=0; i<typeInfo.arrays.size(); ++i)
1675 1676 array_of_unspecified_size = array_of_unspecified_size && typeInfo.arrays.at(i).isEmpty();
1676 1677
1677 1678 if (!array_of_unspecified_size) {
1678 1679 TypeInfo newInfo;
1679 1680 //newInfo.setArguments(typei.arguments());
1680 1681 newInfo.setIndirections(typei.indirections());
1681 1682 newInfo.setConstant(typei.isConstant());
1682 1683 newInfo.setFunctionPointer(typei.isFunctionPointer());
1683 1684 newInfo.setQualifiedName(typei.qualifiedName());
1684 1685 newInfo.setReference(typei.isReference());
1685 1686 newInfo.setVolatile(typei.isVolatile());
1686 1687
1687 1688 AbstractMetaType *elementType = translateType(newInfo, ok);
1688 1689 if (!(*ok))
1689 1690 return 0;
1690 1691
1691 1692 for (int i=typeInfo.arrays.size()-1; i>=0; --i) {
1692 1693 QString s = typeInfo.arrays.at(i);
1693 1694 bool isok;
1694 1695
1695 1696 int elems = s.toInt(&isok);
1696 1697 if (!isok)
1697 1698 return 0;
1698 1699
1699 1700 AbstractMetaType *arrayType = createMetaType();
1700 1701 arrayType->setArrayElementCount(elems);
1701 1702 arrayType->setArrayElementType(elementType);
1702 1703 arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry()));
1703 1704 decideUsagePattern(arrayType);
1704 1705
1705 1706 elementType = arrayType;
1706 1707 }
1707 1708
1708 1709 return elementType;
1709 1710 } else {
1710 1711 typeInfo.indirections += typeInfo.arrays.size();
1711 1712 }
1712 1713 }
1713 1714
1714 1715 QStringList qualifier_list = typeInfo.qualified_name;
1715 1716 if (qualifier_list.isEmpty()) {
1716 1717 ReportHandler::warning(QString("horribly broken type '%1'").arg(_typei.toString()));
1717 1718 *ok = false;
1718 1719 return 0;
1719 1720 }
1720 1721
1721 1722 QString qualified_name = qualifier_list.join("::");
1722 1723 QString name = qualifier_list.takeLast();
1723 1724
1724 1725 // 3. Special case 'void' type
1725 1726 if (name == "void" && typeInfo.indirections == 0) {
1726 1727 return 0;
1727 1728 }
1728 1729
1729 1730 // 4. Special case QFlags (include instantiation in name)
1730 1731 if (qualified_name == "QFlags")
1731 1732 qualified_name = typeInfo.toString();
1732 1733
1733 1734 // 5. Try to find the type
1734 1735 const TypeEntry *type = TypeDatabase::instance()->findType(qualified_name);
1735 1736
1736 1737 // 6. No? Try looking it up as a flags type
1737 1738 if (!type)
1738 1739 type = TypeDatabase::instance()->findFlagsType(qualified_name);
1739 1740
1740 1741 // 7. No? Try looking it up as a container type
1741 1742 if (!type)
1742 1743 type = TypeDatabase::instance()->findContainerType(name);
1743 1744
1744 1745 // 8. No? Check if the current class is a template and this type is one
1745 1746 // of the parameters.
1746 1747 if (type == 0 && m_current_class != 0) {
1747 1748 QList<TypeEntry *> template_args = m_current_class->templateArguments();
1748 1749 foreach (TypeEntry *te, template_args) {
1749 1750 if (te->name() == qualified_name)
1750 1751 type = te;
1751 1752 }
1752 1753 }
1753 1754
1754 1755 // 9. Try finding the type by prefixing it with the current
1755 1756 // context and all baseclasses of the current context
1756 1757 if (!type && !TypeDatabase::instance()->isClassRejected(qualified_name) && m_current_class != 0 && resolveScope) {
1757 1758 QStringList contexts;
1758 1759 contexts.append(m_current_class->qualifiedCppName());
1759 1760 contexts.append(currentScope()->qualifiedName().join("::"));
1760 1761
1761 1762
1762 1763 TypeInfo info = typei;
1763 1764 bool subclasses_done = false;
1764 1765 while (!contexts.isEmpty() && type == 0) {
1765 1766 //type = TypeDatabase::instance()->findType(contexts.at(0) + "::" + qualified_name);
1766 1767
1767 1768 bool isok;
1768 1769 info.setQualifiedName(QStringList() << contexts.at(0) << qualified_name);
1769 1770 AbstractMetaType *t = translateType(info, &isok, true, false);
1770 1771 if (t != 0 && isok)
1771 1772 return t;
1772 1773
1773 1774 ClassModelItem item = m_dom->findClass(contexts.at(0));
1774 1775 if (item != 0)
1775 1776 contexts += item->baseClasses();
1776 1777 contexts.pop_front();
1777 1778
1778 1779 // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so
1779 1780 // enum types from there may be addressed without any scope resolution in properties.
1780 1781 if (contexts.size() == 0 && !subclasses_done) {
1781 1782 contexts << "Qt";
1782 1783 subclasses_done = true;
1783 1784 }
1784 1785 }
1785 1786
1786 1787 }
1787 1788
1788 1789 if (!type) {
1789 1790 *ok = false;
1790 1791 return 0;
1791 1792 }
1792 1793
1793 1794 // Used to for diagnostics later...
1794 1795 m_used_types << type;
1795 1796
1796 1797 // These are only implicit and should not appear in code...
1797 1798 Q_ASSERT(!type->isInterface());
1798 1799
1799 1800 AbstractMetaType *meta_type = createMetaType();
1800 1801 meta_type->setTypeEntry(type);
1801 1802 meta_type->setIndirections(typeInfo.indirections);
1802 1803 meta_type->setReference(typeInfo.is_reference);
1803 1804 meta_type->setConstant(typeInfo.is_constant);
1804 1805 meta_type->setOriginalTypeDescription(_typei.toString());
1805 1806 decideUsagePattern(meta_type);
1806 1807
1807 1808 if (meta_type->typeEntry()->isContainer()) {
1808 1809 ContainerTypeEntry::Type container_type = static_cast<const ContainerTypeEntry *>(type)->type();
1809 1810
1810 1811 if (container_type == ContainerTypeEntry::StringListContainer) {
1811 1812 TypeInfo info;
1812 1813 info.setQualifiedName(QStringList() << "QString");
1813 1814 AbstractMetaType *targ_type = translateType(info, ok);
1814 1815
1815 1816 Q_ASSERT(*ok);
1816 1817 Q_ASSERT(targ_type);
1817 1818
1818 1819 meta_type->addInstantiation(targ_type);
1819 1820 meta_type->setInstantiationInCpp(false);
1820 1821
1821 1822 } else {
1822 1823 foreach (const TypeParser::Info &ta, typeInfo.template_instantiations) {
1823 1824 TypeInfo info;
1824 1825 info.setConstant(ta.is_constant);
1825 1826 info.setReference(ta.is_reference);
1826 1827 info.setIndirections(ta.indirections);
1827 1828
1828 1829 info.setFunctionPointer(false);
1829 1830 info.setQualifiedName(ta.instantiationName().split("::"));
1830 1831
1831 1832 AbstractMetaType *targ_type = translateType(info, ok);
1832 1833 if (!(*ok)) {
1833 1834 delete meta_type;
1834 1835 return 0;
1835 1836 }
1836 1837
1837 1838 meta_type->addInstantiation(targ_type);
1838 1839 }
1839 1840 }
1840 1841
1841 1842 if (container_type == ContainerTypeEntry::ListContainer
1842 1843 || container_type == ContainerTypeEntry::VectorContainer
1843 1844 || container_type == ContainerTypeEntry::StringListContainer) {
1844 1845 Q_ASSERT(meta_type->instantiations().size() == 1);
1845 1846 }
1846 1847 }
1847 1848
1848 1849 return meta_type;
1849 1850 }
1850 1851
1851 1852 void AbstractMetaBuilder::decideUsagePattern(AbstractMetaType *meta_type)
1852 1853 {
1853 1854 const TypeEntry *type = meta_type->typeEntry();
1854 1855
1855 1856 if (type->isPrimitive() && (meta_type->actualIndirections() == 0
1856 1857 || (meta_type->isConstant() && meta_type->isReference() && meta_type->indirections() == 0))) {
1857 1858 meta_type->setTypeUsagePattern(AbstractMetaType::PrimitivePattern);
1858 1859
1859 1860 } else if (type->isVoid()) {
1860 1861 meta_type->setTypeUsagePattern(AbstractMetaType::NativePointerPattern);
1861 1862
1862 1863 } else if (type->isString()
1863 1864 && meta_type->indirections() == 0
1864 1865 && (meta_type->isConstant() == meta_type->isReference()
1865 1866 || meta_type->isConstant())) {
1866 1867 meta_type->setTypeUsagePattern(AbstractMetaType::StringPattern);
1867 1868
1868 1869 } else if (type->isChar()
1869 1870 && meta_type->indirections() == 0
1870 1871 && meta_type->isConstant() == meta_type->isReference()) {
1871 1872 meta_type->setTypeUsagePattern(AbstractMetaType::CharPattern);
1872 1873
1873 1874 } else if (type->isJObjectWrapper()
1874 1875 && meta_type->indirections() == 0
1875 1876 && meta_type->isConstant() == meta_type->isReference()) {
1876 1877 meta_type->setTypeUsagePattern(AbstractMetaType::JObjectWrapperPattern);
1877 1878
1878 1879 } else if (type->isVariant()
1879 1880 && meta_type->indirections() == 0
1880 1881 && meta_type->isConstant() == meta_type->isReference()) {
1881 1882 meta_type->setTypeUsagePattern(AbstractMetaType::VariantPattern);
1882 1883
1883 1884 } else if (type->isEnum() && meta_type->actualIndirections() == 0) {
1884 1885 meta_type->setTypeUsagePattern(AbstractMetaType::EnumPattern);
1885 1886
1886 1887 } else if (type->isObject()
1887 1888 && meta_type->indirections() == 0
1888 1889 && meta_type->isReference()) {
1889 1890 if (((ComplexTypeEntry *) type)->isQObject())
1890 1891 meta_type->setTypeUsagePattern(AbstractMetaType::QObjectPattern);
1891 1892 else
1892 1893 meta_type->setTypeUsagePattern(AbstractMetaType::ObjectPattern);
1893 1894
1894 1895 } else if (type->isObject()
1895 1896 && meta_type->indirections() == 1) {
1896 1897 if (((ComplexTypeEntry *) type)->isQObject())
1897 1898 meta_type->setTypeUsagePattern(AbstractMetaType::QObjectPattern);
1898 1899 else
1899 1900 meta_type->setTypeUsagePattern(AbstractMetaType::ObjectPattern);
1900 1901
1901 1902 // const-references to pointers can be passed as pointers
1902 1903 if (meta_type->isReference() && meta_type->isConstant()) {
1903 1904 meta_type->setReference(false);
1904 1905 meta_type->setConstant(false);
1905 1906 }
1906 1907
1907 1908 } else if (type->isContainer() && meta_type->indirections() == 0) {
1908 1909 meta_type->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
1909 1910
1910 1911 } else if (type->isTemplateArgument()) {
1911 1912
1912 1913 } else if (type->isFlags()
1913 1914 && meta_type->indirections() == 0
1914 1915 && (meta_type->isConstant() == meta_type->isReference())) {
1915 1916 meta_type->setTypeUsagePattern(AbstractMetaType::FlagsPattern);
1916 1917
1917 1918 } else if (type->isArray()) {
1918 1919 meta_type->setTypeUsagePattern(AbstractMetaType::ArrayPattern);
1919 1920
1920 1921 } else if (type->isThread()) {
1921 1922 Q_ASSERT(meta_type->indirections() == 1);
1922 1923 meta_type->setTypeUsagePattern(AbstractMetaType::ThreadPattern);
1923 1924
1924 1925 } else if (type->isValue()
1925 1926 && meta_type->indirections() == 0
1926 1927 && (meta_type->isConstant() == meta_type->isReference()
1927 1928 || !meta_type->isReference())) {
1928 1929 meta_type->setTypeUsagePattern(AbstractMetaType::ValuePattern);
1929 1930
1930 1931 } else {
1931 1932 meta_type->setTypeUsagePattern(AbstractMetaType::NativePointerPattern);
1932 1933 ReportHandler::debugFull(QString("native pointer pattern for '%1'")
1933 1934 .arg(meta_type->cppSignature()));
1934 1935 }
1935 1936 }
1936 1937
1937 1938 QString AbstractMetaBuilder::translateDefaultValue(ArgumentModelItem item, AbstractMetaType *type,
1938 1939 AbstractMetaFunction *fnc, AbstractMetaClass *implementing_class,
1939 1940 int argument_index)
1940 1941 {
1941 1942 QString function_name = fnc->name();
1942 1943 QString class_name = implementing_class->name();
1943 1944
1944 1945 QString replaced_expression = fnc->replacedDefaultExpression(implementing_class, argument_index + 1);
1945 1946 if (fnc->removedDefaultExpression(implementing_class, argument_index +1))
1946 1947 return "";
1947 1948 if (!replaced_expression.isEmpty())
1948 1949 return replaced_expression;
1949 1950
1950 1951 QString expr = item->defaultValueExpression();
1951 1952 if (type != 0 && type->isPrimitive()) {
1952 1953 if (type->name() == "boolean") {
1953 1954 if (expr == "false" || expr=="true") {
1954 1955 return expr;
1955 1956 } else {
1956 1957 bool ok = false;
1957 1958 int number = expr.toInt(&ok);
1958 1959 if (ok && number)
1959 1960 return "true";
1960 1961 else
1961 1962 return "false";
1962 1963 }
1963 1964 } else if (expr == "ULONG_MAX") {
1964 1965 return "Long.MAX_VALUE";
1965 1966 } else if (expr == "QVariant::Invalid") {
1966 1967 return QString::number(QVariant::Invalid);
1967 1968 } else {
1968 1969 // This can be an enum or flag so I need to delay the
1969 1970 // translation untill all namespaces are completly
1970 1971 // processed. This is done in figureOutEnumValues()
1971 1972 return expr;
1972 1973 }
1973 1974 } else if (type != 0 && (type->isFlags() || type->isEnum())) {
1974 1975 // Same as with enum explanation above...
1975 1976 return expr;
1976 1977
1977 1978 } else {
1978 1979
1979 1980 // constructor or functioncall can be a bit tricky...
1980 1981 if (expr == "QVariant()" || expr == "QModelIndex()") {
1981 1982 return "null";
1982 1983 } else if (expr == "QString()") {
1983 1984 return "null";
1984 1985 } else if (expr.endsWith(")") && expr.contains("::")) {
1985 1986 TypeEntry *typeEntry = TypeDatabase::instance()->findType(expr.left(expr.indexOf("::")));
1986 1987 if (typeEntry)
1987 1988 return typeEntry->qualifiedTargetLangName() + "." + expr.right(expr.length() - expr.indexOf("::") - 2);
1988 1989 } else if (expr.endsWith(")") && type != 0 && type->isValue()) {
1989 1990 int pos = expr.indexOf("(");
1990 1991
1991 1992 TypeEntry *typeEntry = TypeDatabase::instance()->findType(expr.left(pos));
1992 1993 if (typeEntry)
1993 1994 return "new " + typeEntry->qualifiedTargetLangName() + expr.right(expr.length() - pos);
1994 1995 else
1995 1996 return expr;
1996 1997 } else if (expr == "0") {
1997 1998 return "null";
1998 1999 } else if (type != 0 && (type->isObject() || type->isValue() || expr.contains("::"))) { // like Qt::black passed to a QColor
1999 2000 TypeEntry *typeEntry = TypeDatabase::instance()->findType(expr.left(expr.indexOf("::")));
2000 2001
2001 2002 expr = expr.right(expr.length() - expr.indexOf("::") - 2);
2002 2003 if (typeEntry) {
2003 2004 return "new " + type->typeEntry()->qualifiedTargetLangName() +
2004 2005 "(" + typeEntry->qualifiedTargetLangName() + "." + expr + ")";
2005 2006 }
2006 2007 }
2007 2008 }
2008 2009
2009 2010 QString warn = QString("unsupported default value '%3' of argument in function '%1', class '%2'")
2010 2011 .arg(function_name).arg(class_name).arg(item->defaultValueExpression());
2011 2012 ReportHandler::warning(warn);
2012 2013
2013 2014 return QString();
2014 2015 }
2015 2016
2016 2017
2017 2018 bool AbstractMetaBuilder::isQObject(const QString &qualified_name)
2018 2019 {
2019 2020 if (qualified_name == "QObject")
2020 2021 return true;
2021 2022
2022 2023 ClassModelItem class_item = m_dom->findClass(qualified_name);
2023 2024
2024 2025 if (!class_item) {
2025 2026 QStringList names = qualified_name.split(QLatin1String("::"));
2026 2027 NamespaceModelItem ns = model_dynamic_cast<NamespaceModelItem>(m_dom);
2027 2028 for (int i=0; i<names.size() - 1 && ns; ++i)
2028 2029 ns = ns->namespaceMap().value(names.at(i));
2029 2030 if (ns && names.size() >= 2)
2030 2031 class_item = ns->findClass(names.at(names.size() - 1));
2031 2032 }
2032 2033
2033 2034 bool isqobject = class_item && class_item->extendsClass("QObject");
2034 2035
2035 2036 if (class_item && !isqobject) {
2036 2037 QStringList baseClasses = class_item->baseClasses();
2037 2038 for (int i=0; i<baseClasses.count(); ++i) {
2038 2039
2039 2040 isqobject = isQObject(baseClasses.at(i));
2040 2041 if (isqobject)
2041 2042 break;
2042 2043 }
2043 2044 }
2044 2045
2045 2046 return isqobject;
2046 2047 }
2047 2048
2048 2049
2049 2050 bool AbstractMetaBuilder::isEnum(const QStringList &qualified_name)
2050 2051 {
2051 2052 CodeModelItem item = m_dom->model()->findItem(qualified_name, m_dom->toItem());
2052 2053 return item && item->kind() == _EnumModelItem::__node_kind;
2053 2054 }
2054 2055
2055 2056 AbstractMetaType *AbstractMetaBuilder::inheritTemplateType(const QList<AbstractMetaType *> &template_types,
2056 2057 AbstractMetaType *meta_type, bool *ok)
2057 2058 {
2058 2059 if (ok != 0)
2059 2060 *ok = true;
2060 2061 if (!meta_type || (!meta_type->typeEntry()->isTemplateArgument() && !meta_type->hasInstantiations()))
2061 2062 return meta_type ? meta_type->copy() : 0;
2062 2063
2063 2064 AbstractMetaType *returned = meta_type->copy();
2064 2065 returned->setOriginalTemplateType(meta_type->copy());
2065 2066
2066 2067 if (returned->typeEntry()->isTemplateArgument()) {
2067 2068 const TemplateArgumentEntry *tae = static_cast<const TemplateArgumentEntry *>(returned->typeEntry());
2068 2069
2069 2070 // If the template is intantiated with void we special case this as rejecting the functions that use this
2070 2071 // parameter from the instantiation.
2071 2072 if (template_types.size() <= tae->ordinal() || template_types.at(tae->ordinal())->typeEntry()->name() == "void") {
2072 2073 if (ok != 0)
2073 2074 *ok = false;
2074 2075 return 0;
2075 2076 }
2076 2077
2077 2078 AbstractMetaType *t = returned->copy();
2078 2079 t->setTypeEntry(template_types.at(tae->ordinal())->typeEntry());
2079 2080 t->setIndirections(template_types.at(tae->ordinal())->indirections() + t->indirections()
2080 2081 ? 1
2081 2082 : 0);
2082 2083 decideUsagePattern(t);
2083 2084
2084 2085 delete returned;
2085 2086 returned = inheritTemplateType(template_types, t, ok);
2086 2087 if (ok != 0 && !(*ok))
2087 2088 return 0;
2088 2089 }
2089 2090
2090 2091 if (returned->hasInstantiations()) {
2091 2092 QList<AbstractMetaType *> instantiations = returned->instantiations();
2092 2093 for (int i=0; i<instantiations.count(); ++i) {
2093 2094 instantiations[i] = inheritTemplateType(template_types, instantiations.at(i), ok);
2094 2095 if (ok != 0 && !(*ok))
2095 2096 return 0;
2096 2097 }
2097 2098 returned->setInstantiations(instantiations);
2098 2099 }
2099 2100
2100 2101 return returned;
2101 2102 }
2102 2103
2103 2104 bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass *subclass,
2104 2105 const AbstractMetaClass *template_class,
2105 2106 const TypeParser::Info &info)
2106 2107 {
2107 2108 QList<TypeParser::Info> targs = info.template_instantiations;
2108 2109
2109 2110 QList<AbstractMetaType *> template_types;
2110 2111 foreach (const TypeParser::Info &i, targs) {
2111 2112 TypeEntry *t = TypeDatabase::instance()->findType(i.qualified_name.join("::"));
2112 2113
2113 2114 if (t != 0) {
2114 2115 AbstractMetaType *temporary_type = createMetaType();
2115 2116 temporary_type->setTypeEntry(t);
2116 2117 temporary_type->setConstant(i.is_constant);
2117 2118 temporary_type->setReference(i.is_reference);
2118 2119 temporary_type->setIndirections(i.indirections);
2119 2120 template_types << temporary_type;
2120 2121 }
2121 2122 }
2122 2123
2123 2124 AbstractMetaFunctionList funcs = subclass->functions();
2124 2125 foreach (const AbstractMetaFunction *function, template_class->functions()) {
2125 2126
2126 2127 if (function->isModifiedRemoved(TypeSystem::All))
2127 2128 continue;
2128 2129
2129 2130 AbstractMetaFunction *f = function->copy();
2130 2131 f->setArguments(AbstractMetaArgumentList());
2131 2132
2132 2133 bool ok = true;
2133 2134 AbstractMetaType *ftype = function->type();
2134 2135 f->setType(inheritTemplateType(template_types, ftype, &ok));
2135 2136 if (!ok) {
2136 2137 delete f;
2137 2138 continue;
2138 2139 }
2139 2140
2140 2141 foreach (AbstractMetaArgument *argument, function->arguments()) {
2141 2142 AbstractMetaType *atype = argument->type();
2142 2143
2143 2144 AbstractMetaArgument *arg = argument->copy();
2144 2145 arg->setType(inheritTemplateType(template_types, atype, &ok));
2145 2146 if (!ok)
2146 2147 break;
2147 2148 f->addArgument(arg);
2148 2149 }
2149 2150
2150 2151 if (!ok) {
2151 2152 delete f;
2152 2153 continue ;
2153 2154 }
2154 2155
2155 2156 // There is no base class in java to inherit from here, so the
2156 2157 // template instantiation is the class that implements the function..
2157 2158 f->setImplementingClass(subclass);
2158 2159
2159 2160 // We also set it as the declaring class, since the superclass is
2160 2161 // supposed to disappear. This allows us to make certain function modifications
2161 2162 // on the inherited functions.
2162 2163 f->setDeclaringClass(subclass);
2163 2164
2164 2165
2165 2166 if (f->isConstructor() && subclass->isTypeAlias()) {
2166 2167 f->setName(subclass->name());
2167 2168 } else if (f->isConstructor()) {
2168 2169 delete f;
2169 2170 continue;
2170 2171 }
2171 2172
2172 2173 // if the instantiation has a function named the same as an existing
2173 2174 // function we have shadowing so we need to skip it.
2174 2175 bool found = false;
2175 2176 for (int i=0; i<funcs.size(); ++i) {
2176 2177 if (funcs.at(i)->name() == f->name()) {
2177 2178 found = true;
2178 2179 continue;
2179 2180 }
2180 2181 }
2181 2182 if (found) {
2182 2183 delete f;
2183 2184 continue;
2184 2185 }
2185 2186
2186 2187 ComplexTypeEntry *te = subclass->typeEntry();
2187 2188 FunctionModificationList mods = function->modifications(template_class);
2188 2189 for (int i=0; i<mods.size(); ++i) {
2189 2190 FunctionModification mod = mods.at(i);
2190 2191 mod.signature = f->minimalSignature();
2191 2192
2192 2193 // If we ever need it... Below is the code to do
2193 2194 // substitution of the template instantation type inside
2194 2195 // injected code..
2195 2196 #if 0
2196 2197 if (mod.modifiers & Modification::CodeInjection) {
2197 2198 for (int j=0; j<template_types.size(); ++j) {
2198 2199 CodeSnip &snip = mod.snips.last();
2199 2200 QString code = snip.code();
2200 2201 code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j),
2201 2202 template_types.at(j)->typeEntry()->qualifiedCppName());
2202 2203 snip.codeList.clear();
2203 2204 snip.addCode(code);
2204 2205 }
2205 2206 }
2206 2207 #endif
2207 2208 te->addFunctionModification(mod);
2208 2209 }
2209 2210
2210 2211 subclass->addFunction(f);
2211 2212 }
2212 2213
2213 2214 // Clean up
2214 2215 foreach (AbstractMetaType *type, template_types) {
2215 2216 delete type;
2216 2217 }
2217 2218
2218 2219
2219 2220 {
2220 2221 subclass->setTemplateBaseClass(template_class);
2221 2222
2222 2223 subclass->setInterfaces(template_class->interfaces());
2223 2224 subclass->setBaseClass(template_class->baseClass());
2224 2225 }
2225 2226
2226 2227 return true;
2227 2228 }
2228 2229
2229 2230 void AbstractMetaBuilder::parseQ_Property(AbstractMetaClass *meta_class, const QStringList &declarations)
2230 2231 {
2231 2232 for (int i=0; i<declarations.size(); ++i) {
2232 2233 QString p = declarations.at(i);
2233 2234
2234 2235 QStringList l = p.split(QLatin1String(" "));
2235 2236
2236 2237
2237 2238 QStringList qualifiedScopeName = currentScope()->qualifiedName();
2238 2239 bool ok = false;
2239 2240 AbstractMetaType *type = 0;
2240 2241 QString scope;
2241 2242 for (int j=qualifiedScopeName.size(); j>=0; --j) {
2242 2243 scope = j > 0 ? QStringList(qualifiedScopeName.mid(0, j)).join("::") + "::" : QString();
2243 2244 TypeInfo info;
2244 2245 info.setQualifiedName((scope + l.at(0)).split("::"));
2245 2246
2246 2247 type = translateType(info, &ok);
2247 2248 if (type != 0 && ok) {
2248 2249 break;
2249 2250 }
2250 2251 }
2251 2252
2252 2253 if (type == 0 || !ok) {
2253 2254 ReportHandler::warning(QString("Unable to decide type of property: '%1' in class '%2'")
2254 2255 .arg(l.at(0)).arg(meta_class->name()));
2255 2256 continue;
2256 2257 }
2257 2258
2258 2259 QString typeName = scope + l.at(0);
2259 2260
2260 2261 QPropertySpec *spec = new QPropertySpec(type->typeEntry());
2261 2262 spec->setName(l.at(1));
2262 2263 spec->setIndex(i);
2263 2264
2264 2265 for (int pos=2; pos+1<l.size(); pos+=2) {
2265 2266 if (l.at(pos) == QLatin1String("READ"))
2266 2267 spec->setRead(l.at(pos+1));
2267 2268 else if (l.at(pos) == QLatin1String("WRITE"))
2268 2269 spec->setWrite(l.at(pos+1));
2269 2270 else if (l.at(pos) == QLatin1String("DESIGNABLE"))
2270 2271 spec->setDesignable(l.at(pos+1));
2271 2272 else if (l.at(pos) == QLatin1String("RESET"))
2272 2273 spec->setReset(l.at(pos+1));
2273 2274 }
2274 2275
2275 2276 meta_class->addPropertySpec(spec);
2276 2277 delete type;
2277 2278 }
2278 2279 }
2279 2280
2280 2281 static void hide_functions(const AbstractMetaFunctionList &l) {
2281 2282 foreach (AbstractMetaFunction *f, l) {
2282 2283 FunctionModification mod;
2283 2284 mod.signature = f->minimalSignature();
2284 2285 mod.modifiers = FunctionModification::Private;
2285 2286 ((ComplexTypeEntry *) f->implementingClass()->typeEntry())->addFunctionModification(mod);
2286 2287 }
2287 2288 }
2288 2289
2289 2290 static void remove_function(AbstractMetaFunction *f) {
2290 2291 FunctionModification mod;
2291 2292 mod.removal = TypeSystem::All;
2292 2293 mod.signature = f->minimalSignature();
2293 2294 ((ComplexTypeEntry *) f->implementingClass()->typeEntry())->addFunctionModification(mod);
2294 2295 }
2295 2296
2296 2297 static AbstractMetaFunctionList filter_functions(const AbstractMetaFunctionList &lst, QSet<QString> *signatures)
2297 2298 {
2298 2299 AbstractMetaFunctionList functions;
2299 2300 foreach (AbstractMetaFunction *f, lst) {
2300 2301 QString signature = f->minimalSignature();
2301 2302 int start = signature.indexOf(QLatin1Char('(')) + 1;
2302 2303 int end = signature.lastIndexOf(QLatin1Char(')'));
2303 2304 signature = signature.mid(start, end - start);
2304 2305 if (signatures->contains(signature)) {
2305 2306 remove_function(f);
2306 2307 continue;
2307 2308 }
2308 2309 (*signatures) << signature;
2309 2310 functions << f;
2310 2311 }
2311 2312 return functions;
2312 2313 }
2313 2314
2314 2315 void AbstractMetaBuilder::setupEquals(AbstractMetaClass *cls)
2315 2316 {
2316 2317 AbstractMetaFunctionList equals;
2317 2318 AbstractMetaFunctionList nequals;
2318 2319
2319 2320 QString op_equals = QLatin1String("operator_equal");
2320 2321 QString op_nequals = QLatin1String("operator_not_equal");
2321 2322
2322 2323 AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements
2323 2324 | AbstractMetaClass::NotRemovedFromTargetLang);
2324 2325 foreach (AbstractMetaFunction *f, functions) {
2325 2326 if (f->name() == op_equals)
2326 2327 equals << f;
2327 2328 else if (f->name() == op_nequals)
2328 2329 nequals << f;
2329 2330 }
2330 2331
2331 2332 if (equals.size() || nequals.size()) {
2332 2333 if (!cls->hasHashFunction()) {
2333 2334 ReportHandler::warning(QString::fromLatin1("Class '%1' has equals operators but no qHash() function")
2334 2335 .arg(cls->name()));
2335 2336 }
2336 2337
2337 2338 hide_functions(equals);
2338 2339 hide_functions(nequals);
2339 2340
2340 2341 // We only need == if we have both == and !=, and one == for
2341 2342 // each signature type, like QDateTime::==(QDate) and (QTime)
2342 2343 // if such a thing exists...
2343 2344 QSet<QString> func_signatures;
2344 2345 cls->setEqualsFunctions(filter_functions(equals, &func_signatures));
2345 2346 cls->setNotEqualsFunctions(filter_functions(nequals, &func_signatures));
2346 2347 }
2347 2348 }
2348 2349
2349 2350 void AbstractMetaBuilder::setupComparable(AbstractMetaClass *cls)
2350 2351 {
2351 2352 AbstractMetaFunctionList greater;
2352 2353 AbstractMetaFunctionList greaterEquals;
2353 2354 AbstractMetaFunctionList less;
2354 2355 AbstractMetaFunctionList lessEquals;
2355 2356
2356 2357 QString op_greater = QLatin1String("operator_greater");
2357 2358 QString op_greater_eq = QLatin1String("operator_greater_or_equal");
2358 2359 QString op_less = QLatin1String("operator_less");
2359 2360 QString op_less_eq = QLatin1String("operator_less_or_equal");
2360 2361
2361 2362 AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements
2362 2363 | AbstractMetaClass::NotRemovedFromTargetLang);
2363 2364 foreach (AbstractMetaFunction *f, functions) {
2364 2365 if (f->name() == op_greater)
2365 2366 greater << f;
2366 2367 else if (f->name() == op_greater_eq)
2367 2368 greaterEquals << f;
2368 2369 else if (f->name() == op_less)
2369 2370 less << f;
2370 2371 else if (f->name() == op_less_eq)
2371 2372 lessEquals << f;
2372 2373 }
2373 2374
2374 2375 bool hasEquals = cls->equalsFunctions().size() || cls->notEqualsFunctions().size();
2375 2376
2376 2377 // Conditions for comparable is:
2377 2378 // >, ==, < - The basic case
2378 2379 // >, == - Less than becomes else case
2379 2380 // <, == - Greater than becomes else case
2380 2381 // >=, <= - if (<= && >=) -> equal
2381 2382 bool mightBeComparable = greater.size() || greaterEquals.size() || less.size() || lessEquals.size()
2382 2383 || greaterEquals.size() == 1 || lessEquals.size() == 1;
2383 2384
2384 2385 if (mightBeComparable) {
2385 2386 QSet<QString> signatures;
2386 2387
2387 2388 // We only hide the original functions if we are able to make a compareTo() method
2388 2389 bool wasComparable = false;
2389 2390
2390 2391 // The three upper cases, prefer the <, == approach
2391 2392 if (hasEquals && (greater.size() || less.size())) {
2392 2393 cls->setLessThanFunctions(filter_functions(less, &signatures));
2393 2394 cls->setGreaterThanFunctions(filter_functions(greater, &signatures));
2394 2395 filter_functions(greaterEquals, &signatures);
2395 2396 filter_functions(lessEquals, &signatures);
2396 2397 wasComparable = true;
2397 2398 } else if (hasEquals && (greaterEquals.size() || lessEquals.size())) {
2398 2399 cls->setLessThanEqFunctions(filter_functions(lessEquals, &signatures));
2399 2400 cls->setGreaterThanEqFunctions(filter_functions(greaterEquals, &signatures));
2400 2401 wasComparable = true;
2401 2402 } else if (greaterEquals.size() == 1 || lessEquals.size() == 1) {
2402 2403 cls->setGreaterThanEqFunctions(greaterEquals);
2403 2404 cls->setLessThanEqFunctions(lessEquals);
2404 2405 filter_functions(less, &signatures);
2405 2406 filter_functions(greater, &signatures);
2406 2407 wasComparable = true;
2407 2408 }
2408 2409
2409 2410 if (wasComparable) {
2410 2411 hide_functions(greater);
2411 2412 hide_functions(greaterEquals);
2412 2413 hide_functions(less);
2413 2414 hide_functions(lessEquals);
2414 2415 }
2415 2416 }
2416 2417
2417 2418 }
2418 2419
2419 2420 void AbstractMetaBuilder::setupClonable(AbstractMetaClass *cls)
2420 2421 {
2421 2422 QString op_assign = QLatin1String("operator_assign");
2422 2423
2423 2424 AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::ClassImplements);
2424 2425 foreach (AbstractMetaFunction *f, functions) {
2425 2426 if ((f->name() == op_assign || f->isConstructor()) && f->isPublic()) {
2426 2427 AbstractMetaArgumentList arguments = f->arguments();
2427 2428 if (arguments.size() == 1) {
2428 2429 if (cls->typeEntry()->qualifiedCppName() == arguments.at(0)->type()->typeEntry()->qualifiedCppName()) {
2429 2430 if (cls->typeEntry()->isValue()) {
2430 2431 cls->setHasCloneOperator(true);
2431 2432 return;
2432 2433 }
2433 2434 }
2434 2435 }
2435 2436 }
2436 2437 }
2437 2438 }
2438 2439
2439 2440 static void write_reject_log_file(const QString &name,
2440 2441 const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects)
2441 2442 {
2442 2443 QFile f(name);
2443 2444 if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
2444 2445 ReportHandler::warning(QString("failed to write log file: '%1'")
2445 2446 .arg(f.fileName()));
2446 2447 return;
2447 2448 }
2448 2449
2449 2450 QTextStream s(&f);
2450 2451
2451 2452
2452 2453 for (int reason=0; reason<AbstractMetaBuilder::NoReason; ++reason) {
2453 2454 s << QString(72, '*') << endl;
2454 2455 switch (reason) {
2455 2456 case AbstractMetaBuilder::NotInTypeSystem:
2456 2457 s << "Not in type system";
2457 2458 break;
2458 2459 case AbstractMetaBuilder::GenerationDisabled:
2459 2460 s << "Generation disabled by type system";
2460 2461 break;
2461 2462 case AbstractMetaBuilder::RedefinedToNotClass:
2462 2463 s << "Type redefined to not be a class";
2463 2464 break;
2464 2465
2465 2466 case AbstractMetaBuilder::UnmatchedReturnType:
2466 2467 s << "Unmatched return type";
2467 2468 break;
2468 2469
2469 2470 case AbstractMetaBuilder::UnmatchedArgumentType:
2470 2471 s << "Unmatched argument type";
2471 2472 break;
2472 2473
2473 2474 default:
2474 2475 s << "unknown reason";
2475 2476 break;
2476 2477 }
2477 2478
2478 2479 s << endl;
2479 2480
2480 2481 for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin();
2481 2482 it != rejects.constEnd(); ++it) {
2482 2483 if (it.value() != reason)
2483 2484 continue;
2484 2485 s << " - " << it.key() << endl;
2485 2486 }
2486 2487
2487 2488 s << QString(72, '*') << endl << endl;
2488 2489 }
2489 2490
2490 2491 }
2491 2492
2492 2493
2493 2494 void AbstractMetaBuilder::dumpLog()
2494 2495 {
2495 2496 write_reject_log_file("mjb_rejected_classes.log", m_rejected_classes);
2496 2497 write_reject_log_file("mjb_rejected_enums.log", m_rejected_enums);
2497 2498 write_reject_log_file("mjb_rejected_functions.log", m_rejected_functions);
2498 2499 write_reject_log_file("mjb_rejected_fields.log", m_rejected_fields);
2499 2500 }
2500 2501
2501 2502 AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted() const
2502 2503 {
2503 2504 AbstractMetaClassList res;
2504 2505
2505 2506 AbstractMetaClassList classes = m_meta_classes;
2506 2507 qSort(classes);
2507 2508
2508 2509 QSet<AbstractMetaClass*> noDependency;
2509 2510 QHash<AbstractMetaClass*, QSet<AbstractMetaClass* >* > hash;
2510 2511 foreach (AbstractMetaClass *cls, classes) {
2511 2512 QSet<AbstractMetaClass* > *depends = new QSet<AbstractMetaClass* >();
2512 2513
2513 2514 if (cls->baseClass())
2514 2515 depends->insert(cls->baseClass());
2515 2516
2516 2517 foreach (AbstractMetaClass *interface, cls->interfaces()) {
2517 2518 AbstractMetaClass *impl = interface->primaryInterfaceImplementor();
2518 2519 if (impl == cls)
2519 2520 continue;
2520 2521 depends->insert(impl);
2521 2522 }
2522 2523
2523 2524 if (depends->empty()) {
2524 2525 noDependency.insert(cls);
2525 2526 } else {
2526 2527 hash.insert(cls, depends);
2527 2528 }
2528 2529 }
2529 2530
2530 2531 while (!noDependency.empty()) {
2531 2532 foreach (AbstractMetaClass *cls, noDependency.values()) {
2532 2533 if(!cls->isInterface())
2533 2534 res.append(cls);
2534 2535 noDependency.remove(cls);
2535 2536 QHashIterator<AbstractMetaClass*, QSet<AbstractMetaClass* >* > i(hash);
2536 2537 while (i.hasNext()) {
2537 2538 i.next();
2538 2539 i.value()->remove(cls);
2539 2540 if (i.value()->empty()) {
2540 2541 AbstractMetaClass *key = i.key();
2541 2542 noDependency.insert(key);
2542 2543 hash.remove(key);
2543 2544 delete(i.value());
2544 2545 }
2545 2546 }
2546 2547 }
2547 2548 }
2548 2549
2549 2550 if (!noDependency.empty() || !hash.empty()) {
2550 2551 qWarning("dependency graph was cyclic.");
2551 2552 }
2552 2553
2553 2554 return res;
2554 2555 }
@@ -1,144 +1,145
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
4 4 **
5 5 ** This file is part of the Qt Script Generator project on Trolltech Labs.
6 6 **
7 7 ** This file may be used under the terms of the GNU General Public
8 8 ** License version 2.0 as published by the Free Software Foundation
9 9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 10 ** this file. Please review the following information to ensure GNU
11 11 ** General Public Licensing requirements will be met:
12 12 ** http://www.trolltech.com/products/qt/opensource.html
13 13 **
14 14 ** If you are unsure which license is appropriate for your use, please
15 15 ** review the following information:
16 16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 17 ** sales department at sales@trolltech.com.
18 18 **
19 19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 21 **
22 22 ****************************************************************************/
23 23
24 24 #ifndef GENERATOR_H
25 25 #define GENERATOR_H
26 26
27 27 #include "metajava.h"
28 28 #include "typesystem.h"
29 29
30 30 #include "codemodel.h"
31 31
32 32 #include <QObject>
33 33 #include <QFile>
34 34
35 35 class Generator : public QObject
36 36 {
37 37 Q_OBJECT
38 38
39 39 Q_PROPERTY(QString outputDirectory READ outputDirectory WRITE setOutputDirectory);
40 40
41 41 public:
42 42 enum Option {
43 43 NoOption = 0x00000000,
44 44 BoxedPrimitive = 0x00000001,
45 45 ExcludeConst = 0x00000002,
46 46 ExcludeReference = 0x00000004,
47 47 UseNativeIds = 0x00000008,
48 48
49 49 EnumAsInts = 0x00000010,
50 50 SkipName = 0x00000020,
51 51 NoCasts = 0x00000040,
52 52 SkipReturnType = 0x00000080,
53 53 OriginalName = 0x00000100,
54 54 ShowStatic = 0x00000200,
55 55 UnderscoreSpaces = 0x00000400,
56 56 ForceEnumCast = 0x00000800,
57 57 ArrayAsPointer = 0x00001000,
58 58 VirtualCall = 0x00002000,
59 59 SkipTemplateParameters = 0x00004000,
60 60 SkipAttributes = 0x00008000,
61 61 OriginalTypeDescription = 0x00010000,
62 62 SkipRemovedArguments = 0x00020000,
63 63 IncludeDefaultExpression = 0x00040000,
64 64 NoReturnStatement = 0x00080000,
65 65 NoBlockedSlot = 0x00100000,
66 66 SuperCall = 0x00200000,
67 67 FirstArgIsWrappedObject = 0x00400000,
68 ConvertReferenceToPtr = 0x00800000,
68 69
69 70 GlobalRefJObject = 0x00100000,
70 71
71 72 ForceValueType = ExcludeReference | ExcludeConst
72 73 };
73 74
74 75 Generator();
75 76
76 77 void setClasses(const AbstractMetaClassList &classes) { m_classes = classes; }
77 78 AbstractMetaClassList classes() const { return m_classes; }
78 79
79 80 QString outputDirectory() const { return m_out_dir; }
80 81 void setOutputDirectory(const QString &outDir) { m_out_dir = outDir; }
81 82 virtual void generate();
82 83 void printClasses();
83 84
84 85 int numGenerated() { return m_num_generated; }
85 86 int numGeneratedAndWritten() { return m_num_generated_written; }
86 87
87 88 virtual bool shouldGenerate(const AbstractMetaClass *) const { return true; }
88 89 virtual QString subDirectoryForClass(const AbstractMetaClass *java_class) const;
89 90 virtual QString fileNameForClass(const AbstractMetaClass *java_class) const;
90 91 virtual void write(QTextStream &s, const AbstractMetaClass *java_class);
91 92
92 93 bool hasDefaultConstructor(const AbstractMetaType *type);
93 94
94 95 // QtScript
95 96 void setQtMetaTypeDeclaredTypeNames(const QSet<QString> &names)
96 97 { m_qmetatype_declared_typenames = names; }
97 98 QSet<QString> qtMetaTypeDeclaredTypeNames() const
98 99 { return m_qmetatype_declared_typenames; }
99 100
100 101 protected:
101 102 void verifyDirectoryFor(const QFile &file);
102 103
103 104 AbstractMetaClassList m_classes;
104 105 int m_num_generated;
105 106 int m_num_generated_written;
106 107 QString m_out_dir;
107 108
108 109 // QtScript
109 110 QSet<QString> m_qmetatype_declared_typenames;
110 111 };
111 112
112 113 class Indentor {
113 114 public:
114 115 Indentor():
115 116 indent(0)
116 117 {}
117 118 int indent;
118 119 };
119 120
120 121 class Indentation {
121 122 public:
122 123 Indentation(Indentor &indentor):
123 124 indentor(indentor)
124 125 {
125 126 indentor.indent++;
126 127 }
127 128 ~Indentation()
128 129 {
129 130 indentor.indent--;
130 131 }
131 132
132 133 private:
133 134 Indentor &indentor;
134 135 };
135 136
136 137 inline QTextStream &operator <<(QTextStream &s, const Indentor &indentor)
137 138 {
138 139 for (int i=0; i<indentor.indent; ++i)
139 140 s << " ";
140 141 return s;
141 142 }
142 143
143 144
144 145 #endif // GENERATOR_H
@@ -1,351 +1,356
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
4 4 **
5 5 ** This file is part of the Qt Script Generator project on Trolltech Labs.
6 6 **
7 7 ** This file may be used under the terms of the GNU General Public
8 8 ** License version 2.0 as published by the Free Software Foundation
9 9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 10 ** this file. Please review the following information to ensure GNU
11 11 ** General Public Licensing requirements will be met:
12 12 ** http://www.trolltech.com/products/qt/opensource.html
13 13 **
14 14 ** If you are unsure which license is appropriate for your use, please
15 15 ** review the following information:
16 16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 17 ** sales department at sales@trolltech.com.
18 18 **
19 19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 21 **
22 22 ****************************************************************************/
23 23
24 24 #include "shellgenerator.h"
25 25 #include "reporthandler.h"
26 26
27 27 #include "metaqtscript.h"
28 28
29 29 bool ShellGenerator::shouldGenerate(const AbstractMetaClass *meta_class) const
30 30 {
31 31 uint cg = meta_class->typeEntry()->codeGeneration();
32 32 if (meta_class->name().startsWith("QtScript")) return false;
33 33 if (meta_class->name().startsWith("QFuture")) return false;
34 34 if (meta_class->name().startsWith("Global")) return false;
35 35 if (meta_class->name().startsWith("QStyleOptionComplex")) return false;
36 36 if (meta_class->name().startsWith("QTextLayout")) return false;
37 37 //if (meta_class->name().startsWith("QTextStream")) return false; // because of >> operators
38 38 //if (meta_class->name().startsWith("QDataStream")) return false; // "
39 39 return ((cg & TypeEntry::GenerateCode) != 0);
40 40 }
41 41
42 42 void ShellGenerator::writeTypeInfo(QTextStream &s, const AbstractMetaType *type, Option options)
43 43 {
44 44 if ((options & OriginalTypeDescription) && !type->originalTypeDescription().isEmpty()) {
45 45 s << type->originalTypeDescription();
46 46 return;
47 47 }
48 48
49 49 if (type->isArray()) {
50 50 writeTypeInfo(s, type->arrayElementType(), options);
51 51 if (options & ArrayAsPointer) {
52 52 s << "*";
53 53 } else {
54 54 s << "[" << type->arrayElementCount() << "]";
55 55 }
56 56 return;
57 57 }
58 58
59 59 const TypeEntry *te = type->typeEntry();
60 60
61 61 if (type->isConstant() && !(options & ExcludeConst))
62 62 s << "const ";
63 63
64 64 if ((options & EnumAsInts) && (te->isEnum() || te->isFlags())) {
65 65 s << "int";
66 66 } else if (te->isFlags()) {
67 67 s << ((FlagsTypeEntry *) te)->originalName();
68 68 } else {
69 69 s << fixCppTypeName(te->qualifiedCppName());
70 70 }
71 71
72 72 if (type->instantiations().size() > 0
73 73 && (!type->isContainer()
74 74 || (static_cast<const ContainerTypeEntry *>(te))->type() != ContainerTypeEntry::StringListContainer)) {
75 75 s << '<';
76 76 QList<AbstractMetaType *> args = type->instantiations();
77 77 bool nested_template = false;
78 78 for (int i=0; i<args.size(); ++i) {
79 79 if (i != 0)
80 80 s << ", ";
81 81 nested_template |= args.at(i)->isContainer();
82 82 writeTypeInfo(s, args.at(i));
83 83 }
84 84 if (nested_template)
85 85 s << ' ';
86 86 s << '>';
87 87 }
88 88
89 89 s << QString(type->indirections(), '*');
90 90
91 if (type->isReference() && !(options & ExcludeReference))
91 if (type->isReference() && !(options & ExcludeReference) && !(options & ConvertReferenceToPtr))
92 92 s << "&";
93
94 if (type->isReference() && (options & ConvertReferenceToPtr)) {
95 s << "*";
96 }
97
93 98
94 99 if (!(options & SkipName))
95 100 s << ' ';
96 101 }
97 102
98 103
99 104 void ShellGenerator::writeFunctionArguments(QTextStream &s, const AbstractMetaClass* owner,
100 105 const AbstractMetaArgumentList &arguments,
101 106 Option option,
102 107 int numArguments)
103 108 {
104 109 if (numArguments < 0) numArguments = arguments.size();
105 110
106 111 for (int i=0; i<numArguments; ++i) {
107 112 if (i != 0)
108 113 s << ", ";
109 114 AbstractMetaArgument *arg = arguments.at(i);
110 115 writeTypeInfo(s, arg->type(), option);
111 116 if (!(option & SkipName))
112 117 s << " " << arg->argumentName();
113 118 if ((option & IncludeDefaultExpression) && !arg->originalDefaultValueExpression().isEmpty()) {
114 119 s << " = ";
115 120
116 121 QString expr = arg->originalDefaultValueExpression();
117 122 if (expr != "0") {
118 123 QString qualifier;
119 124 if (arg->type()->typeEntry()->isEnum() && expr.indexOf("::") < 0) {
120 125 qualifier = ((EnumTypeEntry *)arg->type()->typeEntry())->qualifier();
121 126 } else if (arg->type()->typeEntry()->isFlags() && expr.indexOf("::") < 0) {
122 127 qualifier = ((FlagsTypeEntry *)arg->type()->typeEntry())->originator()->qualifier();
123 128 }
124 129 if (!qualifier.isEmpty()) {
125 130 s << qualifier << "::";
126 131 }
127 132 }
128 133 if (expr.contains("defaultConnection")) {
129 134 expr.replace("defaultConnection","QSqlDatabase::defaultConnection");
130 135 }
131 136 if (expr == "MediaSource()") {
132 137 expr = "Phonon::MediaSource()";
133 138 }
134 139 s << expr;
135 140 }
136 141 }
137 142 }
138 143
139 144 /*!
140 145 * Writes the function \a meta_function signature to the textstream \a s.
141 146 *
142 147 * The \a name_prefix can be used to give the function name a prefix,
143 148 * like "__public_" or "__override_" and \a classname_prefix can
144 149 * be used to give the class name a prefix.
145 150 *
146 151 * The \a option flags can be used to tweak various parameters, such as
147 152 * showing static, original vs renamed name, underscores for space etc.
148 153 *
149 154 * The \a extra_arguments list is a list of extra arguments on the
150 155 * form "bool static_call".
151 156 */
152 157
153 158 void ShellGenerator::writeFunctionSignature(QTextStream &s,
154 159 const AbstractMetaFunction *meta_function,
155 160 const AbstractMetaClass *implementor,
156 161 const QString &name_prefix,
157 162 Option option,
158 163 const QString &classname_prefix,
159 164 const QStringList &extra_arguments,
160 165 int numArguments)
161 166 {
162 167 // ### remove the implementor
163 168 AbstractMetaType *function_type = meta_function->type();
164 169
165 170
166 171 if ((option & SkipReturnType) == 0) {
167 172 if (function_type) {
168 173 writeTypeInfo(s, function_type, option);
169 174 s << " ";
170 175 } else if (!meta_function->isConstructor()) {
171 176 s << "void ";
172 177 }
173 178 }
174 179
175 180 if (implementor) {
176 181 if (classname_prefix.isEmpty())
177 182 s << wrapperClassName(implementor) << "::";
178 183 else
179 184 s << classname_prefix << implementor->name() << "::";
180 185 }
181 186
182 187
183 188 QString function_name;
184 189 if (option & OriginalName)
185 190 function_name = meta_function->originalName();
186 191 else
187 192 function_name = meta_function->name();
188 193
189 194 if (option & UnderscoreSpaces)
190 195 function_name = function_name.replace(' ', '_');
191 196
192 197 if (meta_function->isConstructor())
193 198 function_name = meta_function->ownerClass()->name();
194 199
195 200 if (meta_function->isStatic() && (option & ShowStatic)) {
196 201 function_name = "static_" + meta_function->ownerClass()->name() + "_" + function_name;
197 202 }
198 203
199 204 if (function_name.startsWith("operator")) {
200 205 function_name = meta_function->name();
201 206 }
202 207
203 208 s << name_prefix << function_name;
204 209
205 210 if (meta_function->attributes() & AbstractMetaAttributes::SetterFunction)
206 211 s << "_setter";
207 212 else if (meta_function->attributes() & AbstractMetaAttributes::GetterFunction)
208 213 s << "_getter";
209 214
210 215 s << "(";
211 216
212 217 if ((option & FirstArgIsWrappedObject) && meta_function->ownerClass() && !meta_function->isConstructor() && !meta_function->isStatic()) {
213 218 s << meta_function->ownerClass()->qualifiedCppName() << "* theWrappedObject";
214 219 if (meta_function->arguments().size() != 0) {
215 220 s << ", ";
216 221 }
217 222 }
218 223
219 writeFunctionArguments(s, meta_function->ownerClass(), meta_function->arguments(), option, numArguments);
224 writeFunctionArguments(s, meta_function->ownerClass(), meta_function->arguments(), Option(option & Option(~ConvertReferenceToPtr)), numArguments);
220 225
221 226 // The extra arguments...
222 227 for (int i=0; i<extra_arguments.size(); ++i) {
223 228 if (i > 0 || meta_function->arguments().size() != 0)
224 229 s << ", ";
225 230 s << extra_arguments.at(i);
226 231 }
227 232
228 233 s << ")";
229 234 if (meta_function->isConstant())
230 235 s << " const";
231 236 }
232 237
233 238 AbstractMetaFunctionList ShellGenerator::getFunctionsToWrap(const AbstractMetaClass* meta_class)
234 239 {
235 240 AbstractMetaFunctionList functions = meta_class->queryFunctions(
236 241 AbstractMetaClass::NormalFunctions | AbstractMetaClass::WasPublic
237 242 | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements
238 243 );
239 244 AbstractMetaFunctionList functions2 = meta_class->queryFunctions(
240 245 AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible
241 246 | AbstractMetaClass::NotRemovedFromTargetLang | AbstractMetaClass::ClassImplements
242 247 );
243 248 QSet<AbstractMetaFunction*> set1 = QSet<AbstractMetaFunction*>::fromList(functions);
244 249 foreach(AbstractMetaFunction* func, functions2) {
245 250 set1.insert(func);
246 251 }
247 252
248 253 AbstractMetaFunctionList resultFunctions;
249 254
250 255 foreach(AbstractMetaFunction* func, set1.toList()) {
251 256 if (!func->isAbstract() && func->implementingClass()==meta_class) {
252 257 resultFunctions << func;
253 258 }
254 259 }
255 260 return resultFunctions;
256 261 }
257 262
258 263 AbstractMetaFunctionList ShellGenerator::getVirtualFunctionsForShell(const AbstractMetaClass* meta_class)
259 264 {
260 265 AbstractMetaFunctionList functions = meta_class->queryFunctions(
261 266 AbstractMetaClass::VirtualFunctions | AbstractMetaClass::WasVisible
262 267 // | AbstractMetaClass::NotRemovedFromTargetLang
263 268 );
264 269 return functions;
265 270 }
266 271
267 272 AbstractMetaFunctionList ShellGenerator::getProtectedFunctionsThatNeedPromotion(const AbstractMetaClass* meta_class)
268 273 {
269 274 AbstractMetaFunctionList functions;
270 275 AbstractMetaFunctionList functions1 = getFunctionsToWrap(meta_class);
271 276 foreach(AbstractMetaFunction* func, functions1) {
272 277 if (!func->isPublic() || func->isVirtual()) {
273 278 functions << func;
274 279 }
275 280 }
276 281 return functions;
277 282 }
278 283
279 284 /*!
280 285 Writes the include defined by \a inc to \a stream.
281 286 */
282 287 void ShellGenerator::writeInclude(QTextStream &stream, const Include &inc)
283 288 {
284 289 if (inc.name.isEmpty())
285 290 return;
286 291 if (inc.type == Include::TargetLangImport)
287 292 return;
288 293 stream << "#include ";
289 294 if (inc.type == Include::IncludePath)
290 295 stream << "<";
291 296 else
292 297 stream << "\"";
293 298 stream << inc.name;
294 299 if (inc.type == Include::IncludePath)
295 300 stream << ">";
296 301 else
297 302 stream << "\"";
298 303 stream << endl;
299 304 }
300 305
301 306 /*!
302 307 Returns true if the given function \a fun is operator>>() or
303 308 operator<<() that streams from/to a Q{Data,Text}Stream, false
304 309 otherwise.
305 310 */
306 311 bool ShellGenerator::isSpecialStreamingOperator(const AbstractMetaFunction *fun)
307 312 {
308 313 return ((fun->functionType() == AbstractMetaFunction::GlobalScopeFunction)
309 314 && (fun->arguments().size() == 1)
310 315 && (((fun->originalName() == "operator>>") && (fun->modifiedName() == "readFrom"))
311 316 || ((fun->originalName() == "operator<<") && (fun->modifiedName() == "writeTo"))));
312 317 }
313 318
314 319 bool ShellGenerator::isBuiltIn(const QString& name) {
315 320
316 321 static QSet<QString> builtIn;
317 322 if (builtIn.isEmpty()) {
318 323 builtIn.insert("Qt");
319 324 builtIn.insert("QFont");
320 325 builtIn.insert("QPixmap");
321 326 builtIn.insert("QBrush");
322 327 builtIn.insert("QPalette");
323 328 builtIn.insert("QIcon");
324 329 builtIn.insert("QImage");
325 330 builtIn.insert("QPolygon");
326 331 builtIn.insert("QRegion");
327 332 builtIn.insert("QBitmap");
328 333 builtIn.insert("QCursor");
329 334 builtIn.insert("QColor");
330 335 builtIn.insert("QSizePolicy");
331 336 builtIn.insert("QKeySequence");
332 337 builtIn.insert("QTextLength");
333 338 builtIn.insert("QTextFormat");
334 339 builtIn.insert("QMatrix");
335 340 builtIn.insert("QDate");
336 341 builtIn.insert("QTime");
337 342 builtIn.insert("QDateTime");
338 343 builtIn.insert("QUrl");
339 344 builtIn.insert("QLocale");
340 345 builtIn.insert("QRect");
341 346 builtIn.insert("QRectF");
342 347 builtIn.insert("QSize");
343 348 builtIn.insert("QSizeF");
344 349 builtIn.insert("QLine");
345 350 builtIn.insert("QLineF");
346 351 builtIn.insert("QPoint");
347 352 builtIn.insert("QPointF");
348 353 builtIn.insert("QRegExp");
349 354 }
350 355 return builtIn.contains(name);
351 356 }
@@ -1,272 +1,275
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
4 4 **
5 5 ** This file is part of the Qt Script Generator project on Trolltech Labs.
6 6 **
7 7 ** This file may be used under the terms of the GNU General Public
8 8 ** License version 2.0 as published by the Free Software Foundation
9 9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 10 ** this file. Please review the following information to ensure GNU
11 11 ** General Public Licensing requirements will be met:
12 12 ** http://www.trolltech.com/products/qt/opensource.html
13 13 **
14 14 ** If you are unsure which license is appropriate for your use, please
15 15 ** review the following information:
16 16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 17 ** sales department at sales@trolltech.com.
18 18 **
19 19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 21 **
22 22 ****************************************************************************/
23 23
24 24 #include "shellheadergenerator.h"
25 25 #include "fileout.h"
26 26
27 27 #include <QtCore/QDir>
28 28
29 29 #include <qdebug.h>
30 30
31 31 QString ShellHeaderGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
32 32 {
33 33 return QString("PythonQtWrapper_%1.h").arg(meta_class->name());
34 34 }
35 35
36 36 void writeQtScriptQtBindingsLicense(QTextStream &stream);
37 37
38 38 void ShellHeaderGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
39 39 {
40 40
41 41 setupGenerator->addClass(meta_class);
42 42
43 43 if (FileOut::license)
44 44 writeQtScriptQtBindingsLicense(s);
45 45
46 46 QString include_block = "PYTHONQTWRAPPER_" + meta_class->name().toUpper() + "_H";
47 47
48 48 s << "#ifndef " << include_block << endl
49 49 << "#define " << include_block << endl << endl;
50 50
51 51 Include inc = meta_class->typeEntry()->include();
52 52 ShellGenerator::writeInclude(s, inc);
53 53
54 54 s << "#include <QObject>" << endl << endl;
55 55 s << "#include <PythonQt.h>" << endl << endl;
56 56
57 57 IncludeList list = meta_class->typeEntry()->extraIncludes();
58 58 qSort(list.begin(), list.end());
59 59 foreach (const Include &inc, list) {
60 60 ShellGenerator::writeInclude(s, inc);
61 61 }
62 62 s << endl;
63 63
64 64 QString pro_file_name = meta_class->package().replace(".", "_") + "/" + meta_class->package().replace(".", "_") + ".pri";
65 65
66 66 // if (!meta_class->generateShellClass()) {
67 67 // s << "#endif" << endl << endl;
68 68 // priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class));
69 69 // return ;
70 70 // }
71 71
72 72 AbstractMetaFunctionList ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
73 73 | AbstractMetaClass::WasVisible
74 74 | AbstractMetaClass::NotRemovedFromTargetLang);
75 75
76 76 // Shell-------------------------------------------------------------------
77 77 if (meta_class->generateShellClass()) {
78 78
79 79 AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class);
80 80
81 81 s << "class " << shellClassName(meta_class)
82 82 << " : public " << meta_class->qualifiedCppName() << endl << "{" << endl;
83 83 s << "public:" << endl;
84 84 foreach(AbstractMetaFunction* fun, ctors) {
85 85 s << " ";
86 86 writeFunctionSignature(s, fun, 0,"PythonQtShell_",
87 87 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
88 88 s << ":" << meta_class->qualifiedCppName() << "(";
89 89 QString scriptFunctionName = fun->originalName();
90 90 AbstractMetaArgumentList args = fun->arguments();
91 91 for (int i = 0; i < args.size(); ++i) {
92 92 if (i > 0)
93 93 s << ", ";
94 94 s << args.at(i)->argumentName();
95 95 }
96 96 s << "),_wrapper(NULL) {};" << endl;
97 97 }
98 98 s << endl;
99 99
100 100 foreach(AbstractMetaFunction* fun, virtualsForShell) {
101 101 s << "virtual ";
102 102 writeFunctionSignature(s, fun, 0, QString(),
103 103 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
104 104 s << ";" << endl;
105 105 }
106 106 s << endl;
107 107 s << " PythonQtInstanceWrapper* _wrapper; " << endl;
108 108
109 109 s << "};" << endl << endl;
110 110 }
111 111
112 112 // Promoter-------------------------------------------------------------------
113 113 AbstractMetaFunctionList promoteFunctions = getProtectedFunctionsThatNeedPromotion(meta_class);
114 114 if (!promoteFunctions.isEmpty()) {
115 115 s << "class " << promoterClassName(meta_class)
116 116 << " : public " << meta_class->qualifiedCppName() << endl << "{ public:" << endl;
117 117
118 118 foreach(AbstractMetaFunction* fun, promoteFunctions) {
119 119 s << "inline ";
120 120 writeFunctionSignature(s, fun, 0, "promoted_",
121 121 Option(IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
122 122 s << " { ";
123 123 QString scriptFunctionName = fun->originalName();
124 124 AbstractMetaArgumentList args = fun->arguments();
125 125 if (fun->type())
126 126 s << "return ";
127 127 s << meta_class->qualifiedCppName() << "::";
128 128 s << fun->originalName() << "(";
129 129 for (int i = 0; i < args.size(); ++i) {
130 130 if (i > 0)
131 131 s << ", ";
132 132 s << args.at(i)->argumentName();
133 133 }
134 134 s << "); }" << endl;
135 135 }
136 136
137 137 s << "};" << endl << endl;
138 138 }
139 139
140 140 // Wrapper-------------------------------------------------------------------
141 141
142 142 s << "class " << wrapperClassName(meta_class)
143 143 << " : public QObject" << endl
144 144 << "{ Q_OBJECT" << endl;
145 145
146 146 s << "public:" << endl;
147 147
148 148 AbstractMetaEnumList enums1 = meta_class->enums();
149 149 AbstractMetaEnumList enums;
150 150 QList<FlagsTypeEntry*> flags;
151 151 foreach(AbstractMetaEnum* enum1, enums1) {
152 152 // catch gadgets and enums that are not exported on QObjects...
153 153 if (enum1->wasPublic() && (!meta_class->isQObject() || !enum1->hasQEnumsDeclaration())) {
154 154 enums << enum1;
155 155 if (enum1->typeEntry()->flags()) {
156 156 flags << enum1->typeEntry()->flags();
157 157 }
158 158 }
159 159 }
160 160 if (enums.count()) {
161 161 s << "Q_ENUMS(";
162 162 foreach(AbstractMetaEnum* enum1, enums) {
163 163 s << enum1->name() << " ";
164 164 }
165 165 s << ")" << endl;
166 166
167 167 if (flags.count()) {
168 168 s << "Q_FLAGS(";
169 169 foreach(FlagsTypeEntry* flag1, flags) {
170 170 QString origName = flag1->originalName();
171 171 int idx = origName.lastIndexOf("::");
172 172 if (idx!= -1) {
173 173 origName = origName.mid(idx+2);
174 174 }
175 175 s << origName << " ";
176 176 }
177 177 s << ")" << endl;
178 178 }
179 179
180 180 foreach(AbstractMetaEnum* enum1, enums) {
181 181 s << "enum " << enum1->name() << "{" << endl;
182 182 bool first = true;
183 183 foreach(AbstractMetaEnumValue* value, enum1->values()) {
184 184 if (first) { first = false; }
185 185 else { s << ", "; }
186 186 s << " " << value->name() << " = " << meta_class->qualifiedCppName() << "::" << value->name();
187 187 }
188 188 s << "};" << endl;
189 189 }
190 190 if (flags.count()) {
191 191 foreach(AbstractMetaEnum* enum1, enums) {
192 192 if (enum1->typeEntry()->flags()) {
193 193 QString origName = enum1->typeEntry()->flags()->originalName();
194 194 int idx = origName.lastIndexOf("::");
195 195 if (idx!= -1) {
196 196 origName = origName.mid(idx+2);
197 197 }
198 198 s << "Q_DECLARE_FLAGS("<< origName << ", " << enum1->name() <<")"<<endl;
199 199 }
200 200 }
201 201 }
202 202 }
203 203 s << "public slots:" << endl;
204 204 if (meta_class->generateShellClass() || !meta_class->isAbstract()) {
205 205
206 206 bool copyConstructorSeen = false;
207 207 bool defaultConstructorSeen = false;
208 208 foreach (const AbstractMetaFunction *fun, ctors) {
209 209 if (!fun->isPublic() || fun->isAbstract()) { continue; }
210 210 s << meta_class->qualifiedCppName() << "* ";
211 211 writeFunctionSignature(s, fun, 0, "new_",
212 212 Option(IncludeDefaultExpression | OriginalName | ShowStatic));
213 213 s << ";" << endl;
214 214 if (fun->arguments().size()==1 && meta_class->qualifiedCppName() == fun->arguments().at(0)->type()->typeEntry()->qualifiedCppName()) {
215 215 copyConstructorSeen = true;
216 216 }
217 217 if (fun->arguments().size()==0) {
218 218 defaultConstructorSeen = true;
219 219 }
220 220 }
221 221
222 222 if (meta_class->typeEntry()->isValue()
223 223 && !copyConstructorSeen && defaultConstructorSeen) {
224 224 QString className = meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName();
225 225 s << meta_class->qualifiedCppName() << "* new_" << meta_class->name() << "(const " << meta_class->qualifiedCppName() << "& other) {" << endl;
226 226 s << className << "* a = new " << className << "();" << endl;
227 227 s << "*((" << meta_class->qualifiedCppName() << "*)a) = other;" << endl;
228 228 s << "return a; }" << endl;
229 229 }
230 230 }
231 231 if (meta_class->hasPublicDestructor() && !meta_class->isNamespace()) {
232 232 s << "void delete_" << meta_class->name() << "(" << meta_class->qualifiedCppName() << "* obj) { delete obj; } ";
233 233 s << endl;
234 234 }
235 235 if (meta_class->name()=="QTreeWidgetItem") {
236 236 s << "bool hasOwner(QTreeWidgetItem* theWrappedObject) { return theWrappedObject->treeWidget()!=NULL || theWrappedObject->parent()!=NULL; }" << endl;
237 237 } else if (meta_class->name()=="QGraphicsItem") {
238 238 s << "bool hasOwner(QGraphicsItem* theWrappedObject) { return theWrappedObject->scene()!=NULL || theWrappedObject->parentItem()!=NULL; }" << endl;
239 239 }
240 240
241 241 AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class);
242 242
243 243 foreach (const AbstractMetaFunction *function, functions) {
244 244 if (!function->isSlot()) {
245 245 s << " ";
246 246 writeFunctionSignature(s, function, 0, QString(),
247 Option(FirstArgIsWrappedObject| IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
247 Option(ConvertReferenceToPtr | FirstArgIsWrappedObject| IncludeDefaultExpression | OriginalName | ShowStatic | UnderscoreSpaces));
248 248 s << ";" << endl;
249 249 }
250 250 }
251 if (!meta_class->hasDefaultToStringFunction() && meta_class->hasToStringCapability()) {
252 s << " QString toString(" << meta_class->qualifiedCppName() << "*);" << endl;
253 }
251 254
252 255 // writeInjectedCode(s, meta_class);
253 256
254 257 // s << endl << " QScriptValue __qtscript_self;" << endl;
255 258
256 259 s << "};" << endl << endl
257 260 << "#endif // " << include_block << endl;
258 261
259 262 if (!ShellGenerator::isBuiltIn(meta_class->name())) {
260 263 priGenerator->addHeader(pro_file_name, fileNameForClass(meta_class));
261 264 }
262 265 }
263 266
264 267 void ShellHeaderGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class)
265 268 {
266 269 CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
267 270 foreach (const CodeSnip &cs, code_snips) {
268 271 if (cs.language == TypeSystem::ShellDeclaration) {
269 272 s << cs.code() << endl;
270 273 }
271 274 }
272 275 }
@@ -1,276 +1,295
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
4 4 **
5 5 ** This file is part of the Qt Script Generator project on Trolltech Labs.
6 6 **
7 7 ** This file may be used under the terms of the GNU General Public
8 8 ** License version 2.0 as published by the Free Software Foundation
9 9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 10 ** this file. Please review the following information to ensure GNU
11 11 ** General Public Licensing requirements will be met:
12 12 ** http://www.trolltech.com/products/qt/opensource.html
13 13 **
14 14 ** If you are unsure which license is appropriate for your use, please
15 15 ** review the following information:
16 16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 17 ** sales department at sales@trolltech.com.
18 18 **
19 19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 21 **
22 22 ****************************************************************************/
23 23
24 24 #include "shellimplgenerator.h"
25 25 #include "reporthandler.h"
26 26 #include "fileout.h"
27 27
28 28 extern void declareFunctionMetaTypes(QTextStream &stream,
29 29 const AbstractMetaFunctionList &functions,
30 30 QSet<QString> &registeredTypeNames);
31 31
32 32 QString ShellImplGenerator::fileNameForClass(const AbstractMetaClass *meta_class) const
33 33 {
34 34 return QString("PythonQtWrapper_%1.cpp").arg(meta_class->name());
35 35 }
36 36
37 37 static bool include_less_than(const Include &a, const Include &b)
38 38 {
39 39 return a.name < b.name;
40 40 }
41 41
42 42 static void writeHelperCode(QTextStream &s, const AbstractMetaClass *)
43 43 {
44 44 }
45 45
46 46 void writeQtScriptQtBindingsLicense(QTextStream &stream);
47 47
48 48 void ShellImplGenerator::write(QTextStream &s, const AbstractMetaClass *meta_class)
49 49 {
50 50 if (FileOut::license)
51 51 writeQtScriptQtBindingsLicense(s);
52 52
53 53 QString pro_file_name = meta_class->package().replace(".", "_") + "/" + meta_class->package().replace(".", "_") + ".pri";
54 54
55 55 if (!ShellGenerator::isBuiltIn(meta_class->name())) {
56 56 priGenerator->addSource(pro_file_name, fileNameForClass(meta_class));
57 57 }
58 58
59 59 s << "#include \"PythonQtWrapper_" << meta_class->name() << ".h\"" << endl << endl;
60 60
61 61 s << "#include <PythonQtSignalReceiver.h>" << endl;
62 62 s << "#include <PythonQtMethodInfo.h>" << endl;
63 63 s << "#include <PythonQtConversion.h>" << endl;
64 64
65 65 //if (!meta_class->generateShellClass())
66 66 // return;
67 67
68 68 IncludeList list = meta_class->typeEntry()->extraIncludes();
69 69 qSort(list.begin(), list.end());
70 70 foreach (const Include &inc, list) {
71 71 ShellGenerator::writeInclude(s, inc);
72 72 }
73 73 s << endl;
74 74
75 75 writeHelperCode(s, meta_class);
76 76
77 77 // find constructors
78 78 AbstractMetaFunctionList ctors;
79 79 ctors = meta_class->queryFunctions(AbstractMetaClass::Constructors
80 80 | AbstractMetaClass::WasVisible
81 81 | AbstractMetaClass::NotRemovedFromTargetLang);
82 82 // find member functions
83 83 AbstractMetaFunctionList functions = getFunctionsToWrap(meta_class);
84 84
85 85 // write metatype declarations
86 86 {
87 87 // QSet<QString> registeredTypeNames = m_qmetatype_declared_typenames;
88 88 // declareFunctionMetaTypes(s, functions, registeredTypeNames);
89 89 // s << endl;
90 90 }
91 91
92 92 if (meta_class->generateShellClass()) {
93 93 AbstractMetaFunctionList virtualsForShell = getVirtualFunctionsForShell(meta_class);
94 94 foreach (const AbstractMetaFunction *fun, virtualsForShell) {
95 95 bool hasReturnValue = (fun->type());
96 96 writeFunctionSignature(s, fun, meta_class, QString(),
97 97 Option(OriginalName | ShowStatic | UnderscoreSpaces),
98 98 "PythonQtShell_");
99 99 s << endl << "{" << endl;
100 100
101 101 Option typeOptions = Option(OriginalName | UnderscoreSpaces | SkipName);
102 102 AbstractMetaArgumentList args = fun->arguments();
103 103
104 104 s << "if (_wrapper) {" << endl;
105 105 s << " PyObject* obj = PyObject_GetAttrString((PyObject*)_wrapper, \"" << fun->name() << "\");" << endl;
106 106 s << " PyErr_Clear();" << endl;
107 107 s << " if (obj && !PythonQtSlotFunction_Check(obj)) {" << endl;
108 108 s << " static const char* argumentList[] ={\"";
109 109 if (hasReturnValue) {
110 110 // write the arguments, return type first
111 111 writeTypeInfo(s, fun->type(), typeOptions);
112 112 }
113 113 s << "\"";
114 114 for (int i = 0; i < args.size(); ++i) {
115 115 s << " , \"";
116 116 writeTypeInfo(s, args.at(i)->type(), typeOptions);
117 117 s << "\"";
118 118 }
119 119 s << "};" << endl;
120 120 s << " static const PythonQtMethodInfo* methodInfo = PythonQtMethodInfo::getCachedMethodInfoFromArgumentList(" << QString::number(args.size()+1) << ", argumentList);" << endl;
121 121
122 122 if (hasReturnValue) {
123 123 s << " ";
124 124 writeTypeInfo(s, fun->type(), typeOptions);
125 125 s << " returnValue;" << endl;
126 126 // TODO: POD init to default is missing...
127 127 }
128 128 s << " void* args[" << QString::number(args.size()+1) << "] = {NULL";
129 129 for (int i = 0; i < args.size(); ++i) {
130 130 s << ", (void*)&" << args.at(i)->argumentName();
131 131 }
132 132 s << "};" << endl;
133 133
134 134 s << " PyObject* result = PythonQtSignalTarget::call(obj, methodInfo, args, true);" << endl;
135 135 if (hasReturnValue) {
136 136 s << " if (result) {" << endl;
137 137 s << " args[0] = PythonQtConv::ConvertPythonToQt(methodInfo->parameters().at(0), result, false, NULL, &returnValue);" << endl;
138 138 s << " if (args[0]!=&returnValue) {" << endl;
139 139 s << " if (args[0]==NULL) {" << endl;
140 140 s << " PythonQt::priv()->handleVirtualOverloadReturnError(\"" << fun->name() << "\", methodInfo, result);" << endl;
141 141 s << " } else {" << endl;
142 142 s << " returnValue = *((";
143 143 writeTypeInfo(s, fun->type(), typeOptions);
144 144 s << "*)args[0]);" << endl;
145 145 s << " }" << endl;
146 146 s << " }" << endl;
147 147 s << " }" << endl;
148 148 }
149 149 s << " if (result) { Py_DECREF(result); } " << endl;
150 150 s << " Py_DECREF(obj);" << endl;
151 151 if (hasReturnValue) {
152 152 s << " return returnValue;" << endl;
153 153 } else {
154 154 s << " return;" << endl;
155 155 }
156 156 s << " }" << endl;
157 157 s << "}" << endl;
158 158
159 159 s << " ";
160 160 if (fun->isAbstract()) {
161 161 if (fun->type()) {
162 162 // return empty default object
163 163 writeTypeInfo(s, fun->type(), typeOptions);
164 164 s << " result;" << endl;
165 165 s << "return result";
166 166 s << ";";
167 167 }
168 168 } else {
169 169 if (fun->type()) {
170 170 s << "return ";
171 171 }
172 // call the C++ implementation
173 172 s << meta_class->qualifiedCppName() << "::";
174 173 s << fun->originalName() << "(";
175 174 for (int i = 0; i < args.size(); ++i) {
176 175 if (i > 0)
177 176 s << ", ";
178 177 s << args.at(i)->argumentName();
179 178 }
180 179 s << ");";
181 180 }
182 181 s << endl << "}" << endl;
183 182 }
184 183 }
185 184
186 185 if (meta_class->generateShellClass() || !meta_class->isAbstract()) {
187 186
188 187 // write constructors
189 188 foreach (const AbstractMetaFunction *ctor, ctors) {
190 189 if (!ctor->isPublic() || ctor->isAbstract()) { continue; }
191 190
192 191 s << meta_class->qualifiedCppName() << "* ";
193 192 s << "PythonQtWrapper_" << meta_class->name() << "::";
194 193 writeFunctionSignature(s, ctor, 0, "new_", Option(OriginalName | ShowStatic));
195 194 s << endl;
196 195 s << "{ " << endl;
197 196 s << "return new " << (meta_class->generateShellClass()?shellClassName(meta_class):meta_class->qualifiedCppName()) << "(";
198 197 AbstractMetaArgumentList args = ctor->arguments();
199 198 for (int i = 0; i < args.size(); ++i) {
200 199 if (i > 0)
201 200 s << ", ";
202 201 s << args.at(i)->argumentName();
203 202 }
204 203 s << ");" << " }" << endl << endl;
205 204 }
206 205 }
207 206
208 207 QString wrappedObject = " (*theWrappedObject)";
209 208
210 209 // write member functions
211 210 for (int i = 0; i < functions.size(); ++i) {
212 211 AbstractMetaFunction *fun = functions.at(i);
213 212 if (fun->isSlot()) continue;
214 213
215 214 writeFunctionSignature(s, fun, meta_class, QString(),
216 Option(FirstArgIsWrappedObject | OriginalName | ShowStatic | UnderscoreSpaces),
215 Option(ConvertReferenceToPtr | FirstArgIsWrappedObject | OriginalName | ShowStatic | UnderscoreSpaces),
217 216 "PythonQtWrapper_");
218 217 s << endl << "{" << endl;
219 218 s << " ";
220 219 if (ShellGenerator::isSpecialStreamingOperator(fun)) {
221 220 s << fun->arguments().at(0)->argumentName();
222 221 if (fun->originalName().startsWith("operator>>")) {
223 222 s << " >> ";
224 223 } else {
225 224 s << " << ";
226 225 }
227 226 s << wrappedObject;
228 227 } else {
229 228 QString scriptFunctionName = fun->originalName();
230 229 AbstractMetaArgumentList args = fun->arguments();
231 230 // call the C++ implementation
232 if (fun->type())
231 if (fun->type()) {
233 232 s << "return ";
233 // call the C++ implementation
234 if (fun->type()->isReference()) {
235 s << "&";
236 }
237 }
238 s << "(";
234 239 if (scriptFunctionName.startsWith("operator>>")) {
235 240 s << wrappedObject << " >>" << args.at(0)->argumentName();
236 241 } else if (scriptFunctionName.startsWith("operator<<")) {
237 242 s << wrappedObject << " <<" << args.at(0)->argumentName();
238 243 } else if (scriptFunctionName.startsWith("operator[]")) {
239 244 s << wrappedObject << "[" << args.at(0)->argumentName() << "]";
240 245 } else if (scriptFunctionName.startsWith("operator") && args.size()==1) {
241 246 QString op = scriptFunctionName.mid(8);
242 247 s << wrappedObject << op << " " << args.at(0)->argumentName();
243 248 } else {
244 249 if (fun->isStatic()) {
245 250 s << meta_class->qualifiedCppName() << "::";
246 251 } else {
247 252 if (!fun->isPublic() || fun->isVirtual()) {
248 253 s << " ((" << promoterClassName(meta_class) << "*)theWrappedObject)->promoted_";
249 254 } else {
250 255 s << " theWrappedObject->";
251 256 }
252 257 }
253 258 s << fun->originalName() << "(";
254 259 for (int i = 0; i < args.size(); ++i) {
255 260 if (i > 0)
256 261 s << ", ";
257 262 s << args.at(i)->argumentName();
258 263 }
259 264 s << ")";
260 265 }
266 s << ")";
261 267 }
262 268 s << ";" << endl;
263 269
264 270 s << "}" << endl << endl;
265 271 }
272
273 if (!meta_class->hasDefaultToStringFunction() && meta_class->hasToStringCapability()) {
274 FunctionModelItem fun = meta_class->hasToStringCapability();
275 int indirections = fun->arguments().at(1)->type().indirections();
276 QString deref = QLatin1String(indirections == 0 ? "*" : "");
277 s << "QString PythonQtWrapper_" << meta_class->name() << "::toString(" << meta_class->qualifiedCppName() << "* obj) {" << endl;
278 s << " QString result;" << endl;
279 s << " QDebug d(&result);" << endl;
280 s << " d << " << deref << "obj;" << endl;
281 s << " return result;" << endl;
282 s << "}" << endl << endl;
283 }
284
266 285 }
267 286
268 287 void ShellImplGenerator::writeInjectedCode(QTextStream &s, const AbstractMetaClass *meta_class)
269 288 {
270 289 CodeSnipList code_snips = meta_class->typeEntry()->codeSnips();
271 290 foreach (const CodeSnip &cs, code_snips) {
272 291 if (cs.language == TypeSystem::ShellCode) {
273 292 s << cs.code() << endl;
274 293 }
275 294 }
276 295 }
General Comments 0
You need to be logged in to leave comments. Login now