2 * Copyright (c) 2007-2008 Mauro Iazzi
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
31 #include "codemodel.h"
34 #include "preprocessor.h"
39 #include <QTextStream>
46 #define ID_STR(i) (QString("_").append(QString::number(i->creationId())))
47 #define ATTR_STR(n, v) ( QString(" ") + n + QString("=\"") + v + QString("\"") )
48 #define ATTR_NUM(n, v) ( (QString::number(v)).prepend(" " n "=\"").append("\"") )
49 #define ATTR_TRUE(n) ( ATTR_NUM(n, 1) )
57 QStringList current_context
;
58 QList
<CodeModelItem
> current_scope
;
59 CodeModelItem outer_scope
;
61 XMLVisitor(CodeModelItem c
, bool r
= true):
62 resolve_types(r
), current_scope(), outer_scope(c
) {
65 QString
XMLTag(CodeModelItem
);
66 TypeInfo
solve(const TypeInfo
&, QStringList
);
67 TypeInfo
simplifyType (TypeInfo
const &, CodeModelItem __scope
);
68 QString
visit(const TypeInfo
&, QStringList
);
69 QString
visit(CodeModelItem
);
71 template <typename T> QString visit(T) {
72 std::cerr << "unimplemented CodeModelItem: " << typeid(T).name() << std::endl;
79 TypeInfo
XMLVisitor::simplifyType (TypeInfo
const &__type
, CodeModelItem __scope
)
81 CodeModel
*__model
= __scope
->model ();
82 Q_ASSERT (__model
!= 0);
84 for (int i
=0;i
<__type
.qualifiedName().size();i
++) {
85 QStringList qname
= t
.qualifiedName();
86 qname
<< __type
.qualifiedName().at(i
);
87 t
.setQualifiedName(qname
);
88 //t = this->solve(t, __scope->qualifiedName());
89 QString oldt
= t
.toString();
90 t
= t
.resolveType(t
, __scope
);
91 if (t
.toString()!=oldt
) qDebug() << oldt
<< " --> " << t
.toString();
94 TypeInfo otherType
= __type
;
95 otherType
.setQualifiedName(t
.qualifiedName());
102 TypeInfo
XMLVisitor::solve(const TypeInfo
& t
, QStringList scope
) {
104 if (!resolve_types
) return t
;
106 for (QList
<CodeModelItem
>::const_iterator i
=current_scope
.begin();
107 i
<current_scope
.end();
110 //qDebug() << tt.toString() << ttt.toString();
114 ttt
= ttt
.resolveType(tt
, *i
);
121 QString
XMLVisitor::visit(const TypeInfo
& t
, QStringList scope
) {
122 //t = t.resolveType(t, t.scope());
124 QString oldt
= t
.toString();
125 TypeInfo tt
= solve(t
, scope
);
126 //tt = simplifyType(tt, current_scope.first());
127 while (oldt
!=tt
.toString()) {
128 oldt
= tt
.toString();
129 tt
= solve(tt
, scope
);
131 //if (oldt!=tt.toString()) qDebug() << oldt << " -> " << tt.toString();
133 QString
ret(" type_name=\"");
134 ret
+= tt
.toString().append("\"");
135 ret
+= " type_base=\"";
136 ret
+= tt
.qualifiedName().join("::").append("\"");
137 if (tt
.isConstant()) ret
+= ATTR_TRUE("type_constant");
138 if (tt
.isVolatile()) ret
+= ATTR_TRUE("type_volatile");
139 if (tt
.isReference()) ret
+= ATTR_TRUE("type_reference");
140 if (tt
.indirections()>0) ret
+= ATTR_NUM("indirections", tt
.indirections());
142 QStringList arr
= tt
.arrayElements();
143 QString tmp
= arr
.join(",");
144 if (!tmp
.isEmpty()) ret
+= " array=\"" + tmp
+ "\"";
149 #define TAG_CASE(s) case _CodeModelItem::Kind_##s: return #s
151 QString
XMLVisitor::XMLTag(CodeModelItem i
) {
160 TAG_CASE(Enumerator
);
162 TAG_CASE(FunctionDefinition
);
163 TAG_CASE(TemplateParameter
);
170 QString
templateParametersToString (TemplateParameterList list
) {
172 foreach(TemplateParameterModelItem p
,list
) {
173 ret
= ret
+ p
->name() + ";";
178 QString
XMLVisitor::visit(CodeModelItem i
) {
182 current_id
= ID_STR(i
) + " => " + XMLTag(i
) + " => " + i
->qualifiedName().join("::"); // FIXME: this is debug code
184 ret
+= ATTR_STR("id", ID_STR(i
));
185 ret
+= ATTR_STR("name", i
->name());
186 ret
+= ATTR_STR("scope", i
->scope().join("::"));
187 ret
+= ATTR_STR("context", current_context
.join("::"));
188 // FIXME: is this a dirty hack? yes, it is!
189 if (ArgumentModelItem a
= model_dynamic_cast
<ArgumentModelItem
>(i
)) {
190 //ret += ATTR_STR("fullname", current_context.join("::")+"::"+i->qualifiedName().join("::"));
191 } else if (EnumeratorModelItem a
= model_dynamic_cast
<EnumeratorModelItem
>(i
)) {
192 ret
+= ATTR_STR("fullname", current_context
.join("::")+"::"+i
->qualifiedName().join("::"));
194 ret
+= ATTR_STR("fullname", i
->qualifiedName().join("::"));
197 if (ScopeModelItem s
= model_dynamic_cast
<ScopeModelItem
>(i
)) {
198 ret
+= " members=\"";
200 if (NamespaceModelItem n
= model_dynamic_cast
<NamespaceModelItem
>(i
)) {
201 foreach(NamespaceModelItem m
, n
->namespaces())
202 ret
+= ID_STR(m
).append(" ");
204 if (ScopeModelItem s
= model_dynamic_cast
<ScopeModelItem
>(i
)) {
205 foreach(ClassModelItem n
, s
->classes())
206 ret
+= ID_STR(n
).append(" ");
207 foreach(EnumModelItem n
, s
->enums())
208 ret
+= ID_STR(n
).append(" ");
209 foreach(FunctionModelItem n
, s
->functions())
210 ret
+= ID_STR(n
).append(" ");
211 foreach(TypeAliasModelItem n
, s
->typeAliases())
212 ret
+= ID_STR(n
).append(" ");
213 foreach(VariableModelItem n
, s
->variables())
214 ret
+= ID_STR(n
).append(" ");
216 if (ScopeModelItem s
= model_dynamic_cast
<ScopeModelItem
>(i
)) {
219 if (MemberModelItem m
= model_dynamic_cast
<MemberModelItem
>(i
)) {
220 if (m
->isConstant()) ret
+= ATTR_TRUE("constant");
221 if (m
->isVolatile()) ret
+= ATTR_TRUE("volatile");
222 if (m
->isStatic()) ret
+= ATTR_TRUE("static");
223 if (m
->isAuto()) ret
+= ATTR_TRUE("auto");
224 if (m
->isFriend()) ret
+= ATTR_TRUE("friend");
225 if (m
->isRegister()) ret
+= ATTR_TRUE("register");
226 if (m
->isExtern()) ret
+= ATTR_TRUE("extern");
227 if (m
->isMutable()) ret
+= ATTR_TRUE("mutable");
228 QStringList ownerName
= m
->qualifiedName();
229 ownerName
.pop_back();
230 ret
+= ATTR_STR("member_of", ownerName
.join("::"));
232 if (ClassModelItem c
= model_dynamic_cast
<ClassModelItem
>(current_scope
.last()))
233 ret
+= ATTR_STR("member_of_class", c
->qualifiedName().join("::"));
235 switch (m
->accessPolicy()) {
236 case CodeModel::Public
:
237 ret
+= ATTR_STR("access", "public");
239 case CodeModel::Private
:
240 ret
+= ATTR_STR("access", "private");
242 case CodeModel::Protected
:
243 ret
+= ATTR_STR("access", "protected");
247 ret
+= visit(m
->type(), m
->scope());
248 QString tp
= templateParametersToString(m
->templateParameters());
249 if (tp
!=QString()) ret
+= ATTR_STR("member_template_parameters", tp
);
251 if (FunctionModelItem f
= model_dynamic_cast
<FunctionModelItem
>(i
)) {
252 if (f
->isVirtual()) ret
+= ATTR_TRUE("virtual");
253 if (f
->isInline()) ret
+= ATTR_TRUE("inline");
254 if (f
->isExplicit()) ret
+= ATTR_TRUE("explicit");
255 if (f
->isAbstract()) ret
+= ATTR_TRUE("abstract");
256 if (f
->isVariadics()) ret
+= ATTR_TRUE("variadics");
257 //if (i->name()=="destroyed") qDebug() << CodeModel::Normal << CodeModel::Slot << CodeModel::Signal << m->functionType() << i->qualifiedName();
258 switch(f
->functionType()) {
259 case CodeModel::Normal
:
261 case CodeModel::Slot
:
262 ret
+= ATTR_TRUE("slot");
264 case CodeModel::Signal
:
265 ret
+= ATTR_TRUE("signal");
269 if (ArgumentModelItem a
= model_dynamic_cast
<ArgumentModelItem
>(i
)) {
270 ret
+= visit(a
->type(), a
->scope());
271 if (a
->defaultValue()) {
272 ret
+= ATTR_TRUE("default");
273 ret
+= ATTR_STR("defaultvalue", a
->defaultValueExpression());
276 if (ClassModelItem c
= model_dynamic_cast
<ClassModelItem
>(i
)) {
277 if (c
->baseClasses().size()>0) {
278 ret
+= ATTR_STR("bases", c
->baseClasses().join(";").append(";"));
280 switch(c
->classType()) {
281 case CodeModel::Class
:
282 ret
+= ATTR_STR("class_type", QString("class"));
284 case CodeModel::Struct
:
285 ret
+= ATTR_STR("class_type", QString("struct"));
287 case CodeModel::Union
:
288 ret
+= ATTR_STR("class_type", QString("union"));
291 QString tp
= templateParametersToString(c
->templateParameters());
292 if (tp
!=QString()) ret
+= ATTR_STR("member_template_parameters", tp
);
293 // TODO also list propertyDeclarations (maybe in content?)
295 if (EnumModelItem e
= model_dynamic_cast
<EnumModelItem
>(i
)) {
296 switch (e
->accessPolicy()) {
297 case CodeModel::Public
:
298 ret
+= ATTR_STR("access", "public");
300 case CodeModel::Private
:
301 ret
+= ATTR_STR("access", "private");
303 case CodeModel::Protected
:
304 ret
+= ATTR_STR("access", "protected");
308 if (EnumeratorModelItem e
= model_dynamic_cast
<EnumeratorModelItem
>(i
)) {
309 ret
+= e
->value().prepend(" value=\"").append("\"");
311 if (TypeAliasModelItem t
= model_dynamic_cast
<TypeAliasModelItem
>(i
)) {
312 ret
+= visit(t
->type(), t
->scope());
315 ret
.replace('>', ">");
316 ret
.replace('<', "<");
317 ret
= "<" + ret
+ " >\n";
320 // content of the entry:
321 // - Arguments of functions
322 // - members of scopes
323 // - enumeration values
325 if (NamespaceModelItem n
= model_dynamic_cast
<NamespaceModelItem
>(i
)) {
326 foreach(NamespaceModelItem m
, n
->namespaces())
327 ret
+= visit(model_static_cast
<CodeModelItem
>(m
));
329 if (i
->kind() & _CodeModelItem::Kind_Scope
) {
330 //qDebug() << ID_STR(i) << i->name() << current_context;
331 //CodeModelItem os = current_scope; // save old outer scope
332 if (!i
->name().isEmpty()) { current_context
<< i
->name(); current_scope
<< i
; }
333 foreach(ClassModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->classes())
334 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
335 foreach(EnumModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->enums())
336 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
337 foreach(FunctionModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->functions())
338 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
339 foreach(TypeAliasModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->typeAliases())
340 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
341 foreach(VariableModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->variables())
342 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
343 if (!i
->name().isEmpty()) { current_context
.removeLast(); current_scope
.pop_back(); }
345 if (FunctionModelItem f
= model_dynamic_cast
<FunctionModelItem
>(i
)) {
346 foreach(ArgumentModelItem a
, f
->arguments())
347 ret
+= visit(model_static_cast
<CodeModelItem
>(a
));
349 if (EnumModelItem e
= model_dynamic_cast
<EnumModelItem
>(i
)) {
351 foreach(EnumeratorModelItem n
, model_dynamic_cast
<EnumModelItem
>(i
)->enumerators()) {
352 if (n
->value() == QString()) n
->setValue(last
.append("+1"));
353 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
365 int main (int argc
, char **argv
) {
366 bool onlyPreprocess
= false;
367 bool dontResolve
= false;
372 for (int i
=1;i
<argc
;i
++) options
<< argv
[i
];
374 if ((i
=options
.indexOf("-C"))!=-1) {
375 if (options
.count() > i
+1) {
376 configName
= options
.at(i
+1);
377 options
.removeAt(i
+1);
381 if ((i
=options
.indexOf("-P"))!=-1) {
382 onlyPreprocess
= true;
385 if ((i
=options
.indexOf("-R"))!=-1) {
389 if (options
.count()>1) return 37;
390 sourceName
= options
.at(0);
397 QString qtdir
= getenv ("QTDIR");
398 if (qtdir
.isEmpty()) {
399 fprintf(stderr
, "Generator requires QTDIR to be set\n");
405 QString currentDir
= QDir::current().absolutePath();
406 QFileInfo
sourceInfo(sourceName
);
407 //QDir::setCurrent(sourceInfo.absolutePath());
409 inclist
<< (sourceInfo
.absolutePath());
410 inclist
<< (QDir::convertSeparators(qtdir
));
411 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtXml"));
412 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtNetwork"));
413 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtCore"));
414 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtGui"));
415 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtOpenGL"));
416 //qDebug() << inclist;
418 pp
.addIncludePaths(inclist
);
419 pp
.processFile(sourceName
, configName
);
420 //qDebug() << pp.macroNames();
421 contents
= pp
.result();
422 //qDebug() << contents;
423 //QTextStream(stdout) << contents;
425 if (onlyPreprocess
) {
426 QTextStream(stdout
) << contents
;
432 TranslationUnitAST
*ast
= p
.parse(contents
, contents
.size(), &__pool
);
435 Binder
binder(&model
, p
.location());
436 FileModelItem f_model
= binder
.run(ast
);
438 XMLVisitor
visitor((CodeModelItem
)f_model
, !dontResolve
);
439 QTextStream(stdout
) << visitor
.visit(model_static_cast
<CodeModelItem
>(f_model
));