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
+ "\"";
146 if (tt
.isFunctionPointer()) ret
+= " function_pointer=\"1\"";
151 #define TAG_CASE(s) case _CodeModelItem::Kind_##s: return #s
153 QString
XMLVisitor::XMLTag(CodeModelItem i
) {
162 TAG_CASE(Enumerator
);
164 TAG_CASE(FunctionDefinition
);
165 TAG_CASE(TemplateParameter
);
172 QString
templateParametersToString (TemplateParameterList list
) {
174 foreach(TemplateParameterModelItem p
,list
) {
175 ret
= ret
+ p
->name() + ";";
180 QString
XMLVisitor::visit(CodeModelItem i
) {
184 current_id
= ID_STR(i
) + " => " + XMLTag(i
) + " => " + i
->qualifiedName().join("::"); // FIXME: this is debug code
186 ret
+= ATTR_STR("id", ID_STR(i
));
187 ret
+= ATTR_STR("name", i
->name());
188 ret
+= ATTR_STR("scope", i
->scope().join("::"));
189 ret
+= ATTR_STR("context", current_context
.join("::"));
190 // FIXME: is this a dirty hack? yes, it is!
191 if (ArgumentModelItem a
= model_dynamic_cast
<ArgumentModelItem
>(i
)) {
192 //ret += ATTR_STR("fullname", current_context.join("::")+"::"+i->qualifiedName().join("::"));
193 } else if (EnumeratorModelItem a
= model_dynamic_cast
<EnumeratorModelItem
>(i
)) {
194 ret
+= ATTR_STR("fullname", current_context
.join("::")+"::"+i
->qualifiedName().join("::"));
196 ret
+= ATTR_STR("fullname", i
->qualifiedName().join("::"));
199 if (ScopeModelItem s
= model_dynamic_cast
<ScopeModelItem
>(i
)) {
200 ret
+= " members=\"";
202 if (NamespaceModelItem n
= model_dynamic_cast
<NamespaceModelItem
>(i
)) {
203 foreach(NamespaceModelItem m
, n
->namespaces())
204 ret
+= ID_STR(m
).append(" ");
206 if (ScopeModelItem s
= model_dynamic_cast
<ScopeModelItem
>(i
)) {
207 foreach(ClassModelItem n
, s
->classes())
208 ret
+= ID_STR(n
).append(" ");
209 foreach(EnumModelItem n
, s
->enums())
210 ret
+= ID_STR(n
).append(" ");
211 foreach(FunctionModelItem n
, s
->functions())
212 ret
+= ID_STR(n
).append(" ");
213 foreach(TypeAliasModelItem n
, s
->typeAliases())
214 ret
+= ID_STR(n
).append(" ");
215 foreach(VariableModelItem n
, s
->variables())
216 ret
+= ID_STR(n
).append(" ");
218 if (ScopeModelItem s
= model_dynamic_cast
<ScopeModelItem
>(i
)) {
221 if (MemberModelItem m
= model_dynamic_cast
<MemberModelItem
>(i
)) {
222 if (m
->isConstant()) ret
+= ATTR_TRUE("constant");
223 if (m
->isVolatile()) ret
+= ATTR_TRUE("volatile");
224 if (m
->isStatic()) ret
+= ATTR_TRUE("static");
225 if (m
->isAuto()) ret
+= ATTR_TRUE("auto");
226 if (m
->isFriend()) ret
+= ATTR_TRUE("friend");
227 if (m
->isRegister()) ret
+= ATTR_TRUE("register");
228 if (m
->isExtern()) ret
+= ATTR_TRUE("extern");
229 if (m
->isMutable()) ret
+= ATTR_TRUE("mutable");
230 QStringList ownerName
= m
->qualifiedName();
231 ownerName
.pop_back();
232 ret
+= ATTR_STR("member_of", ownerName
.join("::"));
234 if (ClassModelItem c
= model_dynamic_cast
<ClassModelItem
>(current_scope
.last()))
235 ret
+= ATTR_STR("member_of_class", c
->qualifiedName().join("::"));
237 switch (m
->accessPolicy()) {
238 case CodeModel::Public
:
239 ret
+= ATTR_STR("access", "public");
241 case CodeModel::Private
:
242 ret
+= ATTR_STR("access", "private");
244 case CodeModel::Protected
:
245 ret
+= ATTR_STR("access", "protected");
249 ret
+= visit(m
->type(), m
->scope());
250 QString tp
= templateParametersToString(m
->templateParameters());
251 if (tp
!=QString()) ret
+= ATTR_STR("member_template_parameters", tp
);
253 if (FunctionModelItem f
= model_dynamic_cast
<FunctionModelItem
>(i
)) {
254 if (f
->isVirtual()) ret
+= ATTR_TRUE("virtual");
255 if (f
->isInline()) ret
+= ATTR_TRUE("inline");
256 if (f
->isExplicit()) ret
+= ATTR_TRUE("explicit");
257 if (f
->isAbstract()) ret
+= ATTR_TRUE("abstract");
258 if (f
->isVariadics()) ret
+= ATTR_TRUE("variadics");
259 //if (i->name()=="destroyed") qDebug() << CodeModel::Normal << CodeModel::Slot << CodeModel::Signal << m->functionType() << i->qualifiedName();
260 switch(f
->functionType()) {
261 case CodeModel::Normal
:
263 case CodeModel::Slot
:
264 ret
+= ATTR_TRUE("slot");
266 case CodeModel::Signal
:
267 ret
+= ATTR_TRUE("signal");
271 if (ArgumentModelItem a
= model_dynamic_cast
<ArgumentModelItem
>(i
)) {
272 ret
+= visit(a
->type(), a
->scope());
273 if (a
->defaultValue()) {
274 ret
+= ATTR_TRUE("default");
275 ret
+= ATTR_STR("defaultvalue", a
->defaultValueExpression());
278 if (ClassModelItem c
= model_dynamic_cast
<ClassModelItem
>(i
)) {
279 if (c
->baseClasses().size()>0) {
280 ret
+= ATTR_STR("bases", c
->baseClasses().join(";").append(";"));
282 switch(c
->classType()) {
283 case CodeModel::Class
:
284 ret
+= ATTR_STR("class_type", QString("class"));
286 case CodeModel::Struct
:
287 ret
+= ATTR_STR("class_type", QString("struct"));
289 case CodeModel::Union
:
290 ret
+= ATTR_STR("class_type", QString("union"));
293 QString tp
= templateParametersToString(c
->templateParameters());
294 if (tp
!=QString()) ret
+= ATTR_STR("member_template_parameters", tp
);
295 // TODO also list propertyDeclarations (maybe in content?)
297 if (EnumModelItem e
= model_dynamic_cast
<EnumModelItem
>(i
)) {
298 switch (e
->accessPolicy()) {
299 case CodeModel::Public
:
300 ret
+= ATTR_STR("access", "public");
302 case CodeModel::Private
:
303 ret
+= ATTR_STR("access", "private");
305 case CodeModel::Protected
:
306 ret
+= ATTR_STR("access", "protected");
310 if (EnumeratorModelItem e
= model_dynamic_cast
<EnumeratorModelItem
>(i
)) {
311 ret
+= e
->value().prepend(" value=\"").append("\"");
313 if (TypeAliasModelItem t
= model_dynamic_cast
<TypeAliasModelItem
>(i
)) {
314 ret
+= visit(t
->type(), t
->scope());
317 ret
.replace('&', "&");
318 ret
.replace('>', ">");
319 ret
.replace('<', "<");
320 ret
= "<" + ret
+ " >\n";
323 // content of the entry:
324 // - Arguments of functions
325 // - members of scopes
326 // - enumeration values
328 if (NamespaceModelItem n
= model_dynamic_cast
<NamespaceModelItem
>(i
)) {
329 foreach(NamespaceModelItem m
, n
->namespaces())
330 ret
+= visit(model_static_cast
<CodeModelItem
>(m
));
332 if (i
->kind() & _CodeModelItem::Kind_Scope
) {
333 //qDebug() << ID_STR(i) << i->name() << current_context;
334 //CodeModelItem os = current_scope; // save old outer scope
335 if (!i
->name().isEmpty()) { current_context
<< i
->name(); current_scope
<< i
; }
336 foreach(ClassModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->classes())
337 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
338 foreach(EnumModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->enums())
339 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
340 foreach(FunctionModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->functions())
341 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
342 foreach(TypeAliasModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->typeAliases())
343 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
344 foreach(VariableModelItem n
, model_dynamic_cast
<ScopeModelItem
>(i
)->variables())
345 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
346 if (!i
->name().isEmpty()) { current_context
.removeLast(); current_scope
.pop_back(); }
348 if (FunctionModelItem f
= model_dynamic_cast
<FunctionModelItem
>(i
)) {
349 foreach(ArgumentModelItem a
, f
->arguments())
350 ret
+= visit(model_static_cast
<CodeModelItem
>(a
));
352 if (EnumModelItem e
= model_dynamic_cast
<EnumModelItem
>(i
)) {
354 foreach(EnumeratorModelItem n
, model_dynamic_cast
<EnumModelItem
>(i
)->enumerators()) {
355 if (n
->value() == QString()) n
->setValue(last
.append("+1"));
356 ret
+= visit(model_static_cast
<CodeModelItem
>(n
));
368 int main (int argc
, char **argv
) {
369 bool onlyPreprocess
= false;
370 bool dontResolve
= false;
375 for (int i
=1;i
<argc
;i
++) options
<< argv
[i
];
377 if ((i
=options
.indexOf("-C"))!=-1) {
378 if (options
.count() > i
+1) {
379 configName
= QDir::fromNativeSeparators(options
.at(i
+1));
380 options
.removeAt(i
+1);
384 if ((i
=options
.indexOf("-P"))!=-1) {
385 onlyPreprocess
= true;
388 if ((i
=options
.indexOf("-R"))!=-1) {
392 if (options
.count()>1) return 37;
393 sourceName
= QDir::fromNativeSeparators(options
.at(0));
400 QString qtdir
= QDir::fromNativeSeparators(getenv("QT_INCLUDE"));
401 if (qtdir
.isEmpty()) {
402 fprintf(stderr
, "Generator requires QT_INCLUDE to be set\n");
406 QString currentDir
= QDir::current().absolutePath();
407 QFileInfo
sourceInfo(sourceName
);
408 //QDir::setCurrent(sourceInfo.absolutePath());
410 inclist
<< (sourceInfo
.absolutePath());
411 inclist
<< (QDir::convertSeparators(qtdir
));
412 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtXml"));
413 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtNetwork"));
414 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtCore"));
415 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtGui"));
416 inclist
<< (QDir::convertSeparators(qtdir
+ "/QtOpenGL"));
417 //qDebug() << inclist;
419 pp
.addIncludePaths(inclist
);
420 pp
.processFile(sourceName
, configName
);
421 //qDebug() << pp.macroNames();
422 contents
= pp
.result();
423 //qDebug() << contents;
424 //QTextStream(stdout) << contents;
426 if (onlyPreprocess
) {
427 QTextStream(stdout
) << contents
;
433 TranslationUnitAST
*ast
= p
.parse(contents
, contents
.size(), &__pool
);
436 Binder
binder(&model
, p
.location());
437 FileModelItem f_model
= binder
.run(ast
);
439 XMLVisitor
visitor((CodeModelItem
)f_model
, !dontResolve
);
440 QTextStream(stdout
) << visitor
.visit(model_static_cast
<CodeModelItem
>(f_model
));