comparison generator/typesystem.cpp @ 1:e78566595089

initial import
author mandel
date Mon, 11 May 2009 16:01:50 +0000
parents
children 0a29ce1ae854
comparison
equal deleted inserted replaced
0:36fb74dc547d 1:e78566595089
1 /****************************************************************************
2 **
3 ** Copyright (C) 1992-2008 Nokia. All rights reserved.
4 **
5 ** This file is part of Qt Jambi.
6 **
7 ** * Commercial Usage
8 * Licensees holding valid Qt Commercial licenses may use this file in
9 * accordance with the Qt Commercial License Agreement provided with the
10 * Software or, alternatively, in accordance with the terms contained in
11 * a written agreement between you and Nokia.
12 *
13 *
14 * GNU General Public License Usage
15 * Alternatively, this file may be used under the terms of the GNU
16 * General Public License versions 2.0 or 3.0 as published by the Free
17 * Software Foundation and appearing in the file LICENSE.GPL included in
18 * the packaging of this file. Please review the following information
19 * to ensure GNU General Public Licensing requirements will be met:
20 * http://www.fsf.org/licensing/licenses/info/GPLv2.html and
21 * http://www.gnu.org/copyleft/gpl.html. In addition, as a special
22 * exception, Nokia gives you certain additional rights. These rights
23 * are described in the Nokia Qt GPL Exception version 1.2, included in
24 * the file GPL_EXCEPTION.txt in this package.
25 *
26 * Qt for Windows(R) Licensees
27 * As a special exception, Nokia, as the sole copyright holder for Qt
28 * Designer, grants users of the Qt/Eclipse Integration plug-in the
29 * right for the Qt/Eclipse Integration to link to functionality
30 * provided by Qt Designer and its related libraries.
31 *
32 *
33 * If you are unsure which license is appropriate for your use, please
34 * contact the sales department at qt-sales@nokia.com.
35
36 **
37 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
38 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
39 **
40 ****************************************************************************/
41
42 #include "typesystem.h"
43 #include "generator.h"
44
45 #include "customtypes.h"
46
47 #include <reporthandler.h>
48
49 #include <QtXml>
50
51 QString strings_Object = QLatin1String("Object");
52 QString strings_String = QLatin1String("string");
53 QString strings_Thread = QLatin1String("Thread");
54 QString strings_char = QLatin1String("char");
55 QString strings_java_lang = QLatin1String("java.lang");
56 QString strings_jchar = QLatin1String("jchar");
57 QString strings_jobject = QLatin1String("jobject");
58
59 static void addRemoveFunctionToTemplates(TypeDatabase *db);
60
61 class StackElement
62 {
63 public:
64 enum ElementType {
65 None = 0x0,
66
67 // Type tags (0x1, ... , 0xff)
68 ObjectTypeEntry = 0x1,
69 ValueTypeEntry = 0x2,
70 InterfaceTypeEntry = 0x3,
71 NamespaceTypeEntry = 0x4,
72 ComplexTypeEntryMask = 0xf,
73
74 // Non-complex type tags (0x10, 0x20, ... , 0xf0)
75 PrimitiveTypeEntry = 0x10,
76 EnumTypeEntry = 0x20,
77 TypeEntryMask = 0xff,
78
79 // Simple tags (0x100, 0x200, ... , 0xf00)
80 ExtraIncludes = 0x100,
81 Include = 0x200,
82 ModifyFunction = 0x300,
83 ModifyField = 0x400,
84 Root = 0x500,
85 CustomMetaConstructor = 0x600,
86 CustomMetaDestructor = 0x700,
87 ArgumentMap = 0x800,
88 SuppressedWarning = 0x900,
89 Rejection = 0xa00,
90 LoadTypesystem = 0xb00,
91 RejectEnumValue = 0xc00,
92 Template = 0xd00,
93 TemplateInstanceEnum = 0xe00,
94 Replace = 0xf00,
95 SimpleMask = 0xf00,
96 // qtd stuff
97 AddClass = 0x1100,
98
99 // Code snip tags (0x1000, 0x2000, ... , 0xf000)
100 InjectCode = 0x1000,
101 InjectCodeInFunction = 0x2000,
102 CodeSnipMask = 0xf000,
103
104 // Function modifier tags (0x010000, 0x020000, ... , 0xf00000)
105 Access = 0x010000,
106 Removal = 0x020000,
107 Rename = 0x040000,
108 ModifyArgument = 0x080000,
109 FunctionModifiers = 0xff0000,
110 StoreResult = 0x110000,
111
112 // Argument modifier tags (0x01000000 ... 0xf0000000)
113 ConversionRule = 0x01000000,
114 ReplaceType = 0x02000000,
115 ReplaceDefaultExpression = 0x04000000,
116 RemoveArgument = 0x08000000,
117 DefineOwnership = 0x10000000,
118 RemoveDefaultExpression = 0x20000000,
119 NoNullPointers = 0x40000000,
120 ReferenceCount = 0x80000000,
121 ArgumentModifiers = 0xff000000
122
123 };
124
125 StackElement(StackElement *p) : entry(0), type(None), parent(p){ }
126
127 TypeEntry *entry;
128 ElementType type;
129 StackElement *parent;
130
131 union {
132 TemplateInstance *templateInstance;
133 TemplateEntry *templateEntry;
134 CustomFunction *customFunction;
135 } value;
136 };
137
138 class Handler : public QXmlDefaultHandler
139 {
140 public:
141 Handler(TypeDatabase *database, bool generate)
142 : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
143 {
144 m_current_enum = 0;
145 current = 0;
146
147 tagNames["rejection"] = StackElement::Rejection;
148 tagNames["primitive-type"] = StackElement::PrimitiveTypeEntry;
149 tagNames["object-type"] = StackElement::ObjectTypeEntry;
150 tagNames["value-type"] = StackElement::ValueTypeEntry;
151 tagNames["interface-type"] = StackElement::InterfaceTypeEntry;
152 tagNames["namespace-type"] = StackElement::NamespaceTypeEntry;
153 tagNames["enum-type"] = StackElement::EnumTypeEntry;
154 tagNames["extra-includes"] = StackElement::ExtraIncludes;
155 tagNames["include"] = StackElement::Include;
156 tagNames["inject-code"] = StackElement::InjectCode;
157 tagNames["modify-function"] = StackElement::ModifyFunction;
158 tagNames["modify-field"] = StackElement::ModifyField;
159 tagNames["access"] = StackElement::Access;
160 tagNames["remove"] = StackElement::Removal;
161 tagNames["rename"] = StackElement::Rename;
162 tagNames["typesystem"] = StackElement::Root;
163 tagNames["custom-constructor"] = StackElement::CustomMetaConstructor;
164 tagNames["custom-destructor"] = StackElement::CustomMetaDestructor;
165 tagNames["argument-map"] = StackElement::ArgumentMap;
166 tagNames["suppress-warning"] = StackElement::SuppressedWarning;
167 tagNames["load-typesystem"] = StackElement::LoadTypesystem;
168 tagNames["define-ownership"] = StackElement::DefineOwnership;
169 tagNames["replace-default-expression"] = StackElement::ReplaceDefaultExpression;
170 tagNames["reject-enum-value"] = StackElement::RejectEnumValue;
171 tagNames["replace-type"] = StackElement::ReplaceType;
172 tagNames["conversion-rule"] = StackElement::ConversionRule;
173 tagNames["modify-argument"] = StackElement::ModifyArgument;
174 tagNames["remove-argument"] = StackElement::RemoveArgument;
175 tagNames["remove-default-expression"] = StackElement::RemoveDefaultExpression;
176 tagNames["template"] = StackElement::Template;
177 tagNames["insert-template"] = StackElement::TemplateInstanceEnum;
178 tagNames["replace"] = StackElement::Replace;
179 tagNames["no-null-pointer"] = StackElement::NoNullPointers;
180 tagNames["reference-count"] = StackElement::ReferenceCount;
181 // qtd
182 tagNames["add-class"] = StackElement::AddClass;
183 tagNames["store-result"] = StackElement::StoreResult;
184 }
185
186 bool startElement(const QString &namespaceURI, const QString &localName,
187 const QString &qName, const QXmlAttributes &atts);
188 bool endElement(const QString &namespaceURI, const QString &localName, const QString &qName);
189
190 QString errorString() const { return m_error; }
191 bool error(const QXmlParseException &exception);
192 bool fatalError(const QXmlParseException &exception);
193 bool warning(const QXmlParseException &exception);
194
195 bool characters(const QString &ch);
196
197 private:
198 void fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
199 QHash<QString, QString> *acceptedAttributes);
200
201 bool importFileElement(const QXmlAttributes &atts);
202 bool convertBoolean(const QString &, const QString &, bool);
203
204 TypeDatabase *m_database;
205 StackElement* current;
206 QString m_defaultPackage;
207 QString m_defaultSuperclass;
208 QString m_error;
209 TypeEntry::CodeGeneration m_generate;
210
211 EnumTypeEntry *m_current_enum;
212
213 CodeSnipList m_code_snips;
214 FunctionModificationList m_function_mods;
215 FieldModificationList m_field_mods;
216
217 QHash<QString, StackElement::ElementType> tagNames;
218 };
219
220 bool Handler::error(const QXmlParseException &e)
221 {
222 qWarning("Error: line=%d, column=%d, message=%s\n",
223 e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
224 return false;
225 }
226
227 bool Handler::fatalError(const QXmlParseException &e)
228 {
229 qWarning("Fatal error: line=%d, column=%d, message=%s\n",
230 e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
231
232 return false;
233 }
234
235 bool Handler::warning(const QXmlParseException &e)
236 {
237 qWarning("Warning: line=%d, column=%d, message=%s\n",
238 e.lineNumber(), e.columnNumber(), qPrintable(e.message()));
239
240 return false;
241 }
242
243 void Handler::fetchAttributeValues(const QString &name, const QXmlAttributes &atts,
244 QHash<QString, QString> *acceptedAttributes)
245 {
246 Q_ASSERT(acceptedAttributes != 0);
247
248 for (int i=0; i<atts.length(); ++i) {
249 QString key = atts.localName(i).toLower();
250 QString val = atts.value(i);
251
252 if (!acceptedAttributes->contains(key)) {
253 ReportHandler::warning(QString("Unknown attribute for '%1': '%2'").arg(name).arg(key));
254 } else {
255 (*acceptedAttributes)[key] = val;
256 }
257 }
258 }
259
260 bool Handler::endElement(const QString &, const QString &localName, const QString &)
261 {
262 QString tagName = localName.toLower();
263 if(tagName == "import-file")
264 return true;
265
266 if (!current)
267 return true;
268
269 switch (current->type) {
270 case StackElement::ObjectTypeEntry:
271 case StackElement::ValueTypeEntry:
272 case StackElement::InterfaceTypeEntry:
273 case StackElement::NamespaceTypeEntry:
274 {
275 ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(current->entry);
276 centry->setFunctionModifications(m_function_mods);
277 centry->setFieldModifications(m_field_mods);
278 centry->setCodeSnips(m_code_snips);
279
280 if (centry->designatedInterface()) {
281 centry->designatedInterface()->setCodeSnips(m_code_snips);
282 centry->designatedInterface()->setFunctionModifications(m_function_mods);
283 }
284 m_code_snips = CodeSnipList();
285 m_function_mods = FunctionModificationList();
286 m_field_mods = FieldModificationList();
287 }
288 break;
289 case StackElement::CustomMetaConstructor:
290 {
291 current->entry->setCustomConstructor(*current->value.customFunction);
292 delete current->value.customFunction;
293 }
294 break;
295 case StackElement::CustomMetaDestructor:
296 {
297 current->entry->setCustomDestructor(*current->value.customFunction);
298 delete current->value.customFunction;
299 }
300 break;
301 case StackElement::EnumTypeEntry:
302 m_current_enum = 0;
303 break;
304 case StackElement::Template:
305 m_database->addTemplate(current->value.templateEntry);
306 break;
307 case StackElement::TemplateInstanceEnum:
308 if(current->parent->type == StackElement::InjectCode){
309 m_code_snips.last().addTemplateInstance(current->value.templateInstance);
310 }else if(current->parent->type == StackElement::Template){
311 current->parent->value.templateEntry->addTemplateInstance(current->value.templateInstance);
312 }else if(current->parent->type == StackElement::CustomMetaConstructor || current->parent->type == StackElement::CustomMetaConstructor){
313 current->parent->value.customFunction->addTemplateInstance(current->value.templateInstance);
314 }else if(current->parent->type == StackElement::ConversionRule){
315 m_function_mods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(current->value.templateInstance);
316 }else if(current->parent->type == StackElement::InjectCodeInFunction){
317 m_function_mods.last().snips.last().addTemplateInstance(current->value.templateInstance);
318 }
319 break;
320 default:
321 break;
322 }
323
324 StackElement *child = current;
325 current=current->parent;
326 delete(child);
327
328 return true;
329 }
330
331 bool Handler::characters(const QString &ch)
332 {
333 if(current->type == StackElement::Template){
334 current->value.templateEntry->addCode(ch);
335 return true;
336 }
337
338 if (current->type == StackElement::CustomMetaConstructor || current->type == StackElement::CustomMetaDestructor){
339 current->value.customFunction->addCode(ch);
340 return true;
341 }
342
343 if (current->type == StackElement::ConversionRule){
344 m_function_mods.last().argument_mods.last().conversion_rules.last().addCode(ch);
345 return true;
346 }
347
348 if (current->parent){
349 if ((current->type & StackElement::CodeSnipMask) != 0) {
350 switch (current->parent->type) {
351 case StackElement::Root:
352 ((TypeSystemTypeEntry *) current->parent->entry)->snips.last().addCode(ch);
353 break;
354 case StackElement::ModifyFunction:
355 m_function_mods.last().snips.last().addCode(ch);
356 break;
357 case StackElement::NamespaceTypeEntry:
358 case StackElement::ObjectTypeEntry:
359 case StackElement::ValueTypeEntry:
360 case StackElement::InterfaceTypeEntry:
361 m_code_snips.last().addCode(ch);
362 break;
363 default:
364 Q_ASSERT(false);
365 };
366 return true;
367 }
368 }
369
370 return true;
371 }
372
373 bool Handler::importFileElement(const QXmlAttributes &atts)
374 {
375 QString fileName = atts.value("name");
376 if(fileName.isEmpty()){
377 m_error = "Required attribute 'name' missing for include-file tag.";
378 return false;
379 }
380
381 QFile file(fileName);
382 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
383 file.setFileName(":/trolltech/generator/" + fileName);
384 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
385 m_error = QString("Could not open file: '%1'").arg(fileName);
386 return false;
387 }
388 }
389
390 QString quoteFrom = atts.value("quote-after-line");
391 bool foundFromOk = quoteFrom.isEmpty();
392 bool from = quoteFrom.isEmpty();
393
394 QString quoteTo = atts.value("quote-before-line");
395 bool foundToOk = quoteTo.isEmpty();
396 bool to = true;
397
398 QTextStream in(&file);
399 while (!in.atEnd()) {
400 QString line = in.readLine();
401 if(from && to && line.contains(quoteTo)) {
402 to = false;
403 foundToOk = true;
404 break;
405 }
406 if(from && to)
407 characters(line + "\n");
408 if(!from && line.contains(quoteFrom)) {
409 from = true;
410 foundFromOk = true;
411 }
412 }
413 if(!foundFromOk || !foundToOk){
414 QString fromError = QString("Could not find quote-after-line='%1' in file '%2'.").arg(quoteFrom).arg(fileName);
415 QString toError = QString("Could not find quote-before-line='%1' in file '%2'.").arg(quoteTo).arg(fileName);
416
417 if(!foundToOk)
418 m_error = toError;
419 if(!foundFromOk)
420 m_error = fromError;
421 if(!foundFromOk && !foundToOk)
422 m_error = fromError + " " + toError;
423 return false;
424 }
425
426 return true;
427 }
428
429 bool Handler::convertBoolean(const QString &_value, const QString &attributeName, bool defaultValue)
430 {
431 QString value = _value.toLower();
432 if (value == "true" || value == "yes") {
433 return true;
434 } else if (value == "false" || value == "no") {
435 return false;
436 } else {
437 QString warn = QString("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
438 .arg(value).arg(attributeName).arg(defaultValue ? "yes" : "no");
439
440 ReportHandler::warning(warn);
441 return defaultValue;
442 }
443 }
444
445 bool Handler::startElement(const QString &, const QString &n,
446 const QString &, const QXmlAttributes &atts)
447 {
448 QString tagName = n.toLower();
449 if(tagName == "import-file"){
450 return importFileElement(atts);
451 }
452
453 StackElement *element = new StackElement(current);
454
455 if (!tagNames.contains(tagName)) {
456 m_error = QString("Unknown tag name: '%1'").arg(tagName);
457 return false;
458 }
459
460 element->type = tagNames[tagName];
461 if (element->type & StackElement::TypeEntryMask) {
462 if (current->type != StackElement::Root) {
463 m_error = "Nested types not supported";
464 return false;
465 }
466
467 QHash<QString, QString> attributes;
468 attributes["name"] = QString();
469
470 switch (element->type) {
471 case StackElement::PrimitiveTypeEntry:
472 attributes["java-name"] = QString();
473 attributes["jni-name"] = QString();
474 attributes["preferred-conversion"] = "yes";
475 attributes["preferred-java-type"] = "yes";
476 break;
477 case StackElement::EnumTypeEntry:
478 attributes["flags"] = "no";
479 attributes["upper-bound"] = QString();
480 attributes["lower-bound"] = QString();
481 attributes["force-integer"] = "no";
482 attributes["extensible"] = "no";
483
484 break;
485
486 case StackElement::ObjectTypeEntry:
487 case StackElement::ValueTypeEntry:
488 attributes["force-abstract"] = QString("no");
489 attributes["deprecated"] = QString("no");
490 attributes["wrap"] = QString();
491 // fall throooough
492 case StackElement::InterfaceTypeEntry:
493 attributes["default-superclass"] = m_defaultSuperclass;
494 attributes["polymorphic-id-expression"] = QString();
495 attributes["delete-in-main-thread"] = QString("no");
496 // fall through
497 case StackElement::NamespaceTypeEntry:
498 attributes["java-name"] = QString();
499 attributes["package"] = m_defaultPackage;
500 attributes["expense-cost"] = "1";
501 attributes["expense-limit"] = "none";
502 attributes["polymorphic-base"] = QString("no");
503 attributes["generate"] = QString("yes");
504 attributes["target-type"] = QString();
505 attributes["generic-class"] = QString("no");
506 break;
507 default:
508 ; // nada
509 };
510
511 fetchAttributeValues(tagName, atts, &attributes);
512
513 QString name = attributes["name"];
514
515 // We need to be able to have duplicate primitive type entries, or it's not possible to
516 // cover all primitive java types (which we need to do in order to support fake
517 // meta objects)
518 if (element->type != StackElement::PrimitiveTypeEntry) {
519 TypeEntry *tmp = m_database->findType(name);
520 if (tmp != 0) {
521 ReportHandler::warning(QString("Duplicate type entry: '%1'").arg(name));
522 }
523 }
524
525 if (name.isEmpty()) {
526 m_error = "no 'name' attribute specified";
527 return false;
528 }
529 switch (element->type) {
530 case StackElement::PrimitiveTypeEntry:
531 {
532 QString java_name = attributes["java-name"];
533 QString jni_name = attributes["jni-name"];
534 QString preferred_conversion = attributes["preferred-conversion"].toLower();
535 QString preferred_java_type = attributes["preferred-java-type"].toLower();
536
537 if (java_name.isEmpty())
538 java_name = name;
539 if (jni_name.isEmpty())
540 jni_name = name;
541
542 PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name);
543 type->setCodeGeneration(m_generate);
544 type->setTargetLangName(java_name);
545 type->setJniName(jni_name);
546
547 type->setPreferredConversion(convertBoolean(preferred_conversion, "preferred-conversion", true));
548 type->setPreferredTargetLangType(convertBoolean(preferred_java_type, "preferred-java-type", true));
549
550 element->entry = type;
551 }
552 break;
553 case StackElement::EnumTypeEntry: {
554 QStringList names = name.split(QLatin1String("::"));
555
556 if (names.size() == 1) {
557 m_current_enum = new EnumTypeEntry(QString(), name);
558 }
559 else
560 m_current_enum =
561 new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join("::"),
562 names.last());
563 element->entry = m_current_enum;
564 m_current_enum->setCodeGeneration(m_generate);
565 m_current_enum->setTargetLangPackage(m_defaultPackage);
566 m_current_enum->setUpperBound(attributes["upper-bound"]);
567 m_current_enum->setLowerBound(attributes["lower-bound"]);
568 m_current_enum->setForceInteger(convertBoolean(attributes["force-integer"], "force-integer", false));
569 m_current_enum->setExtensible(convertBoolean(attributes["extensible"], "extensible", false));
570
571 // put in the flags parallel...
572 if (!attributes["flags"].isEmpty() && attributes["flags"].toLower() != "no") {
573 FlagsTypeEntry *ftype = new FlagsTypeEntry("QFlags<" + name + ">");
574 ftype->setOriginator(m_current_enum);
575 ftype->setOriginalName(attributes["flags"]);
576 ftype->setCodeGeneration(m_generate);
577 QString n = ftype->originalName();
578
579 QStringList lst = n.split("::");
580 if (QStringList(lst.mid(0, lst.size() - 1)).join("::") != m_current_enum->javaQualifier()) {
581 ReportHandler::warning(QString("enum %1 and flags %2 differ in qualifiers")
582 .arg(m_current_enum->javaQualifier())
583 .arg(lst.at(0)));
584 }
585
586 ftype->setFlagsName(lst.last());
587 m_current_enum->setFlags(ftype);
588
589 m_database->addFlagsType(ftype);
590 m_database->addType(ftype);
591 }
592 }
593 break;
594
595 case StackElement::InterfaceTypeEntry:
596 {
597 ObjectTypeEntry *otype = new ObjectTypeEntry(name);
598 QString javaName = attributes["java-name"];
599 if (javaName.isEmpty())
600 javaName = name;
601 InterfaceTypeEntry *itype =
602 new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(javaName));
603
604 if (!convertBoolean(attributes["generate"], "generate", true))
605 itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
606 else
607 itype->setCodeGeneration(m_generate);
608 otype->setDesignatedInterface(itype);
609 itype->setOrigin(otype);
610 element->entry = otype;
611 }
612 // fall through
613 case StackElement::NamespaceTypeEntry:
614 if (element->entry == 0) {
615 element->entry = new NamespaceTypeEntry(name);
616 }
617 // fall through
618 case StackElement::ObjectTypeEntry:
619 if (element->entry == 0) {
620 element->entry = new ObjectTypeEntry(name);
621 }
622 // fall through
623 case StackElement::ValueTypeEntry:
624 {
625 if (element->entry == 0) {
626 if(name == "QVariant")
627 element->entry = new VariantTypeEntry(name);
628 else
629 element->entry = new ValueTypeEntry(name);
630 }
631
632 ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
633 ctype->setTargetLangPackage(attributes["package"]);
634 ctype->setDefaultSuperclass(attributes["default-superclass"]);
635 ctype->setGenericClass(convertBoolean(attributes["generic-class"], "generic-class", false));
636
637 // qtd
638 QString wrap = attributes["wrap"];
639 ctype->setStructInD(wrap == "struct" ? true : false);
640 //
641
642 if (!convertBoolean(attributes["generate"], "generate", true))
643 element->entry->setCodeGeneration(TypeEntry::GenerateForSubclass);
644 else
645 element->entry->setCodeGeneration(m_generate);
646
647 QString javaName = attributes["java-name"];
648 if (!javaName.isEmpty())
649 ctype->setTargetLangName(javaName);
650
651 // The expense policy
652 QString limit = attributes["expense-limit"];
653 if (!limit.isEmpty() && limit != "none") {
654 ExpensePolicy ep;
655 ep.limit = limit.toInt();
656 ep.cost = attributes["expense-cost"];
657 ctype->setExpensePolicy(ep);
658 }
659
660 ctype->setIsPolymorphicBase(convertBoolean(attributes["polymorphic-base"], "polymorphic-base", false));
661 ctype->setPolymorphicIdValue(attributes["polymorphic-id-expression"]);
662
663 if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry) {
664 if (convertBoolean(attributes["force-abstract"], "force-abstract", false))
665 ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
666 if (convertBoolean(attributes["deprecated"], "deprecated", false))
667 ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
668 }
669
670 if (element->type == StackElement::InterfaceTypeEntry ||
671 element->type == StackElement::ValueTypeEntry ||
672 element->type == StackElement::ObjectTypeEntry) {
673 if (convertBoolean(attributes["delete-in-main-thread"], "delete-in-main-thread", false))
674 ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread);
675 }
676
677 QString targetType = attributes["target-type"];
678 if (!targetType.isEmpty() && element->entry->isComplex())
679 static_cast<ComplexTypeEntry *>(element->entry)->setTargetType(targetType);
680
681 // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
682 ctype = ctype->designatedInterface();
683 if (ctype != 0)
684 ctype->setTargetLangPackage(attributes["package"]);
685 }
686 break;
687 default:
688 Q_ASSERT(false);
689 };
690
691 if (element->entry)
692 m_database->addType(element->entry);
693 else
694 ReportHandler::warning(QString("Type: %1 was rejected by typesystem").arg(name));
695
696 } else if (element->type != StackElement::None) {
697 bool topLevel = element->type == StackElement::Root
698 || element->type == StackElement::SuppressedWarning
699 || element->type == StackElement::Rejection
700 || element->type == StackElement::LoadTypesystem
701 || element->type == StackElement::InjectCode
702 || element->type == StackElement::Template;
703
704 if (!topLevel && current->type == StackElement::Root) {
705 m_error = QString("Tag requires parent: '%1'").arg(tagName);
706 return false;
707 }
708
709 StackElement topElement = current==0 ? StackElement(0) : *current;
710 element->entry = topElement.entry;
711
712 QHash<QString, QString> attributes;
713 switch (element->type) {
714 case StackElement::Root:
715 attributes["package"] = QString();
716 attributes["default-superclass"] = QString();
717 break;
718 case StackElement::LoadTypesystem:
719 attributes["name"] = QString();
720 attributes["generate"] = "yes";
721 break;
722 case StackElement::NoNullPointers:
723 attributes["default-value"] = QString();
724 break;
725 case StackElement::SuppressedWarning:
726 attributes["text"] = QString();
727 break;
728 case StackElement::ReplaceDefaultExpression:
729 attributes["with"] = QString();
730 break;
731 case StackElement::DefineOwnership:
732 attributes["class"] = "java";
733 attributes["owner"] = "";
734 break;
735 case StackElement::ModifyFunction:
736 attributes["signature"] = QString();
737 attributes["access"] = QString();
738 attributes["remove"] = QString();
739 attributes["rename"] = QString();
740 attributes["deprecated"] = QString("no");
741 attributes["associated-to"] = QString();
742 attributes["virtual-slot"] = QString("no");
743 break;
744 case StackElement::ModifyArgument:
745 attributes["index"] = QString();
746 attributes["replace-value"] = QString();
747 attributes["invalidate-after-use"] = QString("no");
748 break;
749 case StackElement::ModifyField:
750 attributes["name"] = QString();
751 attributes["write"] = "true";
752 attributes["read"] = "true";
753 break;
754 case StackElement::Access:
755 attributes["modifier"] = QString();
756 break;
757 case StackElement::Include:
758 attributes["file-name"] = QString();
759 attributes["location"] = QString();
760 break;
761 case StackElement::CustomMetaConstructor:
762 attributes["name"] = topElement.entry->name().toLower() + "_create";
763 attributes["param-name"] = "copy";
764 break;
765 case StackElement::CustomMetaDestructor:
766 attributes["name"] = topElement.entry->name().toLower() + "_delete";
767 attributes["param-name"] = "copy";
768 break;
769 case StackElement::ReplaceType:
770 attributes["modified-type"] = QString();
771 break;
772 case StackElement::InjectCode:
773 attributes["class"] = "java";
774 attributes["position"] = "beginning";
775 break;
776 case StackElement::ConversionRule:
777 attributes["class"] = "";
778 break;
779 case StackElement::RejectEnumValue:
780 attributes["name"] = "";
781 break;
782 case StackElement::ArgumentMap:
783 attributes["index"] = "1";
784 attributes["meta-name"] = QString();
785 break;
786 case StackElement::Rename:
787 attributes["to"] = QString();
788 break;
789 case StackElement::Rejection:
790 attributes["class"] = "*";
791 attributes["function-name"] = "*";
792 attributes["field-name"] = "*";
793 attributes["enum-name"] = "*";
794 break;
795 case StackElement::Removal:
796 attributes["class"] = "all";
797 break;
798 case StackElement::Template:
799 attributes["name"] = QString();
800 break;
801 case StackElement::TemplateInstanceEnum:
802 attributes["name"] = QString();
803 break;
804 case StackElement::Replace:
805 attributes["from"] = QString();
806 attributes["to"] = QString();
807 break;
808 case StackElement::ReferenceCount:
809 attributes["action"] = QString();
810 attributes["variable-name"] = QString();
811 attributes["thread-safe"] = QString("no");
812 attributes["declare-variable"] = QString();
813 attributes["access"] = QString("private");
814 attributes["conditional"] = QString("");
815 break;
816 // qtd
817 case StackElement::AddClass:
818 attributes["name"] = QString();
819 break;
820 default:
821 ; // nada
822 };
823
824 if (attributes.count() > 0)
825 fetchAttributeValues(tagName, atts, &attributes);
826
827 switch (element->type) {
828 case StackElement::Root:
829 m_defaultPackage = attributes["package"];
830 m_defaultSuperclass = attributes["default-superclass"];
831 element->type = StackElement::Root;
832 element->entry = new TypeSystemTypeEntry(m_defaultPackage);
833 TypeDatabase::instance()->addType(element->entry);
834 break;
835 case StackElement::LoadTypesystem:
836 {
837 QString name = attributes["name"];
838 if (name.isEmpty()) {
839 m_error = "No typesystem name specified";
840 return false;
841 }
842
843 if (!m_database->parseFile(name, convertBoolean(attributes["generate"], "generate", true))) {
844 m_error = QString("Failed to parse: '%1'").arg(name);
845 return false;
846 }
847 }
848 break;
849 case StackElement::RejectEnumValue: {
850 if (!m_current_enum) {
851 m_error = "<reject-enum-value> node must be used inside a <enum-type> node";
852 return false;
853 }
854 QString name = attributes["name"];
855
856 bool added = false;
857 if (!name.isEmpty()) {
858 added = true;
859 m_current_enum->addEnumValueRejection(name);
860 }
861
862 } break;
863 case StackElement::ReplaceType:
864 {
865 if (topElement.type != StackElement::ModifyArgument) {
866 m_error = "Type replacement can only be specified for argument modifications";
867 return false;
868 }
869
870 if (attributes["modified-type"].isEmpty()) {
871 m_error = "Type replacement requires 'modified-type' attribute";
872 return false;
873 }
874
875 m_function_mods.last().argument_mods.last().modified_type = attributes["modified-type"];
876 }
877 break;
878 case StackElement::ConversionRule:
879 {
880 if (topElement.type != StackElement::ModifyArgument) {
881 m_error = "Conversion rules can only be specified for argument modification";
882 return false;
883 }
884
885 static QHash<QString, TypeSystem::Language> languageNames;
886 if (languageNames.isEmpty()) {
887 languageNames["native"] = TypeSystem::NativeCode;
888 languageNames["shell"] = TypeSystem::ShellCode;
889 }
890
891 CodeSnip snip;
892 QString languageAttribute = attributes["class"].toLower();
893 TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
894 if (lang == TypeSystem::NoLanguage) {
895 m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
896 return false;
897 }
898
899 snip.language = lang;
900 m_function_mods.last().argument_mods.last().conversion_rules.append(snip);
901 }
902
903 break;
904 case StackElement::StoreResult:
905 {
906 if (topElement.type != StackElement::ModifyFunction) {
907 m_error = QString::fromLatin1("result storage requires function"
908 " modification as parent, was %1")
909 .arg(topElement.type, 0, 16);
910 return false;
911 }
912
913 m_function_mods.last().store_result = true;
914 }
915 break;
916 case StackElement::ModifyArgument:
917 {
918 if (topElement.type != StackElement::ModifyFunction) {
919 m_error = QString::fromLatin1("argument modification requires function"
920 " modification as parent, was %1")
921 .arg(topElement.type, 0, 16);
922 return false;
923 }
924
925 QString index = attributes["index"];
926 if (index == "return")
927 index = "0";
928 else if (index == "this")
929 index = "-1";
930
931 bool ok = false;
932 int idx = index.toInt(&ok);
933 if (!ok) {
934 m_error = QString("Cannot convert '%1' to integer").arg(index);
935 return false;
936 }
937
938 QString replace_value = attributes["replace-value"];
939
940 if (!replace_value.isEmpty() && idx != 0) {
941 m_error = QString("replace-value is only supported for return values (index=0).");
942 return false;
943 }
944
945 ArgumentModification argumentModification = ArgumentModification(idx);
946 argumentModification.replace_value = replace_value;
947 argumentModification.reset_after_use = convertBoolean(attributes["invalidate-after-use"], "invalidate-after-use", false);
948 m_function_mods.last().argument_mods.append(argumentModification);
949 }
950 break;
951 case StackElement::NoNullPointers:
952 {
953 if (topElement.type != StackElement::ModifyArgument) {
954 m_error = "no-null-pointer requires argument modification as parent";
955 return false;
956 }
957
958 m_function_mods.last().argument_mods.last().no_null_pointers = true;
959 if (m_function_mods.last().argument_mods.last().index == 0) {
960 m_function_mods.last().argument_mods.last().null_pointer_default_value = attributes["default-value"];
961 } else if (!attributes["default-value"].isEmpty()) {
962 ReportHandler::warning("default values for null pointer guards are only effective for return values");
963 }
964 }
965 break;
966 case StackElement::DefineOwnership:
967 {
968 if (topElement.type != StackElement::ModifyArgument) {
969 m_error = "define-ownership requires argument modification as parent";
970 return false;
971 }
972
973 static QHash<QString, TypeSystem::Language> languageNames;
974 if (languageNames.isEmpty()) {
975 languageNames["java"] = TypeSystem::TargetLangCode;
976 languageNames["shell"] = TypeSystem::ShellCode;
977 }
978
979 QString classAttribute = attributes["class"].toLower();
980 TypeSystem::Language lang = languageNames.value(classAttribute, TypeSystem::NoLanguage);
981 if (lang == TypeSystem::NoLanguage) {
982 m_error = QString("unsupported class attribute: '%1'").arg(classAttribute);
983 return false;
984 }
985
986 static QHash<QString, TypeSystem::Ownership> ownershipNames;
987 if (ownershipNames.isEmpty()) {
988 ownershipNames["java"] = TypeSystem::TargetLangOwnership;
989 ownershipNames["c++"] = TypeSystem::CppOwnership;
990 ownershipNames["default"] = TypeSystem::DefaultOwnership;
991 }
992
993 QString ownershipAttribute = attributes["owner"].toLower();
994 TypeSystem::Ownership owner = ownershipNames.value(ownershipAttribute, TypeSystem::InvalidOwnership);
995 if (owner == TypeSystem::InvalidOwnership) {
996 m_error = QString("unsupported owner attribute: '%1'").arg(ownershipAttribute);
997 return false;
998 }
999
1000 m_function_mods.last().argument_mods.last().ownerships[lang] = owner;
1001 }
1002 break;
1003 case StackElement::SuppressedWarning:
1004 if (attributes["text"].isEmpty())
1005 ReportHandler::warning("Suppressed warning with no text specified");
1006 else
1007 m_database->addSuppressedWarning(attributes["text"]);
1008 break;
1009 case StackElement::ArgumentMap:
1010 {
1011 if (!(topElement.type & StackElement::CodeSnipMask)) {
1012 m_error = "Argument maps requires code injection as parent";
1013 return false;
1014 }
1015
1016 bool ok;
1017 int pos = attributes["index"].toInt(&ok);
1018 if (!ok) {
1019 m_error = QString("Can't convert position '%1' to integer")
1020 .arg(attributes["position"]);
1021 return false;
1022 }
1023
1024 if (pos <= 0) {
1025 m_error = QString("Argument position %1 must be a positive number").arg(pos);
1026 return false;
1027 }
1028
1029 QString meta_name = attributes["meta-name"];
1030 if (meta_name.isEmpty()) {
1031 ReportHandler::warning("Empty meta name in argument map");
1032 }
1033
1034 if (topElement.type == StackElement::InjectCodeInFunction) {
1035 m_function_mods.last().snips.last().argumentMap[pos] = meta_name;
1036 } else {
1037 ReportHandler::warning("Argument maps are only useful for injection of code "
1038 "into functions.");
1039 }
1040 }
1041 break;
1042 case StackElement::Removal:
1043 {
1044 if (topElement.type != StackElement::ModifyFunction) {
1045 m_error = "Function modification parent required";
1046 return false;
1047 }
1048
1049 static QHash<QString, TypeSystem::Language> languageNames;
1050 if (languageNames.isEmpty()) {
1051 languageNames["java"] = TypeSystem::TargetLangAndNativeCode;
1052 languageNames["all"] = TypeSystem::All;
1053 }
1054
1055 QString languageAttribute = attributes["class"].toLower();
1056 TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
1057 if (lang == TypeSystem::NoLanguage) {
1058 m_error = QString("unsupported class attribute: '%1'").arg(languageAttribute);
1059 return false;
1060 }
1061
1062 m_function_mods.last().removal = lang;
1063 }
1064 break;
1065 case StackElement::Rename:
1066 case StackElement::Access:
1067 {
1068 if (topElement.type != StackElement::ModifyField
1069 && topElement.type != StackElement::ModifyFunction) {
1070 m_error = "Function or field modification parent required";
1071 return false;
1072 }
1073
1074 Modification *mod = 0;
1075 if (topElement.type == StackElement::ModifyFunction)
1076 mod = &m_function_mods.last();
1077 else
1078 mod = &m_field_mods.last();
1079
1080 QString modifier;
1081 if (element->type == StackElement::Rename) {
1082 modifier = "rename";
1083 QString renamed_to = attributes["to"];
1084 if (renamed_to.isEmpty()) {
1085 m_error = "Rename modifier requires 'to' attribute";
1086 return false;
1087 }
1088
1089 if (topElement.type == StackElement::ModifyFunction)
1090 mod->setRenamedTo(renamed_to);
1091 else
1092 mod->setRenamedTo(renamed_to);
1093 } else {
1094 modifier = attributes["modifier"].toLower();
1095 }
1096
1097 if (modifier.isEmpty()) {
1098 m_error = "No access modification specified";
1099 return false;
1100 }
1101
1102 static QHash<QString, FunctionModification::Modifiers> modifierNames;
1103 if (modifierNames.isEmpty()) {
1104 modifierNames["private"] = Modification::Private;
1105 modifierNames["public"] = Modification::Public;
1106 modifierNames["protected"] = Modification::Protected;
1107 modifierNames["friendly"] = Modification::Friendly;
1108 modifierNames["rename"] = Modification::Rename;
1109 modifierNames["final"] = Modification::Final;
1110 modifierNames["non-final"] = Modification::NonFinal;
1111 }
1112
1113 if (!modifierNames.contains(modifier)) {
1114 m_error = QString("Unknown access modifier: '%1'").arg(modifier);
1115 return false;
1116 }
1117
1118 mod->modifiers |= modifierNames[modifier];
1119 }
1120 break;
1121 case StackElement::RemoveArgument:
1122 if (topElement.type != StackElement::ModifyArgument) {
1123 m_error = "Removing argument requires argument modification as parent";
1124 return false;
1125 }
1126
1127 m_function_mods.last().argument_mods.last().removed = true;
1128
1129 break;
1130
1131 case StackElement::ModifyField:
1132 {
1133 QString name = attributes["name"];
1134 if (name.isEmpty())
1135 break;
1136 FieldModification fm;
1137 fm.name = name;
1138 fm.modifiers = 0;
1139
1140 QString read = attributes["read"];
1141 QString write = attributes["write"];
1142
1143 if (read == "true") fm.modifiers |= FieldModification::Readable;
1144 if (write == "true") fm.modifiers |= FieldModification::Writable;
1145
1146 m_field_mods << fm;
1147 }
1148 break;
1149 case StackElement::AddClass: // qtd - fully :)
1150 {
1151 if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
1152 m_error = QString::fromLatin1("Add class to module requires complex type as parent"
1153 ", was=%1").arg(topElement.type, 0, 16);
1154 return false;
1155 }
1156 QString class_name = attributes["name"];
1157 ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(topElement.entry);
1158 if(!class_name.isEmpty())
1159 ctype->includedClasses << class_name;
1160 }
1161 break;
1162 case StackElement::ModifyFunction:
1163 {
1164 if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
1165 m_error = QString::fromLatin1("Modify function requires complex type as parent"
1166 ", was=%1").arg(topElement.type, 0, 16);
1167 return false;
1168 }
1169 QString signature = attributes["signature"];
1170
1171 signature = QMetaObject::normalizedSignature(signature.toLocal8Bit().constData());
1172 if (signature.isEmpty()) {
1173 m_error = "No signature for modified function";
1174 return false;
1175 }
1176
1177 FunctionModification mod;
1178 mod.signature = signature;
1179
1180 QString access = attributes["access"].toLower();
1181 if (!access.isEmpty()) {
1182 if (access == QLatin1String("private"))
1183 mod.modifiers |= Modification::Private;
1184 else if (access == QLatin1String("protected"))
1185 mod.modifiers |= Modification::Protected;
1186 else if (access == QLatin1String("public"))
1187 mod.modifiers |= Modification::Public;
1188 else if (access == QLatin1String("final"))
1189 mod.modifiers |= Modification::Final;
1190 else if (access == QLatin1String("non-final"))
1191 mod.modifiers |= Modification::NonFinal;
1192 else {
1193 m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
1194 return false;
1195 }
1196 }
1197
1198 if (convertBoolean(attributes["deprecated"], "deprecated", false)) {
1199 mod.modifiers |= Modification::Deprecated;
1200 }
1201
1202 QString remove = attributes["remove"].toLower();
1203 if (!remove.isEmpty()) {
1204 if (remove == QLatin1String("all"))
1205 mod.removal = TypeSystem::All;
1206 else if (remove == QLatin1String("java"))
1207 mod.removal = TypeSystem::TargetLangAndNativeCode;
1208 else {
1209 m_error = QString::fromLatin1("Bad removal type '%1'").arg(remove);
1210 return false;
1211 }
1212 }
1213
1214 QString rename = attributes["rename"];
1215 if (!rename.isEmpty()) {
1216 mod.renamedToName = rename;
1217 mod.modifiers |= Modification::Rename;
1218 }
1219
1220 QString association = attributes["associated-to"];
1221 if (!association.isEmpty())
1222 mod.association = association;
1223
1224 mod.modifiers |= (convertBoolean(attributes["virtual-slot"], "virtual-slot", false) ? Modification::VirtualSlot : 0);
1225
1226 m_function_mods << mod;
1227 }
1228 break;
1229 case StackElement::ReplaceDefaultExpression:
1230 if (!(topElement.type & StackElement::ModifyArgument)) {
1231 m_error = "Replace default expression only allowed as child of argument modification";
1232 return false;
1233 }
1234
1235 if (attributes["with"].isEmpty()) {
1236 m_error = "Default expression replaced with empty string. Use remove-default-expression instead.";
1237 return false;
1238 }
1239
1240 m_function_mods.last().argument_mods.last().replaced_default_expression = attributes["with"];
1241 break;
1242 case StackElement::RemoveDefaultExpression:
1243 m_function_mods.last().argument_mods.last().removed_default_expression = true;
1244 break;
1245 case StackElement::CustomMetaConstructor:
1246 case StackElement::CustomMetaDestructor:
1247 {
1248 CustomFunction *func = new CustomFunction(attributes["name"]);
1249 func->param_name = attributes["param-name"];
1250 element->value.customFunction = func;
1251 }
1252 break;
1253 case StackElement::ReferenceCount:
1254 {
1255 if (topElement.type != StackElement::ModifyArgument) {
1256 m_error = "reference-count must be child of modify-argument";
1257 return false;
1258 }
1259
1260 ReferenceCount rc;
1261 rc.threadSafe = convertBoolean(attributes["thread-safe"], "thread-safe", false);
1262
1263 static QHash<QString, ReferenceCount::Action> actions;
1264 if (actions.isEmpty()) {
1265 actions["add"] = ReferenceCount::Add;
1266 actions["add-all"] = ReferenceCount::AddAll;
1267 actions["remove"] = ReferenceCount::Remove;
1268 actions["set"] = ReferenceCount::Set;
1269 actions["ignore"] = ReferenceCount::Ignore;
1270 }
1271 rc.action = actions.value(attributes["action"].toLower(), ReferenceCount::Invalid);
1272
1273 rc.variableName = attributes["variable-name"];
1274 if (rc.action != ReferenceCount::Ignore && rc.variableName.isEmpty()) {
1275 m_error = "variable-name attribute must be specified";
1276 return false;
1277 }
1278
1279 rc.declareVariable = attributes["declare-variable"];
1280 rc.conditional = attributes["conditional"];
1281
1282 static QHash<QString, int> accessRights;
1283 if (accessRights.isEmpty()) {
1284 accessRights["private"] = ReferenceCount::Private;
1285 accessRights["public"] = ReferenceCount::Public;
1286 accessRights["protected"] = ReferenceCount::Protected;
1287 accessRights["friendly"] = ReferenceCount::Friendly;
1288 }
1289 rc.access = accessRights.value(attributes["access"].toLower(), 0);
1290 if (rc.access == 0) {
1291 m_error = "unrecognized access value: " + attributes["access"];
1292 return false;
1293 }
1294
1295 if (rc.action == ReferenceCount::Invalid) {
1296 m_error = "unrecognized value for action attribute. supported actions:";
1297 foreach (QString action, actions.keys())
1298 m_error += " " + action;
1299 }
1300
1301 m_function_mods.last().argument_mods.last().referenceCounts.append(rc);
1302 }
1303 break;
1304 case StackElement::InjectCode:
1305 {
1306 if (((topElement.type & StackElement::ComplexTypeEntryMask) == 0)
1307 && (topElement.type != StackElement::ModifyFunction)
1308 && (topElement.type != StackElement::Root)) {
1309 m_error = "wrong parent type for code injection";
1310 return false;
1311 }
1312
1313 static QHash<QString, TypeSystem::Language> languageNames;
1314 if (languageNames.isEmpty()) {
1315 languageNames["java"] = TypeSystem::TargetLangCode;
1316 languageNames["native"] = TypeSystem::NativeCode;
1317 languageNames["shell"] = TypeSystem::ShellCode;
1318 languageNames["shell-declaration"] = TypeSystem::ShellDeclaration;
1319 languageNames["library-initializer"] = TypeSystem::PackageInitializer;
1320 languageNames["destructor-function"] = TypeSystem::DestructorFunction;
1321 languageNames["constructors"] = TypeSystem::Constructors;
1322 languageNames["interface"] = TypeSystem::Interface;
1323 }
1324
1325 QString className = attributes["class"].toLower();
1326 if (!languageNames.contains(className)) {
1327 m_error = QString("Invalid class specifier: '%1'").arg(className);
1328 return false;
1329 }
1330
1331
1332 static QHash<QString, CodeSnip::Position> positionNames;
1333 if (positionNames.isEmpty()) {
1334 positionNames["beginning"] = CodeSnip::Beginning;
1335 positionNames["end"] = CodeSnip::End;
1336 }
1337
1338 QString position = attributes["position"].toLower();
1339 if (!positionNames.contains(position)) {
1340 m_error = QString("Invalid position: '%1'").arg(position);
1341 return false;
1342 }
1343
1344 CodeSnip snip;
1345 snip.language = languageNames[className];
1346 snip.position = positionNames[position];
1347
1348 if (snip.language == TypeSystem::Interface && topElement.type != StackElement::InterfaceTypeEntry) {
1349 m_error = "Interface code injections must be direct child of an interface type entry";
1350 return false;
1351 }
1352
1353 if (topElement.type == StackElement::ModifyFunction) {
1354 FunctionModification mod = m_function_mods.last();
1355 if (snip.language == TypeSystem::ShellDeclaration) {
1356 m_error = "no function implementation in shell declaration in which to inject code";
1357 return false;
1358 }
1359
1360 m_function_mods.last().snips << snip;
1361 element->type = StackElement::InjectCodeInFunction;
1362 } else if (topElement.type == StackElement::Root) {
1363 ((TypeSystemTypeEntry *) element->entry)->snips << snip;
1364
1365 } else if (topElement.type != StackElement::Root) {
1366 m_code_snips << snip;
1367 }
1368 }
1369 break;
1370 case StackElement::Include:
1371 {
1372 QString location = attributes["location"].toLower();
1373
1374 static QHash<QString, Include::IncludeType> locationNames;
1375 if (locationNames.isEmpty()) {
1376 locationNames["global"] = Include::IncludePath;
1377 locationNames["local"] = Include::LocalPath;
1378 locationNames["java"] = Include::TargetLangImport;
1379 }
1380
1381 if (!locationNames.contains(location)) {
1382 m_error = QString("Location not recognized: '%1'").arg(location);
1383 return false;
1384 }
1385
1386 Include::IncludeType loc = locationNames[location];
1387 Include inc(loc, attributes["file-name"]);
1388
1389 ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
1390 if (topElement.type & StackElement::ComplexTypeEntryMask) {
1391 ctype->setInclude(inc);
1392 } else if (topElement.type == StackElement::ExtraIncludes) {
1393 ctype->addExtraInclude(inc);
1394 } else {
1395 m_error = "Only supported parents are complex types and extra-includes";
1396 return false;
1397 }
1398
1399 inc = ctype->include();
1400 IncludeList lst = ctype->extraIncludes();
1401 ctype = ctype->designatedInterface();
1402 if (ctype != 0) {
1403 ctype->setExtraIncludes(lst);
1404 ctype->setInclude(inc);
1405 }
1406 }
1407 break;
1408 case StackElement::Rejection:
1409 {
1410 QString cls = attributes["class"];
1411 QString function = attributes["function-name"];
1412 QString field = attributes["field-name"];
1413 QString enum_ = attributes["enum-name"];
1414 if (cls == "*" && function == "*" && field == "*" && enum_ == "*") {
1415 m_error = "bad reject entry, neither 'class', 'function-name' nor "
1416 "'field' specified";
1417 return false;
1418 }
1419 m_database->addRejection(cls, function, field, enum_);
1420 }
1421 break;
1422 case StackElement::Template:
1423 element->value.templateEntry = new TemplateEntry(attributes["name"]);
1424 break;
1425 case StackElement::TemplateInstanceEnum:
1426 if (!(topElement.type & StackElement::CodeSnipMask) &&
1427 (topElement.type != StackElement::Template) &&
1428 (topElement.type != StackElement::CustomMetaConstructor) &&
1429 (topElement.type != StackElement::CustomMetaDestructor) &&
1430 (topElement.type != StackElement::ConversionRule))
1431 {
1432 m_error = "Can only insert templates into code snippets, templates, custom-constructors, custom-destructors or conversion-rule.";
1433 return false;
1434 }
1435 element->value.templateInstance = new TemplateInstance(attributes["name"]);
1436 break;
1437 case StackElement::Replace:
1438 if (topElement.type != StackElement::TemplateInstanceEnum) {
1439 m_error = "Can only insert replace rules into insert-template.";
1440 return false;
1441 }
1442 element->parent->value.templateInstance->addReplaceRule(attributes["from"],attributes["to"]);
1443 break;
1444 default:
1445 break; // nada
1446 };
1447 }
1448
1449 current = element;
1450 return true;
1451 }
1452
1453 TypeDatabase *TypeDatabase::instance()
1454 {
1455 static TypeDatabase *db = new TypeDatabase();
1456 return db;
1457 }
1458
1459 TypeDatabase::TypeDatabase() : m_suppressWarnings(true), m_includeEclipseWarnings(false)
1460 {
1461 addType(new StringTypeEntry("QString"));
1462
1463 StringTypeEntry *e = new StringTypeEntry("QLatin1String");
1464 e->setPreferredConversion(false);
1465 addType(e);
1466
1467 e = new StringTypeEntry("QStringRef");
1468 e->setPreferredConversion(false);
1469 addType(e);
1470
1471 e = new StringTypeEntry("QXmlStreamStringRef");
1472 e->setPreferredConversion(false);
1473 addType(e);
1474
1475 addType(new CharTypeEntry("QChar"));
1476
1477 CharTypeEntry *c = new CharTypeEntry("QLatin1Char");
1478 c->setPreferredConversion(false);
1479 addType(c);
1480
1481 {
1482 VariantTypeEntry *qvariant = new VariantTypeEntry("QVariant");
1483 qvariant->setCodeGeneration(TypeEntry::GenerateAll);
1484 addType(qvariant);
1485 }
1486
1487 {
1488 JObjectWrapperTypeEntry *wrapper = new JObjectWrapperTypeEntry("JObjectWrapper");
1489 wrapper->setCodeGeneration(TypeEntry::GenerateNothing);
1490 addType(wrapper);
1491 }
1492
1493 addType(new ThreadTypeEntry());
1494 addType(new VoidTypeEntry());
1495
1496 // Predefined containers...
1497 addType(new ContainerTypeEntry("QList", ContainerTypeEntry::ListContainer));
1498 addType(new ContainerTypeEntry("QStringList", ContainerTypeEntry::StringListContainer));
1499 addType(new ContainerTypeEntry("QLinkedList", ContainerTypeEntry::LinkedListContainer));
1500 addType(new ContainerTypeEntry("QVector", ContainerTypeEntry::VectorContainer));
1501 addType(new ContainerTypeEntry("QStack", ContainerTypeEntry::StackContainer));
1502 addType(new ContainerTypeEntry("QSet", ContainerTypeEntry::SetContainer));
1503 addType(new ContainerTypeEntry("QMap", ContainerTypeEntry::MapContainer));
1504 addType(new ContainerTypeEntry("QHash", ContainerTypeEntry::HashContainer));
1505 addType(new ContainerTypeEntry("QPair", ContainerTypeEntry::PairContainer));
1506 addType(new ContainerTypeEntry("QQueue", ContainerTypeEntry::QueueContainer));
1507 addType(new ContainerTypeEntry("QMultiMap", ContainerTypeEntry::MultiMapContainer));
1508
1509 // Custom types...
1510 // addType(new QModelIndexTypeEntry());
1511
1512 addRemoveFunctionToTemplates(this);
1513 }
1514
1515 bool TypeDatabase::parseFile(const QString &filename, bool generate)
1516 {
1517 QFile file(filename);
1518 Q_ASSERT(file.exists());
1519 QXmlInputSource source(&file);
1520
1521 int count = m_entries.size();
1522
1523 QXmlSimpleReader reader;
1524 Handler handler(this, generate);
1525
1526 reader.setContentHandler(&handler);
1527 reader.setErrorHandler(&handler);
1528
1529 bool ok = reader.parse(&source, false);
1530
1531 int newCount = m_entries.size();
1532
1533 ReportHandler::debugSparse(QString::fromLatin1("Parsed: '%1', %2 new entries")
1534 .arg(filename)
1535 .arg(newCount - count));
1536
1537 return ok;
1538 }
1539
1540 QString PrimitiveTypeEntry::javaObjectName() const
1541 {
1542 static QHash<QString, QString> table;
1543 if (table.isEmpty()) {
1544 table["boolean"] = "Boolean";
1545 table["byte"] = "Byte";
1546 table["char"] = "Character";
1547 table["short"] = "Short";
1548 table["int"] = "Integer";
1549 table["long"] = "Long";
1550 table["float"] = "Float";
1551 table["double"] = "Double";
1552 }
1553 Q_ASSERT(table.contains(targetLangName()));
1554 return table[targetLangName()];
1555 }
1556
1557 ContainerTypeEntry *TypeDatabase::findContainerType(const QString &name)
1558 {
1559 QString template_name = name;
1560
1561 int pos = name.indexOf('<');
1562 if (pos > 0)
1563 template_name = name.left(pos);
1564
1565 TypeEntry *type_entry = findType(template_name);
1566 if (type_entry && type_entry->isContainer())
1567 return static_cast<ContainerTypeEntry *>(type_entry);
1568 return 0;
1569 }
1570
1571 PrimitiveTypeEntry *TypeDatabase::findTargetLangPrimitiveType(const QString &java_name)
1572 {
1573 foreach (QList<TypeEntry *> entries, m_entries.values()) {
1574 foreach (TypeEntry *e, entries) {
1575 if (e && e->isPrimitive()) {
1576 PrimitiveTypeEntry *pe = static_cast<PrimitiveTypeEntry *>(e);
1577 if (pe->targetLangName() == java_name && pe->preferredConversion())
1578 return pe;
1579 }
1580 }
1581 }
1582
1583 return 0;
1584 }
1585
1586 IncludeList TypeDatabase::extraIncludes(const QString &className)
1587 {
1588 ComplexTypeEntry *typeEntry = findComplexType(className);
1589 if (typeEntry != 0)
1590 return typeEntry->extraIncludes();
1591 else
1592 return IncludeList();
1593 }
1594
1595
1596
1597 QString Include::toString() const
1598 {
1599 if (type == IncludePath)
1600 return "#include <" + name + '>';
1601 else if (type == LocalPath)
1602 return "#include \"" + name + "\"";
1603 else
1604 return "import " + name + ";";
1605 }
1606
1607 QString Modification::accessModifierString() const
1608 {
1609 if (isPrivate()) return "private";
1610 if (isProtected()) return "protected";
1611 if (isPublic()) return "public";
1612 if (isFriendly()) return "friendly";
1613 return QString();
1614 }
1615
1616 FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const
1617 {
1618 FunctionModificationList lst;
1619 for (int i=0; i<m_function_mods.count(); ++i) {
1620 FunctionModification mod = m_function_mods.at(i);
1621 if (mod.signature == signature) {
1622 lst << mod;
1623 }
1624 }
1625
1626 return lst;
1627 }
1628
1629 FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
1630 {
1631 for (int i=0; i<m_field_mods.size(); ++i)
1632 if (m_field_mods.at(i).name == name)
1633 return m_field_mods.at(i);
1634 FieldModification mod;
1635 mod.name = name;
1636 mod.modifiers = FieldModification::Readable | FieldModification::Writable;
1637 return mod;
1638 }
1639
1640 QString ContainerTypeEntry::javaPackage() const
1641 {
1642 if (m_type == PairContainer)
1643 return "qt";
1644 return "java.util";
1645 }
1646
1647 QString ContainerTypeEntry::targetLangName() const
1648 {
1649
1650 switch (m_type) {
1651 case StringListContainer: return "List";
1652 case ListContainer: return "List";
1653 case LinkedListContainer: return "LinkedList";
1654 case VectorContainer: return "List";
1655 case StackContainer: return "Stack";
1656 case QueueContainer: return "Queue";
1657 case SetContainer: return "Set";
1658 case MapContainer: return "SortedMap";
1659 case MultiMapContainer: return "SortedMap";
1660 case HashContainer: return "HashMap";
1661 // case MultiHashCollectio: return "MultiHash";
1662 case PairContainer: return "QPair";
1663 default:
1664 qWarning("bad type... %d", m_type);
1665 break;
1666 }
1667 return QString();
1668 }
1669
1670 QString ContainerTypeEntry::qualifiedCppName() const
1671 {
1672 if (m_type == StringListContainer)
1673 return "QStringList";
1674 return ComplexTypeEntry::qualifiedCppName();
1675 }
1676
1677 QString EnumTypeEntry::javaQualifier() const
1678 {
1679 TypeEntry *te = TypeDatabase::instance()->findType(m_qualifier);
1680 if (te != 0)
1681 return te->targetLangName();
1682 else
1683 return m_qualifier;
1684 }
1685
1686 QString EnumTypeEntry::jniName() const
1687 {
1688 return "jint";
1689 }
1690
1691 QString FlagsTypeEntry::jniName() const
1692 {
1693 return "jint";
1694 }
1695
1696 void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue)
1697 {
1698 m_enum_redirections << EnumValueRedirection(rejected, usedValue);
1699 }
1700
1701 QString EnumTypeEntry::enumValueRedirection(const QString &value) const
1702 {
1703 for (int i=0; i<m_enum_redirections.size(); ++i)
1704 if (m_enum_redirections.at(i).rejected == value)
1705 return m_enum_redirections.at(i).used;
1706 return QString();
1707 }
1708
1709 QString FlagsTypeEntry::qualifiedTargetLangName() const
1710 {
1711 return m_enum->javaQualifier() + "." + targetLangName();
1712 }
1713
1714
1715 void TypeDatabase::addRejection(const QString &class_name, const QString &function_name,
1716 const QString &field_name, const QString &enum_name)
1717 {
1718 TypeRejection r;
1719 r.class_name = class_name;
1720 r.function_name = function_name;
1721 r.field_name = field_name;
1722 r.enum_name = enum_name;
1723
1724 m_rejections << r;
1725 }
1726
1727 bool TypeDatabase::isClassRejected(const QString &class_name)
1728 {
1729 if (!m_rebuild_classes.isEmpty())
1730 return !m_rebuild_classes.contains(class_name);
1731
1732 foreach (const TypeRejection &r, m_rejections)
1733 if (r.class_name == class_name && r.function_name == "*" && r.field_name == "*" && r.enum_name == "*") {
1734 return true;
1735 }
1736 return false;
1737 }
1738
1739 bool TypeDatabase::isEnumRejected(const QString &class_name, const QString &enum_name)
1740 {
1741 foreach (const TypeRejection &r, m_rejections) {
1742 if (r.enum_name == enum_name
1743 && (r.class_name == class_name || r.class_name == "*")) {
1744 return true;
1745 }
1746 }
1747
1748 return false;
1749 }
1750
1751 bool TypeDatabase::isFunctionRejected(const QString &class_name, const QString &function_name)
1752 {
1753 foreach (const TypeRejection &r, m_rejections)
1754 if (r.function_name == function_name &&
1755 (r.class_name == class_name || r.class_name == "*"))
1756 return true;
1757 return false;
1758 }
1759
1760
1761 bool TypeDatabase::isFieldRejected(const QString &class_name, const QString &field_name)
1762 {
1763 foreach (const TypeRejection &r, m_rejections)
1764 if (r.field_name == field_name &&
1765 (r.class_name == class_name || r.class_name == "*"))
1766 return true;
1767 return false;
1768 }
1769
1770 FlagsTypeEntry *TypeDatabase::findFlagsType(const QString &name) const
1771 {
1772 FlagsTypeEntry *fte = (FlagsTypeEntry *) findType(name);
1773 return fte ? fte : (FlagsTypeEntry *) m_flags_entries.value(name);
1774 }
1775
1776 QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/) {
1777 return QLatin1String("Global");
1778 }
1779
1780
1781 /*!
1782 * The Visual Studio 2002 compiler doesn't support these symbols,
1783 * which our typedefs unforntuatly expand to.
1784 */
1785 QString fixCppTypeName(const QString &name)
1786 {
1787 if (name == "long long") return "qint64";
1788 else if (name == "unsigned long long") return "quint64";
1789 return name;
1790 }
1791
1792 QString formattedCodeHelper(QTextStream &s, Indentor &indentor, QStringList &lines) {
1793 bool multilineComment = false;
1794 bool lastEmpty = true;
1795 QString lastLine;
1796 while (!lines.isEmpty()) {
1797 const QString line = lines.takeFirst().trimmed();
1798 if (line.isEmpty()) {
1799 if (!lastEmpty)
1800 s << endl;
1801 lastEmpty = true;
1802 continue;
1803 } else {
1804 lastEmpty = false;
1805 }
1806 if (line.startsWith("/*"))
1807 multilineComment = true;
1808
1809 if (multilineComment) {
1810 s << indentor;
1811 if (line.startsWith("*"))
1812 s << " ";
1813 s << line << endl;
1814 if (line.endsWith("*/"))
1815 multilineComment = false;
1816 } else if (line.startsWith("}")) {
1817 return line;
1818 } else if (line.endsWith("}")) {
1819 s << indentor << line << endl;
1820 return 0;
1821 } else if(line.endsWith("{")) {
1822 s << indentor << line << endl;
1823 QString tmp;
1824 {
1825 Indentation indent(indentor);
1826 tmp = formattedCodeHelper(s, indentor, lines);
1827 }
1828 if (!tmp.isNull()) {
1829 s << indentor << tmp << endl;
1830 }
1831 lastLine = tmp;
1832 continue;
1833 } else {
1834 s << indentor;
1835 if (!lastLine.isEmpty() &&
1836 !lastLine.endsWith(";") &&
1837 !line.startsWith("@") &&
1838 !line.startsWith("//") &&
1839 !lastLine.startsWith("//") &&
1840 !lastLine.endsWith("}") &&
1841 !line.startsWith("{"))
1842 s << " ";
1843 s << line << endl;
1844 }
1845 lastLine = line;
1846 }
1847 return 0;
1848 }
1849
1850
1851 QTextStream &CodeSnip::formattedCode(QTextStream &s, Indentor &indentor) const
1852 {
1853 QStringList lst(code().split("\n"));
1854 while (!lst.isEmpty()) {
1855 QString tmp = formattedCodeHelper(s, indentor, lst);
1856 if (!tmp.isNull()) {
1857 s << indentor << tmp << endl;
1858 }
1859 }
1860 s.flush();
1861 return s;
1862 }
1863
1864 QString TemplateInstance::expandCode() const{
1865 TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name);
1866 if(templateEntry){
1867 QString res = templateEntry->code();
1868 foreach(QString key, replaceRules.keys()){
1869 res.replace(key, replaceRules[key]);
1870 }
1871 return "// TEMPLATE - " + m_name + " - START" + res + "// TEMPLATE - " + m_name + " - END";
1872 }
1873 else{
1874 ReportHandler::warning("insert-template referring to non-existing template '" + m_name + "'");
1875 }
1876 return QString();
1877 }
1878
1879
1880 QString CodeSnipAbstract::code() const{
1881 QString res;
1882 foreach(CodeSnipFragment *codeFrag, codeList){
1883 res.append(codeFrag->code());
1884 }
1885 return res;
1886 }
1887
1888 QString CodeSnipFragment::code() const{
1889 if(m_instance)
1890 return m_instance->expandCode();
1891 else
1892 return m_code;
1893 }
1894
1895 QString FunctionModification::toString() const
1896 {
1897 QString str = signature + QLatin1String("->");
1898 if (modifiers & AccessModifierMask) {
1899 switch (modifiers & AccessModifierMask) {
1900 case Private: str += QLatin1String("private"); break;
1901 case Protected: str += QLatin1String("protected"); break;
1902 case Public: str += QLatin1String("public"); break;
1903 case Friendly: str += QLatin1String("friendly"); break;
1904 }
1905 }
1906
1907 if (modifiers & Final) str += QLatin1String("final");
1908 if (modifiers & NonFinal) str += QLatin1String("non-final");
1909
1910 if (modifiers & Readable) str += QLatin1String("readable");
1911 if (modifiers & Writable) str += QLatin1String("writable");
1912
1913 if (modifiers & CodeInjection) {
1914 foreach (CodeSnip s, snips) {
1915 str += QLatin1String("\n//code injection:\n");
1916 str += s.code();
1917 }
1918 }
1919
1920 if (modifiers & Rename) str += QLatin1String("renamed:") + renamedToName;
1921
1922 if (modifiers & Deprecated) str += QLatin1String("deprecate");
1923
1924 if (modifiers & ReplaceExpression) str += QLatin1String("replace-expression");
1925
1926 return str;
1927 }
1928
1929 static void removeFunction(ComplexTypeEntry *e, const char *signature)
1930 {
1931 FunctionModification mod;
1932 mod.signature = QMetaObject::normalizedSignature(signature);
1933 mod.removal = TypeSystem::All;
1934
1935 e->addFunctionModification(mod);
1936 }
1937
1938
1939
1940
1941 static void injectCode(ComplexTypeEntry *e,
1942 const char *signature,
1943 const QByteArray &code,
1944 const ArgumentMap &args,
1945 TypeSystem::Language lang = TypeSystem::NativeCode)
1946 {
1947 CodeSnip snip;
1948 snip.language = lang;
1949 snip.position = CodeSnip::Beginning;
1950 snip.addCode(QString::fromLatin1(code));
1951 snip.argumentMap = args;
1952
1953 FunctionModification mod;
1954 mod.signature = QMetaObject::normalizedSignature(signature);
1955 mod.snips << snip;
1956 mod.modifiers = Modification::CodeInjection;
1957 e->addFunctionModification(mod);
1958 }
1959
1960
1961 static void addRemoveFunctionToTemplates(TypeDatabase *db)
1962 {
1963 ContainerTypeEntry *qvector = db->findContainerType(QLatin1String("QVector"));
1964 removeFunction(qvector, "constData() const");
1965 removeFunction(qvector, "data() const");
1966 removeFunction(qvector, "data()");
1967 removeFunction(qvector, "first()");
1968 removeFunction(qvector, "last()");
1969 removeFunction(qvector, "operator[](int)");
1970 removeFunction(qvector, "operator[](int) const");
1971 removeFunction(qvector, "operator=(QVector<T>)");
1972
1973 ContainerTypeEntry *qlist = db->findContainerType(QLatin1String("QList"));
1974 removeFunction(qlist, "constData() const");
1975 removeFunction(qlist, "data() const");
1976 removeFunction(qlist, "data()");
1977 removeFunction(qlist, "back()");
1978 removeFunction(qlist, "front()");
1979 removeFunction(qlist, "first()");
1980 removeFunction(qlist, "last()");
1981 removeFunction(qlist, "operator[](int)");
1982 removeFunction(qlist, "operator[](int) const");
1983 removeFunction(qlist, "operator=(QList<T>)");
1984
1985 ContainerTypeEntry *qqueue = db->findContainerType(QLatin1String("QQueue"));
1986 removeFunction(qqueue, "head() const");
1987
1988
1989 ArgumentMap args1;
1990 args1[1] = QLatin1String("$1");
1991 ArgumentMap args2 = args1;
1992 args2[2] = QLatin1String("$2");
1993
1994 QByteArray code =
1995 "\nif ($1 >= __qt_this->size() || $1 < 0) {"
1996 "\n __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
1997 "\n QString::fromLatin1(\"Accessing container of size %3 at %4\")"
1998 "\n .arg(__qt_this->size()).arg($1).toLatin1());"
1999 "\n return;"
2000 "\n}";
2001
2002 QByteArray code_with_return = QByteArray(code).replace("return;", "return 0;");
2003
2004 QByteArray code_index_length =
2005 "\nif ($1 < 0 || $2 < 0 || ($1 + $2) >= __qt_this->size()) {"
2006 "\n __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
2007 "\n QString::fromLatin1(\"Accessing container of size %3 from %4 to %5\")"
2008 "\n .arg(__qt_this->size()).arg($1).arg($1+$2).toLatin1());"
2009 "\n return;"
2010 "\n}";
2011
2012 QByteArray code_non_empty =
2013 "\nif (__qt_this->isEmpty()) {"
2014 "\n __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
2015 "\n QString::fromLatin1(\"Accessing empty container...\").toLatin1());"
2016 "\n return;"
2017 "\n}";
2018
2019 QByteArray code_two_indices =
2020 "\nif ($1 < 0 || $2 < 0 || $1 >= __qt_this->size() || $2 >= __qt_this->size()) {"
2021 "\n __jni_env->ThrowNew(__jni_env->FindClass(\"java/lang/IndexOutOfBoundsException\"),"
2022 "\n QString::fromLatin1(\"Accessing container of size %3 from %4 to %5\")"
2023 "\n .arg(__qt_this->size()).arg($1).arg($1+$2).toLatin1());"
2024 "\n return;"
2025 "\n}";
2026 /* qtd2
2027 { // QVector safty...
2028 injectCode(qvector, "at(int) const", code_with_return, args1, TypeSystem::TargetLangCode);
2029 injectCode(qvector, "replace(int,T)", code, args1, TypeSystem::TargetLangCode);
2030 injectCode(qvector, "remove(int)", code, args1, TypeSystem::TargetLangCode);
2031 injectCode(qvector, "remove(int, int)", code_index_length, args2, TypeSystem::TargetLangCode);
2032 injectCode(qvector, "pop_back()", code_non_empty, ArgumentMap(), TypeSystem::TargetLangCode);
2033 injectCode(qvector, "pop_front()", code_non_empty, ArgumentMap(), TypeSystem::TargetLangCode);
2034 }
2035
2036 { // QList safty...
2037 injectCode(qlist, "at(int) const", code_with_return, args1);
2038 injectCode(qlist, "replace(int, T)", code, args1);
2039 injectCode(qlist, "pop_back()", code_non_empty, ArgumentMap());
2040 injectCode(qlist, "pop_front()", code_non_empty, ArgumentMap());
2041 injectCode(qlist, "swap(int, int)", code_two_indices, args2);
2042 injectCode(qlist, "move(int, int)", code_two_indices, args2);
2043 injectCode(qlist, "removeAt(int)", code, args1);
2044 injectCode(qlist, "takeAt(int)", code_with_return, args1);
2045 }
2046 */
2047 }