1 | /* |
2 | * Copyright 2009 Mauro Iazzi <mauro.iazzi@gmail.com> |
3 | * Copyright 2009 Peter Kümmel <syntheticpp@gmx.net> |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | * Boston, MA 02110-1301 USA |
19 | */ |
20 | |
21 | |
22 | #include <iostream> |
23 | #include <typeinfo> |
24 | |
25 | #include "binder.h" |
26 | #include "codemodel.h" |
27 | #include "control.h" |
28 | #include "parser.h" |
29 | #include "preprocessor.h" |
30 | |
31 | #include <QByteArray> |
32 | #include <QFile> |
33 | #include <QTextCodec> |
34 | #include <QTextStream> |
35 | |
36 | #include <QObject> |
37 | #include <QDir> |
38 | |
39 | #include <QDebug> |
40 | |
41 | |
42 | #define ID_STR(i) (QString('_').append(QString::number(i->creationId()))) |
43 | #define ATTR_STR(n, v) ( QString(' ') + escape_chars(n) + QString("=\"") + escape_chars(v) + QString('\"') ) |
44 | #define ATTR_NUM(n, v) ( (QString::number(v)).prepend(" " n "=\"").append('\"') ) |
45 | #define ATTR_TRUE(n) ( ATTR_NUM(n, 1) ) |
46 | |
47 | |
48 | using namespace std; |
49 | |
50 | QString escape_chars (QString s) { |
51 | QString ret = s; |
52 | ret.replace('&', "&" ); |
53 | ret.replace('"', """ ); |
54 | ret.replace('\'', "'" ); |
55 | ret.replace('>', ">" ); |
56 | ret.replace('<', "<" ); |
57 | return ret; |
58 | } |
59 | |
60 | class XMLVisitor { |
61 | private: |
62 | bool resolve_types; |
63 | QString current_id; |
64 | QStringList current_context; |
65 | QList<CodeModelItem> current_scope; |
66 | CodeModelItem outer_scope; |
67 | public: |
68 | XMLVisitor(CodeModelItem c, bool r = true): |
69 | resolve_types(r), current_scope(), outer_scope(c) { |
70 | current_scope << c; |
71 | } |
72 | QString XMLTag(CodeModelItem); |
73 | TypeInfo solve(const TypeInfo&, QStringList); |
74 | TypeInfo simplifyType (TypeInfo const &, CodeModelItem __scope); |
75 | QString visit(const TypeInfo&, QStringList); |
76 | QString visit(CodeModelItem); |
77 | /* |
78 | template <typename T> QString visit(T) { |
79 | std::cerr << "unimplemented CodeModelItem: " << typeid(T).name() << std::endl; |
80 | return ""; |
81 | } |
82 | */ |
83 | }; |
84 | |
85 | |
86 | TypeInfo XMLVisitor::simplifyType (TypeInfo const &__type, CodeModelItem __scope) |
87 | { |
88 | CodeModel *__model = __scope->model (); |
89 | Q_ASSERT (__model != 0); |
90 | TypeInfo t; |
91 | for (int i=0;i<__type.qualifiedName().size();i++) { |
92 | QStringList qname = t.qualifiedName(); |
93 | qname << __type.qualifiedName().at(i); |
94 | t.setQualifiedName(qname); |
95 | //t = this->solve(t, __scope->qualifiedName()); |
96 | QString oldt = t.toString(); |
97 | t = t.resolveType(t, __scope); |
98 | if (t.toString()!=oldt) qDebug() << oldt << " --> " << t.toString(); |
99 | } |
100 | |
101 | TypeInfo otherType = __type; |
102 | otherType.setQualifiedName(t.qualifiedName()); |
103 | |
104 | return otherType; |
105 | } |
106 | |
107 | |
108 | |
109 | TypeInfo XMLVisitor::solve(const TypeInfo& t, QStringList scope) { |
110 | (void)scope; |
111 | if (!resolve_types) return t; |
112 | TypeInfo tt(t); |
113 | for (QList<CodeModelItem>::const_iterator i=current_scope.constBegin(); |
114 | i<current_scope.constEnd(); |
115 | i++) { |
116 | TypeInfo ttt = tt; |
117 | //qDebug() << tt.toString() << ttt.toString(); |
118 | Q_ASSERT(ttt==tt); |
119 | do { |
120 | tt = ttt; |
121 | ttt = ttt.resolveType(tt, *i); |
122 | } while (ttt!=tt); |
123 | |
124 | } |
125 | return tt; |
126 | } |
127 | |
128 | QString XMLVisitor::visit(const TypeInfo& t, QStringList scope) { |
129 | //t = t.resolveType(t, t.scope()); |
130 | |
131 | QString oldt = t.toString(); |
132 | TypeInfo tt = solve(t, scope); |
133 | //tt = simplifyType(tt, current_scope.first()); |
134 | while (oldt!=tt.toString()) { |
135 | oldt = tt.toString(); |
136 | tt = solve(tt, scope); |
137 | } |
138 | //if (oldt!=tt.toString()) qDebug() << oldt << " -> " << tt.toString(); |
139 | |
140 | QString ret; |
141 | ret += ATTR_STR("type_name" , tt.toString().replace(">>" , "> >" )); |
142 | ret += ATTR_STR("type_base" , tt.qualifiedName().join("::" ).replace(">>" , "> >" )); |
143 | if (tt.isConstant()) ret += ATTR_TRUE("type_constant" ); |
144 | if (tt.isVolatile()) ret += ATTR_TRUE("type_volatile" ); |
145 | if (tt.isReference()) ret += ATTR_TRUE("type_reference" ); |
146 | if (tt.indirections()>0) ret += ATTR_NUM("indirections" , tt.indirections()); |
147 | |
148 | QStringList arr = tt.arrayElements(); |
149 | QString tmp = arr.join("," ); |
150 | if (!tmp.isEmpty()) ret += " array=\"" + tmp + '\"'; |
151 | |
152 | if (tt.isFunctionPointer()) ret += ATTR_TRUE("function_pointer" ); |
153 | |
154 | return ret; |
155 | } |
156 | |
157 | #define TAG_CASE(s) case _CodeModelItem::Kind_##s: return #s |
158 | |
159 | QString XMLVisitor::XMLTag(CodeModelItem i) { |
160 | switch (i->kind()) { |
161 | TAG_CASE(Scope); |
162 | TAG_CASE(Namespace); |
163 | TAG_CASE(Member); |
164 | TAG_CASE(Function); |
165 | TAG_CASE(Argument); |
166 | TAG_CASE(Class); |
167 | TAG_CASE(Enum); |
168 | TAG_CASE(Enumerator); |
169 | TAG_CASE(File); |
170 | TAG_CASE(FunctionDefinition); |
171 | TAG_CASE(TemplateParameter); |
172 | TAG_CASE(TypeAlias); |
173 | TAG_CASE(Variable); |
174 | } |
175 | return QString(); |
176 | } |
177 | |
178 | QString templateParametersToString (TemplateParameterList list) { |
179 | QString ret; |
180 | foreach(TemplateParameterModelItem p,list) { |
181 | ret = ret + p->name() + ';'; |
182 | } |
183 | return ret; |
184 | } |
185 | |
186 | QString XMLVisitor::visit(CodeModelItem i) { |
187 | QString ret; |
188 | ret += XMLTag(i); |
189 | |
190 | current_id = ID_STR(i) + " => " + XMLTag(i) + " => " + i->qualifiedName().join("::" ); // FIXME: this is debug code |
191 | |
192 | ret += ATTR_STR("id" , ID_STR(i)); |
193 | ret += ATTR_STR("name" , i->name()); |
194 | ret += ATTR_STR("scope" , i->scope().join("::" )); |
195 | ret += ATTR_STR("context" , current_context.join("::" )); |
196 | // FIXME: is this a dirty hack? yes, it is! |
197 | if (ArgumentModelItem a = model_dynamic_cast<ArgumentModelItem>(i)) { |
198 | //ret += ATTR_STR("fullname", current_context.join("::")+"::"+i->qualifiedName().join("::")); |
199 | } else if (EnumeratorModelItem a = model_dynamic_cast<EnumeratorModelItem>(i)) { |
200 | ret += ATTR_STR("fullname" , current_context.join("::" )+"::" +i->qualifiedName().join("::" )); |
201 | } else { |
202 | ret += ATTR_STR("fullname" , i->qualifiedName().join("::" )); |
203 | } |
204 | |
205 | if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) { |
206 | ret += " members=\"" ; |
207 | } |
208 | if (NamespaceModelItem n = model_dynamic_cast<NamespaceModelItem>(i)) { |
209 | foreach(NamespaceModelItem m, n->namespaces()) |
210 | ret += ID_STR(m).append(' '); |
211 | } |
212 | if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) { |
213 | foreach(ClassModelItem n, s->classes()) |
214 | ret += ID_STR(n).append(' '); |
215 | foreach(EnumModelItem n, s->enums()) |
216 | ret += ID_STR(n).append(' '); |
217 | foreach(FunctionModelItem n, s->functions()) |
218 | ret += ID_STR(n).append(' '); |
219 | foreach(TypeAliasModelItem n, s->typeAliases()) |
220 | ret += ID_STR(n).append(' '); |
221 | foreach(VariableModelItem n, s->variables()) |
222 | ret += ID_STR(n).append(' '); |
223 | } |
224 | if (ScopeModelItem s = model_dynamic_cast<ScopeModelItem>(i)) { |
225 | ret += '\"'; |
226 | } |
227 | if (MemberModelItem m = model_dynamic_cast<MemberModelItem>(i)) { |
228 | if (m->isConstant()) ret += ATTR_TRUE("constant" ); |
229 | if (m->isVolatile()) ret += ATTR_TRUE("volatile" ); |
230 | if (m->isStatic()) ret += ATTR_TRUE("static" ); |
231 | if (m->isAuto()) ret += ATTR_TRUE("auto" ); |
232 | if (m->isFriend()) ret += ATTR_TRUE("friend" ); |
233 | if (m->isRegister()) ret += ATTR_TRUE("register" ); |
234 | if (m->isExtern()) ret += ATTR_TRUE("extern" ); |
235 | if (m->isMutable()) ret += ATTR_TRUE("mutable" ); |
236 | QStringList ownerName = m->qualifiedName(); |
237 | ownerName.pop_back(); |
238 | ret += ATTR_STR("member_of" , ownerName.join("::" )); |
239 | |
240 | if (ClassModelItem c = model_dynamic_cast<ClassModelItem>(current_scope.last())) |
241 | ret += ATTR_STR("member_of_class" , c->qualifiedName().join("::" )); |
242 | |
243 | switch (m->accessPolicy()) { |
244 | case CodeModel::Public: |
245 | ret += ATTR_STR("access" , "public" ); |
246 | break; |
247 | case CodeModel::Private: |
248 | ret += ATTR_STR("access" , "private" ); |
249 | break; |
250 | case CodeModel::Protected: |
251 | ret += ATTR_STR("access" , "protected" ); |
252 | break; |
253 | }; |
254 | |
255 | ret += visit(m->type(), m->scope()); |
256 | QString tp = templateParametersToString(m->templateParameters()); |
257 | if (tp!=QString()) ret += ATTR_STR("member_template_parameters" , tp); |
258 | } |
259 | if (FunctionModelItem f = model_dynamic_cast<FunctionModelItem>(i)) { |
260 | if (f->isVirtual()) ret += ATTR_TRUE("virtual" ); |
261 | if (f->isInline()) ret += ATTR_TRUE("inline" ); |
262 | if (f->isExplicit()) ret += ATTR_TRUE("explicit" ); |
263 | if (f->isAbstract()) ret += ATTR_TRUE("abstract" ); |
264 | if (f->isVariadics()) ret += ATTR_TRUE("variadics" ); |
265 | //if (i->name()=="destroyed") qDebug() << CodeModel::Normal << CodeModel::Slot << CodeModel::Signal << m->functionType() << i->qualifiedName(); |
266 | switch(f->functionType()) { |
267 | case CodeModel::Normal: |
268 | break; |
269 | case CodeModel::Slot: |
270 | ret += ATTR_TRUE("slot" ); |
271 | break; |
272 | case CodeModel::Signal: |
273 | ret += ATTR_TRUE("signal" ); |
274 | break; |
275 | } |
276 | } |
277 | if (ArgumentModelItem a = model_dynamic_cast<ArgumentModelItem>(i)) { |
278 | ret += visit(a->type(), a->scope()); |
279 | if (a->defaultValue()) { |
280 | ret += ATTR_TRUE("default" ); |
281 | ret += ATTR_STR("defaultvalue" , a->defaultValueExpression()); |
282 | } |
283 | } |
284 | if (ClassModelItem c = model_dynamic_cast<ClassModelItem>(i)) { |
285 | switch (c->accessPolicy()) { |
286 | case CodeModel::Public: |
287 | ret += ATTR_STR("access" , "public" ); |
288 | break; |
289 | case CodeModel::Private: |
290 | ret += ATTR_STR("access" , "private" ); |
291 | break; |
292 | case CodeModel::Protected: |
293 | ret += ATTR_STR("access" , "protected" ); |
294 | break; |
295 | }; |
296 | |
297 | if (c->baseClasses().size()>0) { |
298 | QStringList fullBases; |
299 | ret += ATTR_STR("bases" , c->baseClasses().join(";" ).append(";" )); |
300 | Q_ASSERT (c->baseClasses().size() == c->baseModifiers().size()); |
301 | for (int j=0;j<c->baseClasses().size();j++) { |
302 | fullBases.append(c->baseModifiers().at(j) + " " + c->baseClasses().at(j)); |
303 | } |
304 | ret += ATTR_STR("bases_with_attributes" , fullBases.join(";" ).append(";" )); |
305 | } |
306 | switch(c->classType()) { |
307 | case CodeModel::Class: |
308 | ret += ATTR_STR("class_type" , QString("class" )); |
309 | break; |
310 | case CodeModel::Struct: |
311 | ret += ATTR_STR("class_type" , QString("struct" )); |
312 | break; |
313 | case CodeModel::Union: |
314 | ret += ATTR_STR("class_type" , QString("union" )); |
315 | break; |
316 | } |
317 | QString tp = templateParametersToString(c->templateParameters()); |
318 | if (tp!=QString()) ret += ATTR_STR("member_template_parameters" , tp); |
319 | // TODO also list propertyDeclarations (maybe in content?) |
320 | } |
321 | if (EnumModelItem e = model_dynamic_cast<EnumModelItem>(i)) { |
322 | switch (e->accessPolicy()) { |
323 | case CodeModel::Public: |
324 | ret += ATTR_STR("access" , "public" ); |
325 | break; |
326 | case CodeModel::Private: |
327 | ret += ATTR_STR("access" , "private" ); |
328 | break; |
329 | case CodeModel::Protected: |
330 | ret += ATTR_STR("access" , "protected" ); |
331 | break; |
332 | }; |
333 | } |
334 | if (EnumeratorModelItem e = model_dynamic_cast<EnumeratorModelItem>(i)) { |
335 | ret += ATTR_STR("value" , e->value()); |
336 | } |
337 | if (TypeAliasModelItem t = model_dynamic_cast<TypeAliasModelItem>(i)) { |
338 | ret += visit(t->type(), t->scope()); |
339 | } |
340 | |
341 | // |
342 | // content of the entry: |
343 | // - Arguments of functions |
344 | // - members of scopes |
345 | // - enumeration values |
346 | // |
347 | QString children; |
348 | if (NamespaceModelItem n = model_dynamic_cast<NamespaceModelItem>(i)) { |
349 | foreach(NamespaceModelItem m, n->namespaces()) |
350 | children += visit(model_static_cast<CodeModelItem>(m)); |
351 | } |
352 | if (i->kind() & _CodeModelItem::Kind_Scope) { |
353 | //qDebug() << ID_STR(i) << i->name() << current_context; |
354 | //CodeModelItem os = current_scope; // save old outer scope |
355 | if (!i->name().isEmpty()) { current_context << i->name(); current_scope << i; } |
356 | foreach(ClassModelItem n, model_dynamic_cast<ScopeModelItem>(i)->classes()) |
357 | children += visit(model_static_cast<CodeModelItem>(n)); |
358 | foreach(EnumModelItem n, model_dynamic_cast<ScopeModelItem>(i)->enums()) |
359 | children += visit(model_static_cast<CodeModelItem>(n)); |
360 | foreach(FunctionModelItem n, model_dynamic_cast<ScopeModelItem>(i)->functions()) |
361 | children += visit(model_static_cast<CodeModelItem>(n)); |
362 | foreach(TypeAliasModelItem n, model_dynamic_cast<ScopeModelItem>(i)->typeAliases()) |
363 | children += visit(model_static_cast<CodeModelItem>(n)); |
364 | foreach(VariableModelItem n, model_dynamic_cast<ScopeModelItem>(i)->variables()) |
365 | children += visit(model_static_cast<CodeModelItem>(n)); |
366 | if (!i->name().isEmpty()) { current_context.removeLast(); current_scope.pop_back(); } |
367 | } |
368 | if (FunctionModelItem f = model_dynamic_cast<FunctionModelItem>(i)) { |
369 | foreach(ArgumentModelItem a, f->arguments()) |
370 | children += visit(model_static_cast<CodeModelItem>(a)); |
371 | } |
372 | if (EnumModelItem e = model_dynamic_cast<EnumModelItem>(i)) { |
373 | QString last = QChar('0'); |
374 | foreach(EnumeratorModelItem n, model_dynamic_cast<EnumModelItem>(i)->enumerators()) { |
375 | if (n->value() == QString()) |
376 | n->setValue(last.append("+1" )); //FIXME: Is there a reason for not putting the value itself? :S |
377 | children += visit(model_static_cast<CodeModelItem>(n)); |
378 | last = n->value(); |
379 | } |
380 | } |
381 | //ret.replace('&', "&"); |
382 | //ret.replace('>', ">"); |
383 | //ret.replace('<', "<"); |
384 | |
385 | // TODO fix lua binding generator |
386 | if(false && children.isEmpty()) |
387 | { |
388 | ret = "<" + ret + " />\n" ; |
389 | } |
390 | else |
391 | { |
392 | ret = "<" + ret + " >\n" ; |
393 | ret += children; |
394 | ret += "</" ; |
395 | ret += XMLTag(i); |
396 | ret += ">\n" ; |
397 | } |
398 | return ret; |
399 | } |
400 | |
401 | void printHelp() |
402 | { |
403 | const char* help = |
404 | "Usage: cpptoxml <flags> <file>\n\n" |
405 | "Options:\n" |
406 | "<file> file to parse\n" |
407 | "-C optional parser config file\n" |
408 | "-P only preprocess\n" |
409 | "-R don't resolve\n" |
410 | "-N generate NO code\n" |
411 | "-v verbose\n" |
412 | "-d debug\n" |
413 | "-h print this help\n" |
414 | "-qt default qt config file: -C cpptoxml/parser/rpp/pp-qt-configuration\n" |
415 | "-I Add another include directory\n" |
416 | "-Q Qt include dir\n" |
417 | "-o output file\n" |
418 | ; |
419 | fprintf(stderr, "%s" , help); |
420 | } |
421 | |
422 | |
423 | int main (int argc, char **argv) { |
424 | bool onlyPreprocess = false; |
425 | bool dontResolve = false; |
426 | bool noCode = false; |
427 | bool verbose = false; |
428 | bool debug = false; |
429 | QString configName; |
430 | QString sourceName; |
431 | QStringList inclist; |
432 | QString outputFile; |
433 | QString qtdir; |
434 | |
435 | for(int i=1; i<argc; i++) { |
436 | if(argv[i][0]=='-' && argv[i][1]!=0) { |
437 | QString argValue; |
438 | bool separed = (argv[i][2] == '\0' && argc > i+1 && argv[i+1][0] != '-'); |
439 | if (separed) |
440 | argValue = QDir::fromNativeSeparators(QString::fromLatin1(argv[i+1]).right(strlen(argv[i+1]))); |
441 | else |
442 | argValue = QDir::fromNativeSeparators(QString::fromLatin1(argv[i]).right(strlen(argv[i])-2)); |
443 | |
444 | switch(argv[i][1]) { |
445 | case 'C': |
446 | configName = argValue; |
447 | break; |
448 | case 'P': |
449 | onlyPreprocess = true; |
450 | break; |
451 | case 'R': |
452 | dontResolve = true; |
453 | break; |
454 | case 'N': |
455 | noCode = true; |
456 | break; |
457 | case 'v': |
458 | verbose = true; |
459 | break; |
460 | case 'd': |
461 | debug = true; |
462 | break; |
463 | case 'h': |
464 | printHelp(); |
465 | return 0; |
466 | case 'I': |
467 | inclist.append(argValue); |
468 | break; |
469 | case 'Q': |
470 | qtdir = argValue; |
471 | break; |
472 | case 'q':{ |
473 | if(QString(argv[i]).startsWith("-qt" )) { |
474 | configName = "cpptoxml/parser/rpp/pp-qt-configuration" ; |
475 | #ifdef Q_OS_WIN |
476 | configName += QString("-win" ); |
477 | #endif |
478 | } else |
479 | fprintf(stderr, "found unknown parameter: -%s" ,argv[i]); |
480 | } break; |
481 | case 'o': |
482 | outputFile = argValue; |
483 | break; |
484 | |
485 | default: |
486 | fprintf(stderr, "found unknown parameter: %s" , argv[i]); |
487 | return 1; |
488 | } |
489 | if (separed) |
490 | i++; |
491 | } else { |
492 | #ifdef Q_OS_MAC |
493 | if (sourceName.isEmpty()) |
494 | sourceName = QString::fromLatin1(argv[i]); |
495 | else |
496 | qtdir = QString::fromLatin1(argv[i]); |
497 | #else |
498 | sourceName = QString::fromLatin1(argv[i]); |
499 | #endif |
500 | } |
501 | } |
502 | |
503 | if (qtdir.isEmpty()) |
504 | qtdir = QDir::fromNativeSeparators(getenv("QT_INCLUDE" )); |
505 | if (qtdir.isEmpty()) { |
506 | fprintf(stderr, "Generator requires Qt include dir as option -Q or QT_INCLUDE to be set\n" ); |
507 | return 1; |
508 | } |
509 | |
510 | QString frameworkDir = "/Library/Frameworks" ; |
511 | if (!QFileInfo(sourceName).exists() || QFileInfo(sourceName).isDir()) { |
512 | QString qtincludefile = QDir::fromNativeSeparators(qtdir+'/'+sourceName+'/'+sourceName); |
513 | QString macincludefile = QString("%1/%2.framework/Headers/%2" ).arg(frameworkDir).arg(sourceName); |
514 | if (QFileInfo(qtincludefile).exists()) { |
515 | sourceName = qtincludefile; |
516 | } else if (QFileInfo(macincludefile).exists()) { |
517 | sourceName = macincludefile; |
518 | } else { |
519 | QString msg = "Error: wether '" + sourceName + "' nor '" + qtincludefile; |
520 | #if defined(Q_OS_MAC) |
521 | msg += "' or '" + macincludefile; |
522 | #endif |
523 | msg += "' found" ; |
524 | fprintf(stderr, "%s\n" , msg.toLatin1().constData()); |
525 | return 1; |
526 | } |
527 | } |
528 | |
529 | if(verbose) fprintf(stderr, "Used file: %s" , qPrintable(sourceName)); |
530 | |
531 | QString currentDir = QDir::current().absolutePath(); |
532 | QFileInfo sourceInfo(sourceName); |
533 | //QDir::setCurrent(sourceInfo.absolutePath()); |
534 | |
535 | inclist << (sourceInfo.absolutePath()); |
536 | inclist << (QDir::convertSeparators(qtdir)); |
537 | |
538 | QStringList qts; |
539 | qts << "QtXml" << "QtNetwork" << "QtCore" << "QtGui" |
540 | <<"QtOpenGL" << "QtWebKit" << "QtScript" << "QtSvg" ; |
541 | |
542 | Q_FOREACH(const QString& lib, qts) { |
543 | if (sourceName.contains(frameworkDir)) { |
544 | // TODO does not work with framework because there are no QtCore, QtGui, ... folders |
545 | inclist << QString("%1/%2.framework/Headers" ).arg(frameworkDir).arg(lib); |
546 | } else { |
547 | inclist << QDir::convertSeparators(qtdir + "/" + lib); |
548 | } |
549 | } |
550 | |
551 | if(debug) qDebug() << "atdir: " << qtdir << "sourceName: " << sourceName << inclist; |
552 | |
553 | |
554 | Preprocessor pp; |
555 | pp.addIncludePaths(inclist); |
556 | pp.processFile(configName); |
557 | pp.processFile(sourceName); |
558 | QByteArray contents = pp.result(); |
559 | |
560 | if(debug) qDebug() << pp.macroNames(); |
561 | if(debug) qDebug() << contents; |
562 | if(debug) QTextStream(stdout) << contents; |
563 | |
564 | if (onlyPreprocess) { |
565 | QTextStream(stdout) << contents; |
566 | } else { |
567 | Control control; |
568 | Parser p(&control); |
569 | pool __pool; |
570 | |
571 | TranslationUnitAST *ast = p.parse(contents, contents.size(), &__pool); |
572 | |
573 | CodeModel model; |
574 | Binder binder(&model, p.location()); |
575 | FileModelItem f_model = binder.run(ast); |
576 | |
577 | if (!noCode) { |
578 | XMLVisitor visitor((CodeModelItem)f_model, !dontResolve); |
579 | QString xml = visitor.visit(model_static_cast<CodeModelItem>(f_model)); |
580 | if (outputFile.isEmpty()) { |
581 | QTextStream(stdout) << xml; |
582 | } else { |
583 | QFile file(outputFile); |
584 | if (file.open(QFile::WriteOnly | QFile::Text)) { |
585 | file.write(xml.toLatin1()); |
586 | } |
587 | } |
588 | } |
589 | } |
590 | |
591 | return 0; |
592 | } |
593 | |
594 | |
595 | |
596 | |
597 | |
598 | |
599 | |