Mercurial > projects > qtd
annotate generator/parser/binder.cpp @ 378:7341c47790d4
binding of qwt
author | Eldar Insafutdinov |
---|---|
date | Sat, 10 Jul 2010 21:54:44 +0100 |
parents | 09a0f1d048f2 |
children |
rev | line source |
---|---|
1 | 1 /**************************************************************************** |
2 ** | |
52
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
3 ** Copyright (C) 1992-2009 Nokia. All rights reserved. |
1 | 4 ** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org> |
5 ** | |
6 ** This file is part of Qt Jambi. | |
7 ** | |
52
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
8 ** Commercial Usage |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
9 Licensees holding valid Qt Commercial licenses may use this file in |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
10 accordance with the Qt Commercial License Agreement provided with the |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
11 Software or, alternatively, in accordance with the terms contained in |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
12 a written agreement between you and Nokia. |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
13 |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
14 GNU Lesser General Public License Usage |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
15 Alternatively, this file may be used under the terms of the GNU Lesser |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
16 General Public License version 2.1 as published by the Free Software |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
17 Foundation and appearing in the file LICENSE.LGPL included in the |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
18 packaging of this file. Please review the following information to |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
19 ensure the GNU Lesser General Public License version 2.1 requirements |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
20 will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
21 |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
22 In addition, as a special exception, Nokia gives you certain |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
23 additional rights. These rights are described in the Nokia Qt LGPL |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
24 Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
25 package. |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
26 |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
27 GNU General Public License Usage |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
28 Alternatively, this file may be used under the terms of the GNU |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
29 General Public License version 3.0 as published by the Free Software |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
30 Foundation and appearing in the file LICENSE.GPL included in the |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
31 packaging of this file. Please review the following information to |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
32 ensure the GNU General Public License version 3.0 requirements will be |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
33 met: http://www.gnu.org/copyleft/gpl.html. |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
34 |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
35 If you are unsure which license is appropriate for your use, please |
09a0f1d048f2
update parser to that from jambi 4.5, attemt to fix building with gcc 4.4
eldar
parents:
1
diff
changeset
|
36 contact the sales department at qt-sales@nokia.com. |
1 | 37 |
38 ** | |
39 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | |
40 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
41 ** | |
42 ****************************************************************************/ | |
43 | |
44 #include "binder.h" | |
45 #include "lexer.h" | |
46 #include "control.h" | |
47 #include "symbol.h" | |
48 #include "codemodel_finder.h" | |
49 #include "class_compiler.h" | |
50 #include "compiler_utils.h" | |
51 #include "tokens.h" | |
52 #include "dumptree.h" | |
53 | |
54 #include <iostream> | |
55 | |
56 #include <qdebug.h> | |
57 | |
58 void binder_default_message_handler(const std::string &str) { | |
59 std::cerr << str; | |
60 } | |
61 | |
62 MessageHandler Binder::_M_message_handler = binder_default_message_handler; | |
63 | |
64 Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__control) | |
65 : _M_model(__model), | |
66 _M_location(__location), | |
67 _M_token_stream(&_M_location.token_stream), | |
68 _M_control(__control), | |
69 _M_current_function_type(CodeModel::Normal), | |
70 type_cc(this), | |
71 name_cc(this), | |
72 decl_cc(this) | |
73 { | |
74 _M_qualified_types["char"] = QString(); | |
75 _M_qualified_types["double"] = QString(); | |
76 _M_qualified_types["float"] = QString(); | |
77 _M_qualified_types["int"] = QString(); | |
78 _M_qualified_types["long"] = QString(); | |
79 _M_qualified_types["short"] = QString(); | |
80 _M_qualified_types["void"] = QString(); | |
81 } | |
82 | |
83 Binder::~Binder() | |
84 { | |
85 } | |
86 | |
87 FileModelItem Binder::run(AST *node) | |
88 { | |
89 FileModelItem old = _M_current_file; | |
90 _M_current_access = CodeModel::Public; | |
91 | |
92 _M_current_file = model()->create<FileModelItem>(); | |
93 updateItemPosition (_M_current_file->toItem(), node); | |
94 visit(node); | |
95 FileModelItem result = _M_current_file; | |
96 | |
97 _M_current_file = old; // restore | |
98 | |
99 return result; | |
100 } | |
101 | |
102 ScopeModelItem Binder::currentScope() | |
103 { | |
104 if (_M_current_class) | |
105 return model_static_cast<ScopeModelItem>(_M_current_class); | |
106 else if (_M_current_namespace) | |
107 return model_static_cast<ScopeModelItem>(_M_current_namespace); | |
108 | |
109 return model_static_cast<ScopeModelItem>(_M_current_file); | |
110 } | |
111 | |
112 TemplateParameterList Binder::changeTemplateParameters(TemplateParameterList templateParameters) | |
113 { | |
114 TemplateParameterList old = _M_current_template_parameters; | |
115 _M_current_template_parameters = templateParameters; | |
116 return old; | |
117 } | |
118 | |
119 CodeModel::FunctionType Binder::changeCurrentFunctionType(CodeModel::FunctionType functionType) | |
120 { | |
121 CodeModel::FunctionType old = _M_current_function_type; | |
122 _M_current_function_type = functionType; | |
123 return old; | |
124 } | |
125 | |
126 CodeModel::AccessPolicy Binder::changeCurrentAccess(CodeModel::AccessPolicy accessPolicy) | |
127 { | |
128 CodeModel::AccessPolicy old = _M_current_access; | |
129 _M_current_access = accessPolicy; | |
130 return old; | |
131 } | |
132 | |
133 NamespaceModelItem Binder::changeCurrentNamespace(NamespaceModelItem item) | |
134 { | |
135 NamespaceModelItem old = _M_current_namespace; | |
136 _M_current_namespace = item; | |
137 return old; | |
138 } | |
139 | |
140 ClassModelItem Binder::changeCurrentClass(ClassModelItem item) | |
141 { | |
142 ClassModelItem old = _M_current_class; | |
143 _M_current_class = item; | |
144 return old; | |
145 } | |
146 | |
147 FunctionDefinitionModelItem Binder::changeCurrentFunction(FunctionDefinitionModelItem item) | |
148 { | |
149 FunctionDefinitionModelItem old = _M_current_function; | |
150 _M_current_function = item; | |
151 return old; | |
152 } | |
153 | |
154 int Binder::decode_token(std::size_t index) const | |
155 { | |
156 return _M_token_stream->kind(index); | |
157 } | |
158 | |
159 CodeModel::AccessPolicy Binder::decode_access_policy(std::size_t index) const | |
160 { | |
161 switch (decode_token(index)) | |
162 { | |
163 case Token_class: | |
164 return CodeModel::Private; | |
165 | |
166 case Token_struct: | |
167 case Token_union: | |
168 return CodeModel::Public; | |
169 | |
170 default: | |
171 return CodeModel::Public; | |
172 } | |
173 } | |
174 | |
175 CodeModel::ClassType Binder::decode_class_type(std::size_t index) const | |
176 { | |
177 switch (decode_token(index)) | |
178 { | |
179 case Token_class: | |
180 return CodeModel::Class; | |
181 case Token_struct: | |
182 return CodeModel::Struct; | |
183 case Token_union: | |
184 return CodeModel::Union; | |
185 default: | |
186 _M_message_handler("** WARNING unrecognized class type"); | |
187 } | |
188 return CodeModel::Class; | |
189 } | |
190 | |
191 const NameSymbol *Binder::decode_symbol(std::size_t index) const | |
192 { | |
193 return _M_token_stream->symbol(index); | |
194 } | |
195 | |
196 void Binder::visitAccessSpecifier(AccessSpecifierAST *node) | |
197 { | |
198 const ListNode<std::size_t> *it = node->specs; | |
199 if (it == 0) | |
200 return; | |
201 | |
202 it = it->toFront(); | |
203 const ListNode<std::size_t> *end = it; | |
204 | |
205 do | |
206 { | |
207 switch (decode_token(it->element)) | |
208 { | |
209 default: | |
210 break; | |
211 | |
212 case Token_public: | |
213 changeCurrentAccess(CodeModel::Public); | |
214 changeCurrentFunctionType(CodeModel::Normal); | |
215 break; | |
216 case Token_protected: | |
217 changeCurrentAccess(CodeModel::Protected); | |
218 changeCurrentFunctionType(CodeModel::Normal); | |
219 break; | |
220 case Token_private: | |
221 changeCurrentAccess(CodeModel::Private); | |
222 changeCurrentFunctionType(CodeModel::Normal); | |
223 break; | |
224 case Token_signals: | |
225 changeCurrentAccess(CodeModel::Protected); | |
226 changeCurrentFunctionType(CodeModel::Signal); | |
227 break; | |
228 case Token_slots: | |
229 changeCurrentFunctionType(CodeModel::Slot); | |
230 break; | |
231 } | |
232 it = it->next; | |
233 } | |
234 while (it != end); | |
235 } | |
236 | |
237 void Binder::visitSimpleDeclaration(SimpleDeclarationAST *node) | |
238 { | |
239 visit(node->type_specifier); | |
240 | |
241 if (const ListNode<InitDeclaratorAST*> *it = node->init_declarators) | |
242 { | |
243 it = it->toFront(); | |
244 const ListNode<InitDeclaratorAST*> *end = it; | |
245 do | |
246 { | |
247 InitDeclaratorAST *init_declarator = it->element; | |
248 declare_symbol(node, init_declarator); | |
249 it = it->next; | |
250 } | |
251 while (it != end); | |
252 } | |
253 } | |
254 | |
255 void Binder::declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator) | |
256 { | |
257 DeclaratorAST *declarator = init_declarator->declarator; | |
258 | |
259 while (declarator && declarator->sub_declarator) | |
260 declarator = declarator->sub_declarator; | |
261 | |
262 NameAST *id = declarator->id; | |
263 if (! declarator->id) | |
264 { | |
265 _M_message_handler("** WARNING expected a declarator id"); | |
266 return; | |
267 } | |
268 | |
269 CodeModelFinder finder(model(), this); | |
270 ScopeModelItem symbolScope = finder.resolveScope(id, currentScope()); | |
271 if (! symbolScope) | |
272 { | |
273 name_cc.run(id); | |
274 _M_message_handler(std::string("** WARNING scope not found for symbol:") + qPrintable(name_cc.name())); | |
275 return; | |
276 } | |
277 | |
278 decl_cc.run(declarator); | |
279 | |
280 if (decl_cc.isFunction()) | |
281 { | |
282 name_cc.run(id->unqualified_name); | |
283 | |
284 FunctionModelItem fun = model()->create<FunctionModelItem>(); | |
285 updateItemPosition (fun->toItem(), node); | |
286 fun->setAccessPolicy(_M_current_access); | |
287 fun->setFunctionType(_M_current_function_type); | |
288 fun->setName(name_cc.name()); | |
289 fun->setAbstract(init_declarator->initializer != 0); | |
290 fun->setConstant(declarator->fun_cv != 0); | |
291 fun->setTemplateParameters(_M_current_template_parameters); | |
292 applyStorageSpecifiers(node->storage_specifiers, model_static_cast<MemberModelItem>(fun)); | |
293 applyFunctionSpecifiers(node->function_specifiers, fun); | |
294 | |
295 // build the type | |
296 TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier, | |
297 declarator, | |
298 this); | |
299 | |
300 fun->setType(qualifyType(typeInfo, symbolScope->qualifiedName())); | |
301 | |
302 | |
303 fun->setVariadics (decl_cc.isVariadics ()); | |
304 | |
305 // ... and the signature | |
306 foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) | |
307 { | |
308 ArgumentModelItem arg = model()->create<ArgumentModelItem>(); | |
309 arg->setType(qualifyType(p.type, _M_context)); | |
310 arg->setName(p.name); | |
311 arg->setDefaultValue(p.defaultValue); | |
312 if (p.defaultValue) | |
313 arg->setDefaultValueExpression(p.defaultValueExpression); | |
314 fun->addArgument(arg); | |
315 } | |
316 | |
317 fun->setScope(symbolScope->qualifiedName()); | |
318 symbolScope->addFunction(fun); | |
319 } | |
320 else | |
321 { | |
322 VariableModelItem var = model()->create<VariableModelItem>(); | |
323 updateItemPosition (var->toItem(), node); | |
324 var->setTemplateParameters(_M_current_template_parameters); | |
325 var->setAccessPolicy(_M_current_access); | |
326 name_cc.run(id->unqualified_name); | |
327 var->setName(name_cc.name()); | |
328 TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier, | |
329 declarator, | |
330 this); | |
331 if (declarator != init_declarator->declarator | |
332 && init_declarator->declarator->parameter_declaration_clause != 0) | |
333 { | |
334 typeInfo.setFunctionPointer (true); | |
335 decl_cc.run (init_declarator->declarator); | |
336 foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) | |
337 typeInfo.addArgument(p.type); | |
338 } | |
339 | |
340 var->setType(qualifyType(typeInfo, _M_context)); | |
341 applyStorageSpecifiers(node->storage_specifiers, model_static_cast<MemberModelItem>(var)); | |
342 | |
343 var->setScope(symbolScope->qualifiedName()); | |
344 symbolScope->addVariable(var); | |
345 } | |
346 } | |
347 | |
348 void Binder::visitFunctionDefinition(FunctionDefinitionAST *node) | |
349 { | |
350 Q_ASSERT(node->init_declarator != 0); | |
351 | |
352 ScopeModelItem scope = currentScope(); | |
353 | |
354 InitDeclaratorAST *init_declarator = node->init_declarator; | |
355 DeclaratorAST *declarator = init_declarator->declarator; | |
356 | |
357 // in the case of "void (func)()" or "void ((func))()" we need to | |
358 // skip to the inner most. This is in line with how the declarator | |
359 // node is generated in 'parser.cpp' | |
360 while (declarator && declarator->sub_declarator) | |
361 declarator = declarator->sub_declarator; | |
362 Q_ASSERT(declarator->id); | |
363 | |
364 CodeModelFinder finder(model(), this); | |
365 | |
366 ScopeModelItem functionScope = finder.resolveScope(declarator->id, scope); | |
367 if (! functionScope) | |
368 { | |
369 name_cc.run(declarator->id); | |
370 _M_message_handler(std::string("** WARNING scope not found for function definition:") | |
371 + qPrintable(name_cc.name()) | |
372 + std::string(" - definition *ignored*")); | |
373 return; | |
374 } | |
375 | |
376 decl_cc.run(declarator); | |
377 | |
378 Q_ASSERT(! decl_cc.id().isEmpty()); | |
379 | |
380 FunctionDefinitionModelItem | |
381 old = changeCurrentFunction(_M_model->create<FunctionDefinitionModelItem>()); | |
382 _M_current_function->setScope(functionScope->qualifiedName()); | |
383 updateItemPosition (_M_current_function->toItem(), node); | |
384 | |
385 Q_ASSERT(declarator->id->unqualified_name != 0); | |
386 name_cc.run(declarator->id->unqualified_name); | |
387 QString unqualified_name = name_cc.name(); | |
388 | |
389 _M_current_function->setName(unqualified_name); | |
390 TypeInfo tmp_type = CompilerUtils::typeDescription(node->type_specifier, | |
391 declarator, this); | |
392 | |
393 _M_current_function->setType(qualifyType(tmp_type, _M_context)); | |
394 _M_current_function->setAccessPolicy(_M_current_access); | |
395 _M_current_function->setFunctionType(_M_current_function_type); | |
396 _M_current_function->setConstant(declarator->fun_cv != 0); | |
397 _M_current_function->setTemplateParameters(_M_current_template_parameters); | |
398 | |
399 applyStorageSpecifiers(node->storage_specifiers, | |
400 model_static_cast<MemberModelItem>(_M_current_function)); | |
401 applyFunctionSpecifiers(node->function_specifiers, | |
402 model_static_cast<FunctionModelItem>(_M_current_function)); | |
403 | |
404 _M_current_function->setVariadics (decl_cc.isVariadics ()); | |
405 | |
406 foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) | |
407 { | |
408 ArgumentModelItem arg = model()->create<ArgumentModelItem>(); | |
409 arg->setType(qualifyType(p.type, functionScope->qualifiedName())); | |
410 arg->setName(p.name); | |
411 arg->setDefaultValue(p.defaultValue); | |
412 if (p.defaultValue) | |
413 arg->setDefaultValueExpression(p.defaultValueExpression); | |
414 _M_current_function->addArgument(arg); | |
415 } | |
416 | |
417 functionScope->addFunctionDefinition(_M_current_function); | |
418 | |
419 FunctionModelItem prototype = model_static_cast<FunctionModelItem>(_M_current_function); | |
420 FunctionModelItem declared = functionScope->declaredFunction(prototype); | |
421 | |
422 // try to find a function declaration for this definition.. | |
423 if (! declared) | |
424 { | |
425 functionScope->addFunction(prototype); | |
426 } | |
427 else | |
428 { | |
429 applyFunctionSpecifiers(node->function_specifiers, declared); | |
430 | |
431 // fix the function type and the access policy | |
432 _M_current_function->setAccessPolicy(declared->accessPolicy()); | |
433 _M_current_function->setFunctionType(declared->functionType()); | |
434 } | |
435 | |
436 changeCurrentFunction(old); | |
437 } | |
438 | |
439 void Binder::visitTemplateDeclaration(TemplateDeclarationAST *node) | |
440 { | |
441 const ListNode<TemplateParameterAST*> *it = node->template_parameters; | |
442 if (it == 0) | |
443 return; | |
444 | |
445 TemplateParameterList savedTemplateParameters = changeTemplateParameters(TemplateParameterList()); | |
446 | |
447 it = it->toFront(); | |
448 const ListNode<TemplateParameterAST*> *end = it; | |
449 | |
450 TemplateParameterList templateParameters; | |
451 do { | |
452 TemplateParameterAST *parameter = it->element; | |
453 TypeParameterAST *type_parameter = parameter->type_parameter; | |
454 | |
455 NameAST *name; | |
456 if (!type_parameter) { | |
457 // A hacky hack to work around missing support for parameter declarations in | |
458 // templates. We just need the to get the name of the variable, since we | |
459 // aren't actually compiling these anyway. We are still not supporting much | |
460 // more, but we are refusing to fail for a few more declarations | |
461 if (parameter->parameter_declaration == 0 || | |
462 parameter->parameter_declaration->declarator == 0 || | |
463 parameter->parameter_declaration->declarator->id == 0) { | |
464 | |
465 /*std::cerr << "** WARNING template declaration not supported ``"; | |
466 Token const &tk = _M_token_stream->token ((int) node->start_token); | |
467 Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token); | |
468 | |
469 std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''" | |
470 << std::endl << std::endl;*/ | |
471 | |
472 changeTemplateParameters(savedTemplateParameters); | |
473 return; | |
474 | |
475 } | |
476 | |
477 name = parameter->parameter_declaration->declarator->id; | |
478 } else { | |
479 int tk = decode_token(type_parameter->type); | |
480 if (tk != Token_typename && tk != Token_class) | |
481 { | |
482 /*std::cerr << "** WARNING template declaration not supported ``"; | |
483 Token const &tk = _M_token_stream->token ((int) node->start_token); | |
484 Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token); | |
485 | |
486 std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''" | |
487 << std::endl << std::endl;*/ | |
488 | |
489 changeTemplateParameters(savedTemplateParameters); | |
490 return; | |
491 } | |
492 assert(tk == Token_typename || tk == Token_class); | |
493 | |
494 name = type_parameter->name; | |
495 } | |
496 | |
497 TemplateParameterModelItem p = model()->create<TemplateParameterModelItem>(); | |
498 name_cc.run(name); | |
499 p->setName(name_cc.name()); | |
500 | |
501 _M_current_template_parameters.append(p); | |
502 it = it->next; | |
503 } while (it != end); | |
504 | |
505 visit(node->declaration); | |
506 | |
507 changeTemplateParameters(savedTemplateParameters); | |
508 } | |
509 | |
510 void Binder::visitTypedef(TypedefAST *node) | |
511 { | |
512 const ListNode<InitDeclaratorAST*> *it = node->init_declarators; | |
513 if (it == 0) | |
514 return; | |
515 | |
516 it = it->toFront(); | |
517 const ListNode<InitDeclaratorAST*> *end = it; | |
518 | |
519 do | |
520 { | |
521 InitDeclaratorAST *init_declarator = it->element; | |
522 it = it->next; | |
523 | |
524 Q_ASSERT(init_declarator->declarator != 0); | |
525 | |
526 // the name | |
527 decl_cc.run (init_declarator->declarator); | |
528 QString alias_name = decl_cc.id (); | |
529 | |
530 if (alias_name.isEmpty ()) | |
531 { | |
532 _M_message_handler("** WARNING anonymous typedef not supported! ``"); | |
533 Token const &tk = _M_token_stream->token ((int) node->start_token); | |
534 Token const &end_tk = _M_token_stream->token ((int) node->end_token); | |
535 | |
536 _M_message_handler(std::string(&tk.text[tk.position], end_tk.position - tk.position)); | |
537 continue; | |
538 } | |
539 | |
540 // build the type | |
541 TypeInfo typeInfo = CompilerUtils::typeDescription (node->type_specifier, | |
542 init_declarator->declarator, | |
543 this); | |
544 DeclaratorAST *decl = init_declarator->declarator; | |
545 while (decl && decl->sub_declarator) | |
546 decl = decl->sub_declarator; | |
547 | |
548 if (decl != init_declarator->declarator | |
549 && init_declarator->declarator->parameter_declaration_clause != 0) | |
550 { | |
551 typeInfo.setFunctionPointer (true); | |
552 decl_cc.run (init_declarator->declarator); | |
553 foreach (DeclaratorCompiler::Parameter p, decl_cc.parameters()) | |
554 typeInfo.addArgument(p.type); | |
555 } | |
556 | |
557 ScopeModelItem scope = currentScope(); | |
558 DeclaratorAST *declarator = init_declarator->declarator; | |
559 CodeModelFinder finder(model(), this); | |
560 ScopeModelItem typedefScope = finder.resolveScope(declarator->id, scope); | |
561 | |
562 TypeAliasModelItem typeAlias = model ()->create<TypeAliasModelItem> (); | |
563 updateItemPosition (typeAlias->toItem (), node); | |
564 typeAlias->setName (alias_name); | |
565 typeAlias->setType (qualifyType (typeInfo, currentScope ()->qualifiedName ())); | |
566 typeAlias->setScope (typedefScope->qualifiedName()); | |
567 _M_qualified_types[typeAlias->qualifiedName().join(".")] = QString(); | |
568 currentScope ()->addTypeAlias (typeAlias); | |
569 } | |
570 while (it != end); | |
571 } | |
572 | |
573 void Binder::visitNamespace(NamespaceAST *node) | |
574 { | |
575 bool anonymous = (node->namespace_name == 0); | |
576 | |
577 ScopeModelItem scope = currentScope(); | |
578 | |
579 NamespaceModelItem old; | |
580 if (! anonymous) | |
581 { | |
582 QString name = decode_symbol(node->namespace_name)->as_string(); | |
583 | |
584 QStringList qualified_name = scope->qualifiedName(); | |
585 qualified_name += name; | |
586 NamespaceModelItem ns = | |
587 model_safe_cast<NamespaceModelItem>(_M_model->findItem(qualified_name, | |
588 _M_current_file->toItem())); | |
589 if (!ns) | |
590 { | |
591 ns = _M_model->create<NamespaceModelItem>(); | |
592 updateItemPosition (ns->toItem(), node); | |
593 ns->setName(name); | |
594 ns->setScope(scope->qualifiedName()); | |
595 } | |
596 old = changeCurrentNamespace(ns); | |
597 | |
598 _M_context.append(name); | |
599 } | |
600 | |
601 DefaultVisitor::visitNamespace(node); | |
602 | |
603 if (! anonymous) | |
604 { | |
605 Q_ASSERT(scope->kind() == _CodeModelItem::Kind_Namespace | |
606 || scope->kind() == _CodeModelItem::Kind_File); | |
607 | |
608 _M_context.removeLast(); | |
609 | |
610 if (NamespaceModelItem ns = model_static_cast<NamespaceModelItem>(scope)) | |
611 { | |
612 ns->addNamespace(_M_current_namespace); | |
613 } | |
614 | |
615 changeCurrentNamespace(old); | |
616 } | |
617 } | |
618 | |
619 void Binder::visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *node) | |
620 { | |
621 name_cc.run(node->name); | |
622 if (name_cc.name().isEmpty()) | |
623 return; | |
624 | |
625 ScopeModelItem scope = currentScope(); | |
626 _M_qualified_types[(scope->qualifiedName() + name_cc.qualifiedName()).join(".") ] = QString(); | |
627 } | |
628 | |
629 void Binder::visitClassSpecifier(ClassSpecifierAST *node) | |
630 { | |
631 ClassCompiler class_cc(this); | |
632 class_cc.run(node); | |
633 | |
634 if (class_cc.name().isEmpty()) | |
635 { | |
636 // anonymous not supported | |
637 return; | |
638 } | |
639 | |
640 Q_ASSERT(node->name != 0 && node->name->unqualified_name != 0); | |
641 | |
642 ScopeModelItem scope = currentScope(); | |
643 | |
644 ClassModelItem old = changeCurrentClass(_M_model->create<ClassModelItem>()); | |
645 updateItemPosition (_M_current_class->toItem(), node); | |
646 _M_current_class->setName(class_cc.name()); | |
647 | |
648 QStringList baseClasses = class_cc.baseClasses(); TypeInfo info; | |
649 for (int i=0; i<baseClasses.size(); ++i) | |
650 { | |
651 info.setQualifiedName(baseClasses.at(i).split("::")); | |
652 baseClasses[i] = qualifyType(info, scope->qualifiedName()).qualifiedName().join("::"); | |
653 } | |
654 | |
655 _M_current_class->setBaseClasses(baseClasses); | |
656 _M_current_class->setClassType(decode_class_type(node->class_key)); | |
657 _M_current_class->setTemplateParameters(_M_current_template_parameters); | |
658 | |
659 if (! _M_current_template_parameters.isEmpty()) | |
660 { | |
661 QString name = _M_current_class->name(); | |
662 name += "<"; | |
663 for (int i = 0; i<_M_current_template_parameters.size(); ++i) | |
664 { | |
665 if (i != 0) | |
666 name += ","; | |
667 | |
668 name += _M_current_template_parameters.at(i)->name(); | |
669 } | |
670 | |
671 name += ">"; | |
672 _M_current_class->setName(name); | |
673 } | |
674 | |
675 CodeModel::AccessPolicy oldAccessPolicy = changeCurrentAccess(decode_access_policy(node->class_key)); | |
676 CodeModel::FunctionType oldFunctionType = changeCurrentFunctionType(CodeModel::Normal); | |
677 | |
678 _M_current_class->setScope(scope->qualifiedName()); | |
679 _M_qualified_types[_M_current_class->qualifiedName().join(".")] = QString(); | |
680 | |
681 scope->addClass(_M_current_class); | |
682 | |
683 name_cc.run(node->name->unqualified_name); | |
684 _M_context.append(name_cc.name()); | |
685 visitNodes(this, node->member_specs); | |
686 _M_context.removeLast(); | |
687 | |
688 changeCurrentClass(old); | |
689 changeCurrentAccess(oldAccessPolicy); | |
690 changeCurrentFunctionType(oldFunctionType); | |
691 } | |
692 | |
693 void Binder::visitLinkageSpecification(LinkageSpecificationAST *node) | |
694 { | |
695 DefaultVisitor::visitLinkageSpecification(node); | |
696 } | |
697 | |
698 void Binder::visitUsing(UsingAST *node) | |
699 { | |
700 DefaultVisitor::visitUsing(node); | |
701 } | |
702 | |
703 void Binder::visitEnumSpecifier(EnumSpecifierAST *node) | |
704 { | |
705 CodeModelFinder finder(model(), this); | |
706 ScopeModelItem scope = currentScope(); | |
707 ScopeModelItem enumScope = finder.resolveScope(node->name, scope); | |
708 | |
709 name_cc.run(node->name); | |
710 QString name = name_cc.name(); | |
711 | |
712 if (name.isEmpty()) | |
713 { | |
714 // anonymous enum | |
715 QString key = _M_context.join("::"); | |
716 int current = ++_M_anonymous_enums[key]; | |
717 name += QLatin1String("enum_"); | |
718 name += QString::number(current); | |
719 } | |
720 | |
721 _M_current_enum = model()->create<EnumModelItem>(); | |
722 _M_current_enum->setAccessPolicy(_M_current_access); | |
723 updateItemPosition (_M_current_enum->toItem(), node); | |
724 _M_current_enum->setName(name); | |
725 _M_current_enum->setScope(enumScope->qualifiedName()); | |
726 | |
727 _M_qualified_types[_M_current_enum->qualifiedName().join(".")] = QString(); | |
728 | |
729 enumScope->addEnum(_M_current_enum); | |
730 | |
731 DefaultVisitor::visitEnumSpecifier(node); | |
732 | |
733 _M_current_enum = 0; | |
734 } | |
735 | |
736 static QString strip_preprocessor_lines(const QString &name) | |
737 { | |
738 QStringList lst = name.split("\n"); | |
739 QString s; | |
740 for (int i=0; i<lst.size(); ++i) { | |
741 if (!lst.at(i).startsWith('#')) | |
742 s += lst.at(i); | |
743 } | |
744 return s.trimmed(); | |
745 } | |
746 | |
747 void Binder::visitEnumerator(EnumeratorAST *node) | |
748 { | |
749 Q_ASSERT(_M_current_enum != 0); | |
750 EnumeratorModelItem e = model()->create<EnumeratorModelItem>(); | |
751 updateItemPosition (e->toItem(), node); | |
752 e->setName(decode_symbol(node->id)->as_string()); | |
753 | |
754 if (ExpressionAST *expr = node->expression) | |
755 { | |
756 const Token &start_token = _M_token_stream->token((int) expr->start_token); | |
757 const Token &end_token = _M_token_stream->token((int) expr->end_token); | |
758 | |
759 e->setValue(strip_preprocessor_lines(QString::fromUtf8(&start_token.text[start_token.position], | |
760 (int) (end_token.position - start_token.position)).trimmed()).remove(' ')); | |
761 } | |
762 | |
763 _M_current_enum->addEnumerator(e); | |
764 } | |
765 | |
766 void Binder::visitUsingDirective(UsingDirectiveAST *node) | |
767 { | |
768 DefaultVisitor::visitUsingDirective(node); | |
769 } | |
770 | |
771 void Binder::visitQEnums(QEnumsAST *node) | |
772 { | |
773 const Token &start = _M_token_stream->token((int) node->start_token); | |
774 const Token &end = _M_token_stream->token((int) node->end_token); | |
775 QStringList enum_list = QString::fromLatin1(start.text + start.position, | |
776 end.position - start.position).split(' '); | |
777 | |
778 ScopeModelItem scope = currentScope(); | |
779 for (int i=0; i<enum_list.size(); ++i) | |
780 scope->addEnumsDeclaration(enum_list.at(i)); | |
781 } | |
782 | |
783 void Binder::visitQProperty(QPropertyAST *node) | |
784 { | |
785 const Token &start = _M_token_stream->token((int) node->start_token); | |
786 const Token &end = _M_token_stream->token((int) node->end_token); | |
787 QString property = QString::fromLatin1(start.text + start.position, | |
788 end.position - start.position); | |
789 _M_current_class->addPropertyDeclaration(property); | |
790 } | |
791 | |
792 void Binder::applyStorageSpecifiers(const ListNode<std::size_t> *it, MemberModelItem item) | |
793 { | |
794 if (it == 0) | |
795 return; | |
796 | |
797 it = it->toFront(); | |
798 const ListNode<std::size_t> *end = it; | |
799 | |
800 do | |
801 { | |
802 switch (decode_token(it->element)) | |
803 { | |
804 default: | |
805 break; | |
806 | |
807 case Token_friend: | |
808 item->setFriend(true); | |
809 break; | |
810 case Token_auto: | |
811 item->setAuto(true); | |
812 break; | |
813 case Token_register: | |
814 item->setRegister(true); | |
815 break; | |
816 case Token_static: | |
817 item->setStatic(true); | |
818 break; | |
819 case Token_extern: | |
820 item->setExtern(true); | |
821 break; | |
822 case Token_mutable: | |
823 item->setMutable(true); | |
824 break; | |
825 } | |
826 it = it->next; | |
827 } | |
828 while (it != end); | |
829 } | |
830 | |
831 void Binder::applyFunctionSpecifiers(const ListNode<std::size_t> *it, FunctionModelItem item) | |
832 { | |
833 if (it == 0) | |
834 return; | |
835 | |
836 it = it->toFront(); | |
837 const ListNode<std::size_t> *end = it; | |
838 | |
839 do | |
840 { | |
841 switch (decode_token(it->element)) | |
842 { | |
843 default: | |
844 break; | |
845 | |
846 case Token_inline: | |
847 item->setInline(true); | |
848 break; | |
849 | |
850 case Token_virtual: | |
851 item->setVirtual(true); | |
852 break; | |
853 | |
854 case Token_explicit: | |
855 item->setExplicit(true); | |
856 break; | |
857 | |
858 case Token_Q_INVOKABLE: | |
859 item->setInvokable(true); | |
860 break; | |
861 } | |
862 it = it->next; | |
863 } | |
864 while (it != end); | |
865 } | |
866 | |
867 TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) const | |
868 { | |
869 // ### Potentially improve to use string list in the name table to | |
870 if (context.size() == 0) | |
871 { | |
872 // ### We can assume that this means global namespace for now... | |
873 return type; | |
874 } | |
875 else if (_M_qualified_types.contains(type.qualifiedName().join("."))) | |
876 { | |
877 return type; | |
878 } | |
879 else | |
880 { | |
881 QStringList expanded = context; | |
882 expanded << type.qualifiedName(); | |
883 if (_M_qualified_types.contains(expanded.join("."))) | |
884 { | |
885 TypeInfo modified_type = type; | |
886 modified_type.setQualifiedName(expanded); | |
887 return modified_type; | |
888 } | |
889 else | |
890 { | |
891 CodeModelItem scope = model ()->findItem (context, _M_current_file->toItem ()); | |
892 | |
893 if (ClassModelItem klass = model_dynamic_cast<ClassModelItem> (scope)) | |
894 { | |
895 foreach (QString base, klass->baseClasses ()) | |
896 { | |
897 QStringList ctx = context; | |
898 ctx.removeLast(); | |
899 ctx.append (base); | |
900 | |
901 TypeInfo qualified = qualifyType (type, ctx); | |
902 if (qualified != type) | |
903 return qualified; | |
904 } | |
905 } | |
906 | |
907 QStringList copy = context; | |
908 copy.removeLast(); | |
909 return qualifyType(type, copy); | |
910 } | |
911 } | |
912 } | |
913 | |
914 void Binder::updateItemPosition(CodeModelItem item, AST *node) | |
915 { | |
916 QString filename; | |
917 int line, column; | |
918 | |
919 assert (node != 0); | |
920 _M_location.positionAt (_M_token_stream->position(node->start_token), &line, &column, &filename); | |
921 item->setFileName (filename); | |
922 } | |
923 | |
924 void Binder::installMessageHandler(MessageHandler handler) | |
925 { | |
926 _M_message_handler = handler; | |
927 } | |
928 | |
929 // kate: space-indent on; indent-width 2; replace-tabs on; |