1 /****************************************************************************
3 ** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
5 ** This file is part of the Qt Script Generator project on Trolltech Labs.
7 ** This file may be used under the terms of the GNU General Public
8 ** License version 2.0 as published by the Free Software Foundation
9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 ** this file. Please review the following information to ensure GNU
11 ** General Public Licensing requirements will be met:
12 ** http://www.trolltech.com/products/qt/opensource.html
14 ** If you are unsure which license is appropriate for your use, please
15 ** review the following information:
16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 ** sales department at sales@trolltech.com.
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 ****************************************************************************/
24 #include "abstractmetabuilder.h"
25 #include "reporthandler.h"
30 #include "default_visitor.h"
36 #include <QtCore/QDebug>
37 #include <QtCore/QFile>
38 #include <QtCore/QFileInfo>
39 #include <QtCore/QTextCodec>
40 #include <QtCore/QTextStream>
41 #include <QtCore/QVariant>
43 static QString
strip_template_args(const QString
&name
)
45 int pos
= name
.indexOf('<');
46 return pos
< 0 ? name
: name
.left(pos
);
49 static QHash
<QString
, QString
> *operator_names
;
50 QString
rename_operator(const QString
&oper
)
52 QString op
= oper
.trimmed();
53 if (!operator_names
) {
54 operator_names
= new QHash
<QString
, QString
>;
56 operator_names
->insert("+", "add");
57 operator_names
->insert("-", "subtract");
58 operator_names
->insert("*", "multiply");
59 operator_names
->insert("/", "divide");
60 operator_names
->insert("%", "modulo");
61 operator_names
->insert("&", "and");
62 operator_names
->insert("|", "or");
63 operator_names
->insert("^", "xor");
64 operator_names
->insert("~", "negate");
65 operator_names
->insert("<<", "shift_left");
66 operator_names
->insert(">>", "shift_right");
69 operator_names
->insert("=", "assign");
70 operator_names
->insert("+=", "add_assign");
71 operator_names
->insert("-=", "subtract_assign");
72 operator_names
->insert("*=", "multiply_assign");
73 operator_names
->insert("/=", "divide_assign");
74 operator_names
->insert("%=", "modulo_assign");
75 operator_names
->insert("&=", "and_assign");
76 operator_names
->insert("|=", "or_assign");
77 operator_names
->insert("^=", "xor_assign");
78 operator_names
->insert("<<=", "shift_left_assign");
79 operator_names
->insert(">>=", "shift_right_assign");
82 operator_names
->insert("&&", "logical_and");
83 operator_names
->insert("||", "logical_or");
84 operator_names
->insert("!", "not");
87 operator_names
->insert("++", "increment");
88 operator_names
->insert("--", "decrement");
91 operator_names
->insert("<", "less");
92 operator_names
->insert(">", "greater");
93 operator_names
->insert("<=", "less_or_equal");
94 operator_names
->insert(">=", "greater_or_equal");
95 operator_names
->insert("!=", "not_equal");
96 operator_names
->insert("==", "equal");
99 operator_names
->insert("[]", "subscript");
100 operator_names
->insert("->", "pointer");
103 if (!operator_names
->contains(op
)) {
104 TypeDatabase
*tb
= TypeDatabase::instance();
106 TypeParser::Info typeInfo
= TypeParser::parse(op
);
107 QString cast_to_name
= typeInfo
.qualified_name
.join("::");
108 TypeEntry
*te
= tb
->findType(cast_to_name
);
109 if ((te
&& te
->codeGeneration() == TypeEntry::GenerateNothing
)
110 || tb
->isClassRejected(cast_to_name
)) {
113 return "operator_cast_" + typeInfo
.qualified_name
.join("_");
115 ReportHandler::warning(QString("unknown operator '%1'").arg(op
));
116 return "operator " + op
;
120 return "operator_" + operator_names
->value(op
);
123 AbstractMetaBuilder::AbstractMetaBuilder()
128 void AbstractMetaBuilder::checkFunctionModifications()
130 TypeDatabase
*types
= TypeDatabase::instance();
131 SingleTypeEntryHash entryHash
= types
->entries();
132 QList
<TypeEntry
*> entries
= entryHash
.values();
133 foreach (TypeEntry
*entry
, entries
) {
136 if (!entry
->isComplex() || entry
->codeGeneration() == TypeEntry::GenerateNothing
)
139 ComplexTypeEntry
*centry
= static_cast<ComplexTypeEntry
*>(entry
);
140 FunctionModificationList modifications
= centry
->functionModifications();
142 foreach (FunctionModification modification
, modifications
) {
143 QString signature
= modification
.signature
;
145 QString name
= signature
.trimmed();
146 name
= name
.mid(0, signature
.indexOf("("));
148 AbstractMetaClass
*clazz
= m_meta_classes
.findClass(centry
->qualifiedCppName());
152 AbstractMetaFunctionList functions
= clazz
->functions();
154 QStringList possibleSignatures
;
155 foreach (AbstractMetaFunction
*function
, functions
) {
156 if (function
->minimalSignature() == signature
&& function
->implementingClass() == clazz
) {
161 if (function
->originalName() == name
)
162 possibleSignatures
.append(function
->minimalSignature() + " in " + function
->implementingClass()->name());
167 = QString("signature '%1' for function modification in '%2' not found. Possible candidates: %3")
169 .arg(clazz
->qualifiedCppName())
170 .arg(possibleSignatures
.join(", "));
172 ReportHandler::warning(warning
);
178 AbstractMetaClass
*AbstractMetaBuilder::argumentToClass(ArgumentModelItem argument
)
180 AbstractMetaClass
*returned
= 0;
182 AbstractMetaType
*type
= translateType(argument
->type(), &ok
);
183 if (ok
&& type
!= 0 && type
->typeEntry() != 0 && type
->typeEntry()->isComplex()) {
184 const TypeEntry
*entry
= type
->typeEntry();
185 returned
= m_meta_classes
.findClass(entry
->name());
192 * Checks the argument of a hash function and flags the type if it is a complex type
194 void AbstractMetaBuilder::registerHashFunction(FunctionModelItem function_item
)
196 ArgumentList arguments
= function_item
->arguments();
197 if (arguments
.size() == 1) {
198 if (AbstractMetaClass
*cls
= argumentToClass(arguments
.at(0)))
199 cls
->setHasHashFunction(true);
204 * Check if a class has a debug stream operator that can be used as toString
207 void AbstractMetaBuilder::registerToStringCapability(FunctionModelItem function_item
)
209 ArgumentList arguments
= function_item
->arguments();
210 if (arguments
.size() == 2) {
211 if (arguments
.at(0)->type().toString() == "QDebug"){
212 ArgumentModelItem arg
= arguments
.at(1);
213 if (AbstractMetaClass
*cls
= argumentToClass(arg
)) {
214 if (arg
->type().indirections() < 2) {
215 cls
->setToStringCapability(function_item
);
222 void AbstractMetaBuilder::traverseCompareOperator(FunctionModelItem item
) {
223 ArgumentList arguments
= item
->arguments();
224 if (arguments
.size() == 2 && item
->accessPolicy() == CodeModel::Public
) {
225 AbstractMetaClass
*comparer_class
= argumentToClass(arguments
.at(0));
226 AbstractMetaClass
*compared_class
= argumentToClass(arguments
.at(1));
227 if (comparer_class
!= 0 && compared_class
!= 0) {
228 AbstractMetaClass
*old_current_class
= m_current_class
;
229 m_current_class
= comparer_class
;
231 AbstractMetaFunction
*meta_function
= traverseFunction(item
);
232 if (meta_function
!= 0 && !meta_function
->isInvalid()) {
233 // Strip away first argument, since that is the containing object
234 AbstractMetaArgumentList arguments
= meta_function
->arguments();
235 arguments
.pop_front();
236 meta_function
->setArguments(arguments
);
238 meta_function
->setFunctionType(AbstractMetaFunction::GlobalScopeFunction
);
240 meta_function
->setOriginalAttributes(meta_function
->attributes());
241 setupFunctionDefaults(meta_function
, comparer_class
);
243 comparer_class
->addFunction(meta_function
);
244 } else if (meta_function
!= 0) {
245 delete meta_function
;
248 m_current_class
= old_current_class
;
253 void AbstractMetaBuilder::traverseStreamOperator(FunctionModelItem item
)
255 ArgumentList arguments
= item
->arguments();
256 if (arguments
.size() == 2 && item
->accessPolicy() == CodeModel::Public
) {
257 AbstractMetaClass
*streamClass
= argumentToClass(arguments
.at(0));
258 AbstractMetaClass
*streamedClass
= argumentToClass(arguments
.at(1));
260 if (streamClass
!= 0 && streamedClass
!= 0
261 && (streamClass
->name() == "QDataStream" || streamClass
->name() == "QTextStream")) {
262 AbstractMetaClass
*old_current_class
= m_current_class
;
263 m_current_class
= streamedClass
;
264 AbstractMetaFunction
*streamFunction
= traverseFunction(item
);
266 if (streamFunction
!= 0 && !streamFunction
->isInvalid()) {
267 QString name
= item
->name();
268 streamFunction
->setFunctionType(AbstractMetaFunction::GlobalScopeFunction
);
270 if (name
.endsWith("<<"))
271 streamFunction
->setName("writeTo");
273 streamFunction
->setName("readFrom");
275 // Strip away last argument, since that is the containing object
276 AbstractMetaArgumentList arguments
= streamFunction
->arguments();
277 arguments
.pop_back();
278 streamFunction
->setArguments(arguments
);
280 *streamFunction
+= AbstractMetaAttributes::Final
;
281 *streamFunction
+= AbstractMetaAttributes::Public
;
282 streamFunction
->setOriginalAttributes(streamFunction
->attributes());
284 streamFunction
->setType(0);
286 setupFunctionDefaults(streamFunction
, streamedClass
);
288 streamedClass
->addFunction(streamFunction
);
289 streamedClass
->typeEntry()->addExtraInclude(streamClass
->typeEntry()->include());
291 m_current_class
= old_current_class
;
297 void AbstractMetaBuilder::fixQObjectForScope(TypeDatabase
*types
,
298 NamespaceModelItem scope
)
300 foreach (ClassModelItem item
, scope
->classes()) {
301 QString qualified_name
= item
->qualifiedName().join("::");
302 TypeEntry
*entry
= types
->findType(qualified_name
);
304 if (isQObject(qualified_name
) && entry
->isComplex()) {
305 ((ComplexTypeEntry
*) entry
)->setQObject(true);
310 foreach (NamespaceModelItem item
, scope
->namespaceMap().values()) {
312 fixQObjectForScope(types
, item
);
316 static bool class_less_than(AbstractMetaClass
*a
, AbstractMetaClass
*b
)
318 return a
->name() < b
->name();
322 void AbstractMetaBuilder::sortLists()
324 qSort(m_meta_classes
.begin(), m_meta_classes
.end(), class_less_than
);
325 foreach (AbstractMetaClass
*cls
, m_meta_classes
) {
326 cls
->sortFunctions();
330 bool AbstractMetaBuilder::build()
332 Q_ASSERT(!m_file_name
.isEmpty());
334 QFile
file(m_file_name
);
336 if (!file
.open(QFile::ReadOnly
))
339 QTextStream
stream(&file
);
340 stream
.setCodec(QTextCodec::codecForName("UTF-8"));
341 QByteArray contents
= stream
.readAll().toUtf8();
348 TranslationUnitAST
*ast
= p
.parse(contents
, contents
.size(), &__pool
);
351 Binder
binder(&model
, p
.location());
352 m_dom
= binder
.run(ast
);
354 pushScope(model_dynamic_cast
<ScopeModelItem
>(m_dom
));
356 QHash
<QString
, ClassModelItem
> typeMap
= m_dom
->classMap();
359 // fix up QObject's in the type system..
360 TypeDatabase
*types
= TypeDatabase::instance();
361 fixQObjectForScope(types
, model_dynamic_cast
<NamespaceModelItem
>(m_dom
));
364 // Start the generation...
365 foreach (ClassModelItem item
, typeMap
.values()) {
366 AbstractMetaClass
*cls
= traverseClass(item
);
367 addAbstractMetaClass(cls
);
371 QHash
<QString
, NamespaceModelItem
> namespaceMap
= m_dom
->namespaceMap();
372 foreach (NamespaceModelItem item
, namespaceMap
.values()) {
373 AbstractMetaClass
*meta_class
= traverseNamespace(item
);
375 m_meta_classes
<< meta_class
;
379 // Some trickery to support global-namespace enums...
380 QHash
<QString
, EnumModelItem
> enumMap
= m_dom
->enumMap();
382 foreach (EnumModelItem item
, enumMap
) {
383 AbstractMetaEnum
*meta_enum
= traverseEnum(item
, 0, QSet
<QString
>());
386 QString package
= meta_enum
->typeEntry()->javaPackage();
387 QString globalName
= TypeDatabase::globalNamespaceClassName(meta_enum
->typeEntry());
389 AbstractMetaClass
*global
= m_meta_classes
.findClass(package
+ "." + globalName
);
391 ComplexTypeEntry
*gte
= new ObjectTypeEntry(globalName
);
392 gte
->setTargetLangPackage(meta_enum
->typeEntry()->javaPackage());
393 gte
->setCodeGeneration(meta_enum
->typeEntry()->codeGeneration());
394 global
= createMetaClass();
395 global
->setTypeEntry(gte
);
396 *global
+= AbstractMetaAttributes::Final
;
397 *global
+= AbstractMetaAttributes::Public
;
398 *global
+= AbstractMetaAttributes::Fake
;
400 m_meta_classes
<< global
;
403 global
->addEnum(meta_enum
);
404 meta_enum
->setEnclosingClass(global
);
405 meta_enum
->typeEntry()->setQualifier(globalName
);
412 // Go through all typedefs to see if we have defined any
413 // specific typedefs to be used as classes.
414 TypeAliasList typeAliases
= m_dom
->typeAliases();
415 foreach (TypeAliasModelItem typeAlias
, typeAliases
) {
416 AbstractMetaClass
*cls
= traverseTypeAlias(typeAlias
);
417 addAbstractMetaClass(cls
);
423 foreach (AbstractMetaClass
*cls
, m_meta_classes
) {
424 if (!cls
->isInterface() && !cls
->isNamespace()) {
425 setupInheritance(cls
);
430 foreach (AbstractMetaClass
*cls
, m_meta_classes
) {
433 if (cls
->typeEntry() == 0) {
434 ReportHandler::warning(QString("class '%1' does not have an entry in the type system")
437 if (!cls
->hasConstructors() && !cls
->isFinalInCpp() && !cls
->isInterface() && !cls
->isNamespace())
438 cls
->addDefaultConstructor();
441 if (cls
->isAbstract() && !cls
->isInterface()) {
442 cls
->typeEntry()->setLookupName(cls
->typeEntry()->targetLangName() + "$ConcreteWrapper");
446 QList
<TypeEntry
*> entries
= TypeDatabase::instance()->entries().values();
447 foreach (const TypeEntry
*entry
, entries
) {
448 if (entry
->isPrimitive())
451 if ((entry
->isValue() || entry
->isObject())
452 && !entry
->isString()
454 && !entry
->isContainer()
455 && !entry
->isCustom()
456 && !entry
->isVariant()
457 && !m_meta_classes
.findClass(entry
->qualifiedCppName())) {
458 ReportHandler::warning(QString("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.")
459 .arg(entry
->qualifiedCppName()));
462 if (entry
->isEnum()) {
463 QString pkg
= entry
->javaPackage();
464 QString name
= (pkg
.isEmpty() ? QString() : pkg
+ ".")
465 + ((EnumTypeEntry
*) entry
)->javaQualifier();
466 AbstractMetaClass
*cls
= m_meta_classes
.findClass(name
);
469 ReportHandler::warning(QString("namespace '%1' for enum '%2' is not declared")
470 .arg(name
).arg(entry
->targetLangName()));
472 AbstractMetaEnum
*e
= cls
->findEnum(entry
->targetLangName());
474 ReportHandler::warning(QString("enum '%1' is specified in typesystem, "
476 .arg(entry
->qualifiedCppName()));
482 FunctionList hash_functions
= m_dom
->findFunctions("qHash");
483 foreach (FunctionModelItem item
, hash_functions
) {
484 registerHashFunction(item
);
489 FunctionList hash_functions
= m_dom
->findFunctions("operator<<");
490 foreach (FunctionModelItem item
, hash_functions
) {
491 registerToStringCapability(item
);
496 FunctionList compare_operators
= m_dom
->findFunctions("operator==")
497 + m_dom
->findFunctions("operator<=")
498 + m_dom
->findFunctions("operator>=")
499 + m_dom
->findFunctions("operator<")
500 + m_dom
->findFunctions("operator>");
501 foreach (FunctionModelItem item
, compare_operators
) {
502 traverseCompareOperator(item
);
507 FunctionList stream_operators
= m_dom
->findFunctions("operator<<") + m_dom
->findFunctions("operator>>");
508 foreach (FunctionModelItem item
, stream_operators
) {
509 traverseStreamOperator(item
);
513 figureOutEnumValues();
514 figureOutDefaultEnumArguments();
515 checkFunctionModifications();
517 foreach (AbstractMetaClass
*cls
, m_meta_classes
) {
519 setupComparable(cls
);
531 void AbstractMetaBuilder::addAbstractMetaClass(AbstractMetaClass
*cls
)
536 cls
->setOriginalAttributes(cls
->attributes());
537 if (cls
->typeEntry()->isContainer()) {
540 m_meta_classes
<< cls
;
541 if (cls
->typeEntry()->designatedInterface()) {
542 AbstractMetaClass
*interface
= cls
->extractInterface();
543 m_meta_classes
<< interface
;
544 ReportHandler::debugSparse(QString(" -> interface '%1'").arg(interface
->name()));
550 AbstractMetaClass
*AbstractMetaBuilder::traverseNamespace(NamespaceModelItem namespace_item
)
552 QString namespace_name
= (!m_namespace_prefix
.isEmpty() ? m_namespace_prefix
+ "::" : QString()) + namespace_item
->name();
553 NamespaceTypeEntry
*type
= TypeDatabase::instance()->findNamespaceType(namespace_name
);
555 if (TypeDatabase::instance()->isClassRejected(namespace_name
)) {
556 m_rejected_classes
.insert(namespace_name
, GenerationDisabled
);
561 ReportHandler::warning(QString("namespace '%1' does not have a type entry")
562 .arg(namespace_name
));
566 AbstractMetaClass
*meta_class
= createMetaClass();
567 meta_class
->setTypeEntry(type
);
569 *meta_class
+= AbstractMetaAttributes::Public
;
571 m_current_class
= meta_class
;
573 ReportHandler::debugSparse(QString("namespace '%1.%2'")
574 .arg(meta_class
->package())
575 .arg(namespace_item
->name()));
577 traverseEnums(model_dynamic_cast
<ScopeModelItem
>(namespace_item
), meta_class
, namespace_item
->enumsDeclarations());
578 traverseFunctions(model_dynamic_cast
<ScopeModelItem
>(namespace_item
), meta_class
);
579 // traverseClasses(model_dynamic_cast<ScopeModelItem>(namespace_item));
581 pushScope(model_dynamic_cast
<ScopeModelItem
>(namespace_item
));
582 m_namespace_prefix
= currentScope()->qualifiedName().join("::");
585 ClassList classes
= namespace_item
->classes();
586 foreach (ClassModelItem cls
, classes
) {
587 AbstractMetaClass
*mjc
= traverseClass(cls
);
588 addAbstractMetaClass(mjc
);
591 // Go through all typedefs to see if we have defined any
592 // specific typedefs to be used as classes.
593 TypeAliasList typeAliases
= namespace_item
->typeAliases();
594 foreach (TypeAliasModelItem typeAlias
, typeAliases
) {
595 AbstractMetaClass
*cls
= traverseTypeAlias(typeAlias
);
596 addAbstractMetaClass(cls
);
601 // Traverse namespaces recursively
602 QList
<NamespaceModelItem
> inner_namespaces
= namespace_item
->namespaceMap().values();
603 foreach (const NamespaceModelItem
&ni
, inner_namespaces
) {
604 AbstractMetaClass
*mjc
= traverseNamespace(ni
);
605 addAbstractMetaClass(mjc
);
612 m_namespace_prefix
= currentScope()->qualifiedName().join("::");
614 if (!type
->include().isValid()) {
615 QFileInfo
info(namespace_item
->fileName());
616 type
->setInclude(Include(Include::IncludePath
, info
.fileName()));
624 enum Type
{ Plus
, ShiftLeft
, None
};
626 Operator() : type(None
) { }
628 int calculate(int x
) {
630 case Plus
: return x
+ value
;
631 case ShiftLeft
: return x
<< value
;
643 Operator
findOperator(QString
*s
) {
644 const char *names
[] = {
649 for (int i
=0; i
<Operator::None
; ++i
) {
650 QString name
= QLatin1String(names
[i
]);
652 int splitPoint
= str
.indexOf(name
);
653 if (splitPoint
> 0) {
655 QString right
= str
.mid(splitPoint
+ name
.length());
657 op
.value
= right
.toInt(&ok
);
659 op
.type
= Operator::Type(i
);
660 *s
= str
.left(splitPoint
).trimmed();
668 int AbstractMetaBuilder::figureOutEnumValue(const QString
&stringValue
,
670 AbstractMetaEnum
*meta_enum
,
671 AbstractMetaFunction
*meta_function
)
673 if (stringValue
.isEmpty())
674 return oldValuevalue
;
676 QStringList stringValues
= stringValue
.split("|");
680 bool matched
= false;
682 for (int i
=0; i
<stringValues
.size(); ++i
) {
683 QString s
= stringValues
.at(i
).trimmed();
688 Operator op
= findOperator(&s
);
690 if (s
.length() > 0 && s
.at(0) == QLatin1Char('0'))
691 v
= s
.toUInt(&ok
, 0);
698 } else if (m_enum_values
.contains(s
)) {
699 v
= m_enum_values
[s
]->value();
703 AbstractMetaEnumValue
*ev
= 0;
705 if (meta_enum
&& (ev
= meta_enum
->values().find(s
))) {
709 } else if (meta_enum
&& (ev
= meta_enum
->enclosingClass()->findEnumValue(s
, meta_enum
))) {
715 ReportHandler::warning("unhandled enum value: " + s
+ " in "
716 + meta_enum
->enclosingClass()->name() + "::"
717 + meta_enum
->name());
719 ReportHandler::warning("unhandled enum value: Unknown enum");
724 returnValue
|= op
.calculate(v
);
728 QString warn
= QString("unmatched enum %1").arg(stringValue
);
730 if (meta_function
!= 0) {
731 warn
+= QString(" when parsing default value of '%1' in class '%2'")
732 .arg(meta_function
->name())
733 .arg(meta_function
->implementingClass()->name());
736 ReportHandler::warning(warn
);
737 returnValue
= oldValuevalue
;
743 void AbstractMetaBuilder::figureOutEnumValuesForClass(AbstractMetaClass
*meta_class
,
744 QSet
<AbstractMetaClass
*> *classes
)
746 AbstractMetaClass
*base
= meta_class
->baseClass();
748 if (base
!= 0 && !classes
->contains(base
))
749 figureOutEnumValuesForClass(base
, classes
);
751 if (classes
->contains(meta_class
))
754 AbstractMetaEnumList enums
= meta_class
->enums();
755 foreach (AbstractMetaEnum
*e
, enums
) {
757 ReportHandler::warning("bad enum in class " + meta_class
->name());
760 AbstractMetaEnumValueList lst
= e
->values();
762 for (int i
=0; i
<lst
.size(); ++i
) {
763 value
= figureOutEnumValue(lst
.at(i
)->stringValue(), value
, e
);
764 lst
.at(i
)->setValue(value
);
768 // Check for duplicate values...
769 EnumTypeEntry
*ete
= e
->typeEntry();
770 if (!ete
->forceInteger()) {
771 QHash
<int, AbstractMetaEnumValue
*> entries
;
772 foreach (AbstractMetaEnumValue
*v
, lst
) {
774 bool vRejected
= ete
->isEnumValueRejected(v
->name());
776 AbstractMetaEnumValue
*current
= entries
.value(v
->value());
778 bool currentRejected
= ete
->isEnumValueRejected(current
->name());
779 if (!currentRejected
&& !vRejected
) {
780 ReportHandler::warning(
781 QString("duplicate enum values: %1::%2, %3 and %4 are %5, already rejected: (%6)")
782 .arg(meta_class
->name())
785 .arg(entries
[v
->value()]->name())
787 .arg(ete
->enumValueRejections().join(", ")));
793 entries
[v
->value()] = v
;
796 // Entries now contain all the original entries, no
797 // rejected ones... Use this to generate the enumValueRedirection table.
798 foreach (AbstractMetaEnumValue
*reject
, lst
) {
799 if (!ete
->isEnumValueRejected(reject
->name()))
802 AbstractMetaEnumValue
*used
= entries
.value(reject
->value());
804 ReportHandler::warning(
805 QString::fromLatin1("Rejected enum has no alternative...: %1::%2")
806 .arg(meta_class
->name())
807 .arg(reject
->name()));
810 ete
->addEnumValueRedirection(reject
->name(), used
->name());
818 *classes
+= meta_class
;
822 void AbstractMetaBuilder::figureOutEnumValues()
824 // Keep a set of classes that we already traversed. We use this to
825 // enforce that we traverse base classes prior to subclasses.
826 QSet
<AbstractMetaClass
*> classes
;
827 foreach (AbstractMetaClass
*c
, m_meta_classes
) {
828 figureOutEnumValuesForClass(c
, &classes
);
832 void AbstractMetaBuilder::figureOutDefaultEnumArguments()
834 foreach (AbstractMetaClass
*meta_class
, m_meta_classes
) {
835 foreach (AbstractMetaFunction
*meta_function
, meta_class
->functions()) {
836 foreach (AbstractMetaArgument
*arg
, meta_function
->arguments()) {
838 QString expr
= arg
->defaultValueExpression();
842 if (!meta_function
->replacedDefaultExpression(meta_function
->implementingClass(),
843 arg
->argumentIndex()+1).isEmpty()) {
847 QString new_expr
= expr
;
848 if (arg
->type()->isEnum()) {
849 QStringList lst
= expr
.split(QLatin1String("::"));
850 if (lst
.size() == 1) {
851 QVector
<AbstractMetaClass
*> classes(1, meta_class
);
852 AbstractMetaEnum
*e
= 0;
853 while (!classes
.isEmpty() && e
== 0) {
854 if (classes
.front() != 0) {
855 classes
<< classes
.front()->baseClass();
857 AbstractMetaClassList interfaces
= classes
.front()->interfaces();
858 foreach (AbstractMetaClass
*interface
, interfaces
)
859 classes
<< interface
->primaryInterfaceImplementor();
861 e
= classes
.front()->findEnumForValue(expr
);
868 new_expr
= QString("%1.%2")
869 .arg(e
->typeEntry()->qualifiedTargetLangName())
872 ReportHandler::warning("Cannot find enum constant for value '" + expr
+ "' in '" + meta_class
->name() + "' or any of its super classes");
874 } else if (lst
.size() == 2) {
875 AbstractMetaClass
*cl
= m_meta_classes
.findClass(lst
.at(0));
877 ReportHandler::warning("missing required class for enums: " + lst
.at(0));
880 new_expr
= QString("%1.%2.%3")
881 .arg(cl
->typeEntry()->qualifiedTargetLangName())
882 .arg(arg
->type()->name())
885 ReportHandler::warning("bad default value passed to enum " + expr
);
888 } else if(arg
->type()->isFlags()) {
889 const FlagsTypeEntry
*flagsEntry
=
890 static_cast<const FlagsTypeEntry
*>(arg
->type()->typeEntry());
891 EnumTypeEntry
*enumEntry
= flagsEntry
->originator();
892 AbstractMetaEnum
*meta_enum
= m_meta_classes
.findEnum(enumEntry
);
894 ReportHandler::warning("unknown required enum " + enumEntry
->qualifiedCppName());
898 int value
= figureOutEnumValue(expr
, 0, meta_enum
, meta_function
);
899 new_expr
= QString::number(value
);
901 } else if (arg
->type()->isPrimitive()) {
902 AbstractMetaEnumValue
*value
= 0;
903 if (expr
.contains("::"))
904 value
= m_meta_classes
.findEnumValue(expr
);
906 value
= meta_class
->findEnumValue(expr
, 0);
909 new_expr
= QString::number(value
->value());
910 } else if (expr
.contains(QLatin1Char('+'))) {
911 new_expr
= QString::number(figureOutEnumValue(expr
, 0, 0));
919 arg
->setDefaultValueExpression(new_expr
);
926 AbstractMetaEnum
*AbstractMetaBuilder::traverseEnum(EnumModelItem enum_item
, AbstractMetaClass
*enclosing
, const QSet
<QString
> &enumsDeclarations
)
928 // Skipping private enums.
929 if (enum_item
->accessPolicy() == CodeModel::Private
) {
933 QString qualified_name
= enum_item
->qualifiedName().join("::");
935 TypeEntry
*type_entry
= TypeDatabase::instance()->findType(qualified_name
);
936 QString enum_name
= enum_item
->name();
940 class_name
= m_current_class
->typeEntry()->qualifiedCppName();
942 if (TypeDatabase::instance()->isEnumRejected(class_name
, enum_name
)) {
943 m_rejected_enums
.insert(qualified_name
, GenerationDisabled
);
947 if (!type_entry
|| !type_entry
->isEnum()) {
948 QString context
= m_current_class
? m_current_class
->name() : QLatin1String("");
949 ReportHandler::warning(QString("enum '%1' does not have a type entry or is not an enum")
950 .arg(qualified_name
));
951 m_rejected_enums
.insert(qualified_name
, NotInTypeSystem
);
955 AbstractMetaEnum
*meta_enum
= createMetaEnum();
956 if ( enumsDeclarations
.contains(qualified_name
)
957 || enumsDeclarations
.contains(enum_name
)) {
958 meta_enum
->setHasQEnumsDeclaration(true);
961 meta_enum
->setTypeEntry((EnumTypeEntry
*) type_entry
);
962 switch (enum_item
->accessPolicy()) {
963 case CodeModel::Public
: *meta_enum
+= AbstractMetaAttributes::Public
; break;
964 case CodeModel::Protected
: *meta_enum
+= AbstractMetaAttributes::Protected
; break;
965 // case CodeModel::Private: *meta_enum += AbstractMetaAttributes::Private; break;
969 ReportHandler::debugMedium(QString(" - traversing enum %1").arg(meta_enum
->fullName()));
971 foreach (EnumeratorModelItem value
, enum_item
->enumerators()) {
973 AbstractMetaEnumValue
*meta_enum_value
= createMetaEnumValue();
974 meta_enum_value
->setName(value
->name());
975 // Deciding the enum value...
977 meta_enum_value
->setStringValue(value
->value());
978 meta_enum
->addEnumValue(meta_enum_value
);
980 ReportHandler::debugFull(" - " + meta_enum_value
->name() + " = "
981 + meta_enum_value
->value());
983 // Add into global register...
985 m_enum_values
[enclosing
->name() + "::" + meta_enum_value
->name()] = meta_enum_value
;
987 m_enum_values
[meta_enum_value
->name()] = meta_enum_value
;
990 m_enums
<< meta_enum
;
995 AbstractMetaClass
*AbstractMetaBuilder::traverseTypeAlias(TypeAliasModelItem typeAlias
)
997 QString class_name
= strip_template_args(typeAlias
->name());
999 QString full_class_name
= class_name
;
1000 // we have an inner class
1001 if (m_current_class
) {
1002 full_class_name
= strip_template_args(m_current_class
->typeEntry()->qualifiedCppName())
1003 + "::" + full_class_name
;
1006 // If we haven't specified anything for the typedef, then we don't care
1007 ComplexTypeEntry
*type
= TypeDatabase::instance()->findComplexType(full_class_name
);
1011 if (type
->isObject())
1012 static_cast<ObjectTypeEntry
*>(type
)->setQObject(isQObject(strip_template_args(typeAlias
->type().qualifiedName().join("::"))));
1014 AbstractMetaClass
*meta_class
= createMetaClass();
1015 meta_class
->setTypeAlias(true);
1016 meta_class
->setTypeEntry(type
);
1017 meta_class
->setBaseClassNames(QStringList() << typeAlias
->type().qualifiedName().join("::"));
1018 *meta_class
+= AbstractMetaAttributes::Public
;
1020 // Set the default include file name
1021 if (!type
->include().isValid()) {
1022 QFileInfo
info(typeAlias
->fileName());
1023 type
->setInclude(Include(Include::IncludePath
, info
.fileName()));
1029 AbstractMetaClass
*AbstractMetaBuilder::traverseClass(ClassModelItem class_item
)
1031 QString class_name
= strip_template_args(class_item
->name());
1032 QString full_class_name
= class_name
;
1034 // we have inner an class
1035 if (m_current_class
) {
1036 full_class_name
= strip_template_args(m_current_class
->typeEntry()->qualifiedCppName())
1037 + "::" + full_class_name
;
1040 ComplexTypeEntry
*type
= TypeDatabase::instance()->findComplexType(full_class_name
);
1041 RejectReason reason
= NoReason
;
1043 if (full_class_name
== "QMetaTypeId") {
1044 // QtScript: record which types have been declared
1045 int lpos
= class_item
->name().indexOf('<');
1046 int rpos
= class_item
->name().lastIndexOf('>');
1047 if ((lpos
!= -1) && (rpos
!= -1)) {
1048 QString declared_typename
= class_item
->name().mid(lpos
+1, rpos
- lpos
-1);
1049 m_qmetatype_declared_typenames
.insert(declared_typename
);
1053 if (TypeDatabase::instance()->isClassRejected(full_class_name
)) {
1054 reason
= GenerationDisabled
;
1056 TypeEntry
*te
= TypeDatabase::instance()->findType(full_class_name
);
1057 if (te
&& !te
->isComplex())
1058 reason
= RedefinedToNotClass
;
1060 reason
= NotInTypeSystem
;
1061 } else if (type
->codeGeneration() == TypeEntry::GenerateNothing
) {
1062 reason
= GenerationDisabled
;
1065 if (reason
!= NoReason
) {
1066 m_rejected_classes
.insert(full_class_name
, reason
);
1070 if (type
->isObject()) {
1071 ((ObjectTypeEntry
*)type
)->setQObject(isQObject(full_class_name
));
1074 AbstractMetaClass
*meta_class
= createMetaClass();
1075 meta_class
->setTypeEntry(type
);
1076 meta_class
->setBaseClassNames(class_item
->baseClasses());
1077 *meta_class
+= AbstractMetaAttributes::Public
;
1079 AbstractMetaClass
*old_current_class
= m_current_class
;
1080 m_current_class
= meta_class
;
1082 if (type
->isContainer()) {
1083 ReportHandler::debugSparse(QString("container: '%1'").arg(full_class_name
));
1085 ReportHandler::debugSparse(QString("class: '%1'").arg(meta_class
->fullName()));
1088 TemplateParameterList template_parameters
= class_item
->templateParameters();
1089 QList
<TypeEntry
*> template_args
;
1090 template_args
.clear();
1091 for (int i
=0; i
<template_parameters
.size(); ++i
) {
1092 const TemplateParameterModelItem
¶m
= template_parameters
.at(i
);
1093 TemplateArgumentEntry
*param_type
= new TemplateArgumentEntry(param
->name());
1094 param_type
->setOrdinal(i
);
1095 template_args
.append(param_type
);
1097 meta_class
->setTemplateArguments(template_args
);
1099 parseQ_Property(meta_class
, class_item
->propertyDeclarations());
1101 traverseFunctions(model_dynamic_cast
<ScopeModelItem
>(class_item
), meta_class
);
1102 traverseEnums(model_dynamic_cast
<ScopeModelItem
>(class_item
), meta_class
, class_item
->enumsDeclarations());
1103 traverseFields(model_dynamic_cast
<ScopeModelItem
>(class_item
), meta_class
);
1107 QList
<ClassModelItem
> inner_classes
= class_item
->classMap().values();
1108 foreach (const ClassModelItem
&ci
, inner_classes
) {
1109 AbstractMetaClass
*cl
= traverseClass(ci
);
1111 cl
->setEnclosingClass(meta_class
);
1112 m_meta_classes
<< cl
;
1118 // Go through all typedefs to see if we have defined any
1119 // specific typedefs to be used as classes.
1120 TypeAliasList typeAliases
= class_item
->typeAliases();
1121 foreach (TypeAliasModelItem typeAlias
, typeAliases
) {
1122 AbstractMetaClass
*cls
= traverseTypeAlias(typeAlias
);
1124 cls
->setEnclosingClass(meta_class
);
1125 addAbstractMetaClass(cls
);
1130 m_current_class
= old_current_class
;
1132 // Set the default include file name
1133 if (!type
->include().isValid()) {
1134 QFileInfo
info(class_item
->fileName());
1135 type
->setInclude(Include(Include::IncludePath
, info
.fileName()));
1141 AbstractMetaField
*AbstractMetaBuilder::traverseField(VariableModelItem field
, const AbstractMetaClass
*cls
)
1143 QString field_name
= field
->name();
1144 QString class_name
= m_current_class
->typeEntry()->qualifiedCppName();
1146 // Ignore friend decl.
1147 if (field
->isFriend())
1150 if (field
->accessPolicy() == CodeModel::Private
)
1153 if (TypeDatabase::instance()->isFieldRejected(class_name
, field_name
)) {
1154 m_rejected_fields
.insert(class_name
+ "::" + field_name
, GenerationDisabled
);
1159 AbstractMetaField
*meta_field
= createMetaField();
1160 meta_field
->setName(field_name
);
1161 meta_field
->setEnclosingClass(cls
);
1164 TypeInfo field_type
= field
->type();
1165 AbstractMetaType
*meta_type
= translateType(field_type
, &ok
);
1167 if (!meta_type
|| !ok
) {
1168 ReportHandler::warning(QString("skipping field '%1::%2' with unmatched type '%3'")
1169 .arg(m_current_class
->name())
1171 .arg(TypeInfo::resolveType(field_type
, currentScope()->toItem()).qualifiedName().join("::")));
1176 meta_field
->setType(meta_type
);
1179 if (field
->isStatic())
1180 attr
|= AbstractMetaAttributes::Static
;
1182 CodeModel::AccessPolicy policy
= field
->accessPolicy();
1183 if (policy
== CodeModel::Public
)
1184 attr
|= AbstractMetaAttributes::Public
;
1185 else if (policy
== CodeModel::Protected
)
1186 attr
|= AbstractMetaAttributes::Protected
;
1188 attr
|= AbstractMetaAttributes::Private
;
1189 meta_field
->setAttributes(attr
);
1194 void AbstractMetaBuilder::traverseFields(ScopeModelItem scope_item
, AbstractMetaClass
*meta_class
)
1196 foreach (VariableModelItem field
, scope_item
->variables()) {
1197 AbstractMetaField
*meta_field
= traverseField(field
, meta_class
);
1200 meta_field
->setOriginalAttributes(meta_field
->attributes());
1201 meta_class
->addField(meta_field
);
1206 void AbstractMetaBuilder::setupFunctionDefaults(AbstractMetaFunction
*meta_function
, AbstractMetaClass
*meta_class
)
1208 // Set the default value of the declaring class. This may be changed
1209 // in fixFunctions later on
1210 meta_function
->setDeclaringClass(meta_class
);
1212 // Some of the queries below depend on the implementing class being set
1213 // to function properly. Such as function modifications
1214 meta_function
->setImplementingClass(meta_class
);
1216 if (meta_function
->name() == "operator_equal")
1217 meta_class
->setHasEqualsOperator(true);
1219 if (!meta_function
->isFinalInTargetLang()
1220 && meta_function
->isRemovedFrom(meta_class
, TypeSystem::TargetLangCode
)) {
1221 *meta_function
+= AbstractMetaAttributes::FinalInCpp
;
1225 void AbstractMetaBuilder::traverseFunctions(ScopeModelItem scope_item
, AbstractMetaClass
*meta_class
)
1227 foreach (FunctionModelItem function
, scope_item
->functions()) {
1228 AbstractMetaFunction
*meta_function
= traverseFunction(function
);
1230 if (meta_function
) {
1231 meta_function
->setOriginalAttributes(meta_function
->attributes());
1232 if (meta_class
->isNamespace())
1233 *meta_function
+= AbstractMetaAttributes::Static
;
1235 if (QPropertySpec
*read
= meta_class
->propertySpecForRead(meta_function
->name())) {
1236 if (read
->type() == meta_function
->type()->typeEntry()) {
1237 *meta_function
+= AbstractMetaAttributes::PropertyReader
;
1238 meta_function
->setPropertySpec(read
);
1239 // printf("%s is reader for %s\n",
1240 // qPrintable(meta_function->name()),
1241 // qPrintable(read->name()));
1243 } else if (QPropertySpec
*write
=
1244 meta_class
->propertySpecForWrite(meta_function
->name())) {
1245 if (write
->type() == meta_function
->arguments().at(0)->type()->typeEntry()) {
1246 *meta_function
+= AbstractMetaAttributes::PropertyWriter
;
1247 meta_function
->setPropertySpec(write
);
1248 // printf("%s is writer for %s\n",
1249 // qPrintable(meta_function->name()),
1250 // qPrintable(write->name()));
1252 } else if (QPropertySpec
*reset
=
1253 meta_class
->propertySpecForReset(meta_function
->name())) {
1254 *meta_function
+= AbstractMetaAttributes::PropertyResetter
;
1255 meta_function
->setPropertySpec(reset
);
1256 // printf("%s is resetter for %s\n",
1257 // qPrintable(meta_function->name()),
1258 // qPrintable(reset->name()));
1262 bool isInvalidDestructor
= meta_function
->isDestructor() && meta_function
->isPrivate();
1263 bool isInvalidConstructor
= meta_function
->isConstructor()
1264 && (meta_function
->isPrivate() || meta_function
->isInvalid());
1265 if ((isInvalidDestructor
|| isInvalidConstructor
)
1266 && !meta_class
->hasNonPrivateConstructor()) {
1267 *meta_class
+= AbstractMetaAttributes::Final
;
1268 } else if (meta_function
->isConstructor() && !meta_function
->isPrivate()) {
1269 *meta_class
-= AbstractMetaAttributes::Final
;
1270 meta_class
->setHasNonPrivateConstructor(true);
1273 // Classes with virtual destructors should always have a shell class
1274 // (since we aren't registering the destructors, we need this extra check)
1275 if (meta_function
->isDestructor() && !meta_function
->isFinal())
1276 meta_class
->setForceShellClass(true);
1278 if (!meta_function
->isDestructor()
1279 && !meta_function
->isInvalid()
1280 && (!meta_function
->isConstructor() || !meta_function
->isPrivate())) {
1282 if (meta_class
->typeEntry()->designatedInterface() && !meta_function
->isPublic()
1283 && !meta_function
->isPrivate()) {
1284 QString warn
= QString("non-public function '%1' in interface '%2'")
1285 .arg(meta_function
->name()).arg(meta_class
->name());
1286 ReportHandler::warning(warn
);
1288 meta_function
->setVisibility(AbstractMetaClass::Public
);
1291 setupFunctionDefaults(meta_function
, meta_class
);
1293 if (meta_function
->isSignal() && meta_class
->hasSignal(meta_function
)) {
1294 QString warn
= QString("signal '%1' in class '%2' is overloaded.")
1295 .arg(meta_function
->name()).arg(meta_class
->name());
1296 ReportHandler::warning(warn
);
1299 if (meta_function
->isSignal() && !meta_class
->isQObject()) {
1300 QString warn
= QString("signal '%1' in non-QObject class '%2'")
1301 .arg(meta_function
->name()).arg(meta_class
->name());
1302 ReportHandler::warning(warn
);
1305 meta_class
->addFunction(meta_function
);
1306 } else if (meta_function
->isDestructor() && !meta_function
->isPublic()) {
1307 meta_class
->setHasPublicDestructor(false);
1313 bool AbstractMetaBuilder::setupInheritance(AbstractMetaClass
*meta_class
)
1315 Q_ASSERT(!meta_class
->isInterface());
1317 if (m_setup_inheritance_done
.contains(meta_class
))
1319 m_setup_inheritance_done
.insert(meta_class
);
1321 QStringList base_classes
= meta_class
->baseClassNames();
1323 TypeDatabase
*types
= TypeDatabase::instance();
1325 // we only support our own containers and ONLY if there is only one baseclass
1326 if (base_classes
.size() == 1 && base_classes
.first().count('<') == 1) {
1327 QStringList scope
= meta_class
->typeEntry()->qualifiedCppName().split("::");
1329 for (int i
=scope
.size(); i
>=0; --i
) {
1330 QString prefix
= i
> 0 ? QStringList(scope
.mid(0, i
)).join("::") + "::" : QString();
1331 QString complete_name
= prefix
+ base_classes
.first();
1332 TypeParser::Info info
= TypeParser::parse(complete_name
);
1333 QString base_name
= info
.qualified_name
.join("::");
1335 AbstractMetaClass
*templ
= 0;
1336 foreach (AbstractMetaClass
*c
, m_templates
) {
1337 if (c
->typeEntry()->name() == base_name
) {
1344 templ
= m_meta_classes
.findClass(base_name
);
1347 setupInheritance(templ
);
1348 inheritTemplate(meta_class
, templ
, info
);
1353 ReportHandler::warning(QString("template baseclass '%1' of '%2' is not known")
1354 .arg(base_classes
.first())
1355 .arg(meta_class
->name()));
1361 for (int i
=0; i
<base_classes
.size(); ++i
) {
1363 if (types
->isClassRejected(base_classes
.at(i
)))
1366 TypeEntry
*base_class_entry
= types
->findType(base_classes
.at(i
));
1367 if (!base_class_entry
) {
1368 ReportHandler::warning(QString("class '%1' inherits from unknown base class '%2'")
1369 .arg(meta_class
->name()).arg(base_classes
.at(i
)));
1372 // true for primary base class
1373 else if (!base_class_entry
->designatedInterface()) {
1374 if (primaries
> 0) {
1375 ReportHandler::warning(QString("class '%1' has multiple primary base classes"
1377 .arg(meta_class
->name())
1378 .arg(base_classes
.at(primary
))
1379 .arg(base_class_entry
->name()));
1388 AbstractMetaClass
*base_class
= m_meta_classes
.findClass(base_classes
.at(primary
));
1390 ReportHandler::warning(QString("unknown baseclass for '%1': '%2'")
1391 .arg(meta_class
->name())
1392 .arg(base_classes
.at(primary
)));
1395 meta_class
->setBaseClass(base_class
);
1397 if (meta_class
->typeEntry()->designatedInterface() != 0 && meta_class
->isQObject()) {
1398 ReportHandler::warning(QString("QObject extended by interface type '%1'. This is not supported and the generated Java code will not compile.")
1399 .arg(meta_class
->name()));
1400 } else if (meta_class
->typeEntry()->designatedInterface() != 0 && base_class
!= 0 && !base_class
->isInterface()) {
1401 ReportHandler::warning(QString("object type '%1' extended by interface type '%2'. The resulting API will be less expressive than the original.")
1402 .arg(base_class
->name())
1403 .arg(meta_class
->name()));
1408 for (int i
=0; i
<base_classes
.size(); ++i
) {
1409 if (types
->isClassRejected(base_classes
.at(i
)))
1413 AbstractMetaClass
*base_class
= m_meta_classes
.findClass(base_classes
.at(i
));
1414 if (base_class
== 0) {
1415 ReportHandler::warning(QString("class not found for setup inheritance '%1'").arg(base_classes
.at(i
)));
1419 setupInheritance(base_class
);
1421 QString interface_name
= InterfaceTypeEntry::interfaceName(base_class
->name());
1422 AbstractMetaClass
*iface
= m_meta_classes
.findClass(interface_name
);
1424 ReportHandler::warning(QString("unknown interface for '%1': '%2'")
1425 .arg(meta_class
->name())
1426 .arg(interface_name
));
1429 meta_class
->addInterface(iface
);
1431 AbstractMetaClassList interfaces
= iface
->interfaces();
1432 foreach (AbstractMetaClass
*iface
, interfaces
)
1433 meta_class
->addInterface(iface
);
1440 void AbstractMetaBuilder::traverseEnums(ScopeModelItem scope_item
, AbstractMetaClass
*meta_class
, const QStringList
&enumsDeclarations
)
1442 EnumList enums
= scope_item
->enums();
1443 foreach (EnumModelItem enum_item
, enums
) {
1444 AbstractMetaEnum
*meta_enum
= traverseEnum(enum_item
, meta_class
, QSet
<QString
>::fromList(enumsDeclarations
));
1446 meta_enum
->setOriginalAttributes(meta_enum
->attributes());
1447 meta_class
->addEnum(meta_enum
);
1448 meta_enum
->setEnclosingClass(meta_class
);
1453 AbstractMetaFunction
*AbstractMetaBuilder::traverseFunction(FunctionModelItem function_item
)
1455 QString function_name
= function_item
->name();
1456 QString class_name
= m_current_class
->typeEntry()->qualifiedCppName();
1458 if (TypeDatabase::instance()->isFunctionRejected(class_name
, function_name
)) {
1459 m_rejected_functions
.insert(class_name
+ "::" + function_name
, GenerationDisabled
);
1464 Q_ASSERT(function_item
->functionType() == CodeModel::Normal
1465 || function_item
->functionType() == CodeModel::Signal
1466 || function_item
->functionType() == CodeModel::Slot
);
1468 if (function_item
->isFriend())
1474 if (function_name
.startsWith("operator")) {
1475 function_name
= rename_operator(function_name
.mid(8));
1476 if (function_name
.isEmpty()) {
1477 m_rejected_functions
.insert(class_name
+ "::" + function_name
,
1478 GenerationDisabled
);
1481 if (function_name
.contains("_cast_"))
1482 cast_type
= function_name
.mid(14).trimmed();
1485 AbstractMetaFunction
*meta_function
= createMetaFunction();
1486 meta_function
->setConstant(function_item
->isConstant());
1488 ReportHandler::debugMedium(QString(" - %2()").arg(function_name
));
1490 meta_function
->setName(function_name
);
1491 meta_function
->setOriginalName(function_item
->name());
1493 if (function_item
->isAbstract())
1494 *meta_function
+= AbstractMetaAttributes::Abstract
;
1496 if (!meta_function
->isAbstract())
1497 *meta_function
+= AbstractMetaAttributes::Native
;
1499 if (!function_item
->isVirtual())
1500 *meta_function
+= AbstractMetaAttributes::Final
;
1502 if (function_item
->isInvokable())
1503 *meta_function
+= AbstractMetaAttributes::Invokable
;
1505 if (function_item
->isStatic()) {
1506 *meta_function
+= AbstractMetaAttributes::Static
;
1507 *meta_function
+= AbstractMetaAttributes::Final
;
1511 if (function_item
->accessPolicy() == CodeModel::Public
)
1512 *meta_function
+= AbstractMetaAttributes::Public
;
1513 else if (function_item
->accessPolicy() == CodeModel::Private
)
1514 *meta_function
+= AbstractMetaAttributes::Private
;
1516 *meta_function
+= AbstractMetaAttributes::Protected
;
1519 QString stripped_class_name
= class_name
;
1520 int cc_pos
= stripped_class_name
.lastIndexOf("::");
1522 stripped_class_name
= stripped_class_name
.mid(cc_pos
+ 2);
1524 TypeInfo function_type
= function_item
->type();
1525 if (function_name
.startsWith('~')) {
1526 meta_function
->setFunctionType(AbstractMetaFunction::DestructorFunction
);
1527 meta_function
->setInvalid(true);
1528 } else if (strip_template_args(function_name
) == stripped_class_name
) {
1529 meta_function
->setFunctionType(AbstractMetaFunction::ConstructorFunction
);
1530 meta_function
->setName(m_current_class
->name());
1533 AbstractMetaType
*type
= 0;
1535 if (!cast_type
.isEmpty()) {
1537 info
.setQualifiedName(QStringList(cast_type
));
1538 type
= translateType(info
, &ok
);
1540 type
= translateType(function_type
, &ok
);
1544 ReportHandler::warning(QString("skipping function '%1::%2', unmatched return type '%3'")
1546 .arg(function_item
->name())
1547 .arg(function_item
->type().toString()));
1548 m_rejected_functions
[class_name
+ "::" + function_name
] =
1549 UnmatchedReturnType
;
1550 meta_function
->setInvalid(true);
1551 return meta_function
;
1553 meta_function
->setType(type
);
1555 if (function_item
->functionType() == CodeModel::Signal
)
1556 meta_function
->setFunctionType(AbstractMetaFunction::SignalFunction
);
1557 else if (function_item
->functionType() == CodeModel::Slot
)
1558 meta_function
->setFunctionType(AbstractMetaFunction::SlotFunction
);
1561 ArgumentList arguments
= function_item
->arguments();
1562 AbstractMetaArgumentList meta_arguments
;
1564 int first_default_argument
= 0;
1565 for (int i
=0; i
<arguments
.size(); ++i
) {
1566 ArgumentModelItem arg
= arguments
.at(i
);
1569 AbstractMetaType
*meta_type
= translateType(arg
->type(), &ok
);
1570 if (!meta_type
|| !ok
) {
1571 ReportHandler::warning(QString("skipping function '%1::%2', "
1572 "unmatched parameter type '%3'")
1574 .arg(function_item
->name())
1575 .arg(arg
->type().toString()));
1576 m_rejected_functions
[class_name
+ "::" + function_name
] =
1577 UnmatchedArgumentType
;
1578 meta_function
->setInvalid(true);
1579 return meta_function
;
1581 AbstractMetaArgument
*meta_argument
= createMetaArgument();
1582 meta_argument
->setType(meta_type
);
1583 meta_argument
->setName(arg
->name());
1584 meta_argument
->setArgumentIndex(i
);
1585 meta_arguments
<< meta_argument
;
1588 meta_function
->setArguments(meta_arguments
);
1590 // Find the correct default values
1591 for (int i
=0; i
<arguments
.size(); ++i
) {
1592 ArgumentModelItem arg
= arguments
.at(i
);
1593 AbstractMetaArgument
*meta_arg
= meta_arguments
.at(i
);
1594 if (arg
->defaultValue()) {
1595 QString expr
= arg
->defaultValueExpression();
1596 if (!expr
.isEmpty())
1597 meta_arg
->setOriginalDefaultValueExpression(expr
);
1599 expr
= translateDefaultValue(arg
, meta_arg
->type(), meta_function
, m_current_class
, i
);
1600 if (expr
.isEmpty()) {
1601 first_default_argument
= i
;
1603 meta_arg
->setDefaultValueExpression(expr
);
1606 if (meta_arg
->type()->isEnum() || meta_arg
->type()->isFlags()) {
1607 m_enum_default_arguments
1608 << QPair
<AbstractMetaArgument
*, AbstractMetaFunction
*>(meta_arg
, meta_function
);
1614 // If we where not able to translate the default argument make it
1615 // reset all default arguments before this one too.
1616 for (int i
=0; i
<first_default_argument
; ++i
)
1617 meta_arguments
[i
]->setDefaultValueExpression(QString());
1619 if (ReportHandler::debugLevel() == ReportHandler::FullDebug
)
1620 foreach(AbstractMetaArgument
*arg
, meta_arguments
)
1621 ReportHandler::debugFull(" - " + arg
->toString());
1623 return meta_function
;
1627 AbstractMetaType
*AbstractMetaBuilder::translateType(const TypeInfo
&_typei
, bool *ok
, bool resolveType
, bool resolveScope
)
1632 // 1. Test the type info without resolving typedefs in case this is present in the
1637 AbstractMetaType
*t
= translateType(_typei
, &isok
, false, resolveScope
);
1645 // Go through all parts of the current scope (including global namespace)
1646 // to resolve typedefs. The parser does not properly resolve typedefs in
1647 // the global scope when they are referenced from inside a namespace.
1648 // This is a work around to fix this bug since fixing it in resolveType
1649 // seemed non-trivial
1650 int i
= m_scopes
.size() - 1;
1652 typei
= TypeInfo::resolveType(_typei
, m_scopes
.at(i
--)->toItem());
1653 if (typei
.qualifiedName().join("::") != _typei
.qualifiedName().join("::"))
1659 if (typei
.isFunctionPointer()) {
1664 TypeParser::Info typeInfo
= TypeParser::parse(typei
.toString());
1665 if (typeInfo
.is_busted
) {
1670 // 2. Handle pointers specified as arrays with unspecified size
1671 bool array_of_unspecified_size
= false;
1672 if (typeInfo
.arrays
.size() > 0) {
1673 array_of_unspecified_size
= true;
1674 for (int i
=0; i
<typeInfo
.arrays
.size(); ++i
)
1675 array_of_unspecified_size
= array_of_unspecified_size
&& typeInfo
.arrays
.at(i
).isEmpty();
1677 if (!array_of_unspecified_size
) {
1679 //newInfo.setArguments(typei.arguments());
1680 newInfo
.setIndirections(typei
.indirections());
1681 newInfo
.setConstant(typei
.isConstant());
1682 newInfo
.setFunctionPointer(typei
.isFunctionPointer());
1683 newInfo
.setQualifiedName(typei
.qualifiedName());
1684 newInfo
.setReference(typei
.isReference());
1685 newInfo
.setVolatile(typei
.isVolatile());
1687 AbstractMetaType
*elementType
= translateType(newInfo
, ok
);
1691 for (int i
=typeInfo
.arrays
.size()-1; i
>=0; --i
) {
1692 QString s
= typeInfo
.arrays
.at(i
);
1695 int elems
= s
.toInt(&isok
);
1699 AbstractMetaType
*arrayType
= createMetaType();
1700 arrayType
->setArrayElementCount(elems
);
1701 arrayType
->setArrayElementType(elementType
);
1702 arrayType
->setTypeEntry(new ArrayTypeEntry(elementType
->typeEntry()));
1703 decideUsagePattern(arrayType
);
1705 elementType
= arrayType
;
1710 typeInfo
.indirections
+= typeInfo
.arrays
.size();
1714 QStringList qualifier_list
= typeInfo
.qualified_name
;
1715 if (qualifier_list
.isEmpty()) {
1716 ReportHandler::warning(QString("horribly broken type '%1'").arg(_typei
.toString()));
1721 QString qualified_name
= qualifier_list
.join("::");
1722 QString name
= qualifier_list
.takeLast();
1724 // 3. Special case 'void' type
1725 if (name
== "void" && typeInfo
.indirections
== 0) {
1729 // 4. Special case QFlags (include instantiation in name)
1730 if (qualified_name
== "QFlags")
1731 qualified_name
= typeInfo
.toString();
1733 // 5. Try to find the type
1734 const TypeEntry
*type
= TypeDatabase::instance()->findType(qualified_name
);
1736 // 6. No? Try looking it up as a flags type
1738 type
= TypeDatabase::instance()->findFlagsType(qualified_name
);
1740 // 7. No? Try looking it up as a container type
1742 type
= TypeDatabase::instance()->findContainerType(name
);
1744 // 8. No? Check if the current class is a template and this type is one
1745 // of the parameters.
1746 if (type
== 0 && m_current_class
!= 0) {
1747 QList
<TypeEntry
*> template_args
= m_current_class
->templateArguments();
1748 foreach (TypeEntry
*te
, template_args
) {
1749 if (te
->name() == qualified_name
)
1754 // 9. Try finding the type by prefixing it with the current
1755 // context and all baseclasses of the current context
1756 if (!type
&& !TypeDatabase::instance()->isClassRejected(qualified_name
) && m_current_class
!= 0 && resolveScope
) {
1757 QStringList contexts
;
1758 contexts
.append(m_current_class
->qualifiedCppName());
1759 contexts
.append(currentScope()->qualifiedName().join("::"));
1762 TypeInfo info
= typei
;
1763 bool subclasses_done
= false;
1764 while (!contexts
.isEmpty() && type
== 0) {
1765 //type = TypeDatabase::instance()->findType(contexts.at(0) + "::" + qualified_name);
1768 info
.setQualifiedName(QStringList() << contexts
.at(0) << qualified_name
);
1769 AbstractMetaType
*t
= translateType(info
, &isok
, true, false);
1773 ClassModelItem item
= m_dom
->findClass(contexts
.at(0));
1775 contexts
+= item
->baseClasses();
1776 contexts
.pop_front();
1778 // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so
1779 // enum types from there may be addressed without any scope resolution in properties.
1780 if (contexts
.size() == 0 && !subclasses_done
) {
1782 subclasses_done
= true;
1793 // Used to for diagnostics later...
1794 m_used_types
<< type
;
1796 // These are only implicit and should not appear in code...
1797 Q_ASSERT(!type
->isInterface());
1799 AbstractMetaType
*meta_type
= createMetaType();
1800 meta_type
->setTypeEntry(type
);
1801 meta_type
->setIndirections(typeInfo
.indirections
);
1802 meta_type
->setReference(typeInfo
.is_reference
);
1803 meta_type
->setConstant(typeInfo
.is_constant
);
1804 meta_type
->setOriginalTypeDescription(_typei
.toString());
1805 decideUsagePattern(meta_type
);
1807 if (meta_type
->typeEntry()->isContainer()) {
1808 ContainerTypeEntry::Type container_type
= static_cast<const ContainerTypeEntry
*>(type
)->type();
1810 if (container_type
== ContainerTypeEntry::StringListContainer
) {
1812 info
.setQualifiedName(QStringList() << "QString");
1813 AbstractMetaType
*targ_type
= translateType(info
, ok
);
1816 Q_ASSERT(targ_type
);
1818 meta_type
->addInstantiation(targ_type
);
1819 meta_type
->setInstantiationInCpp(false);
1822 foreach (const TypeParser::Info
&ta
, typeInfo
.template_instantiations
) {
1824 info
.setConstant(ta
.is_constant
);
1825 info
.setReference(ta
.is_reference
);
1826 info
.setIndirections(ta
.indirections
);
1828 info
.setFunctionPointer(false);
1829 info
.setQualifiedName(ta
.instantiationName().split("::"));
1831 AbstractMetaType
*targ_type
= translateType(info
, ok
);
1837 meta_type
->addInstantiation(targ_type
);
1841 if (container_type
== ContainerTypeEntry::ListContainer
1842 || container_type
== ContainerTypeEntry::VectorContainer
1843 || container_type
== ContainerTypeEntry::StringListContainer
) {
1844 Q_ASSERT(meta_type
->instantiations().size() == 1);
1851 void AbstractMetaBuilder::decideUsagePattern(AbstractMetaType
*meta_type
)
1853 const TypeEntry
*type
= meta_type
->typeEntry();
1855 if (type
->isPrimitive() && (meta_type
->actualIndirections() == 0
1856 || (meta_type
->isConstant() && meta_type
->isReference() && meta_type
->indirections() == 0))) {
1857 meta_type
->setTypeUsagePattern(AbstractMetaType::PrimitivePattern
);
1859 } else if (type
->isVoid()) {
1860 meta_type
->setTypeUsagePattern(AbstractMetaType::NativePointerPattern
);
1862 } else if (type
->isString()
1863 && meta_type
->indirections() == 0
1864 && (meta_type
->isConstant() == meta_type
->isReference()
1865 || meta_type
->isConstant())) {
1866 meta_type
->setTypeUsagePattern(AbstractMetaType::StringPattern
);
1868 } else if (type
->isChar()
1869 && meta_type
->indirections() == 0
1870 && meta_type
->isConstant() == meta_type
->isReference()) {
1871 meta_type
->setTypeUsagePattern(AbstractMetaType::CharPattern
);
1873 } else if (type
->isJObjectWrapper()
1874 && meta_type
->indirections() == 0
1875 && meta_type
->isConstant() == meta_type
->isReference()) {
1876 meta_type
->setTypeUsagePattern(AbstractMetaType::JObjectWrapperPattern
);
1878 } else if (type
->isVariant()
1879 && meta_type
->indirections() == 0
1880 && meta_type
->isConstant() == meta_type
->isReference()) {
1881 meta_type
->setTypeUsagePattern(AbstractMetaType::VariantPattern
);
1883 } else if (type
->isEnum() && meta_type
->actualIndirections() == 0) {
1884 meta_type
->setTypeUsagePattern(AbstractMetaType::EnumPattern
);
1886 } else if (type
->isObject()
1887 && meta_type
->indirections() == 0
1888 && meta_type
->isReference()) {
1889 if (((ComplexTypeEntry
*) type
)->isQObject())
1890 meta_type
->setTypeUsagePattern(AbstractMetaType::QObjectPattern
);
1892 meta_type
->setTypeUsagePattern(AbstractMetaType::ObjectPattern
);
1894 } else if (type
->isObject()
1895 && meta_type
->indirections() == 1) {
1896 if (((ComplexTypeEntry
*) type
)->isQObject())
1897 meta_type
->setTypeUsagePattern(AbstractMetaType::QObjectPattern
);
1899 meta_type
->setTypeUsagePattern(AbstractMetaType::ObjectPattern
);
1901 // const-references to pointers can be passed as pointers
1902 if (meta_type
->isReference() && meta_type
->isConstant()) {
1903 meta_type
->setReference(false);
1904 meta_type
->setConstant(false);
1907 } else if (type
->isContainer() && meta_type
->indirections() == 0) {
1908 meta_type
->setTypeUsagePattern(AbstractMetaType::ContainerPattern
);
1910 } else if (type
->isTemplateArgument()) {
1912 } else if (type
->isFlags()
1913 && meta_type
->indirections() == 0
1914 && (meta_type
->isConstant() == meta_type
->isReference())) {
1915 meta_type
->setTypeUsagePattern(AbstractMetaType::FlagsPattern
);
1917 } else if (type
->isArray()) {
1918 meta_type
->setTypeUsagePattern(AbstractMetaType::ArrayPattern
);
1920 } else if (type
->isThread()) {
1921 Q_ASSERT(meta_type
->indirections() == 1);
1922 meta_type
->setTypeUsagePattern(AbstractMetaType::ThreadPattern
);
1924 } else if (type
->isValue()
1925 && meta_type
->indirections() == 0
1926 && (meta_type
->isConstant() == meta_type
->isReference()
1927 || !meta_type
->isReference())) {
1928 meta_type
->setTypeUsagePattern(AbstractMetaType::ValuePattern
);
1931 meta_type
->setTypeUsagePattern(AbstractMetaType::NativePointerPattern
);
1932 ReportHandler::debugFull(QString("native pointer pattern for '%1'")
1933 .arg(meta_type
->cppSignature()));
1937 QString
AbstractMetaBuilder::translateDefaultValue(ArgumentModelItem item
, AbstractMetaType
*type
,
1938 AbstractMetaFunction
*fnc
, AbstractMetaClass
*implementing_class
,
1941 QString function_name
= fnc
->name();
1942 QString class_name
= implementing_class
->name();
1944 QString replaced_expression
= fnc
->replacedDefaultExpression(implementing_class
, argument_index
+ 1);
1945 if (fnc
->removedDefaultExpression(implementing_class
, argument_index
+1))
1947 if (!replaced_expression
.isEmpty())
1948 return replaced_expression
;
1950 QString expr
= item
->defaultValueExpression();
1951 if (type
!= 0 && type
->isPrimitive()) {
1952 if (type
->name() == "boolean") {
1953 if (expr
== "false" || expr
=="true") {
1957 int number
= expr
.toInt(&ok
);
1963 } else if (expr
== "ULONG_MAX") {
1964 return "Long.MAX_VALUE";
1965 } else if (expr
== "QVariant::Invalid") {
1966 return QString::number(QVariant::Invalid
);
1968 // This can be an enum or flag so I need to delay the
1969 // translation untill all namespaces are completly
1970 // processed. This is done in figureOutEnumValues()
1973 } else if (type
!= 0 && (type
->isFlags() || type
->isEnum())) {
1974 // Same as with enum explanation above...
1979 // constructor or functioncall can be a bit tricky...
1980 if (expr
== "QVariant()" || expr
== "QModelIndex()") {
1982 } else if (expr
== "QString()") {
1984 } else if (expr
.endsWith(")") && expr
.contains("::")) {
1985 TypeEntry
*typeEntry
= TypeDatabase::instance()->findType(expr
.left(expr
.indexOf("::")));
1987 return typeEntry
->qualifiedTargetLangName() + "." + expr
.right(expr
.length() - expr
.indexOf("::") - 2);
1988 } else if (expr
.endsWith(")") && type
!= 0 && type
->isValue()) {
1989 int pos
= expr
.indexOf("(");
1991 TypeEntry
*typeEntry
= TypeDatabase::instance()->findType(expr
.left(pos
));
1993 return "new " + typeEntry
->qualifiedTargetLangName() + expr
.right(expr
.length() - pos
);
1996 } else if (expr
== "0") {
1998 } else if (type
!= 0 && (type
->isObject() || type
->isValue() || expr
.contains("::"))) { // like Qt::black passed to a QColor
1999 TypeEntry
*typeEntry
= TypeDatabase::instance()->findType(expr
.left(expr
.indexOf("::")));
2001 expr
= expr
.right(expr
.length() - expr
.indexOf("::") - 2);
2003 return "new " + type
->typeEntry()->qualifiedTargetLangName() +
2004 "(" + typeEntry
->qualifiedTargetLangName() + "." + expr
+ ")";
2009 QString warn
= QString("unsupported default value '%3' of argument in function '%1', class '%2'")
2010 .arg(function_name
).arg(class_name
).arg(item
->defaultValueExpression());
2011 ReportHandler::warning(warn
);
2017 bool AbstractMetaBuilder::isQObject(const QString
&qualified_name
)
2019 if (qualified_name
== "QObject")
2022 ClassModelItem class_item
= m_dom
->findClass(qualified_name
);
2025 QStringList names
= qualified_name
.split(QLatin1String("::"));
2026 NamespaceModelItem ns
= model_dynamic_cast
<NamespaceModelItem
>(m_dom
);
2027 for (int i
=0; i
<names
.size() - 1 && ns
; ++i
)
2028 ns
= ns
->namespaceMap().value(names
.at(i
));
2029 if (ns
&& names
.size() >= 2)
2030 class_item
= ns
->findClass(names
.at(names
.size() - 1));
2033 bool isqobject
= class_item
&& class_item
->extendsClass("QObject");
2035 if (class_item
&& !isqobject
) {
2036 QStringList baseClasses
= class_item
->baseClasses();
2037 for (int i
=0; i
<baseClasses
.count(); ++i
) {
2039 isqobject
= isQObject(baseClasses
.at(i
));
2049 bool AbstractMetaBuilder::isEnum(const QStringList
&qualified_name
)
2051 CodeModelItem item
= m_dom
->model()->findItem(qualified_name
, m_dom
->toItem());
2052 return item
&& item
->kind() == _EnumModelItem::__node_kind
;
2055 AbstractMetaType
*AbstractMetaBuilder::inheritTemplateType(const QList
<AbstractMetaType
*> &template_types
,
2056 AbstractMetaType
*meta_type
, bool *ok
)
2060 if (!meta_type
|| (!meta_type
->typeEntry()->isTemplateArgument() && !meta_type
->hasInstantiations()))
2061 return meta_type
? meta_type
->copy() : 0;
2063 AbstractMetaType
*returned
= meta_type
->copy();
2064 returned
->setOriginalTemplateType(meta_type
->copy());
2066 if (returned
->typeEntry()->isTemplateArgument()) {
2067 const TemplateArgumentEntry
*tae
= static_cast<const TemplateArgumentEntry
*>(returned
->typeEntry());
2069 // If the template is intantiated with void we special case this as rejecting the functions that use this
2070 // parameter from the instantiation.
2071 if (template_types
.size() <= tae
->ordinal() || template_types
.at(tae
->ordinal())->typeEntry()->name() == "void") {
2077 AbstractMetaType
*t
= returned
->copy();
2078 t
->setTypeEntry(template_types
.at(tae
->ordinal())->typeEntry());
2079 t
->setIndirections(template_types
.at(tae
->ordinal())->indirections() + t
->indirections()
2082 decideUsagePattern(t
);
2085 returned
= inheritTemplateType(template_types
, t
, ok
);
2086 if (ok
!= 0 && !(*ok
))
2090 if (returned
->hasInstantiations()) {
2091 QList
<AbstractMetaType
*> instantiations
= returned
->instantiations();
2092 for (int i
=0; i
<instantiations
.count(); ++i
) {
2093 instantiations
[i
] = inheritTemplateType(template_types
, instantiations
.at(i
), ok
);
2094 if (ok
!= 0 && !(*ok
))
2097 returned
->setInstantiations(instantiations
);
2103 bool AbstractMetaBuilder::inheritTemplate(AbstractMetaClass
*subclass
,
2104 const AbstractMetaClass
*template_class
,
2105 const TypeParser::Info
&info
)
2107 QList
<TypeParser::Info
> targs
= info
.template_instantiations
;
2109 QList
<AbstractMetaType
*> template_types
;
2110 foreach (const TypeParser::Info
&i
, targs
) {
2111 TypeEntry
*t
= TypeDatabase::instance()->findType(i
.qualified_name
.join("::"));
2114 AbstractMetaType
*temporary_type
= createMetaType();
2115 temporary_type
->setTypeEntry(t
);
2116 temporary_type
->setConstant(i
.is_constant
);
2117 temporary_type
->setReference(i
.is_reference
);
2118 temporary_type
->setIndirections(i
.indirections
);
2119 template_types
<< temporary_type
;
2123 AbstractMetaFunctionList funcs
= subclass
->functions();
2124 foreach (const AbstractMetaFunction
*function
, template_class
->functions()) {
2126 if (function
->isModifiedRemoved(TypeSystem::All
))
2129 AbstractMetaFunction
*f
= function
->copy();
2130 f
->setArguments(AbstractMetaArgumentList());
2133 AbstractMetaType
*ftype
= function
->type();
2134 f
->setType(inheritTemplateType(template_types
, ftype
, &ok
));
2140 foreach (AbstractMetaArgument
*argument
, function
->arguments()) {
2141 AbstractMetaType
*atype
= argument
->type();
2143 AbstractMetaArgument
*arg
= argument
->copy();
2144 arg
->setType(inheritTemplateType(template_types
, atype
, &ok
));
2147 f
->addArgument(arg
);
2155 // There is no base class in java to inherit from here, so the
2156 // template instantiation is the class that implements the function..
2157 f
->setImplementingClass(subclass
);
2159 // We also set it as the declaring class, since the superclass is
2160 // supposed to disappear. This allows us to make certain function modifications
2161 // on the inherited functions.
2162 f
->setDeclaringClass(subclass
);
2165 if (f
->isConstructor() && subclass
->isTypeAlias()) {
2166 f
->setName(subclass
->name());
2167 } else if (f
->isConstructor()) {
2172 // if the instantiation has a function named the same as an existing
2173 // function we have shadowing so we need to skip it.
2175 for (int i
=0; i
<funcs
.size(); ++i
) {
2176 if (funcs
.at(i
)->name() == f
->name()) {
2186 ComplexTypeEntry
*te
= subclass
->typeEntry();
2187 FunctionModificationList mods
= function
->modifications(template_class
);
2188 for (int i
=0; i
<mods
.size(); ++i
) {
2189 FunctionModification mod
= mods
.at(i
);
2190 mod
.signature
= f
->minimalSignature();
2192 // If we ever need it... Below is the code to do
2193 // substitution of the template instantation type inside
2196 if (mod
.modifiers
& Modification::CodeInjection
) {
2197 for (int j
=0; j
<template_types
.size(); ++j
) {
2198 CodeSnip
&snip
= mod
.snips
.last();
2199 QString code
= snip
.code();
2200 code
.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j
),
2201 template_types
.at(j
)->typeEntry()->qualifiedCppName());
2202 snip
.codeList
.clear();
2207 te
->addFunctionModification(mod
);
2210 subclass
->addFunction(f
);
2214 foreach (AbstractMetaType
*type
, template_types
) {
2220 subclass
->setTemplateBaseClass(template_class
);
2222 subclass
->setInterfaces(template_class
->interfaces());
2223 subclass
->setBaseClass(template_class
->baseClass());
2229 void AbstractMetaBuilder::parseQ_Property(AbstractMetaClass
*meta_class
, const QStringList
&declarations
)
2231 for (int i
=0; i
<declarations
.size(); ++i
) {
2232 QString p
= declarations
.at(i
);
2234 QStringList l
= p
.split(QLatin1String(" "));
2237 QStringList qualifiedScopeName
= currentScope()->qualifiedName();
2239 AbstractMetaType
*type
= 0;
2241 for (int j
=qualifiedScopeName
.size(); j
>=0; --j
) {
2242 scope
= j
> 0 ? QStringList(qualifiedScopeName
.mid(0, j
)).join("::") + "::" : QString();
2244 info
.setQualifiedName((scope
+ l
.at(0)).split("::"));
2246 type
= translateType(info
, &ok
);
2247 if (type
!= 0 && ok
) {
2252 if (type
== 0 || !ok
) {
2253 ReportHandler::warning(QString("Unable to decide type of property: '%1' in class '%2'")
2254 .arg(l
.at(0)).arg(meta_class
->name()));
2258 QString typeName
= scope
+ l
.at(0);
2260 QPropertySpec
*spec
= new QPropertySpec(type
->typeEntry());
2261 spec
->setName(l
.at(1));
2264 for (int pos
=2; pos
+1<l
.size(); pos
+=2) {
2265 if (l
.at(pos
) == QLatin1String("READ"))
2266 spec
->setRead(l
.at(pos
+1));
2267 else if (l
.at(pos
) == QLatin1String("WRITE"))
2268 spec
->setWrite(l
.at(pos
+1));
2269 else if (l
.at(pos
) == QLatin1String("DESIGNABLE"))
2270 spec
->setDesignable(l
.at(pos
+1));
2271 else if (l
.at(pos
) == QLatin1String("RESET"))
2272 spec
->setReset(l
.at(pos
+1));
2275 meta_class
->addPropertySpec(spec
);
2280 static void hide_functions(const AbstractMetaFunctionList
&l
) {
2281 foreach (AbstractMetaFunction
*f
, l
) {
2282 FunctionModification mod
;
2283 mod
.signature
= f
->minimalSignature();
2284 mod
.modifiers
= FunctionModification::Private
;
2285 ((ComplexTypeEntry
*) f
->implementingClass()->typeEntry())->addFunctionModification(mod
);
2289 static void remove_function(AbstractMetaFunction
*f
) {
2290 FunctionModification mod
;
2291 mod
.removal
= TypeSystem::All
;
2292 mod
.signature
= f
->minimalSignature();
2293 ((ComplexTypeEntry
*) f
->implementingClass()->typeEntry())->addFunctionModification(mod
);
2296 static AbstractMetaFunctionList
filter_functions(const AbstractMetaFunctionList
&lst
, QSet
<QString
> *signatures
)
2298 AbstractMetaFunctionList functions
;
2299 foreach (AbstractMetaFunction
*f
, lst
) {
2300 QString signature
= f
->minimalSignature();
2301 int start
= signature
.indexOf(QLatin1Char('(')) + 1;
2302 int end
= signature
.lastIndexOf(QLatin1Char(')'));
2303 signature
= signature
.mid(start
, end
- start
);
2304 if (signatures
->contains(signature
)) {
2308 (*signatures
) << signature
;
2314 void AbstractMetaBuilder::setupEquals(AbstractMetaClass
*cls
)
2316 AbstractMetaFunctionList equals
;
2317 AbstractMetaFunctionList nequals
;
2319 QString op_equals
= QLatin1String("operator_equal");
2320 QString op_nequals
= QLatin1String("operator_not_equal");
2322 AbstractMetaFunctionList functions
= cls
->queryFunctions(AbstractMetaClass::ClassImplements
2323 | AbstractMetaClass::NotRemovedFromTargetLang
);
2324 foreach (AbstractMetaFunction
*f
, functions
) {
2325 if (f
->name() == op_equals
)
2327 else if (f
->name() == op_nequals
)
2331 if (equals
.size() || nequals
.size()) {
2332 if (!cls
->hasHashFunction()) {
2333 ReportHandler::warning(QString::fromLatin1("Class '%1' has equals operators but no qHash() function")
2337 hide_functions(equals
);
2338 hide_functions(nequals
);
2340 // We only need == if we have both == and !=, and one == for
2341 // each signature type, like QDateTime::==(QDate) and (QTime)
2342 // if such a thing exists...
2343 QSet
<QString
> func_signatures
;
2344 cls
->setEqualsFunctions(filter_functions(equals
, &func_signatures
));
2345 cls
->setNotEqualsFunctions(filter_functions(nequals
, &func_signatures
));
2349 void AbstractMetaBuilder::setupComparable(AbstractMetaClass
*cls
)
2351 AbstractMetaFunctionList greater
;
2352 AbstractMetaFunctionList greaterEquals
;
2353 AbstractMetaFunctionList less
;
2354 AbstractMetaFunctionList lessEquals
;
2356 QString op_greater
= QLatin1String("operator_greater");
2357 QString op_greater_eq
= QLatin1String("operator_greater_or_equal");
2358 QString op_less
= QLatin1String("operator_less");
2359 QString op_less_eq
= QLatin1String("operator_less_or_equal");
2361 AbstractMetaFunctionList functions
= cls
->queryFunctions(AbstractMetaClass::ClassImplements
2362 | AbstractMetaClass::NotRemovedFromTargetLang
);
2363 foreach (AbstractMetaFunction
*f
, functions
) {
2364 if (f
->name() == op_greater
)
2366 else if (f
->name() == op_greater_eq
)
2368 else if (f
->name() == op_less
)
2370 else if (f
->name() == op_less_eq
)
2374 bool hasEquals
= cls
->equalsFunctions().size() || cls
->notEqualsFunctions().size();
2376 // Conditions for comparable is:
2377 // >, ==, < - The basic case
2378 // >, == - Less than becomes else case
2379 // <, == - Greater than becomes else case
2380 // >=, <= - if (<= && >=) -> equal
2381 bool mightBeComparable
= greater
.size() || greaterEquals
.size() || less
.size() || lessEquals
.size()
2382 || greaterEquals
.size() == 1 || lessEquals
.size() == 1;
2384 if (mightBeComparable
) {
2385 QSet
<QString
> signatures
;
2387 // We only hide the original functions if we are able to make a compareTo() method
2388 bool wasComparable
= false;
2390 // The three upper cases, prefer the <, == approach
2391 if (hasEquals
&& (greater
.size() || less
.size())) {
2392 cls
->setLessThanFunctions(filter_functions(less
, &signatures
));
2393 cls
->setGreaterThanFunctions(filter_functions(greater
, &signatures
));
2394 filter_functions(greaterEquals
, &signatures
);
2395 filter_functions(lessEquals
, &signatures
);
2396 wasComparable
= true;
2397 } else if (hasEquals
&& (greaterEquals
.size() || lessEquals
.size())) {
2398 cls
->setLessThanEqFunctions(filter_functions(lessEquals
, &signatures
));
2399 cls
->setGreaterThanEqFunctions(filter_functions(greaterEquals
, &signatures
));
2400 wasComparable
= true;
2401 } else if (greaterEquals
.size() == 1 || lessEquals
.size() == 1) {
2402 cls
->setGreaterThanEqFunctions(greaterEquals
);
2403 cls
->setLessThanEqFunctions(lessEquals
);
2404 filter_functions(less
, &signatures
);
2405 filter_functions(greater
, &signatures
);
2406 wasComparable
= true;
2409 if (wasComparable
) {
2410 hide_functions(greater
);
2411 hide_functions(greaterEquals
);
2412 hide_functions(less
);
2413 hide_functions(lessEquals
);
2419 void AbstractMetaBuilder::setupClonable(AbstractMetaClass
*cls
)
2421 QString op_assign
= QLatin1String("operator_assign");
2423 AbstractMetaFunctionList functions
= cls
->queryFunctions(AbstractMetaClass::ClassImplements
);
2424 foreach (AbstractMetaFunction
*f
, functions
) {
2425 if ((f
->name() == op_assign
|| f
->isConstructor()) && f
->isPublic()) {
2426 AbstractMetaArgumentList arguments
= f
->arguments();
2427 if (arguments
.size() == 1) {
2428 if (cls
->typeEntry()->qualifiedCppName() == arguments
.at(0)->type()->typeEntry()->qualifiedCppName()) {
2429 if (cls
->typeEntry()->isValue()) {
2430 cls
->setHasCloneOperator(true);
2439 static void write_reject_log_file(const QString
&name
,
2440 const QMap
<QString
, AbstractMetaBuilder::RejectReason
> &rejects
)
2443 if (!f
.open(QIODevice::WriteOnly
| QIODevice::Text
)) {
2444 ReportHandler::warning(QString("failed to write log file: '%1'")
2445 .arg(f
.fileName()));
2452 for (int reason
=0; reason
<AbstractMetaBuilder::NoReason
; ++reason
) {
2453 s
<< QString(72, '*') << endl
;
2455 case AbstractMetaBuilder::NotInTypeSystem
:
2456 s
<< "Not in type system";
2458 case AbstractMetaBuilder::GenerationDisabled
:
2459 s
<< "Generation disabled by type system";
2461 case AbstractMetaBuilder::RedefinedToNotClass
:
2462 s
<< "Type redefined to not be a class";
2465 case AbstractMetaBuilder::UnmatchedReturnType
:
2466 s
<< "Unmatched return type";
2469 case AbstractMetaBuilder::UnmatchedArgumentType
:
2470 s
<< "Unmatched argument type";
2474 s
<< "unknown reason";
2480 for (QMap
<QString
, AbstractMetaBuilder::RejectReason
>::const_iterator it
= rejects
.constBegin();
2481 it
!= rejects
.constEnd(); ++it
) {
2482 if (it
.value() != reason
)
2484 s
<< " - " << it
.key() << endl
;
2487 s
<< QString(72, '*') << endl
<< endl
;
2493 void AbstractMetaBuilder::dumpLog()
2495 write_reject_log_file("mjb_rejected_classes.log", m_rejected_classes
);
2496 write_reject_log_file("mjb_rejected_enums.log", m_rejected_enums
);
2497 write_reject_log_file("mjb_rejected_functions.log", m_rejected_functions
);
2498 write_reject_log_file("mjb_rejected_fields.log", m_rejected_fields
);
2501 AbstractMetaClassList
AbstractMetaBuilder::classesTopologicalSorted() const
2503 AbstractMetaClassList res
;
2505 AbstractMetaClassList classes
= m_meta_classes
;
2508 QSet
<AbstractMetaClass
*> noDependency
;
2509 QHash
<AbstractMetaClass
*, QSet
<AbstractMetaClass
* >* > hash
;
2510 foreach (AbstractMetaClass
*cls
, classes
) {
2511 QSet
<AbstractMetaClass
* > *depends
= new QSet
<AbstractMetaClass
* >();
2513 if (cls
->baseClass())
2514 depends
->insert(cls
->baseClass());
2516 foreach (AbstractMetaClass
*interface
, cls
->interfaces()) {
2517 AbstractMetaClass
*impl
= interface
->primaryInterfaceImplementor();
2520 depends
->insert(impl
);
2523 if (depends
->empty()) {
2524 noDependency
.insert(cls
);
2526 hash
.insert(cls
, depends
);
2530 while (!noDependency
.empty()) {
2531 foreach (AbstractMetaClass
*cls
, noDependency
.values()) {
2532 if(!cls
->isInterface())
2534 noDependency
.remove(cls
);
2535 QHashIterator
<AbstractMetaClass
*, QSet
<AbstractMetaClass
* >* > i(hash
);
2536 while (i
.hasNext()) {
2538 i
.value()->remove(cls
);
2539 if (i
.value()->empty()) {
2540 AbstractMetaClass
*key
= i
.key();
2541 noDependency
.insert(key
);
2549 if (!noDependency
.empty() || !hash
.empty()) {
2550 qWarning("dependency graph was cyclic.");