source: trunk/tools/porting/src/semantic.cpp@ 348

Last change on this file since 348 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 41.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5** Copyright (C) 2001-2004 Roberto Raggi
6**
7** This file is part of the qt3to4 porting application of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain
25** additional rights. These rights are described in the Nokia Qt LGPL
26** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
27** package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37** If you are unsure which license is appropriate for your use, please
38** contact the sales department at [email protected].
39** $QT_END_LICENSE$
40**
41****************************************************************************/
42
43#include "smallobject.h"
44#include "tokenengine.h"
45#include "semantic.h"
46#include <QtDebug>
47#include <QString>
48#include <QRegExp>
49
50QT_BEGIN_NAMESPACE
51
52using namespace TokenStreamAdapter;
53using namespace TokenEngine;
54using namespace CodeModel;
55
56Semantic::Semantic(CodeModel::NamespaceScope *globalScope,
57 TokenStreamAdapter::TokenStream *tokenStream,
58 TypedPool<CodeModel::Item> *storage)
59{
60 m_storage = storage;
61 m_tokenStream = tokenStream;
62
63 m_currentAccess = CodeModel::Member::Public;
64 m_inSlots = false;
65 m_inSignals = false;
66 m_inStorageSpec = false;
67 m_inTypedef = false;
68
69 globalScope->setName("::");
70 currentScope.push(globalScope);
71
72 //create global UnknownType and UnknownTypeMember
73 UnknownType *type = Create<UnknownType>(m_storage);
74 type->setName("__UnknownType");
75 globalScope->addType(type);
76 type->setParent(globalScope);
77
78 m_sharedUnknownMember = Create<TypeMember>(m_storage);
79 m_sharedUnknownMember->setNameToken(TokenRef());
80 m_sharedUnknownMember->setName("Unknown");
81 m_sharedUnknownMember->setType(type);
82 globalScope->addMember(m_sharedUnknownMember);
83 m_sharedUnknownMember->setParent(globalScope);
84
85}
86
87void Semantic::parseAST(TranslationUnitAST *node)
88{
89 TreeWalker::parseTranslationUnit(node);
90}
91
92
93void Semantic::parseLinkageSpecification(LinkageSpecificationAST *ast)
94{
95 if(!ast)
96 return;
97 int inStorageSpec = m_inStorageSpec;
98 m_inStorageSpec = true;
99 TreeWalker::parseLinkageSpecification(ast);
100 m_inStorageSpec = inStorageSpec;
101}
102
103void Semantic::parseNamespace(NamespaceAST *ast)
104{
105 CodeModel::NamespaceScope *parent = currentScope.top()->toNamespaceScope();
106 if(!parent->toNamespaceScope()) {
107 emit error("Error in Semantic::parseNamespace: parent scope was not a namespace");
108 return;
109 }
110
111 QByteArray nsName;
112 if (!ast->namespaceName() || textOf(ast->namespaceName()).isEmpty()){
113 nsName = "(__QT_ANON_NAMESPACE)";
114 } else {
115 nsName = textOf(ast->namespaceName());
116 }
117
118 CodeModel::NamespaceScope *namespaceScope = 0;
119
120 // Look up namespace scope in case it is already defined.
121 // (Unlike classes, C++ namespaces are "open" and can be added to.)
122 CodeModel::Scope *scope = parent->scopes().value(nsName);
123 if (scope)
124 namespaceScope = scope->toNamespaceScope();
125
126 // Create new namespace if not found.
127 if (!namespaceScope) {
128 namespaceScope = CodeModel::Create<CodeModel::NamespaceScope>(m_storage);
129 namespaceScope->setName(nsName);
130 parent->addScope(namespaceScope);
131
132 NamespaceMember *namespaceMember = Create<NamespaceMember>(m_storage);
133 namespaceMember->setNameToken(tokenRefFromAST(ast->namespaceName()));
134 namespaceMember->setName(nsName);
135 namespaceMember->setNamespaceScope(namespaceScope);
136 currentScope.top()->addMember(namespaceMember);
137 namespaceMember->setParent(currentScope.top());
138 }
139
140 currentScope.push(namespaceScope);
141 TreeWalker::parseNamespace(ast);
142 currentScope.pop();
143}
144
145void Semantic::parseClassSpecifier(ClassSpecifierAST *ast)
146{
147 if (!ast->name()){
148 return;
149 }
150
151 QByteArray kind = textOf(ast->classKey());
152 if (kind == "class")
153 m_currentAccess = CodeModel::Member::Private;
154 else // kind =="struct"
155 m_currentAccess = CodeModel::Member::Public;
156
157 QByteArray className = textOf(ast->name()->unqualifiedName());
158
159 //create ClassScope
160 CodeModel::ClassScope *klass = CodeModel::Create<CodeModel::ClassScope>(m_storage);
161 klass->setName(className);
162 currentScope.top()->addScope(klass);
163
164 //create ClassType
165 CodeModel::ClassType *type = CodeModel::Create<CodeModel::ClassType>(m_storage);
166 type->setScope(klass);
167 currentScope.top()->addType(type);
168 type->setParent(currentScope.top());
169
170 //create TypeMember
171 CodeModel::TypeMember *typeMember = CodeModel::Create<CodeModel::TypeMember>(m_storage);
172 typeMember->setNameToken(tokenRefFromAST(ast->name()->unqualifiedName()));
173 typeMember->setName(className);
174 typeMember->setType(type);
175 currentScope.top()->addMember(typeMember);
176 typeMember->setParent(currentScope.top());
177
178 currentScope.push(klass);
179 if (ast->baseClause())
180 parseBaseClause(ast->baseClause(), klass);
181
182 //TreeWalker::parseClassSpecifier(ast);
183 parseNode(ast->winDeclSpec());
184 parseNode(ast->classKey());
185 parseNode(ast->baseClause());
186
187 // Here's the trick for parsing c++ classes:
188 // All inline function definitions must be interpreted as if they were
189 // written after any other declarations in the class.
190 QList<DeclarationAST *> functionDefinitions;
191 if (ast->declarationList())
192 foreach(DeclarationAST *decl, *ast->declarationList()) {
193 if(decl->nodeType() == NodeType_FunctionDefinition)
194 functionDefinitions.append(decl);
195 else
196 parseNode(decl);
197 }
198 foreach(DeclarationAST *decl, functionDefinitions)
199 parseNode(decl);
200
201 currentScope.pop();
202}
203/*
204 Parse a class, struct or enum forward decalration.
205*/
206void Semantic::parseElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node)
207{
208 if (!node)
209 return;
210 AST *kind = node->kind();
211 if (!kind)
212 return;
213
214 const QByteArray kindText = textOf(kind);
215 const QByteArray nameText = textOf(node->name());
216
217 // Don't do anything if the class, struct or enum has already been declared or defined.
218 if (lookupNameInScope(currentScope.top(), node->name()).count() > 0)
219 return;
220
221 if (kindText == "class" || kindText == "struct") {
222 // Create ClassType.
223 CodeModel::ClassType *type = CodeModel::Create<CodeModel::ClassType>(m_storage);
224 type->setScope(0);
225 currentScope.top()->addType(type);
226 type->setParent(currentScope.top());
227
228 // Create TypeMember.
229 CodeModel::TypeMember *typeMember = CodeModel::Create<CodeModel::TypeMember>(m_storage);
230 typeMember->setNameToken(tokenRefFromAST(node->name()->unqualifiedName()));
231 typeMember->setName(nameText);
232 typeMember->setType(type);
233 currentScope.top()->addMember(typeMember);
234 typeMember->setParent(currentScope.top());
235 } else if (kindText == "enum") {
236 //create a Type
237 CodeModel::EnumType *enumType = CodeModel::Create<CodeModel::EnumType>(m_storage);
238 enumType->setName(nameText);
239 currentScope.top()->addType(enumType);
240 enumType->setParent(currentScope.top());
241
242 //create a TypeMember
243 CodeModel::TypeMember *typeMember = CodeModel::Create<CodeModel::TypeMember>(m_storage);
244 if(node->name())
245 typeMember->setNameToken(tokenRefFromAST(node->name()->unqualifiedName()));
246 typeMember->setName(nameText);
247 typeMember->setType(enumType);
248 currentScope.top()->addMember(typeMember);
249 typeMember->setParent(currentScope.top());
250 }
251}
252
253void Semantic::parseSimpleDeclaration(SimpleDeclarationAST *ast)
254{
255 TypeSpecifierAST *typeSpec = ast->typeSpec();
256 InitDeclaratorListAST *declarators = ast->initDeclaratorList();
257
258 if (typeSpec)
259 parseTypeSpecifier(typeSpec);
260
261 if (declarators){
262 List<InitDeclaratorAST*> l = *declarators->initDeclaratorList();
263
264 foreach (InitDeclaratorAST *current, l) {
265 parseDeclaration(ast->functionSpecifier(), ast->storageSpecifier(), typeSpec, current);
266 }
267 }
268}
269
270void Semantic::parseDeclaration(AST *funSpec, AST *storageSpec, TypeSpecifierAST *typeSpec, InitDeclaratorAST *decl)
271{
272 if (m_inStorageSpec)
273 return;
274
275 if(!decl)
276 return;
277
278 DeclaratorAST *d = decl->declarator();
279 if (!d)
280 return;
281
282 if (!d->subDeclarator() && d->parameterDeclarationClause()) {
283 parseFunctionDeclaration(funSpec, storageSpec, typeSpec, decl);
284 return;
285 }
286 if(!typeSpec || !typeSpec->name())
287 return;
288
289 DeclaratorAST *t = d;
290 while (t && t->subDeclarator())
291 t = t->subDeclarator();
292
293 QByteArray id;
294 if (t && t->declaratorId() && t->declaratorId()->unqualifiedName())
295 id = textOf(t->declaratorId()->unqualifiedName());
296
297 if (!t || !t->declaratorId() || !t->declaratorId()->unqualifiedName())
298 return;
299 AST *nameAST = t->declaratorId()->unqualifiedName();
300 QByteArray name = textOf(nameAST);
301
302
303 if (!scopeOfDeclarator(d, QList<QByteArray>()).isEmpty()){
304 return;
305 }
306
307 //Check if this is possibly a function call by searching for '(' and ')'
308 const QByteArray declText = textOf(decl);
309 if (declText.contains("(") && declText.contains(")")) {
310 if (decl->declarator() && decl->declarator()->subDeclarator()) {
311
312 NameAST * name = decl->declarator()->subDeclarator()->declaratorId();
313 if (name)
314 parseNameUse(name);
315 return;
316 }
317 }
318
319 //create VariableMember
320 CodeModel::VariableMember *variableMember = CodeModel::Create<CodeModel::VariableMember>(m_storage);
321 variableMember->setNameToken(tokenRefFromAST(nameAST));
322 variableMember->setName(name);
323 variableMember->setAccess(m_currentAccess);
324 variableMember->setParent(currentScope.top());
325 currentScope.top()->addMember(variableMember);
326
327 //look up type of variableMember,
328
329 TypeMember *typeMember = typeLookup(currentScope.top(), typeSpec->name());
330 if(typeMember) {
331 variableMember->setType(typeMember->type());
332 } else {
333 QByteArray text = typeOfDeclaration(typeSpec, d);
334 CodeModel::UnknownType *type = CodeModel::Create<CodeModel::UnknownType>(m_storage);
335 type->setName(text);
336 variableMember->setType(type);
337 }
338
339 if (decl)
340 parseNode(decl->initializer());
341
342}
343
344void Semantic::parseFunctionDeclaration(AST *funSpec, AST *storageSpec,
345 TypeSpecifierAST * typeSpec, InitDeclaratorAST * initDeclarator)
346{
347 bool isFriend = false;
348 bool isVirtual = false;
349 bool isStatic = false;
350 bool isInline = false;
351 bool isPure = initDeclarator->initializer() != 0;
352
353 if (funSpec){
354 List<AST*> l = *funSpec->children();
355 foreach (AST *current, l) {
356 QByteArray text = textOf(current);
357 if (text == "virtual") isVirtual = true;
358 else if (text == "inline") isInline = true;
359 }
360 }
361
362 if (storageSpec){
363 List<AST*> l = *storageSpec->children();
364 foreach (AST *current, l) {
365 QByteArray text = textOf(current);
366 if (text == "friend") isFriend = true;
367 else if (text == "static") isStatic = true;
368 }
369 }
370 DeclaratorAST *declarator = initDeclarator->declarator();
371 if(!declarator || !declarator->declaratorId())
372 return;
373 AST *nameAST = declarator->declaratorId()->unqualifiedName();
374 QByteArray name = textOf(nameAST);
375
376 CodeModel::FunctionMember *method = CodeModel::Create<CodeModel::FunctionMember>(m_storage);
377 method->setNameToken(tokenRefFromAST(nameAST));
378 method->setName(name);
379 method->setAccess(m_currentAccess);
380 method->setStatic(isStatic);
381 method->setVirtual(isVirtual);
382 method->setAbstract(isPure);
383
384 parseFunctionArguments(declarator, method);
385
386 if (m_inSignals)
387 method->setSignal(true);
388
389 if (m_inSlots)
390 method->setSlot(true);
391
392 method->setConstant(declarator->constant() != 0);
393
394 QByteArray text = typeOfDeclaration(typeSpec, declarator);
395 if (!text.isEmpty()) {
396 CodeModel::UnknownType *type = CodeModel::Create<CodeModel::UnknownType>(m_storage);
397 type->setName(text);
398 method->setReturnType(type);
399 }
400
401 method->setParent(currentScope.top());
402 currentScope.top()->addMember(method);
403}
404
405
406void Semantic::parseBaseClause(BaseClauseAST * baseClause, CodeModel::ClassScope *klass)
407{
408 if(!baseClause)
409 return;
410 if(!klass)
411 return;
412 List<BaseSpecifierAST*> *l = baseClause->baseSpecifierList();
413 if (!l)
414 return;
415 foreach (BaseSpecifierAST *baseSpecifier, *l) {
416 QByteArray baseName;
417 if (!baseSpecifier->name())
418 continue;
419
420 // Look up a class with the correct name.
421 QList<Member *> candidates = nameLookup(klass, baseSpecifier->name());
422 if (candidates.count() == 1 ) {
423 Member *member = candidates.at(0);
424 Q_ASSERT(member);
425 TypeMember *typeMember = member->toTypeMember();
426 if (typeMember) {
427 Q_ASSERT(typeMember->type());
428 ClassType *classType = typeMember->type()->toClassType();
429 if (classType) {
430 klass->addBaseClass(classType);
431 }
432 }
433 }
434 }
435}
436void Semantic::parseFunctionArguments(const DeclaratorAST *declarator, CodeModel::FunctionMember *method)
437{
438 if(!declarator || !method)
439 return;
440
441 ParameterDeclarationClauseAST *clause = declarator->parameterDeclarationClause();
442
443 if (clause && clause->parameterDeclarationList()){
444 ParameterDeclarationListAST *params = clause->parameterDeclarationList();
445 List<ParameterDeclarationAST*> *l = params->parameterList();
446 if (!l)
447 return;
448 foreach (ParameterDeclarationAST *param, *l) {
449 CodeModel::Argument *arg = CodeModel::Create<CodeModel::Argument>(m_storage);
450 arg->setParent(method);
451
452 if (param->declarator()){
453 QByteArray text = declaratorToString(param->declarator(), QByteArray(), true);
454 if(param->declarator()->declaratorId())
455 arg->setNameToken(tokenRefFromAST(param->declarator()->declaratorId()->unqualifiedName()));
456 if (!text.isEmpty())
457 arg->setName(text);
458 }
459
460 QByteArray tp = typeOfDeclaration(param->typeSpec(), param->declarator());
461 if (!tp.isEmpty()) {
462 CodeModel::UnknownType *type = CodeModel::Create<CodeModel::UnknownType>(m_storage);
463 type->setName(tp);
464 arg->setType(type);
465 }
466
467 method->addArgument(arg);
468 }
469 }
470}
471
472// using directive (using namespace A)
473void Semantic::parseUsingDirective(UsingDirectiveAST *ast)
474{
475 QByteArray qualifiedname = textOf(ast->name());
476 QByteArray name = textOf(ast->name()->unqualifiedName());
477
478 //look up target namespace name
479 QList<Member *> memberList = nameLookup(currentScope.top(), ast->name());
480
481 NamespaceScope *targetNamespace = 0;
482
483 // search for namespace in member list.
484 QList<Member *>::ConstIterator it = memberList.constBegin();
485 while(it != memberList.constEnd()) {
486 if (NamespaceMember *namespaceMember = (*it)->toNamespaceMember()) {
487 targetNamespace = namespaceMember->namespaceScope();
488 break;
489 }
490 ++it;
491 }
492
493 if (targetNamespace == 0)
494 return;
495
496 // Find the insertion namespace, which is the first common
497 // ancesotor namespace for the current scope and the target namespace
498
499 // currentScope might be a block scope, find its first namespace parent
500 CodeModel::Scope *currentParent = currentScope.top();
501 while (currentParent->toNamespaceScope() == 0) {
502 currentParent = currentParent->parent();
503 }
504
505 CodeModel::Scope *namespaceA = currentParent;
506 while (namespaceA != 0) {
507 CodeModel::Scope *namespaceB = targetNamespace;
508 while (namespaceB != 0) {
509 if (namespaceB == namespaceA)
510 break;
511 namespaceB = namespaceB->parent();
512 }
513 if (namespaceB == namespaceA)
514 break;
515 namespaceA = namespaceA->parent();
516 }
517
518 if (namespaceA == 0 || namespaceA->toNamespaceScope() == 0)
519 return;
520
521 NamespaceScope *insertionNamespace = namespaceA->toNamespaceScope();
522
523 // Create using directive link
524 UsingDirectiveLink *usingDirectiveLink = Create<UsingDirectiveLink>(m_storage);
525 usingDirectiveLink->setParent(currentScope.top());
526 usingDirectiveLink->setTargetNamespace(targetNamespace);
527 usingDirectiveLink->setInsertionNamespace(insertionNamespace);
528
529 // add it to current namespace
530 if (NamespaceScope *namespaceScope = currentScope.top()->toNamespaceScope())
531 namespaceScope->addUsingDirectiveLink(usingDirectiveLink);
532 else if (BlockScope *blockScope = currentScope.top()->toBlockScope())
533 blockScope->addUsingDirectiveLink(usingDirectiveLink);
534}
535
536void Semantic::parseFunctionDefinition(FunctionDefinitionAST *ast)
537{
538 AST *funSpec = ast->functionSpecifier();
539 AST *storageSpec = ast->storageSpecifier();
540 TypeSpecifierAST *typeSpec = ast->typeSpec();
541 InitDeclaratorAST *initDeclarator = ast->initDeclarator();
542 if (!ast->initDeclarator())
543 return;
544
545 DeclaratorAST *d = initDeclarator->declarator();
546
547 if (!d->declaratorId())
548 return;
549
550 parseFunctionDeclaration(funSpec, storageSpec, typeSpec, initDeclarator);
551 CodeModel::FunctionMember *method = functionLookup(currentScope.top(), d);
552
553 if(!method) {
554 emit error("Error in Semantic::parseFunctionDefinition: Could not find declaration for function definition");
555 return;
556 }
557
558 CodeModel::Scope *parent = method->parent();
559
560 if(!ast->functionBody()) {
561 emit error("Error in Semantic::parseFunctionDefinition: no function body in function definition");
562 return;
563 }
564
565 //create child function scope
566 QByteArray id = textOf(d->declaratorId()->unqualifiedName());
567 CodeModel::BlockScope *functionScope = CodeModel::Create<CodeModel::BlockScope>(m_storage);
568 functionScope->setName(QByteArray("__QT_ANON_BLOCK_SCOPE(Function: ") + id + QByteArray(")"));
569 functionScope->setParent(parent);
570 method->setFunctionBodyScope(functionScope);
571
572 //add arguments to child scope
573 ArgumentCollection arguments = method->arguments();
574 ArgumentCollection::ConstIterator it = arguments.constBegin();
575 while(it != arguments.constEnd()) {
576 CodeModel::Argument *argument = *it;
577 CodeModel::VariableMember *variableMember = CodeModel::Create<CodeModel::VariableMember>(m_storage);
578 variableMember->setNameToken(argument->nameToken());
579 variableMember->setType(argument->type());
580 variableMember->setName(argument->name());
581 variableMember->setParent(functionScope);
582 functionScope->addMember(variableMember);
583 ++it;
584 }
585
586 //push function scope and parse function body
587 currentScope.push(functionScope);
588 parseStatementList(ast->functionBody());
589 currentScope.pop();
590}
591
592void Semantic::parseStatementList(StatementListAST *statemenList)
593{
594 if(!statemenList)
595 return;
596 CodeModel::BlockScope *blockScope = CodeModel::Create<CodeModel::BlockScope>(m_storage);
597 blockScope->setName("__QT_ANON_BLOCK_SCOPE");
598 blockScope->setParent(currentScope.top());
599 currentScope.top()->addScope(blockScope);
600
601 currentScope.push(blockScope);
602 TreeWalker::parseStatementList(statemenList);
603 currentScope.pop();
604}
605
606void Semantic::parseExpression(AbstractExpressionAST* node)
607{
608 if(!node)
609 return;
610 if(node->nodeType() == NodeType_ClassMemberAccess)
611 parseClassMemberAccess(static_cast<ClassMemberAccessAST *>(node));
612 else
613 TreeWalker::parseExpression(node);
614}
615
616/*
617 Pretty hardwired code for handling class member access of the types:
618 object.member and objectPtr->member.
619
620 This function creates a name use for object to its declaration, and a
621 name use from member to its declaration in the class.
622*/
623void Semantic::parseClassMemberAccess(ClassMemberAccessAST *node)
624{
625 if(!node)
626 return;
627 parseExpression(node->expression());
628 // Get a name use for the 'object' name.
629 NameUse *nameUse = findNameUse(node->expression());
630 // Since the NameUse refers to an object, its decalaration must be
631 // a ClassType. Get the scope of this class type.
632 if( nameUse
633 && nameUse->declaration()
634 && nameUse->declaration()->toVariableMember()
635 && nameUse->declaration()->toVariableMember()->type()
636 && nameUse->declaration()->toVariableMember()->type()->toClassType()
637 && nameUse->declaration()->toVariableMember()->type()->toClassType()->scope()) {
638
639 CodeModel::Scope *scope = nameUse->declaration()->toVariableMember()->type()->toClassType()->scope();
640 QList<CodeModel::Member *> members = lookupNameInScope(scope, node->name());
641 if(members.count() != 0) {
642 createNameUse(members.at(0), node->name());
643 return;
644 }
645 }
646 // Create a NameUse that refers to the global shared unknown type.
647 createNameUse(m_sharedUnknownMember, node->name());
648}
649
650void Semantic::parseExpressionStatement(ExpressionStatementAST *node)
651{
652 TreeWalker::parseExpressionStatement(node);
653}
654
655// using declaration (using A::b)
656void Semantic::parseUsing(UsingAST *ast)
657{
658 //CodeModel::Scope *s = lookUpScope(currentScope.top(), ast->name());
659 QList<CodeModel::Member *> members = nameLookup(currentScope.top(), ast->name());
660 if(members.isEmpty()) {
661 emit error("Error in Semantic::parseUsing: could not look up using target");
662 return;
663 }
664 //TODO: handle multiple members (when nameLookup returns a set of overloded functions)
665 CodeModel::Member *member = members[0];
666 CodeModel::Scope *targetScope = member->parent();
667 if(!targetScope) {
668 emit error("Error in Semantic::parseUsing: target has no parent scope");
669 return;
670 }
671
672 if(!ast->name())
673 return;
674 AST *nameAST = ast->name()->unqualifiedName();
675 if(!nameAST)
676 return;
677 QByteArray name = textOf(nameAST);
678}
679
680void Semantic::parseEnumSpecifier(EnumSpecifierAST *ast)
681{
682 if (!ast->name())
683 return;
684
685 QByteArray name = textOf(ast->name());
686
687 //create a Type
688 CodeModel::EnumType *enumType = CodeModel::Create<CodeModel::EnumType>(m_storage);
689 enumType->setName(name);
690 currentScope.top()->addType(enumType);
691 enumType->setParent(currentScope.top());
692
693 //create a TypeMember
694 CodeModel::TypeMember *typeMember = CodeModel::Create<CodeModel::TypeMember>(m_storage);
695 if(ast->name())
696 typeMember->setNameToken(tokenRefFromAST(ast->name()->unqualifiedName()));
697 typeMember->setName(name);
698 typeMember->setType(enumType);
699 currentScope.top()->addMember(typeMember);
700 typeMember->setParent(currentScope.top());
701
702 //parse the eneumerators
703 List<EnumeratorAST*> *list = ast->enumeratorList();
704 if (!list)
705 return;
706 foreach (EnumeratorAST *current, *list) {
707 CodeModel::VariableMember *enumerator = CodeModel::Create<CodeModel::VariableMember>(m_storage);
708 enumerator->setNameToken(tokenRefFromAST(current->id()));
709 enumerator->setName(textOf(current->id()));
710 enumerator->setAccess(m_currentAccess);
711 enumerator->setStatic(true);
712 enumerator->setType(enumType);
713 currentScope.top()->addMember(enumerator);
714 enumerator->setParent(currentScope.top());
715 }
716
717}
718
719void Semantic::parseTypedef(TypedefAST *ast)
720{
721 TypeSpecifierAST *typeSpec = ast->typeSpec();
722 InitDeclaratorListAST *declarators = ast->initDeclaratorList();
723
724 if (typeSpec && declarators){
725 QByteArray typeId;
726
727 if (typeSpec->name())
728 typeId = textOf(typeSpec->name());
729
730 List<InitDeclaratorAST*> *l = declarators->initDeclaratorList();
731 if (!l)
732 return;
733 foreach (InitDeclaratorAST *initDecl, *l) {
734 QByteArray type, id;
735 if (initDecl->declarator()){
736 type = typeOfDeclaration(typeSpec, initDecl->declarator());
737
738 DeclaratorAST *d = initDecl->declarator();
739 while (d->subDeclarator()){
740 d = d->subDeclarator();
741 }
742
743 if (d->declaratorId())
744 id = textOf(d->declaratorId());
745 }
746
747 //create a type
748 CodeModel::Scope *scope = currentScope.top();
749 CodeModel::AliasType *typeAlias = CodeModel::Create<CodeModel::AliasType>(m_storage);
750 //typeAlias->setName(id);
751 //typeAlias->setParent(scope);
752 scope->addType(typeAlias);
753
754 //create a TypeMember
755 CodeModel::TypeMember *typeMember = CodeModel::Create<CodeModel::TypeMember>(m_storage);
756 if(typeSpec->name())
757 typeMember->setNameToken(tokenRefFromAST(typeSpec->name()->unqualifiedName()));
758 typeMember->setName(id);
759 typeMember->setType(typeAlias);
760 currentScope.top()->addMember(typeMember);
761 typeMember->setParent(currentScope.top());
762
763 }
764
765 }
766}
767
768void Semantic::parseTypeSpecifier(TypeSpecifierAST *ast)
769{
770 // If this is a classSpecifier or a EnumSpecifier we skip the name lookup,
771 // becuase looking up the name "E" in a class definition like
772 // "class E { ..." makes no sense. (There might be a variable named E
773 // already declared, but that variable is now shadowed by the class type.)
774 if( ast->nodeType() != NodeType_EnumSpecifier
775 && ast->nodeType() != NodeType_ClassSpecifier
776 && ast->nodeType() != NodeType_ElaboratedTypeSpecifier )
777 parseNameUse(ast->name());
778 TreeWalker::parseTypeSpecifier(ast);
779}
780
781/*
782 Parses a name: looks up name, creates name use.
783*/
784void Semantic::parseNameUse(NameAST* name)
785{
786 if(!name)
787 return;
788
789 // Look up name
790 QList<CodeModel::Member *> members = nameLookup(currentScope.top(), name);
791 if(members.isEmpty()) {
792 //cout << "no declaration found for " << textOf(name).constData() << endl;
793 // Create NameUse that refer to a shared UnknownMember
794 createNameUse(m_sharedUnknownMember, name);
795 return;
796 }
797
798 //TODO: handle multiple members (when nameLookup returns a set of overloaded functions)
799 CodeModel::Member *member = members[0];
800 if(!member->parent()) {
801 emit error("Error in Semantic::parseUsing: target has no parent scope");
802 return;
803 }
804
805 createNameUse(member, name);
806}
807
808/*
809 looks up name used in basescope. If name->isGlobal() is true or if classOrNamespaceList()
810 returns a non-emty list, the C++ qualified name lookup rules are used. Otherwise the
811 unquialified name lookup rules are used. Returns the a list of members that was found,
812 In most cases this list will contain zero or one element, exept in the case of overloaded functions.
813 TODO: Argument-dependent name lookup
814*/
815QList<CodeModel::Member *> Semantic::nameLookup(CodeModel::Scope *baseScope, const NameAST* name)
816{
817 if (name->isGlobal() || (name->classOrNamespaceNameList()
818 && name->classOrNamespaceNameList()->size()>0 )) {
819 return qualifiedNameLookup(baseScope, name);
820 } else {
821 return unqualifiedNameLookup(baseScope, name);
822 }
823}
824
825//look up an unqualified name
826QList<CodeModel::Member *> Semantic::unqualifiedNameLookup(CodeModel::Scope *baseScope, const NameAST* name)
827{
828 QList<UsingDirectiveLink *> usingDirectiveLinks;
829 CodeModel::Scope *currentScope = baseScope;
830 QList<CodeModel::Member *> entities;
831
832 while (currentScope != 0) {
833 // Add any "using namespace" directive links for the current scope to
834 // usingDirectiveLinks
835 if (NamespaceScope *namespaceScope = currentScope->toNamespaceScope())
836 usingDirectiveLinks += namespaceScope->usingDirectiveLinks();
837 if (BlockScope *blockScope = currentScope->toBlockScope())
838 usingDirectiveLinks += blockScope->usingDirectiveLinks();
839
840 // Search usingDirectiveLinks for a link where currentScope is the
841 // insertion namespace. If found look up name in the target namespace
842 // for that link.
843 if (NamespaceScope *namespaceScope = currentScope->toNamespaceScope()) {
844 QList<UsingDirectiveLink *>::ConstIterator it = usingDirectiveLinks.constBegin();
845 while (it != usingDirectiveLinks.constEnd()) {
846 if ((*it)->insertionNamespace() == namespaceScope)
847 entities = lookupNameInScope((*it)->targetNamespace(), name);
848 ++it;
849 }
850 }
851
852 // Look up names in this scope.
853 entities += lookupNameInScope(currentScope, name);
854 if (!entities.isEmpty())
855 break;
856 currentScope = currentScope->parent();
857 }
858 return entities;
859}
860
861//look up a qualified name
862QList<CodeModel::Member *> Semantic::qualifiedNameLookup(CodeModel::Scope *baseScope, const NameAST* name)
863{
864 QList<CodeModel::Member *> entities;
865 CodeModel::Scope *currentScope = baseScope;
866
867 // Check if the global ("::") scope has been specified.
868 if(name->isGlobal()) {
869 while (currentScope->parent())
870 currentScope = currentScope->parent();
871 }
872
873 while (entities.isEmpty() && currentScope != 0) {
874 CodeModel::Scope *targetScope = scopeLookup(currentScope, name);
875 entities = lookupNameInScope(targetScope, name);
876 currentScope = currentScope->parent();
877 }
878
879 return entities;
880}
881
882//looks up a name in a scope, includes base classes if scope is a class scope
883QList<CodeModel::Member *> Semantic::lookupNameInScope(CodeModel::Scope *scope, const NameAST* name)
884{
885 QList<CodeModel::Member *> entities;
886
887 if(!scope || !name)
888 return entities;
889
890 QByteArray nameText = textOf(name->unqualifiedName()->name());
891 //look up name in members of current scope
892 const CodeModel::MemberCollection members = scope->members();
893 if (members.contains(nameText))
894 entities.append(members.value(nameText));
895
896 // if not found, look up name in base classes (if any)
897 CodeModel::ClassScope *classScope = scope->toClassScope();
898 if (entities.isEmpty() && classScope) {
899 const TypeCollection baseClasses = classScope->baseClasses();
900 TypeCollection::ConstIterator it = baseClasses.constBegin();
901 while (it != baseClasses.constEnd()) {
902 CodeModel::Scope *baseClass = it.value()->toClassType()->scope();
903 if (scope != baseClass)
904 entities += lookupNameInScope(baseClass, name);
905 ++it;
906 }
907
908 if (entities.count() > 1)
909 emit error("Error in Semantic::lookupNameInScope: name "
910 + nameText + " is ambigous");
911 }
912 return entities;
913}
914
915/*
916 Resolves the classOrNamespaceNameList part of a NameAST against a base scope.
917*/
918CodeModel::Scope *Semantic::scopeLookup(CodeModel::Scope *baseScope, const NameAST* name)
919{
920 CodeModel::Scope *currentScope = baseScope;
921 const List<ClassOrNamespaceNameAST *> *scopeList = name->classOrNamespaceNameList();
922 // if there is no scope list, then the scope we are looking for is baseScope
923 if (!scopeList)
924 return baseScope;
925
926 // Check if the global ("::") scope has been specified.
927 if(name->isGlobal()) {
928 while (currentScope->parent())
929 currentScope = currentScope->parent();
930 }
931
932 while(currentScope != 0) {
933 int nestingCounter = 0;
934 CodeModel::Scope *nestedScope = currentScope;
935 while (nestingCounter < scopeList->count()) {
936 const QByteArray nameText = textOf((*scopeList)[nestingCounter]->name());
937 nestedScope = nestedScope->scopes().value(nameText);
938 if (!nestedScope)
939 break;
940 ++nestingCounter;
941 }
942 if(nestedScope) // found target scope?
943 return nestedScope;
944
945 currentScope = currentScope->parent(); //look in parent scope
946 }
947
948 return 0;
949}
950
951TypeMember *Semantic::typeLookup(CodeModel::Scope *baseScope, const NameAST* name)
952{
953 QList<CodeModel::Member *> memberList = nameLookup(baseScope, name);
954
955 foreach(Member *member, memberList) {
956 if(TypeMember *typeMember = member->toTypeMember())
957 return typeMember;
958 }
959 return 0;
960}
961
962FunctionMember *Semantic::functionLookup(CodeModel::Scope *baseScope,
963 const DeclaratorAST *functionDeclarator)
964{
965
966 QList<CodeModel::Member*> candidateList =
967 nameLookup(baseScope, functionDeclarator->declaratorId());
968 return selectFunction(candidateList, functionDeclarator);
969}
970
971/*
972 This is a simplified function lookup routine, for matching member function
973 definitions with member function declarations. It does not implement
974 the general C++ function overload resolution rules.
975*/
976FunctionMember *Semantic::selectFunction(QList<CodeModel::Member*> candidatateList, const DeclaratorAST *functionDeclarator)
977{
978 // get arguments for funciton we are looking for
979 FunctionMember testFunction;
980 parseFunctionArguments(functionDeclarator, &testFunction);
981 const ArgumentCollection testArgumentCollection = testFunction.arguments();
982
983 //test againts functions in overload list.
984 foreach(Member* member, candidatateList) {
985 FunctionMember *function = member->toFunctionMember();
986 if (!function)
987 continue;
988 const ArgumentCollection argumentCollection = function->arguments();
989
990 //test argument types and number of arguments
991 ArgumentCollection::ConstIterator arg1 = argumentCollection.constBegin();
992 ArgumentCollection::ConstIterator arg2 = testArgumentCollection.constBegin();
993 bool match = true;
994 while(arg1 != argumentCollection.constEnd() && arg2 != testArgumentCollection.constEnd()) {
995 if( arg1.value()->type()->name() != arg2.value()->type()->name() ) {
996 match = false;
997 break;
998 }
999 ++arg1;
1000 ++arg2;
1001 }
1002 if(match)
1003 return function;
1004 }
1005 return 0;
1006}
1007
1008QByteArray Semantic::typeOfDeclaration(TypeSpecifierAST *typeSpec, DeclaratorAST *declarator)
1009{
1010 if (!typeSpec)
1011 return QByteArray();
1012
1013 QByteArray text;
1014
1015 if (typeSpec->cvQualify()) {
1016 List<AST*> cv = *typeSpec->cvQualify()->children();
1017 foreach (AST *current, cv) {
1018 text += " " + textOf(current);
1019 }
1020 text += " ";
1021 }
1022
1023
1024 text += textOf(typeSpec);
1025
1026 if (typeSpec->cv2Qualify()) {
1027 List<AST*> cv = *typeSpec->cv2Qualify()->children();
1028 foreach (AST *current, cv) {
1029 text += textOf(current) + " ";
1030 }
1031 }
1032
1033 if (declarator && declarator->ptrOpList()) {
1034 List<AST*> ptrOpList = *declarator->ptrOpList();
1035 foreach (AST *current, ptrOpList) {
1036 text += " " + textOf(current);
1037 }
1038 text += " ";
1039 }
1040
1041 return text.trimmed().simplified();
1042}
1043
1044
1045
1046QList<QByteArray> Semantic::scopeOfName(NameAST *id, const QList<QByteArray>& startScope)
1047{
1048 QList<QByteArray> scope = startScope;
1049 if (id && id->classOrNamespaceNameList()){
1050 if (id->isGlobal())
1051 scope.clear();
1052
1053 List<ClassOrNamespaceNameAST*> l = *id->classOrNamespaceNameList();
1054 foreach (ClassOrNamespaceNameAST *current, l) {
1055 if (current->name())
1056 scope << textOf(current->name());
1057 }
1058 }
1059
1060 return scope;
1061}
1062
1063QList<QByteArray> Semantic::scopeOfDeclarator(DeclaratorAST *d, const QList<QByteArray>& startScope)
1064{
1065 if(!d)
1066 return QList<QByteArray>();
1067 return scopeOfName(d->declaratorId(), startScope);
1068}
1069
1070QByteArray Semantic::typeSpecToString(TypeSpecifierAST* typeSpec)
1071{
1072 if (!typeSpec)
1073 return QByteArray();
1074
1075 QByteArray tp;
1076 if (typeSpec->cvQualify()) {
1077 tp += "const ";
1078 }
1079
1080 tp += (QString::fromLatin1(textOf(typeSpec)).replace(QRegExp(QLatin1String(" :: ")), QString::fromUtf8("::"))).toLatin1();
1081 return tp;
1082}
1083
1084QByteArray Semantic::declaratorToString(DeclaratorAST* declarator, const QByteArray& scope, bool skipPtrOp)
1085{
1086 if (!declarator)
1087 return QByteArray();
1088
1089 QByteArray text;
1090
1091 if (!skipPtrOp && declarator->ptrOpList()){
1092 List<AST*> ptrOpList = *declarator->ptrOpList();
1093 foreach (AST *current, ptrOpList) {
1094 text += textOf(current);
1095 }
1096 text += QByteArray(" ");
1097 }
1098
1099 text += scope;
1100
1101 if (declarator->subDeclarator())
1102 text += QByteArray("(") + declaratorToString(declarator->subDeclarator()) + QByteArray(")");
1103
1104 if (declarator->declaratorId())
1105 text += textOf(declarator->declaratorId());
1106
1107 if (declarator->arrayDimensionList()) {
1108 List<AST*> arrays = *declarator->arrayDimensionList();
1109 foreach (AST *current, arrays) {
1110 current=current; //silence unused symbol warning
1111 text += QByteArray("[]");
1112 }
1113 }
1114
1115 if (declarator->parameterDeclarationClause()){
1116 text += QByteArray("(");
1117
1118 ParameterDeclarationListAST* l = declarator->parameterDeclarationClause()->parameterDeclarationList();
1119 if (l != 0){
1120 List<ParameterDeclarationAST*> params = *l->parameterList();
1121 foreach (ParameterDeclarationAST *current, params) {
1122 QByteArray type = typeSpecToString(current->typeSpec());
1123 text += type;
1124 if (!type.isEmpty())
1125 text += QByteArray(" ");
1126 text += declaratorToString(current->declarator());
1127
1128 // ### FIXME if (it.current())
1129 text += QByteArray(", ");
1130 }
1131 }
1132
1133 text += QByteArray(")");
1134
1135 if (declarator->constant() != 0)
1136 text += QByteArray(" const");
1137 }
1138
1139 return QString::fromLatin1(text).replace(QRegExp(QLatin1String(" :: ")), QLatin1String("::")).simplified().toLatin1();
1140}
1141
1142QByteArray Semantic::textOf(const AST *node) const
1143{
1144 if (!node)
1145 return QByteArray();
1146 QByteArray text;
1147 for (int i = node->startToken(); i < node->endToken(); ++i) {
1148 if (!m_tokenStream->isHidden(i)) {
1149 if (i != node->startToken())
1150 text += QByteArray(" ");
1151 text += m_tokenStream->tokenText(i);
1152 }
1153 }
1154 return text;
1155}
1156
1157void Semantic::createNameUse(Member *member, NameAST *name)
1158{
1159 if (!name)
1160 return;
1161
1162 AST *unqualifedName = name->unqualifiedName()->name();
1163
1164 if(!unqualifedName || !member)
1165 return;
1166
1167 CodeModel::NameUse *nameUse = CodeModel::Create<CodeModel::NameUse>(m_storage);
1168 nameUse->setParent(currentScope.top());
1169 nameUse->setNameToken(tokenRefFromAST(unqualifedName));
1170 nameUse->setName(textOf(unqualifedName));
1171 nameUse->setDeclaration(member);
1172
1173 currentScope.top()->addNameUse(nameUse);
1174 addNameUse(unqualifedName, nameUse);
1175}
1176
1177void Semantic::addNameUse(AST *node, NameUse *nameUse)
1178{
1179 const int tokenIndex = node->startToken();
1180 m_nameUses.insert(tokenIndex, nameUse);
1181}
1182
1183/*
1184 Searches a AST node and all its children for a nameUse. The name use is
1185 found by looking up each node's tokens in the m_nameUses map. A depth-first
1186 search is used.
1187*/
1188NameUse *Semantic::findNameUse(AST *node)
1189{
1190 if(!node)
1191 return 0;
1192
1193 List<AST*> *children = node->children();
1194 if(children) {
1195 NameUse *nameUse = 0;
1196 foreach(AST* child , *children) {
1197 nameUse = findNameUse(child);
1198 if(nameUse)
1199 break;
1200 }
1201 if (nameUse)
1202 return nameUse;
1203 }
1204
1205 for (int t = node->startToken(); t < node->endToken(); ++t) {
1206 // cout << t <<" |" <<m_tokenStream->tokenText(t).constData() << "|" << endl;
1207 if (m_nameUses.contains(t))
1208 return m_nameUses.value(t);
1209 }
1210 return 0;
1211}
1212
1213/*
1214 Gets a TokenRef from an AST node.
1215 Assumes that the node only covers one token, which means that
1216 node->statToken() == node->endToken(). If this is not the case
1217 then the TokenRef will reference the token at startToken.
1218*/
1219TokenEngine::TokenRef Semantic::tokenRefFromAST(AST *node)
1220{
1221 const int startTokenIndex = node->startToken();
1222 const TokenEngine::TokenContainer tokenContainer = m_tokenStream->tokenContainer(startTokenIndex);
1223 const int containerIndex = m_tokenStream->containerIndex(startTokenIndex);
1224 return TokenEngine::TokenRef(tokenContainer, containerIndex);
1225}
1226
1227QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.