2 * Copyright (c) 2007 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) ( (v).prepend(" " n "=\"").append("\"") )
48 #define ATTR_NUM(n, v) ( (QString::number(v)).prepend(" " n "=\"").append("\"") )
49 #define ATTR_TRUE(n) ( ATTR_NUM(n, 1) )
55 QString
XMLTag(CodeModelItem
);
56 QString
visit(TypeInfo
);
57 QString
visit(CodeModelItem
);
58 template <typename T
> QString
visit(T
) {
59 std::cerr
<< "unimplemented CodeModelItem: " << typeid(T
).name() << std::endl
;
63 QString
XMLVisitor::visit(TypeInfo t
) {
66 QStringList::const_iterator constIterator;
67 for (constIterator = s_list.constBegin(); constIterator != s_list.constEnd(); ++constIterator)
68 qDebug() << *constIterator << "::";
69 qDebug() << "const " << t.isConstant();
70 qDebug() << "volatile " << t.isVolatile();
71 qDebug() << "reference " << t.isReference();
72 qDebug() << "indir " << t.indirections();
73 qDebug() << "fp? " << t.isFunctionPointer();
74 //QStringList arrayElements();
75 //QList<TypeInfo> arguments();
76 qDebug() << t.toString();
78 //if (s_list.size()>1) qDebug() << t.toString() << s_list;
79 //if (s_list.join("::")!=t.toString()) qDebug() << s_list.join("::") << t.toString();
80 QString
ret(" type_name=\"");
81 ret
+= t
.toString().append("\"");
82 ret
+= " type_base=\"";
83 ret
+= t
.qualifiedName().join("::").append("\"");
84 if (t
.isConstant()) ret
+= ATTR_TRUE("type_constant");
85 if (t
.isVolatile()) ret
+= ATTR_TRUE("type_volatile");
86 if (t
.isReference()) ret
+= ATTR_TRUE("type_reference");
87 if (t
.indirections()>0) ret
+= ATTR_NUM("indirections", t
.indirections());
91 #define TAG_CASE(s) case _CodeModelItem::Kind_##s: return #s
92 QString
XMLVisitor::XMLTag(CodeModelItem i
) {
101 TAG_CASE(Enumerator
);
103 TAG_CASE(FunctionDefinition
);
104 TAG_CASE(TemplateParameter
);
110 QString
XMLVisitor::visit(CodeModelItem i
) {
114 ret
+= ATTR_STR("id", ID_STR(i
));
115 ret
+= ATTR_STR("name", i
->name());
116 ret
+= ATTR_STR("context", i
->scope().join("::").append("::"));
117 ret
+= ATTR_STR("fullname", i
->qualifiedName().join("::"));
119 if (i
->kind() & _CodeModelItem::Kind_Scope
) {
120 ret
+= " members=\"";
122 if ((i
->kind() & _CodeModelItem::Kind_Namespace
) == _CodeModelItem::Kind_Namespace
) {
123 foreach(NamespaceModelItem n
, model_dynamic_cast
<NamespaceModelItem
>(i
)->namespaces())
124 ret
+= ID_STR(n
).append(" ");
126 if (i
->kind() & _CodeModelItem::Kind_Scope
) {
127 foreach(ClassModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->classes())
128 ret
+= ID_STR(n
).append(" ");
129 foreach(EnumModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->enums())
130 ret
+= ID_STR(n
).append(" ");
131 foreach(FunctionModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->functions())
132 ret
+= ID_STR(n
).append(" ");
133 foreach(TypeAliasModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->typeAliases())
134 ret
+= ID_STR(n
).append(" ");
135 foreach(VariableModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->variables())
136 ret
+= ID_STR(n
).append(" ");
138 if (i
->kind() & _CodeModelItem::Kind_Scope
) {
141 if (i
->kind() & _CodeModelItem::Kind_Member
) {
142 MemberModelItem m
= model_dynamic_cast
<MemberModelItem
>(i
);
143 if (m
->isConstant()) ret
+= ATTR_TRUE("constant");
144 if (m
->isVolatile()) ret
+= ATTR_TRUE("volatile");
145 if (m
->isStatic()) ret
+= ATTR_TRUE("static");
146 if (m
->isAuto()) ret
+= ATTR_TRUE("auto");
147 if (m
->isFriend()) ret
+= ATTR_TRUE("friend");
148 if (m
->isRegister()) ret
+= ATTR_TRUE("register");
149 if (m
->isExtern()) ret
+= ATTR_TRUE("extern");
150 if (m
->isMutable()) ret
+= ATTR_TRUE("mutable");
153 switch (m
->accessPolicy()) {
154 case CodeModel::Public
:
157 case CodeModel::Private
:
160 case CodeModel::Protected
:
166 ret
+= visit(m
->type());
168 if ((i
->kind() & _CodeModelItem::Kind_Function
) == _CodeModelItem::Kind_Function
) {
169 FunctionModelItem m
= model_dynamic_cast
<FunctionModelItem
>(i
);
170 if (m
->isVirtual()) ret
+= ATTR_TRUE("virtual");
171 if (m
->isInline()) ret
+= ATTR_TRUE("inline");
172 if (m
->isExplicit()) ret
+= ATTR_TRUE("explicit");
173 if (m
->isAbstract()) ret
+= ATTR_TRUE("abstract");
174 if (m
->isVariadics()) ret
+= ATTR_TRUE("variadics");
175 //if (i->name()=="destroyed") qDebug() << CodeModel::Normal << CodeModel::Slot << CodeModel::Signal << m->functionType() << i->qualifiedName();
176 switch(m
->functionType()) {
177 case CodeModel::Normal
:
179 case CodeModel::Slot
:
180 ret
+= ATTR_TRUE("slot");
182 case CodeModel::Signal
:
183 ret
+= ATTR_TRUE("signal");
187 if (i
->kind() == _CodeModelItem::Kind_Argument
) {
188 ArgumentModelItem a
= model_dynamic_cast
<ArgumentModelItem
>(i
);
189 ret
+= visit(a
->type());
190 if (a
->defaultValue()) {
191 ret
+= ATTR_TRUE("default");
192 ret
+= ATTR_STR("defaultvalue", a
->defaultValueExpression());
195 if (i
->kind() == _CodeModelItem::Kind_Class
) {
196 ClassModelItem c
= model_dynamic_cast
<ClassModelItem
>(i
);
197 if (c
->baseClasses().size()>0) {
198 ret
+= ATTR_STR("bases", c
->baseClasses().join(";").append(";"));
200 switch(c
->classType()) {
201 case CodeModel::Class
:
202 ret
+= ATTR_STR("class_type", QString("class"));
204 case CodeModel::Struct
:
205 ret
+= ATTR_STR("class_type", QString("struct"));
207 case CodeModel::Union
:
208 ret
+= ATTR_STR("class_type", QString("union"));
211 // TODO also list templateParameters (maybe in content?)
212 // TODO also list propertyDeclarations (maybe in content?)
214 if (i
->kind() == _CodeModelItem::Kind_Enum
) {
215 EnumModelItem e
= model_dynamic_cast
<EnumModelItem
>(i
);
216 // TODO try to understand the meaning of the access policy of enums
218 if (i
->kind() == _CodeModelItem::Kind_Enumerator
) {
219 EnumeratorModelItem e
= model_dynamic_cast
<EnumeratorModelItem
>(i
);
220 ret
+= e
->value().prepend(" value=\"").append("\"");
222 if (i
->kind() == _CodeModelItem::Kind_TypeAlias
) {
223 TypeAliasModelItem a
= model_dynamic_cast
<TypeAliasModelItem
>(i
);
224 ret
+= visit(a
->type());
227 ret
.replace('>', ">");
228 ret
.replace('<', "<");
229 ret
= "<" + ret
+ " >\n";
232 // content of the entry:
233 // - Arguments of functions
234 // - members of scopes
235 // - enumeration values
237 if ((i
->kind() & _CodeModelItem::Kind_Namespace
) == _CodeModelItem::Kind_Namespace
) {
238 foreach(NamespaceModelItem n
, model_dynamic_cast
<NamespaceModelItem
>(i
)->namespaces())
239 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
241 if (i
->kind() & _CodeModelItem::Kind_Scope
) {
242 foreach(ClassModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->classes())
243 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
244 foreach(EnumModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->enums())
245 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
246 foreach(FunctionModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->functions())
247 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
248 foreach(TypeAliasModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->typeAliases())
249 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
250 foreach(VariableModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->variables())
251 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
253 if ((i
->kind() & _CodeModelItem::Kind_Function
) == _CodeModelItem::Kind_Function
) {
254 foreach(ArgumentModelItem n
, model_dynamic_cast
<FunctionModelItem
>(i
)->arguments())
255 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
257 if (i
->kind() == _CodeModelItem::Kind_Enum
) {
259 EnumModelItem e
= model_dynamic_cast
<EnumModelItem
>(i
);
260 foreach(EnumeratorModelItem n
, model_dynamic_cast
<EnumModelItem
>(i
)->enumerators()) {
261 if (n
->value() == QString()) n
->setValue(last
.append("+1"));
262 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
275 QString XMLVisitor::visit<CodeModelItem>(CodeModelItem i) {
277 ret += "unknown CodeModelItem"; ret += i->name();
278 QStringList s_list = i->qualifiedName();
279 QStringList::const_iterator constIterator;
280 for (constIterator = s_list.constBegin(); constIterator != s_list.constEnd(); ++constIterator) ret += *constIterator;
284 QString XMLVisitor::visit<ClassModelItem>(ClassModelItem i) {
286 switch (i->classType()) {
287 case CodeModel::Struct: buf += "Struct"; break;
288 case CodeModel::Class: buf += "Class"; break;
289 case CodeModel::Union: buf += "Union"; break;
291 buf.append(" id=\"").append(ID_STR(i)).append("\"");
292 buf += QString(" name=\"").append(i->name().isEmpty()?QString("::"):i->name()).append("\"");
293 buf += " members=\"";
294 foreach (ClassModelItem m, i->classes()) buf += ID_STR(m).append(" ");
295 foreach (EnumModelItem m, i->enums()) buf += ID_STR(m).append(" ");
296 foreach (FunctionModelItem m, i->functions()) buf += ID_STR(m).append(" ");
297 foreach (TypeAliasModelItem m, i->typeAliases()) buf += ID_STR(m).append(" ");
298 foreach (VariableModelItem m, i->variables()) buf += ID_STR(m).append(" ");
299 buf.append("\" />\n");
301 foreach (ClassModelItem m, i->classes()) visit(m);
302 foreach (EnumModelItem m, i->enums()) visit(m);
303 foreach (FunctionModelItem m, i->functions()) visit(m);
304 foreach (TypeAliasModelItem m, i->typeAliases()) visit(m);
305 foreach (VariableModelItem m, i->variables()) visit(m);
309 QString XMLVisitor::visit<NamespaceModelItem>(NamespaceModelItem n) {
310 QString buf("<Namespace");
311 buf.append(" id=\"").append(ID_STR(n)).append("\"");
312 buf += QString(" name=\"").append(n->name().isEmpty()?QString("::"):n->name()).append("\"");
313 buf += " members=\"";
314 foreach (NamespaceModelItem m, n->namespaces()) buf += ID_STR(m).append(" ");
315 foreach (ClassModelItem m, n->classes()) buf += ID_STR(m).append(" ");
316 foreach (EnumModelItem m, n->enums()) buf += ID_STR(m).append(" ");
317 foreach (FunctionModelItem m, n->functions()) buf += ID_STR(m).append(" ");
318 foreach (TypeAliasModelItem m, n->typeAliases()) buf += ID_STR(m).append(" ");
319 foreach (VariableModelItem m, n->variables()) buf += ID_STR(m).append(" ");
320 buf.append("\" />\n");
322 foreach (NamespaceModelItem m, n->namespaces()) buf += visit(m);
323 foreach (ClassModelItem m, n->classes()) buf += visit(m);
324 foreach (EnumModelItem m, n->enums()) buf += visit(m);
325 foreach (FunctionModelItem m, n->functions()) buf += visit(m);
326 foreach (TypeAliasModelItem m, n->typeAliases()) buf += visit(m);
327 foreach (VariableModelItem m, n->variables()) buf += visit(m);
331 int main (int argc
, char **argv
) {
332 bool onlyPreprocess
= false;
337 for (int i
=1;i
<argc
;i
++) options
<< argv
[i
];
339 if ((i
=options
.indexOf("-C"))!=-1) {
340 if (options
.count() > i
+1) {
341 configName
= options
.at(i
+1);
342 options
.removeAt(i
+1);
346 if ((i
=options
.indexOf("-P"))!=-1) {
347 onlyPreprocess
= true;
350 if (options
.count()>1) return 37;
351 sourceName
= options
.at(0);
357 if (!file
.open(QFile::ReadOnly
))
360 QTextStream
stream(&file
);
361 stream
.setCodec(QTextCodec::codecForName("UTF-8"));
362 contents
= stream
.readAll().toUtf8();
368 QString qtdir
= getenv ("QTDIR");
369 if (qtdir
.isEmpty()) {
370 fprintf(stderr
, "Generator requires QTDIR to be set\n");
376 QString currentDir
= QDir::current().absolutePath();
377 QFileInfo
sourceInfo(sourceName
);
378 //QDir::setCurrent(sourceInfo.absolutePath());
380 inclist
<< (sourceInfo
.absolutePath());
381 inclist
<< (QDir::convertSeparators(qtdir
));
382 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtXml"));
383 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtNetwork"));
384 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtCore"));
385 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtGui"));
386 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtOpenGL"));
387 //qDebug() << inclist;
389 pp
.addIncludePaths(inclist
);
390 pp
.processFile(sourceName
, configName
);
391 //qDebug() << pp.macroNames();
392 contents
= pp
.result();
393 //qDebug() << contents;
394 //QTextStream(stdout) << contents;
397 if (onlyPreprocess
) {
398 QTextStream(stdout
) << contents
;
404 TranslationUnitAST
*ast
= p
.parse(contents
, contents
.size(), &__pool
);
407 Binder
binder(&model
, p
.location());
408 FileModelItem f_model
= binder
.run(ast
);
411 QTextStream(stdout
) << visitor
.visit(model_static_cast
<CodeModelItem
>(f_model
));