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