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 |
|
---|
50 | QT_BEGIN_NAMESPACE
|
---|
51 |
|
---|
52 | using namespace TokenStreamAdapter;
|
---|
53 | using namespace TokenEngine;
|
---|
54 | using namespace CodeModel;
|
---|
55 |
|
---|
56 | Semantic::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 |
|
---|
87 | void Semantic::parseAST(TranslationUnitAST *node)
|
---|
88 | {
|
---|
89 | TreeWalker::parseTranslationUnit(node);
|
---|
90 | }
|
---|
91 |
|
---|
92 |
|
---|
93 | void 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 |
|
---|
103 | void 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 |
|
---|
145 | void 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 | */
|
---|
206 | void 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 |
|
---|
253 | void 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 |
|
---|
270 | void 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 |
|
---|
344 | void 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 |
|
---|
406 | void 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 | }
|
---|
436 | void 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)
|
---|
473 | void 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 |
|
---|
536 | void 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 |
|
---|
592 | void 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 |
|
---|
606 | void 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 | */
|
---|
623 | void 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 |
|
---|
650 | void Semantic::parseExpressionStatement(ExpressionStatementAST *node)
|
---|
651 | {
|
---|
652 | TreeWalker::parseExpressionStatement(node);
|
---|
653 | }
|
---|
654 |
|
---|
655 | // using declaration (using A::b)
|
---|
656 | void 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 |
|
---|
680 | void 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 |
|
---|
719 | void 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 |
|
---|
768 | void 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 | */
|
---|
784 | void 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 | */
|
---|
815 | QList<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
|
---|
826 | QList<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
|
---|
862 | QList<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
|
---|
883 | QList<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 | */
|
---|
918 | CodeModel::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 |
|
---|
951 | TypeMember *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 |
|
---|
962 | FunctionMember *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 | */
|
---|
976 | FunctionMember *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 |
|
---|
1008 | QByteArray 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 |
|
---|
1046 | QList<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 |
|
---|
1063 | QList<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 |
|
---|
1070 | QByteArray 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 |
|
---|
1084 | QByteArray 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 |
|
---|
1142 | QByteArray 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 |
|
---|
1157 | void 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 |
|
---|
1177 | void 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 | */
|
---|
1188 | NameUse *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 | */
|
---|
1219 | TokenEngine::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 |
|
---|
1227 | QT_END_NAMESPACE
|
---|