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 "typesystem.h"
25 #include "generator.h"
27 #include "customtypes.h"
29 #include <reporthandler.h>
35 QString strings_Object
= QLatin1String("Object");
36 QString strings_String
= QLatin1String("String");
37 QString strings_Thread
= QLatin1String("Thread");
38 QString strings_char
= QLatin1String("char");
39 QString strings_java_lang
= QLatin1String("java.lang");
40 QString strings_jchar
= QLatin1String("jchar");
41 QString strings_jobject
= QLatin1String("jobject");
43 static void addRemoveFunctionToTemplates(TypeDatabase
*db
);
51 // Type tags (0x1, ... , 0xff)
52 ObjectTypeEntry
= 0x1,
54 InterfaceTypeEntry
= 0x3,
55 NamespaceTypeEntry
= 0x4,
56 ComplexTypeEntryMask
= 0xf,
58 // Non-complex type tags (0x10, 0x20, ... , 0xf0)
59 PrimitiveTypeEntry
= 0x10,
63 // Simple tags (0x100, 0x200, ... , 0xf00)
64 ExtraIncludes
= 0x100,
66 ModifyFunction
= 0x300,
69 CustomMetaConstructor
= 0x600,
70 CustomMetaDestructor
= 0x700,
72 SuppressedWarning
= 0x900,
74 LoadTypesystem
= 0xb00,
75 RejectEnumValue
= 0xc00,
77 TemplateInstanceEnum
= 0xe00,
81 // Code snip tags (0x1000, 0x2000, ... , 0xf000)
83 InjectCodeInFunction
= 0x2000,
84 CodeSnipMask
= 0xf000,
86 // Function modifier tags (0x010000, 0x020000, ... , 0xf00000)
90 ModifyArgument
= 0x080000,
91 FunctionModifiers
= 0xff0000,
93 // Argument modifier tags (0x01000000 ... 0xf0000000)
94 ConversionRule
= 0x01000000,
95 ReplaceType
= 0x02000000,
96 ReplaceDefaultExpression
= 0x04000000,
97 RemoveArgument
= 0x08000000,
98 DefineOwnership
= 0x10000000,
99 RemoveDefaultExpression
= 0x20000000,
100 NoNullPointers
= 0x40000000,
101 ReferenceCount
= 0x80000000,
102 ArgumentModifiers
= 0xff000000
105 StackElement(StackElement
*p
) : entry(0), type(None
), parent(p
){ }
109 StackElement
*parent
;
112 TemplateInstance
*templateInstance
;
113 TemplateEntry
*templateEntry
;
114 CustomFunction
*customFunction
;
118 class Handler
: public QXmlDefaultHandler
121 Handler(TypeDatabase
*database
, bool generate
)
122 : m_database(database
), m_generate(generate
? TypeEntry::GenerateAll
: TypeEntry::GenerateForSubclass
)
127 tagNames
["rejection"] = StackElement::Rejection
;
128 tagNames
["primitive-type"] = StackElement::PrimitiveTypeEntry
;
129 tagNames
["object-type"] = StackElement::ObjectTypeEntry
;
130 tagNames
["value-type"] = StackElement::ValueTypeEntry
;
131 tagNames
["interface-type"] = StackElement::InterfaceTypeEntry
;
132 tagNames
["namespace-type"] = StackElement::NamespaceTypeEntry
;
133 tagNames
["enum-type"] = StackElement::EnumTypeEntry
;
134 tagNames
["extra-includes"] = StackElement::ExtraIncludes
;
135 tagNames
["include"] = StackElement::Include
;
136 tagNames
["inject-code"] = StackElement::InjectCode
;
137 tagNames
["modify-function"] = StackElement::ModifyFunction
;
138 tagNames
["modify-field"] = StackElement::ModifyField
;
139 tagNames
["access"] = StackElement::Access
;
140 tagNames
["remove"] = StackElement::Removal
;
141 tagNames
["rename"] = StackElement::Rename
;
142 tagNames
["typesystem"] = StackElement::Root
;
143 tagNames
["custom-constructor"] = StackElement::CustomMetaConstructor
;
144 tagNames
["custom-destructor"] = StackElement::CustomMetaDestructor
;
145 tagNames
["argument-map"] = StackElement::ArgumentMap
;
146 tagNames
["suppress-warning"] = StackElement::SuppressedWarning
;
147 tagNames
["load-typesystem"] = StackElement::LoadTypesystem
;
148 tagNames
["define-ownership"] = StackElement::DefineOwnership
;
149 tagNames
["replace-default-expression"] = StackElement::ReplaceDefaultExpression
;
150 tagNames
["reject-enum-value"] = StackElement::RejectEnumValue
;
151 tagNames
["replace-type"] = StackElement::ReplaceType
;
152 tagNames
["conversion-rule"] = StackElement::ConversionRule
;
153 tagNames
["modify-argument"] = StackElement::ModifyArgument
;
154 tagNames
["remove-argument"] = StackElement::RemoveArgument
;
155 tagNames
["remove-default-expression"] = StackElement::RemoveDefaultExpression
;
156 tagNames
["template"] = StackElement::Template
;
157 tagNames
["insert-template"] = StackElement::TemplateInstanceEnum
;
158 tagNames
["replace"] = StackElement::Replace
;
159 tagNames
["no-null-pointer"] = StackElement::NoNullPointers
;
160 tagNames
["reference-count"] = StackElement::ReferenceCount
;
163 bool startElement(const QString
&namespaceURI
, const QString
&localName
,
164 const QString
&qName
, const QXmlAttributes
&atts
);
165 bool endElement(const QString
&namespaceURI
, const QString
&localName
, const QString
&qName
);
167 QString
errorString() const { return m_error
; }
168 bool error(const QXmlParseException
&exception
);
169 bool fatalError(const QXmlParseException
&exception
);
170 bool warning(const QXmlParseException
&exception
);
172 bool characters(const QString
&ch
);
175 void fetchAttributeValues(const QString
&name
, const QXmlAttributes
&atts
,
176 QHash
<QString
, QString
> *acceptedAttributes
);
178 bool importFileElement(const QXmlAttributes
&atts
);
179 bool convertBoolean(const QString
&, const QString
&, bool);
181 TypeDatabase
*m_database
;
182 StackElement
* current
;
183 QString m_defaultPackage
;
184 QString m_defaultSuperclass
;
186 TypeEntry::CodeGeneration m_generate
;
188 EnumTypeEntry
*m_current_enum
;
190 CodeSnipList m_code_snips
;
191 FunctionModificationList m_function_mods
;
192 FieldModificationList m_field_mods
;
194 QHash
<QString
, StackElement::ElementType
> tagNames
;
197 bool Handler::error(const QXmlParseException
&e
)
199 qWarning("Error: line=%d, column=%d, message=%s\n",
200 e
.lineNumber(), e
.columnNumber(), qPrintable(e
.message()));
204 bool Handler::fatalError(const QXmlParseException
&e
)
206 qWarning("Fatal error: line=%d, column=%d, message=%s\n",
207 e
.lineNumber(), e
.columnNumber(), qPrintable(e
.message()));
212 bool Handler::warning(const QXmlParseException
&e
)
214 qWarning("Warning: line=%d, column=%d, message=%s\n",
215 e
.lineNumber(), e
.columnNumber(), qPrintable(e
.message()));
220 void Handler::fetchAttributeValues(const QString
&name
, const QXmlAttributes
&atts
,
221 QHash
<QString
, QString
> *acceptedAttributes
)
223 Q_ASSERT(acceptedAttributes
!= 0);
225 for (int i
=0; i
<atts
.length(); ++i
) {
226 QString key
= atts
.localName(i
).toLower();
227 QString val
= atts
.value(i
);
229 if (!acceptedAttributes
->contains(key
)) {
230 ReportHandler::warning(QString("Unknown attribute for '%1': '%2'").arg(name
).arg(key
));
232 (*acceptedAttributes
)[key
] = val
;
237 bool Handler::endElement(const QString
&, const QString
&localName
, const QString
&)
239 QString tagName
= localName
.toLower();
240 if(tagName
== "import-file")
246 switch (current
->type
) {
247 case StackElement::ObjectTypeEntry
:
248 case StackElement::ValueTypeEntry
:
249 case StackElement::InterfaceTypeEntry
:
250 case StackElement::NamespaceTypeEntry
:
252 ComplexTypeEntry
*centry
= static_cast<ComplexTypeEntry
*>(current
->entry
);
253 centry
->setFunctionModifications(m_function_mods
);
254 centry
->setFieldModifications(m_field_mods
);
255 centry
->setCodeSnips(m_code_snips
);
257 if (centry
->designatedInterface()) {
258 centry
->designatedInterface()->setCodeSnips(m_code_snips
);
259 centry
->designatedInterface()->setFunctionModifications(m_function_mods
);
261 m_code_snips
= CodeSnipList();
262 m_function_mods
= FunctionModificationList();
263 m_field_mods
= FieldModificationList();
266 case StackElement::CustomMetaConstructor
:
268 current
->entry
->setCustomConstructor(*current
->value
.customFunction
);
269 delete current
->value
.customFunction
;
272 case StackElement::CustomMetaDestructor
:
274 current
->entry
->setCustomDestructor(*current
->value
.customFunction
);
275 delete current
->value
.customFunction
;
278 case StackElement::EnumTypeEntry
:
281 case StackElement::Template
:
282 m_database
->addTemplate(current
->value
.templateEntry
);
284 case StackElement::TemplateInstanceEnum
:
285 if(current
->parent
->type
== StackElement::InjectCode
){
286 m_code_snips
.last().addTemplateInstance(current
->value
.templateInstance
);
287 }else if(current
->parent
->type
== StackElement::Template
){
288 current
->parent
->value
.templateEntry
->addTemplateInstance(current
->value
.templateInstance
);
289 }else if(current
->parent
->type
== StackElement::CustomMetaConstructor
|| current
->parent
->type
== StackElement::CustomMetaConstructor
){
290 current
->parent
->value
.customFunction
->addTemplateInstance(current
->value
.templateInstance
);
291 }else if(current
->parent
->type
== StackElement::ConversionRule
){
292 m_function_mods
.last().argument_mods
.last().conversion_rules
.last().addTemplateInstance(current
->value
.templateInstance
);
293 }else if(current
->parent
->type
== StackElement::InjectCodeInFunction
){
294 m_function_mods
.last().snips
.last().addTemplateInstance(current
->value
.templateInstance
);
301 StackElement
*child
= current
;
302 current
=current
->parent
;
308 bool Handler::characters(const QString
&ch
)
310 if(current
->type
== StackElement::Template
){
311 current
->value
.templateEntry
->addCode(ch
);
315 if (current
->type
== StackElement::CustomMetaConstructor
|| current
->type
== StackElement::CustomMetaDestructor
){
316 current
->value
.customFunction
->addCode(ch
);
320 if (current
->type
== StackElement::ConversionRule
){
321 m_function_mods
.last().argument_mods
.last().conversion_rules
.last().addCode(ch
);
325 if (current
->parent
){
326 if ((current
->type
& StackElement::CodeSnipMask
) != 0) {
327 switch (current
->parent
->type
) {
328 case StackElement::Root
:
329 ((TypeSystemTypeEntry
*) current
->parent
->entry
)->snips
.last().addCode(ch
);
331 case StackElement::ModifyFunction
:
332 m_function_mods
.last().snips
.last().addCode(ch
);
334 case StackElement::NamespaceTypeEntry
:
335 case StackElement::ObjectTypeEntry
:
336 case StackElement::ValueTypeEntry
:
337 case StackElement::InterfaceTypeEntry
:
338 m_code_snips
.last().addCode(ch
);
350 bool Handler::importFileElement(const QXmlAttributes
&atts
)
352 QString fileName
= atts
.value("name");
353 if(fileName
.isEmpty()){
354 m_error
= "Required attribute 'name' missing for include-file tag.";
358 QFile
file(fileName
);
359 if (!file
.open(QIODevice::ReadOnly
| QIODevice::Text
)) {
360 file
.setFileName(":/trolltech/generator/" + fileName
);
361 if (!file
.open(QIODevice::ReadOnly
| QIODevice::Text
)) {
362 m_error
= QString("Could not open file: '%1'").arg(fileName
);
367 QString quoteFrom
= atts
.value("quote-after-line");
368 bool foundFromOk
= quoteFrom
.isEmpty();
369 bool from
= quoteFrom
.isEmpty();
371 QString quoteTo
= atts
.value("quote-before-line");
372 bool foundToOk
= quoteTo
.isEmpty();
375 QTextStream
in(&file
);
376 while (!in
.atEnd()) {
377 QString line
= in
.readLine();
378 if(from
&& to
&& line
.contains(quoteTo
)) {
384 characters(line
+ "\n");
385 if(!from
&& line
.contains(quoteFrom
)) {
390 if(!foundFromOk
|| !foundToOk
){
391 QString fromError
= QString("Could not find quote-after-line='%1' in file '%2'.").arg(quoteFrom
).arg(fileName
);
392 QString toError
= QString("Could not find quote-before-line='%1' in file '%2'.").arg(quoteTo
).arg(fileName
);
398 if(!foundFromOk
&& !foundToOk
)
399 m_error
= fromError
+ " " + toError
;
406 bool Handler::convertBoolean(const QString
&_value
, const QString
&attributeName
, bool defaultValue
)
408 QString value
= _value
.toLower();
409 if (value
== "true" || value
== "yes") {
411 } else if (value
== "false" || value
== "no") {
414 QString warn
= QString("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
415 .arg(value
).arg(attributeName
).arg(defaultValue
? "yes" : "no");
417 ReportHandler::warning(warn
);
422 bool Handler::startElement(const QString
&, const QString
&n
,
423 const QString
&, const QXmlAttributes
&atts
)
425 QString tagName
= n
.toLower();
426 if(tagName
== "import-file"){
427 return importFileElement(atts
);
430 std::auto_ptr
<StackElement
> element(new StackElement(current
));
432 if (!tagNames
.contains(tagName
)) {
433 m_error
= QString("Unknown tag name: '%1'").arg(tagName
);
437 element
->type
= tagNames
[tagName
];
438 if (element
->type
& StackElement::TypeEntryMask
) {
439 if (current
->type
!= StackElement::Root
) {
440 m_error
= "Nested types not supported";
444 QHash
<QString
, QString
> attributes
;
445 attributes
["name"] = QString();
447 switch (element
->type
) {
448 case StackElement::PrimitiveTypeEntry
:
449 attributes
["java-name"] = QString();
450 attributes
["jni-name"] = QString();
451 attributes
["preferred-conversion"] = "yes";
452 attributes
["preferred-java-type"] = "yes";
454 case StackElement::EnumTypeEntry
:
455 attributes
["flags"] = "no";
456 attributes
["upper-bound"] = QString();
457 attributes
["lower-bound"] = QString();
458 attributes
["force-integer"] = "no";
459 attributes
["extensible"] = "no";
463 case StackElement::ObjectTypeEntry
:
464 case StackElement::ValueTypeEntry
:
465 attributes
["force-abstract"] = QString("no");
466 attributes
["deprecated"] = QString("no");
468 case StackElement::InterfaceTypeEntry
:
469 attributes
["default-superclass"] = m_defaultSuperclass
;
470 attributes
["polymorphic-id-expression"] = QString();
471 attributes
["delete-in-main-thread"] = QString("no");
473 case StackElement::NamespaceTypeEntry
:
474 attributes
["java-name"] = QString();
475 attributes
["package"] = m_defaultPackage
;
476 attributes
["expense-cost"] = "1";
477 attributes
["expense-limit"] = "none";
478 attributes
["polymorphic-base"] = QString("no");
479 attributes
["generate"] = QString("yes");
480 attributes
["target-type"] = QString();
481 attributes
["generic-class"] = QString("no");
487 fetchAttributeValues(tagName
, atts
, &attributes
);
489 QString name
= attributes
["name"];
491 // We need to be able to have duplicate primitive type entries, or it's not possible to
492 // cover all primitive java types (which we need to do in order to support fake
494 if (element
->type
!= StackElement::PrimitiveTypeEntry
) {
495 TypeEntry
*tmp
= m_database
->findType(name
);
497 ReportHandler::warning(QString("Duplicate type entry: '%1'").arg(name
));
501 if (name
.isEmpty()) {
502 m_error
= "no 'name' attribute specified";
505 switch (element
->type
) {
506 case StackElement::PrimitiveTypeEntry
:
508 QString java_name
= attributes
["java-name"];
509 QString jni_name
= attributes
["jni-name"];
510 QString preferred_conversion
= attributes
["preferred-conversion"].toLower();
511 QString preferred_java_type
= attributes
["preferred-java-type"].toLower();
513 if (java_name
.isEmpty())
515 if (jni_name
.isEmpty())
518 PrimitiveTypeEntry
*type
= new PrimitiveTypeEntry(name
);
519 type
->setCodeGeneration(m_generate
);
520 type
->setTargetLangName(java_name
);
521 type
->setJniName(jni_name
);
523 type
->setPreferredConversion(convertBoolean(preferred_conversion
, "preferred-conversion", true));
524 type
->setPreferredTargetLangType(convertBoolean(preferred_java_type
, "preferred-java-type", true));
526 element
->entry
= type
;
529 case StackElement::EnumTypeEntry
: {
530 QStringList names
= name
.split(QLatin1String("::"));
532 if (names
.size() == 1) {
533 m_current_enum
= new EnumTypeEntry(QString(), name
);
537 new EnumTypeEntry(QStringList(names
.mid(0, names
.size() - 1)).join("::"),
539 element
->entry
= m_current_enum
;
540 m_current_enum
->setCodeGeneration(m_generate
);
541 m_current_enum
->setTargetLangPackage(m_defaultPackage
);
542 m_current_enum
->setUpperBound(attributes
["upper-bound"]);
543 m_current_enum
->setLowerBound(attributes
["lower-bound"]);
544 m_current_enum
->setForceInteger(convertBoolean(attributes
["force-integer"], "force-integer", false));
545 m_current_enum
->setExtensible(convertBoolean(attributes
["extensible"], "extensible", false));
547 // put in the flags parallel...
548 if (!attributes
["flags"].isEmpty() && attributes
["flags"].toLower() != "no") {
549 FlagsTypeEntry
*ftype
= new FlagsTypeEntry("QFlags<" + name
+ ">");
550 ftype
->setOriginator(m_current_enum
);
551 ftype
->setOriginalName(attributes
["flags"]);
552 ftype
->setCodeGeneration(m_generate
);
553 QString origname
= ftype
->originalName();
555 QStringList lst
= origname
.split("::");
556 if (QStringList(lst
.mid(0, lst
.size() - 1)).join("::") != m_current_enum
->javaQualifier()) {
557 ReportHandler::warning(QString("enum %1 and flags %2 differ in qualifiers")
558 .arg(m_current_enum
->javaQualifier())
562 ftype
->setFlagsName(lst
.last());
563 m_current_enum
->setFlags(ftype
);
565 m_database
->addFlagsType(ftype
);
566 m_database
->addType(ftype
);
571 case StackElement::InterfaceTypeEntry
:
573 ObjectTypeEntry
*otype
= new ObjectTypeEntry(name
);
574 QString javaName
= attributes
["java-name"];
575 if (javaName
.isEmpty())
577 InterfaceTypeEntry
*itype
=
578 new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(javaName
));
580 if (!convertBoolean(attributes
["generate"], "generate", true))
581 itype
->setCodeGeneration(TypeEntry::GenerateForSubclass
);
583 itype
->setCodeGeneration(m_generate
);
584 otype
->setDesignatedInterface(itype
);
585 itype
->setOrigin(otype
);
586 element
->entry
= otype
;
589 case StackElement::NamespaceTypeEntry
:
590 if (element
->entry
== 0) {
591 element
->entry
= new NamespaceTypeEntry(name
);
594 case StackElement::ObjectTypeEntry
:
595 if (element
->entry
== 0) {
596 element
->entry
= new ObjectTypeEntry(name
);
599 case StackElement::ValueTypeEntry
:
601 if (element
->entry
== 0) {
602 element
->entry
= new ValueTypeEntry(name
);
605 ComplexTypeEntry
*ctype
= static_cast<ComplexTypeEntry
*>(element
->entry
);
606 ctype
->setTargetLangPackage(attributes
["package"]);
607 ctype
->setDefaultSuperclass(attributes
["default-superclass"]);
608 ctype
->setGenericClass(convertBoolean(attributes
["generic-class"], "generic-class", false));
610 if (!convertBoolean(attributes
["generate"], "generate", true))
611 element
->entry
->setCodeGeneration(TypeEntry::GenerateForSubclass
);
613 element
->entry
->setCodeGeneration(m_generate
);
615 QString javaName
= attributes
["java-name"];
616 if (!javaName
.isEmpty())
617 ctype
->setTargetLangName(javaName
);
619 // The expense policy
620 QString limit
= attributes
["expense-limit"];
621 if (!limit
.isEmpty() && limit
!= "none") {
623 ep
.limit
= limit
.toInt();
624 ep
.cost
= attributes
["expense-cost"];
625 ctype
->setExpensePolicy(ep
);
628 ctype
->setIsPolymorphicBase(convertBoolean(attributes
["polymorphic-base"], "polymorphic-base", false));
629 ctype
->setPolymorphicIdValue(attributes
["polymorphic-id-expression"]);
631 if (element
->type
== StackElement::ObjectTypeEntry
|| element
->type
== StackElement::ValueTypeEntry
) {
632 if (convertBoolean(attributes
["force-abstract"], "force-abstract", false))
633 ctype
->setTypeFlags(ctype
->typeFlags() | ComplexTypeEntry::ForceAbstract
);
634 if (convertBoolean(attributes
["deprecated"], "deprecated", false))
635 ctype
->setTypeFlags(ctype
->typeFlags() | ComplexTypeEntry::Deprecated
);
638 if (element
->type
== StackElement::InterfaceTypeEntry
||
639 element
->type
== StackElement::ValueTypeEntry
||
640 element
->type
== StackElement::ObjectTypeEntry
) {
641 if (convertBoolean(attributes
["delete-in-main-thread"], "delete-in-main-thread", false))
642 ctype
->setTypeFlags(ctype
->typeFlags() | ComplexTypeEntry::DeleteInMainThread
);
645 QString targetType
= attributes
["target-type"];
646 if (!targetType
.isEmpty() && element
->entry
->isComplex())
647 static_cast<ComplexTypeEntry
*>(element
->entry
)->setTargetType(targetType
);
649 // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
650 ctype
= ctype
->designatedInterface();
652 ctype
->setTargetLangPackage(attributes
["package"]);
661 m_database
->addType(element
->entry
);
663 ReportHandler::warning(QString("Type: %1 was rejected by typesystem").arg(name
));
665 } else if (element
->type
!= StackElement::None
) {
666 bool topLevel
= element
->type
== StackElement::Root
667 || element
->type
== StackElement::SuppressedWarning
668 || element
->type
== StackElement::Rejection
669 || element
->type
== StackElement::LoadTypesystem
670 || element
->type
== StackElement::InjectCode
671 || element
->type
== StackElement::Template
;
673 if (!topLevel
&& current
->type
== StackElement::Root
) {
674 m_error
= QString("Tag requires parent: '%1'").arg(tagName
);
678 StackElement topElement
= current
==0 ? StackElement(0) : *current
;
679 element
->entry
= topElement
.entry
;
681 QHash
<QString
, QString
> attributes
;
682 switch (element
->type
) {
683 case StackElement::Root
:
684 attributes
["package"] = QString();
685 attributes
["default-superclass"] = QString();
687 case StackElement::LoadTypesystem
:
688 attributes
["name"] = QString();
689 attributes
["generate"] = "yes";
691 case StackElement::NoNullPointers
:
692 attributes
["default-value"] = QString();
694 case StackElement::SuppressedWarning
:
695 attributes
["text"] = QString();
697 case StackElement::ReplaceDefaultExpression
:
698 attributes
["with"] = QString();
700 case StackElement::DefineOwnership
:
701 attributes
["class"] = "java";
702 attributes
["owner"] = "";
704 case StackElement::ModifyFunction
:
705 attributes
["signature"] = QString();
706 attributes
["access"] = QString();
707 attributes
["remove"] = QString();
708 attributes
["rename"] = QString();
709 attributes
["deprecated"] = QString("no");
710 attributes
["associated-to"] = QString();
711 attributes
["virtual-slot"] = QString("no");
713 case StackElement::ModifyArgument
:
714 attributes
["index"] = QString();
715 attributes
["replace-value"] = QString();
716 attributes
["invalidate-after-use"] = QString("no");
718 case StackElement::ModifyField
:
719 attributes
["name"] = QString();
720 attributes
["write"] = "true";
721 attributes
["read"] = "true";
723 case StackElement::Access
:
724 attributes
["modifier"] = QString();
726 case StackElement::Include
:
727 attributes
["file-name"] = QString();
728 attributes
["location"] = QString();
730 case StackElement::CustomMetaConstructor
:
731 attributes
["name"] = topElement
.entry
->name().toLower() + "_create";
732 attributes
["param-name"] = "copy";
734 case StackElement::CustomMetaDestructor
:
735 attributes
["name"] = topElement
.entry
->name().toLower() + "_delete";
736 attributes
["param-name"] = "copy";
738 case StackElement::ReplaceType
:
739 attributes
["modified-type"] = QString();
741 case StackElement::InjectCode
:
742 attributes
["class"] = "java";
743 attributes
["position"] = "beginning";
745 case StackElement::ConversionRule
:
746 attributes
["class"] = "";
748 case StackElement::RejectEnumValue
:
749 attributes
["name"] = "";
751 case StackElement::ArgumentMap
:
752 attributes
["index"] = "1";
753 attributes
["meta-name"] = QString();
755 case StackElement::Rename
:
756 attributes
["to"] = QString();
758 case StackElement::Rejection
:
759 attributes
["class"] = "*";
760 attributes
["function-name"] = "*";
761 attributes
["field-name"] = "*";
762 attributes
["enum-name"] = "*";
764 case StackElement::Removal
:
765 attributes
["class"] = "all";
767 case StackElement::Template
:
768 attributes
["name"] = QString();
770 case StackElement::TemplateInstanceEnum
:
771 attributes
["name"] = QString();
773 case StackElement::Replace
:
774 attributes
["from"] = QString();
775 attributes
["to"] = QString();
777 case StackElement::ReferenceCount
:
778 attributes
["action"] = QString();
779 attributes
["variable-name"] = QString();
780 attributes
["thread-safe"] = QString("no");
781 attributes
["declare-variable"] = QString();
782 attributes
["access"] = QString("private");
783 attributes
["conditional"] = QString("");
789 if (attributes
.count() > 0)
790 fetchAttributeValues(tagName
, atts
, &attributes
);
792 switch (element
->type
) {
793 case StackElement::Root
:
794 m_defaultPackage
= attributes
["package"];
795 m_defaultSuperclass
= attributes
["default-superclass"];
796 element
->type
= StackElement::Root
;
797 element
->entry
= new TypeSystemTypeEntry(m_defaultPackage
);
798 TypeDatabase::instance()->addType(element
->entry
);
800 case StackElement::LoadTypesystem
:
802 QString name
= attributes
["name"];
803 if (name
.isEmpty()) {
804 m_error
= "No typesystem name specified";
808 if (!m_database
->parseFile(name
, convertBoolean(attributes
["generate"], "generate", true))) {
809 m_error
= QString("Failed to parse: '%1'").arg(name
);
814 case StackElement::RejectEnumValue
: {
815 if (!m_current_enum
) {
816 m_error
= "<reject-enum-value> node must be used inside a <enum-type> node";
819 QString name
= attributes
["name"];
822 if (!name
.isEmpty()) {
824 m_current_enum
->addEnumValueRejection(name
);
828 case StackElement::ReplaceType
:
830 if (topElement
.type
!= StackElement::ModifyArgument
) {
831 m_error
= "Type replacement can only be specified for argument modifications";
835 if (attributes
["modified-type"].isEmpty()) {
836 m_error
= "Type replacement requires 'modified-type' attribute";
840 m_function_mods
.last().argument_mods
.last().modified_type
= attributes
["modified-type"];
843 case StackElement::ConversionRule
:
845 if (topElement
.type
!= StackElement::ModifyArgument
) {
846 m_error
= "Conversion rules can only be specified for argument modification";
850 static QHash
<QString
, TypeSystem::Language
> languageNames
;
851 if (languageNames
.isEmpty()) {
852 languageNames
["native"] = TypeSystem::NativeCode
;
853 languageNames
["shell"] = TypeSystem::ShellCode
;
857 QString languageAttribute
= attributes
["class"].toLower();
858 TypeSystem::Language lang
= languageNames
.value(languageAttribute
, TypeSystem::NoLanguage
);
859 if (lang
== TypeSystem::NoLanguage
) {
860 m_error
= QString("unsupported class attribute: '%1'").arg(languageAttribute
);
864 snip
.language
= lang
;
865 m_function_mods
.last().argument_mods
.last().conversion_rules
.append(snip
);
869 case StackElement::ModifyArgument
:
871 if (topElement
.type
!= StackElement::ModifyFunction
) {
872 m_error
= QString::fromLatin1("argument modification requires function"
873 " modification as parent, was %1")
874 .arg(topElement
.type
, 0, 16);
878 QString index
= attributes
["index"];
879 if (index
== "return")
881 else if (index
== "this")
885 int idx
= index
.toInt(&ok
);
887 m_error
= QString("Cannot convert '%1' to integer").arg(index
);
891 QString replace_value
= attributes
["replace-value"];
893 if (!replace_value
.isEmpty() && idx
!= 0) {
894 m_error
= QString("replace-value is only supported for return values (index=0).");
898 ArgumentModification argumentModification
= ArgumentModification(idx
);
899 argumentModification
.replace_value
= replace_value
;
900 argumentModification
.reset_after_use
= convertBoolean(attributes
["invalidate-after-use"], "invalidate-after-use", false);
901 m_function_mods
.last().argument_mods
.append(argumentModification
);
904 case StackElement::NoNullPointers
:
906 if (topElement
.type
!= StackElement::ModifyArgument
) {
907 m_error
= "no-null-pointer requires argument modification as parent";
911 m_function_mods
.last().argument_mods
.last().no_null_pointers
= true;
912 if (m_function_mods
.last().argument_mods
.last().index
== 0) {
913 m_function_mods
.last().argument_mods
.last().null_pointer_default_value
= attributes
["default-value"];
914 } else if (!attributes
["default-value"].isEmpty()) {
915 ReportHandler::warning("default values for null pointer guards are only effective for return values");
919 case StackElement::DefineOwnership
:
921 if (topElement
.type
!= StackElement::ModifyArgument
) {
922 m_error
= "define-ownership requires argument modification as parent";
926 static QHash
<QString
, TypeSystem::Language
> languageNames
;
927 if (languageNames
.isEmpty()) {
928 languageNames
["java"] = TypeSystem::TargetLangCode
;
929 languageNames
["shell"] = TypeSystem::ShellCode
;
932 QString classAttribute
= attributes
["class"].toLower();
933 TypeSystem::Language lang
= languageNames
.value(classAttribute
, TypeSystem::NoLanguage
);
934 if (lang
== TypeSystem::NoLanguage
) {
935 m_error
= QString("unsupported class attribute: '%1'").arg(classAttribute
);
939 static QHash
<QString
, TypeSystem::Ownership
> ownershipNames
;
940 if (ownershipNames
.isEmpty()) {
941 ownershipNames
["java"] = TypeSystem::TargetLangOwnership
;
942 ownershipNames
["c++"] = TypeSystem::CppOwnership
;
943 ownershipNames
["default"] = TypeSystem::DefaultOwnership
;
946 QString ownershipAttribute
= attributes
["owner"].toLower();
947 TypeSystem::Ownership owner
= ownershipNames
.value(ownershipAttribute
, TypeSystem::InvalidOwnership
);
948 if (owner
== TypeSystem::InvalidOwnership
) {
949 m_error
= QString("unsupported owner attribute: '%1'").arg(ownershipAttribute
);
953 m_function_mods
.last().argument_mods
.last().ownerships
[lang
] = owner
;
956 case StackElement::SuppressedWarning
:
957 if (attributes
["text"].isEmpty())
958 ReportHandler::warning("Suppressed warning with no text specified");
960 m_database
->addSuppressedWarning(attributes
["text"]);
962 case StackElement::ArgumentMap
:
964 if (!(topElement
.type
& StackElement::CodeSnipMask
)) {
965 m_error
= "Argument maps requires code injection as parent";
970 int pos
= attributes
["index"].toInt(&ok
);
972 m_error
= QString("Can't convert position '%1' to integer")
973 .arg(attributes
["position"]);
978 m_error
= QString("Argument position %1 must be a positive number").arg(pos
);
982 QString meta_name
= attributes
["meta-name"];
983 if (meta_name
.isEmpty()) {
984 ReportHandler::warning("Empty meta name in argument map");
987 if (topElement
.type
== StackElement::InjectCodeInFunction
) {
988 m_function_mods
.last().snips
.last().argumentMap
[pos
] = meta_name
;
990 ReportHandler::warning("Argument maps are only useful for injection of code "
995 case StackElement::Removal
:
997 if (topElement
.type
!= StackElement::ModifyFunction
) {
998 m_error
= "Function modification parent required";
1002 static QHash
<QString
, TypeSystem::Language
> languageNames
;
1003 if (languageNames
.isEmpty()) {
1004 languageNames
["java"] = TypeSystem::TargetLangAndNativeCode
;
1005 languageNames
["all"] = TypeSystem::All
;
1008 QString languageAttribute
= attributes
["class"].toLower();
1009 TypeSystem::Language lang
= languageNames
.value(languageAttribute
, TypeSystem::NoLanguage
);
1010 if (lang
== TypeSystem::NoLanguage
) {
1011 m_error
= QString("unsupported class attribute: '%1'").arg(languageAttribute
);
1015 m_function_mods
.last().removal
= lang
;
1018 case StackElement::Rename
:
1019 case StackElement::Access
:
1021 if (topElement
.type
!= StackElement::ModifyField
1022 && topElement
.type
!= StackElement::ModifyFunction
) {
1023 m_error
= "Function or field modification parent required";
1027 Modification
*mod
= 0;
1028 if (topElement
.type
== StackElement::ModifyFunction
)
1029 mod
= &m_function_mods
.last();
1031 mod
= &m_field_mods
.last();
1034 if (element
->type
== StackElement::Rename
) {
1035 modifier
= "rename";
1036 QString renamed_to
= attributes
["to"];
1037 if (renamed_to
.isEmpty()) {
1038 m_error
= "Rename modifier requires 'to' attribute";
1042 if (topElement
.type
== StackElement::ModifyFunction
)
1043 mod
->setRenamedTo(renamed_to
);
1045 mod
->setRenamedTo(renamed_to
);
1047 modifier
= attributes
["modifier"].toLower();
1050 if (modifier
.isEmpty()) {
1051 m_error
= "No access modification specified";
1055 static QHash
<QString
, FunctionModification::Modifiers
> modifierNames
;
1056 if (modifierNames
.isEmpty()) {
1057 modifierNames
["private"] = Modification::Private
;
1058 modifierNames
["public"] = Modification::Public
;
1059 modifierNames
["protected"] = Modification::Protected
;
1060 modifierNames
["friendly"] = Modification::Friendly
;
1061 modifierNames
["rename"] = Modification::Rename
;
1062 modifierNames
["final"] = Modification::Final
;
1063 modifierNames
["non-final"] = Modification::NonFinal
;
1066 if (!modifierNames
.contains(modifier
)) {
1067 m_error
= QString("Unknown access modifier: '%1'").arg(modifier
);
1071 mod
->modifiers
|= modifierNames
[modifier
];
1074 case StackElement::RemoveArgument
:
1075 if (topElement
.type
!= StackElement::ModifyArgument
) {
1076 m_error
= "Removing argument requires argument modification as parent";
1080 m_function_mods
.last().argument_mods
.last().removed
= true;
1084 case StackElement::ModifyField
:
1086 QString name
= attributes
["name"];
1089 FieldModification fm
;
1093 QString read
= attributes
["read"];
1094 QString write
= attributes
["write"];
1096 if (read
== "true") fm
.modifiers
|= FieldModification::Readable
;
1097 if (write
== "true") fm
.modifiers
|= FieldModification::Writable
;
1102 case StackElement::ModifyFunction
:
1104 if (!(topElement
.type
& StackElement::ComplexTypeEntryMask
)) {
1105 m_error
= QString::fromLatin1("Modify function requires complex type as parent"
1106 ", was=%1").arg(topElement
.type
, 0, 16);
1109 QString signature
= attributes
["signature"];
1111 signature
= QMetaObject::normalizedSignature(signature
.toLocal8Bit().constData());
1112 if (signature
.isEmpty()) {
1113 m_error
= "No signature for modified function";
1117 FunctionModification mod
;
1118 mod
.signature
= signature
;
1120 QString access
= attributes
["access"].toLower();
1121 if (!access
.isEmpty()) {
1122 if (access
== QLatin1String("private"))
1123 mod
.modifiers
|= Modification::Private
;
1124 else if (access
== QLatin1String("protected"))
1125 mod
.modifiers
|= Modification::Protected
;
1126 else if (access
== QLatin1String("public"))
1127 mod
.modifiers
|= Modification::Public
;
1128 else if (access
== QLatin1String("final"))
1129 mod
.modifiers
|= Modification::Final
;
1130 else if (access
== QLatin1String("non-final"))
1131 mod
.modifiers
|= Modification::NonFinal
;
1133 m_error
= QString::fromLatin1("Bad access type '%1'").arg(access
);
1138 if (convertBoolean(attributes
["deprecated"], "deprecated", false)) {
1139 mod
.modifiers
|= Modification::Deprecated
;
1142 QString remove
= attributes
["remove"].toLower();
1143 if (!remove
.isEmpty()) {
1144 if (remove
== QLatin1String("all"))
1145 mod
.removal
= TypeSystem::All
;
1146 else if (remove
== QLatin1String("java"))
1147 mod
.removal
= TypeSystem::TargetLangAndNativeCode
;
1149 m_error
= QString::fromLatin1("Bad removal type '%1'").arg(remove
);
1154 QString rename
= attributes
["rename"];
1155 if (!rename
.isEmpty()) {
1156 mod
.renamedToName
= rename
;
1157 mod
.modifiers
|= Modification::Rename
;
1160 QString association
= attributes
["associated-to"];
1161 if (!association
.isEmpty())
1162 mod
.association
= association
;
1164 mod
.modifiers
|= (convertBoolean(attributes
["virtual-slot"], "virtual-slot", false) ? Modification::VirtualSlot
: 0);
1166 m_function_mods
<< mod
;
1169 case StackElement::ReplaceDefaultExpression
:
1170 if (!(topElement
.type
& StackElement::ModifyArgument
)) {
1171 m_error
= "Replace default expression only allowed as child of argument modification";
1175 if (attributes
["with"].isEmpty()) {
1176 m_error
= "Default expression replaced with empty string. Use remove-default-expression instead.";
1180 m_function_mods
.last().argument_mods
.last().replaced_default_expression
= attributes
["with"];
1182 case StackElement::RemoveDefaultExpression
:
1183 m_function_mods
.last().argument_mods
.last().removed_default_expression
= true;
1185 case StackElement::CustomMetaConstructor
:
1186 case StackElement::CustomMetaDestructor
:
1188 CustomFunction
*func
= new CustomFunction(attributes
["name"]);
1189 func
->param_name
= attributes
["param-name"];
1190 element
->value
.customFunction
= func
;
1193 case StackElement::ReferenceCount
:
1195 if (topElement
.type
!= StackElement::ModifyArgument
) {
1196 m_error
= "reference-count must be child of modify-argument";
1201 rc
.threadSafe
= convertBoolean(attributes
["thread-safe"], "thread-safe", false);
1203 static QHash
<QString
, ReferenceCount::Action
> actions
;
1204 if (actions
.isEmpty()) {
1205 actions
["add"] = ReferenceCount::Add
;
1206 actions
["add-all"] = ReferenceCount::AddAll
;
1207 actions
["remove"] = ReferenceCount::Remove
;
1208 actions
["set"] = ReferenceCount::Set
;
1209 actions
["ignore"] = ReferenceCount::Ignore
;
1211 rc
.action
= actions
.value(attributes
["action"].toLower(), ReferenceCount::Invalid
);
1213 rc
.variableName
= attributes
["variable-name"];
1214 if (rc
.action
!= ReferenceCount::Ignore
&& rc
.variableName
.isEmpty()) {
1215 m_error
= "variable-name attribute must be specified";
1219 rc
.declareVariable
= attributes
["declare-variable"];
1220 rc
.conditional
= attributes
["conditional"];
1222 static QHash
<QString
, int> accessRights
;
1223 if (accessRights
.isEmpty()) {
1224 accessRights
["private"] = ReferenceCount::Private
;
1225 accessRights
["public"] = ReferenceCount::Public
;
1226 accessRights
["protected"] = ReferenceCount::Protected
;
1227 accessRights
["friendly"] = ReferenceCount::Friendly
;
1229 rc
.access
= accessRights
.value(attributes
["access"].toLower(), 0);
1230 if (rc
.access
== 0) {
1231 m_error
= "unrecognized access value: " + attributes
["access"];
1235 if (rc
.action
== ReferenceCount::Invalid
) {
1236 m_error
= "unrecognized value for action attribute. supported actions:";
1237 foreach (QString action
, actions
.keys())
1238 m_error
+= " " + action
;
1241 m_function_mods
.last().argument_mods
.last().referenceCounts
.append(rc
);
1244 case StackElement::InjectCode
:
1246 if (((topElement
.type
& StackElement::ComplexTypeEntryMask
) == 0)
1247 && (topElement
.type
!= StackElement::ModifyFunction
)
1248 && (topElement
.type
!= StackElement::Root
)) {
1249 m_error
= "wrong parent type for code injection";
1253 static QHash
<QString
, TypeSystem::Language
> languageNames
;
1254 if (languageNames
.isEmpty()) {
1255 languageNames
["java"] = TypeSystem::TargetLangCode
;
1256 languageNames
["native"] = TypeSystem::NativeCode
;
1257 languageNames
["shell"] = TypeSystem::ShellCode
;
1258 languageNames
["shell-declaration"] = TypeSystem::ShellDeclaration
;
1259 languageNames
["library-initializer"] = TypeSystem::PackageInitializer
;
1260 languageNames
["destructor-function"] = TypeSystem::DestructorFunction
;
1261 languageNames
["constructors"] = TypeSystem::Constructors
;
1262 languageNames
["interface"] = TypeSystem::Interface
;
1265 QString className
= attributes
["class"].toLower();
1266 if (!languageNames
.contains(className
)) {
1267 m_error
= QString("Invalid class specifier: '%1'").arg(className
);
1272 static QHash
<QString
, CodeSnip::Position
> positionNames
;
1273 if (positionNames
.isEmpty()) {
1274 positionNames
["beginning"] = CodeSnip::Beginning
;
1275 positionNames
["end"] = CodeSnip::End
;
1277 positionNames
["prototype-initialization"] = CodeSnip::PrototypeInitialization
;
1278 positionNames
["constructor-initialization"] = CodeSnip::ConstructorInitialization
;
1279 positionNames
["constructor"] = CodeSnip::Constructor
;
1282 QString position
= attributes
["position"].toLower();
1283 if (!positionNames
.contains(position
)) {
1284 m_error
= QString("Invalid position: '%1'").arg(position
);
1289 snip
.language
= languageNames
[className
];
1290 snip
.position
= positionNames
[position
];
1292 if (snip
.language
== TypeSystem::Interface
&& topElement
.type
!= StackElement::InterfaceTypeEntry
) {
1293 m_error
= "Interface code injections must be direct child of an interface type entry";
1297 if (topElement
.type
== StackElement::ModifyFunction
) {
1298 FunctionModification mod
= m_function_mods
.last();
1299 if (snip
.language
== TypeSystem::ShellDeclaration
) {
1300 m_error
= "no function implementation in shell declaration in which to inject code";
1304 m_function_mods
.last().snips
<< snip
;
1305 element
->type
= StackElement::InjectCodeInFunction
;
1306 } else if (topElement
.type
== StackElement::Root
) {
1307 ((TypeSystemTypeEntry
*) element
->entry
)->snips
<< snip
;
1309 } else if (topElement
.type
!= StackElement::Root
) {
1310 m_code_snips
<< snip
;
1314 case StackElement::Include
:
1316 QString location
= attributes
["location"].toLower();
1318 static QHash
<QString
, Include::IncludeType
> locationNames
;
1319 if (locationNames
.isEmpty()) {
1320 locationNames
["global"] = Include::IncludePath
;
1321 locationNames
["local"] = Include::LocalPath
;
1322 locationNames
["java"] = Include::TargetLangImport
;
1325 if (!locationNames
.contains(location
)) {
1326 m_error
= QString("Location not recognized: '%1'").arg(location
);
1330 Include::IncludeType loc
= locationNames
[location
];
1331 Include
inc(loc
, attributes
["file-name"]);
1333 ComplexTypeEntry
*ctype
= static_cast<ComplexTypeEntry
*>(element
->entry
);
1334 if (topElement
.type
& StackElement::ComplexTypeEntryMask
) {
1335 ctype
->setInclude(inc
);
1336 } else if (topElement
.type
== StackElement::ExtraIncludes
) {
1337 ctype
->addExtraInclude(inc
);
1339 m_error
= "Only supported parents are complex types and extra-includes";
1343 inc
= ctype
->include();
1344 IncludeList lst
= ctype
->extraIncludes();
1345 ctype
= ctype
->designatedInterface();
1347 ctype
->setExtraIncludes(lst
);
1348 ctype
->setInclude(inc
);
1352 case StackElement::Rejection
:
1354 QString cls
= attributes
["class"];
1355 QString function
= attributes
["function-name"];
1356 QString field
= attributes
["field-name"];
1357 QString enum_
= attributes
["enum-name"];
1358 if (cls
== "*" && function
== "*" && field
== "*" && enum_
== "*") {
1359 m_error
= "bad reject entry, neither 'class', 'function-name' nor "
1360 "'field' specified";
1363 m_database
->addRejection(cls
, function
, field
, enum_
);
1366 case StackElement::Template
:
1367 element
->value
.templateEntry
= new TemplateEntry(attributes
["name"]);
1369 case StackElement::TemplateInstanceEnum
:
1370 if (!(topElement
.type
& StackElement::CodeSnipMask
) &&
1371 (topElement
.type
!= StackElement::Template
) &&
1372 (topElement
.type
!= StackElement::CustomMetaConstructor
) &&
1373 (topElement
.type
!= StackElement::CustomMetaDestructor
) &&
1374 (topElement
.type
!= StackElement::ConversionRule
))
1376 m_error
= "Can only insert templates into code snippets, templates, custom-constructors, custom-destructors or conversion-rule.";
1379 element
->value
.templateInstance
= new TemplateInstance(attributes
["name"]);
1381 case StackElement::Replace
:
1382 if (topElement
.type
!= StackElement::TemplateInstanceEnum
) {
1383 m_error
= "Can only insert replace rules into insert-template.";
1386 element
->parent
->value
.templateInstance
->addReplaceRule(attributes
["from"],attributes
["to"]);
1393 current
= element
.release();
1397 TypeDatabase
*TypeDatabase::instance()
1399 static TypeDatabase
*db
= new TypeDatabase();
1403 TypeDatabase::TypeDatabase() : m_suppressWarnings(true)
1405 addType(new StringTypeEntry("QString"));
1407 StringTypeEntry
*e
= new StringTypeEntry("QLatin1String");
1408 e
->setPreferredConversion(false);
1411 e
= new StringTypeEntry("QStringRef");
1412 e
->setPreferredConversion(false);
1415 e
= new StringTypeEntry("QXmlStreamStringRef");
1416 e
->setPreferredConversion(false);
1419 addType(new CharTypeEntry("QChar"));
1421 CharTypeEntry
*c
= new CharTypeEntry("QLatin1Char");
1422 c
->setPreferredConversion(false);
1426 VariantTypeEntry
*qvariant
= new VariantTypeEntry("QVariant");
1427 qvariant
->setCodeGeneration(TypeEntry::GenerateNothing
);
1432 JObjectWrapperTypeEntry
*wrapper
= new JObjectWrapperTypeEntry("JObjectWrapper");
1433 wrapper
->setCodeGeneration(TypeEntry::GenerateNothing
);
1437 addType(new ThreadTypeEntry());
1438 addType(new VoidTypeEntry());
1440 // Predefined containers...
1441 addType(new ContainerTypeEntry("QList", ContainerTypeEntry::ListContainer
));
1442 addType(new ContainerTypeEntry("QStringList", ContainerTypeEntry::StringListContainer
));
1443 addType(new ContainerTypeEntry("QLinkedList", ContainerTypeEntry::LinkedListContainer
));
1444 addType(new ContainerTypeEntry("QVector", ContainerTypeEntry::VectorContainer
));
1445 addType(new ContainerTypeEntry("QStack", ContainerTypeEntry::StackContainer
));
1446 addType(new ContainerTypeEntry("QSet", ContainerTypeEntry::SetContainer
));
1447 addType(new ContainerTypeEntry("QMap", ContainerTypeEntry::MapContainer
));
1448 addType(new ContainerTypeEntry("QHash", ContainerTypeEntry::HashContainer
));
1449 addType(new ContainerTypeEntry("QPair", ContainerTypeEntry::PairContainer
));
1450 addType(new ContainerTypeEntry("QQueue", ContainerTypeEntry::QueueContainer
));
1451 addType(new ContainerTypeEntry("QMultiMap", ContainerTypeEntry::MultiMapContainer
));
1454 addType(new QModelIndexTypeEntry());
1456 addRemoveFunctionToTemplates(this);
1459 bool TypeDatabase::parseFile(const QString
&filename
, bool generate
)
1461 QFile
file(filename
);
1462 Q_ASSERT(file
.exists());
1463 QXmlInputSource
source(&file
);
1465 int count
= m_entries
.size();
1467 QXmlSimpleReader reader
;
1468 Handler
handler(this, generate
);
1470 reader
.setContentHandler(&handler
);
1471 reader
.setErrorHandler(&handler
);
1473 bool ok
= reader
.parse(&source
, false);
1475 int newCount
= m_entries
.size();
1477 ReportHandler::debugSparse(QString::fromLatin1("Parsed: '%1', %2 new entries")
1479 .arg(newCount
- count
));
1484 QString
PrimitiveTypeEntry::javaObjectName() const
1486 static QHash
<QString
, QString
> table
;
1487 if (table
.isEmpty()) {
1488 table
["boolean"] = "Boolean";
1489 table
["byte"] = "Byte";
1490 table
["char"] = "Character";
1491 table
["short"] = "Short";
1492 table
["int"] = "Integer";
1493 table
["long"] = "Long";
1494 table
["float"] = "Float";
1495 table
["double"] = "Double";
1497 Q_ASSERT(table
.contains(targetLangName()));
1498 return table
[targetLangName()];
1501 ContainerTypeEntry
*TypeDatabase::findContainerType(const QString
&name
)
1503 QString template_name
= name
;
1505 int pos
= name
.indexOf('<');
1507 template_name
= name
.left(pos
);
1509 TypeEntry
*type_entry
= findType(template_name
);
1510 if (type_entry
&& type_entry
->isContainer())
1511 return static_cast<ContainerTypeEntry
*>(type_entry
);
1515 PrimitiveTypeEntry
*TypeDatabase::findTargetLangPrimitiveType(const QString
&java_name
)
1517 foreach (QList
<TypeEntry
*> entries
, m_entries
.values()) {
1518 foreach (TypeEntry
*e
, entries
) {
1519 if (e
&& e
->isPrimitive()) {
1520 PrimitiveTypeEntry
*pe
= static_cast<PrimitiveTypeEntry
*>(e
);
1521 if (pe
->targetLangName() == java_name
&& pe
->preferredConversion())
1530 IncludeList
TypeDatabase::extraIncludes(const QString
&className
)
1532 ComplexTypeEntry
*typeEntry
= findComplexType(className
);
1534 return typeEntry
->extraIncludes();
1536 return IncludeList();
1541 QString
Include::toString() const
1543 if (type
== IncludePath
)
1544 return "#include <" + name
+ '>';
1545 else if (type
== LocalPath
)
1546 return "#include \"" + name
+ "\"";
1548 return "import " + name
+ ";";
1551 QString
Modification::accessModifierString() const
1553 if (isPrivate()) return "private";
1554 if (isProtected()) return "protected";
1555 if (isPublic()) return "public";
1556 if (isFriendly()) return "friendly";
1560 FunctionModificationList
ComplexTypeEntry::functionModifications(const QString
&signature
) const
1562 FunctionModificationList lst
;
1563 for (int i
=0; i
<m_function_mods
.count(); ++i
) {
1564 FunctionModification mod
= m_function_mods
.at(i
);
1565 if (mod
.signature
== signature
) {
1573 FieldModification
ComplexTypeEntry::fieldModification(const QString
&name
) const
1575 for (int i
=0; i
<m_field_mods
.size(); ++i
)
1576 if (m_field_mods
.at(i
).name
== name
)
1577 return m_field_mods
.at(i
);
1578 FieldModification mod
;
1580 mod
.modifiers
= FieldModification::Readable
| FieldModification::Writable
;
1584 QString
ContainerTypeEntry::javaPackage() const
1586 if (m_type
== PairContainer
)
1587 return "com.trolltech.qt";
1591 QString
ContainerTypeEntry::targetLangName() const
1595 case StringListContainer
: return "List";
1596 case ListContainer
: return "List";
1597 case LinkedListContainer
: return "LinkedList";
1598 case VectorContainer
: return "List";
1599 case StackContainer
: return "Stack";
1600 case QueueContainer
: return "Queue";
1601 case SetContainer
: return "Set";
1602 case MapContainer
: return "SortedMap";
1603 case MultiMapContainer
: return "SortedMap";
1604 case HashContainer
: return "HashMap";
1605 // case MultiHashCollectio: return "MultiHash";
1606 case PairContainer
: return "QPair";
1608 qWarning("bad type... %d", m_type
);
1614 QString
ContainerTypeEntry::qualifiedCppName() const
1616 if (m_type
== StringListContainer
)
1617 return "QStringList";
1618 return ComplexTypeEntry::qualifiedCppName();
1621 QString
EnumTypeEntry::javaQualifier() const
1623 TypeEntry
*te
= TypeDatabase::instance()->findType(m_qualifier
);
1625 return te
->targetLangName();
1630 QString
EnumTypeEntry::jniName() const
1635 QString
FlagsTypeEntry::jniName() const
1640 void EnumTypeEntry::addEnumValueRedirection(const QString
&rejected
, const QString
&usedValue
)
1642 m_enum_redirections
<< EnumValueRedirection(rejected
, usedValue
);
1645 QString
EnumTypeEntry::enumValueRedirection(const QString
&value
) const
1647 for (int i
=0; i
<m_enum_redirections
.size(); ++i
)
1648 if (m_enum_redirections
.at(i
).rejected
== value
)
1649 return m_enum_redirections
.at(i
).used
;
1653 QString
FlagsTypeEntry::qualifiedTargetLangName() const
1655 return javaPackage() + "." + m_enum
->javaQualifier() + "." + targetLangName();
1659 void TypeDatabase::addRejection(const QString
&class_name
, const QString
&function_name
,
1660 const QString
&field_name
, const QString
&enum_name
)
1663 r
.class_name
= class_name
;
1664 r
.function_name
= function_name
;
1665 r
.field_name
= field_name
;
1666 r
.enum_name
= enum_name
;
1671 bool TypeDatabase::isClassRejected(const QString
&class_name
)
1673 if (!m_rebuild_classes
.isEmpty())
1674 return !m_rebuild_classes
.contains(class_name
);
1676 foreach (const TypeRejection
&r
, m_rejections
)
1677 if (r
.class_name
== class_name
&& r
.function_name
== "*" && r
.field_name
== "*" && r
.enum_name
== "*") {
1683 bool TypeDatabase::isEnumRejected(const QString
&class_name
, const QString
&enum_name
)
1685 foreach (const TypeRejection
&r
, m_rejections
) {
1686 if (r
.enum_name
== enum_name
1687 && (r
.class_name
== class_name
|| r
.class_name
== "*")) {
1695 bool TypeDatabase::isFunctionRejected(const QString
&class_name
, const QString
&function_name
)
1697 foreach (const TypeRejection
&r
, m_rejections
)
1698 if (r
.function_name
== function_name
&&
1699 (r
.class_name
== class_name
|| r
.class_name
== "*"))
1705 bool TypeDatabase::isFieldRejected(const QString
&class_name
, const QString
&field_name
)
1707 foreach (const TypeRejection
&r
, m_rejections
)
1708 if (r
.field_name
== field_name
&&
1709 (r
.class_name
== class_name
|| r
.class_name
== "*"))
1714 FlagsTypeEntry
*TypeDatabase::findFlagsType(const QString
&name
) const
1716 FlagsTypeEntry
*fte
= (FlagsTypeEntry
*) findType(name
);
1717 return fte
? fte
: (FlagsTypeEntry
*) m_flags_entries
.value(name
);
1720 QString
TypeDatabase::globalNamespaceClassName(const TypeEntry
* /*entry*/) {
1721 return QLatin1String("Global");
1726 * The Visual Studio 2002 compiler doesn't support these symbols,
1727 * which our typedefs unforntuatly expand to.
1729 QString
fixCppTypeName(const QString
&name
)
1731 if (name
== "long long") return "qint64";
1732 else if (name
== "unsigned long long") return "quint64";
1736 QString
formattedCodeHelper(QTextStream
&s
, Indentor
&indentor
, QStringList
&lines
) {
1737 bool multilineComment
= false;
1738 bool lastEmpty
= true;
1740 while (!lines
.isEmpty()) {
1741 const QString line
= lines
.takeFirst().trimmed();
1742 if (line
.isEmpty()) {
1750 if (line
.startsWith("/*"))
1751 multilineComment
= true;
1753 if (multilineComment
) {
1755 if (line
.startsWith("*"))
1758 if (line
.endsWith("*/"))
1759 multilineComment
= false;
1760 } else if (line
.startsWith("}")) {
1762 } else if (line
.endsWith("}")) {
1763 s
<< indentor
<< line
<< endl
;
1765 } else if(line
.endsWith("{")) {
1766 s
<< indentor
<< line
<< endl
;
1769 Indentation
indent(indentor
);
1770 tmp
= formattedCodeHelper(s
, indentor
, lines
);
1772 if (!tmp
.isNull()) {
1773 s
<< indentor
<< tmp
<< endl
;
1779 if (!lastLine
.isEmpty() &&
1780 !lastLine
.endsWith(";") &&
1781 !line
.startsWith("@") &&
1782 !line
.startsWith("//") &&
1783 !lastLine
.startsWith("//") &&
1784 !lastLine
.endsWith("}") &&
1785 !line
.startsWith("{"))
1795 QTextStream
&CodeSnip::formattedCode(QTextStream
&s
, Indentor
&indentor
) const
1797 QStringList
lst(code().split("\n"));
1798 while (!lst
.isEmpty()) {
1799 QString tmp
= formattedCodeHelper(s
, indentor
, lst
);
1800 if (!tmp
.isNull()) {
1801 s
<< indentor
<< tmp
<< endl
;
1808 QString
TemplateInstance::expandCode() const{
1809 TemplateEntry
*templateEntry
= TypeDatabase::instance()->findTemplate(m_name
);
1811 QString res
= templateEntry
->code();
1812 foreach(QString key
, replaceRules
.keys()){
1813 res
.replace(key
, replaceRules
[key
]);
1815 return "// TEMPLATE - " + m_name
+ " - START" + res
+ "// TEMPLATE - " + m_name
+ " - END";
1818 ReportHandler::warning("insert-template referring to non-existing template '" + m_name
+ "'");
1824 QString
CodeSnipAbstract::code() const{
1826 foreach(CodeSnipFragment
*codeFrag
, codeList
){
1827 res
.append(codeFrag
->code());
1832 QString
CodeSnipFragment::code() const{
1834 return m_instance
->expandCode();
1839 QString
FunctionModification::toString() const
1841 QString str
= signature
+ QLatin1String("->");
1842 if (modifiers
& AccessModifierMask
) {
1843 switch (modifiers
& AccessModifierMask
) {
1844 case Private
: str
+= QLatin1String("private"); break;
1845 case Protected
: str
+= QLatin1String("protected"); break;
1846 case Public
: str
+= QLatin1String("public"); break;
1847 case Friendly
: str
+= QLatin1String("friendly"); break;
1851 if (modifiers
& Final
) str
+= QLatin1String("final");
1852 if (modifiers
& NonFinal
) str
+= QLatin1String("non-final");
1854 if (modifiers
& Readable
) str
+= QLatin1String("readable");
1855 if (modifiers
& Writable
) str
+= QLatin1String("writable");
1857 if (modifiers
& CodeInjection
) {
1858 foreach (CodeSnip s
, snips
) {
1859 str
+= QLatin1String("\n//code injection:\n");
1864 if (modifiers
& Rename
) str
+= QLatin1String("renamed:") + renamedToName
;
1866 if (modifiers
& Deprecated
) str
+= QLatin1String("deprecate");
1868 if (modifiers
& ReplaceExpression
) str
+= QLatin1String("replace-expression");
1873 static void removeFunction(ComplexTypeEntry
*e
, const char *signature
)
1875 FunctionModification mod
;
1876 mod
.signature
= QMetaObject::normalizedSignature(signature
);
1877 mod
.removal
= TypeSystem::All
;
1879 e
->addFunctionModification(mod
);
1885 static void injectCode(ComplexTypeEntry
*e
,
1886 const char *signature
,
1887 const QByteArray
&code
,
1888 const ArgumentMap
&args
)
1891 snip
.language
= TypeSystem::NativeCode
;
1892 snip
.position
= CodeSnip::Beginning
;
1893 snip
.addCode(QString::fromLatin1(code
));
1894 snip
.argumentMap
= args
;
1896 FunctionModification mod
;
1897 mod
.signature
= QMetaObject::normalizedSignature(signature
);
1899 mod
.modifiers
= Modification::CodeInjection
;
1900 e
->addFunctionModification(mod
);
1904 static void addRemoveFunctionToTemplates(TypeDatabase
*db
)
1906 ContainerTypeEntry
*qvector
= db
->findContainerType(QLatin1String("QVector"));
1907 removeFunction(qvector
, "constData() const");
1908 removeFunction(qvector
, "data() const");
1909 removeFunction(qvector
, "data()");
1910 removeFunction(qvector
, "first()");
1911 removeFunction(qvector
, "last()");
1912 removeFunction(qvector
, "operator[](int)");
1913 removeFunction(qvector
, "operator[](int) const");
1914 removeFunction(qvector
, "operator=(QVector<T>)");
1916 ContainerTypeEntry
*qlist
= db
->findContainerType(QLatin1String("QList"));
1917 removeFunction(qlist
, "constData() const");
1918 removeFunction(qlist
, "data() const");
1919 removeFunction(qlist
, "data()");
1920 removeFunction(qlist
, "back()");
1921 removeFunction(qlist
, "front()");
1922 removeFunction(qlist
, "first()");
1923 removeFunction(qlist
, "last()");
1924 removeFunction(qlist
, "operator[](int)");
1925 removeFunction(qlist
, "operator[](int) const");
1926 removeFunction(qlist
, "operator=(QList<T>)");
1928 ContainerTypeEntry
*qqueue
= db
->findContainerType(QLatin1String("QQueue"));
1929 removeFunction(qqueue
, "head() const");
1931 // QtScript: The next part is Java-specific, skip it for now...
1935 args1
[1] = QLatin1String("$1");
1936 ArgumentMap args2
= args1
;
1937 args2
[2] = QLatin1String("$2");
1940 "\nif ($1 >= __qt_this->size() || $1 < 0) {"
1941 "\n __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
1942 "\n QString::fromLatin1(\"Accessing container of size %3 at %4\")"
1943 "\n .arg(__qt_this->size()).arg($1).toLatin1());"
1947 QByteArray code_with_return
= QByteArray(code
).replace("return;", "return 0;");
1949 QByteArray code_index_length
=
1950 "\nif ($1 < 0 || $2 < 0 || ($1 + $2) >= __qt_this->size()) {"
1951 "\n __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
1952 "\n QString::fromLatin1(\"Accessing container of size %3 from %4 to %5\")"
1953 "\n .arg(__qt_this->size()).arg($1).arg($1+$2).toLatin1());"
1957 QByteArray code_non_empty
=
1958 "\nif (__qt_this->isEmpty()) {"
1959 "\n __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
1960 "\n QString::fromLatin1(\"Accessing empty container...\").toLatin1());"
1964 QByteArray code_two_indices
=
1965 "\nif ($1 < 0 || $2 < 0 || $1 >= __qt_this->size() || $2 >= __qt_this->size()) {"
1966 "\n __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
1967 "\n QString::fromLatin1(\"Accessing container of size %3 from %4 to %5\")"
1968 "\n .arg(__qt_this->size()).arg($1).arg($1+$2).toLatin1());"
1972 { // QVector safty...
1973 injectCode(qvector
, "at(int) const", code_with_return
, args1
);
1974 injectCode(qvector
, "replace(int,T)", code
, args1
);
1975 injectCode(qvector
, "remove(int)", code
, args1
);
1976 injectCode(qvector
, "remove(int, int)", code_index_length
, args2
);
1977 injectCode(qvector
, "pop_back()", code_non_empty
, ArgumentMap());
1978 injectCode(qvector
, "pop_front()", code_non_empty
, ArgumentMap());
1982 injectCode(qlist
, "at(int) const", code_with_return
, args1
);
1983 injectCode(qlist
, "replace(int, T)", code
, args1
);
1984 injectCode(qlist
, "pop_back()", code_non_empty
, ArgumentMap());
1985 injectCode(qlist
, "pop_front()", code_non_empty
, ArgumentMap());
1986 injectCode(qlist
, "swap(int, int)", code_two_indices
, args2
);
1987 injectCode(qlist
, "move(int, int)", code_two_indices
, args2
);
1988 injectCode(qlist
, "removeAt(int)", code
, args1
);
1989 injectCode(qlist
, "takeAt(int)", code_with_return
, args1
);