|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 // Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> |
|
42 // |
|
43 // Permission is hereby granted, free of charge, to any person obtaining a copy |
|
44 // of this software and associated documentation files (the "Software"), to deal |
|
45 // in the Software without restriction, including without limitation the rights |
|
46 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
47 // copies of the Software, and to permit persons to whom the Software is |
|
48 // furnished to do so, subject to the following conditions: |
|
49 // |
|
50 // The above copyright notice and this permission notice shall be included in |
|
51 // all copies or substantial portions of the Software. |
|
52 // |
|
53 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
54 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
55 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
56 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
57 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
58 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
59 // THE SOFTWARE. |
|
60 |
|
61 #include "CheckDeclaration.h" |
|
62 #include "Semantic.h" |
|
63 #include "AST.h" |
|
64 #include "TranslationUnit.h" |
|
65 #include "Scope.h" |
|
66 #include "Names.h" |
|
67 #include "CoreTypes.h" |
|
68 #include "Symbols.h" |
|
69 #include "Control.h" |
|
70 #include "Literals.h" |
|
71 #include <string> |
|
72 #include <cassert> |
|
73 |
|
74 using namespace CPlusPlus; |
|
75 |
|
76 CheckDeclaration::CheckDeclaration(Semantic *semantic) |
|
77 : SemanticCheck(semantic), |
|
78 _declaration(0), |
|
79 _scope(0), |
|
80 _templateParameters(0), |
|
81 _checkAnonymousArguments(false) |
|
82 { } |
|
83 |
|
84 CheckDeclaration::~CheckDeclaration() |
|
85 { } |
|
86 |
|
87 void CheckDeclaration::check(DeclarationAST *declaration, |
|
88 Scope *scope, TemplateParameters *templateParameters) |
|
89 { |
|
90 Scope *previousScope = switchScope(scope); |
|
91 TemplateParameters *previousTemplateParameters = switchTemplateParameters(templateParameters); |
|
92 DeclarationAST *previousDeclaration = switchDeclaration(declaration); |
|
93 accept(declaration); |
|
94 (void) switchDeclaration(previousDeclaration); |
|
95 (void) switchTemplateParameters(previousTemplateParameters); |
|
96 (void) switchScope(previousScope); |
|
97 } |
|
98 |
|
99 DeclarationAST *CheckDeclaration::switchDeclaration(DeclarationAST *declaration) |
|
100 { |
|
101 DeclarationAST *previousDeclaration = _declaration; |
|
102 _declaration = declaration; |
|
103 return previousDeclaration; |
|
104 } |
|
105 |
|
106 Scope *CheckDeclaration::switchScope(Scope *scope) |
|
107 { |
|
108 Scope *previousScope = _scope; |
|
109 _scope = scope; |
|
110 return previousScope; |
|
111 } |
|
112 |
|
113 TemplateParameters *CheckDeclaration::switchTemplateParameters(TemplateParameters *templateParameters) |
|
114 { |
|
115 TemplateParameters *previousTemplateParameters = _templateParameters; |
|
116 _templateParameters = templateParameters; |
|
117 return previousTemplateParameters; |
|
118 } |
|
119 |
|
120 void CheckDeclaration::checkFunctionArguments(Function *fun) |
|
121 { |
|
122 if (! _checkAnonymousArguments) |
|
123 return; |
|
124 |
|
125 if (_scope->isClassScope() && fun->isPublic()) { |
|
126 for (unsigned argc = 0; argc < fun->argumentCount(); ++argc) { |
|
127 Argument *arg = fun->argumentAt(argc)->asArgument(); |
|
128 assert(arg != 0); |
|
129 |
|
130 if (! arg->name()) { |
|
131 translationUnit()->warning(arg->sourceLocation(), |
|
132 "anonymous argument"); |
|
133 } |
|
134 } |
|
135 } |
|
136 } |
|
137 |
|
138 unsigned CheckDeclaration::locationOfDeclaratorId(DeclaratorAST *declarator) const |
|
139 { |
|
140 if (declarator && declarator->core_declarator) { |
|
141 if (DeclaratorIdAST *declaratorId = declarator->core_declarator->asDeclaratorId()) |
|
142 return declaratorId->firstToken(); |
|
143 else if (NestedDeclaratorAST *nested = declarator->core_declarator->asNestedDeclarator()) |
|
144 return locationOfDeclaratorId(nested->declarator); |
|
145 } |
|
146 |
|
147 return 0; |
|
148 } |
|
149 |
|
150 bool CheckDeclaration::visit(SimpleDeclarationAST *ast) |
|
151 { |
|
152 FullySpecifiedType ty = semantic()->check(ast->decl_specifier_list, _scope); |
|
153 FullySpecifiedType qualTy = ty.qualifiedType(); |
|
154 |
|
155 if (_templateParameters && ty) { |
|
156 if (Class *klass = ty->asClassType()) { |
|
157 klass->setTemplateParameters(_templateParameters); |
|
158 } |
|
159 } |
|
160 |
|
161 if (! ast->declarator_list && ast->decl_specifier_list && ! ast->decl_specifier_list->next) { |
|
162 if (ElaboratedTypeSpecifierAST *elab_type_spec = ast->decl_specifier_list->value->asElaboratedTypeSpecifier()) { |
|
163 |
|
164 unsigned sourceLocation = elab_type_spec->firstToken(); |
|
165 |
|
166 if (elab_type_spec->name) |
|
167 sourceLocation = elab_type_spec->name->firstToken(); |
|
168 |
|
169 const Name *name = semantic()->check(elab_type_spec->name, _scope); |
|
170 ForwardClassDeclaration *symbol = |
|
171 control()->newForwardClassDeclaration(sourceLocation, name); |
|
172 |
|
173 if (_templateParameters) { |
|
174 symbol->setTemplateParameters(_templateParameters); |
|
175 _templateParameters = 0; |
|
176 } |
|
177 |
|
178 _scope->enterSymbol(symbol); |
|
179 return false; |
|
180 } |
|
181 } |
|
182 |
|
183 const bool isQ_SLOT = ast->qt_invokable_token && tokenKind(ast->qt_invokable_token) == T_Q_SLOT; |
|
184 const bool isQ_SIGNAL = ast->qt_invokable_token && tokenKind(ast->qt_invokable_token) == T_Q_SIGNAL; |
|
185 #ifdef ICHECK_BUILD |
|
186 const bool isQ_INVOKABLE = (ast->invoke_token > 0); |
|
187 #endif |
|
188 |
|
189 List<Declaration *> **decl_it = &ast->symbols; |
|
190 for (DeclaratorListAST *it = ast->declarator_list; it; it = it->next) { |
|
191 const Name *name = 0; |
|
192 FullySpecifiedType declTy = semantic()->check(it->value, qualTy, |
|
193 _scope, &name); |
|
194 |
|
195 unsigned location = locationOfDeclaratorId(it->value); |
|
196 if (! location) { |
|
197 if (it->value) |
|
198 location = it->value->firstToken(); |
|
199 else |
|
200 location = ast->firstToken(); |
|
201 } |
|
202 |
|
203 Function *fun = 0; |
|
204 if (declTy && 0 != (fun = declTy->asFunctionType())) { |
|
205 fun->setSourceLocation(location); |
|
206 fun->setScope(_scope); |
|
207 fun->setName(name); |
|
208 fun->setMethodKey(semantic()->currentMethodKey()); |
|
209 fun->setVirtual(ty.isVirtual()); |
|
210 if (isQ_SIGNAL) |
|
211 fun->setMethodKey(Function::SignalMethod); |
|
212 else if (isQ_SLOT) |
|
213 fun->setMethodKey(Function::SlotMethod); |
|
214 #ifdef ICHECK_BUILD |
|
215 else if (isQ_INVOKABLE) |
|
216 fun->setInvokable(true); |
|
217 #endif |
|
218 fun->setVisibility(semantic()->currentVisibility()); |
|
219 } else if (semantic()->currentMethodKey() != Function::NormalMethod) { |
|
220 translationUnit()->warning(ast->firstToken(), |
|
221 "expected a function declaration"); |
|
222 } |
|
223 |
|
224 Declaration *symbol = control()->newDeclaration(location, name); |
|
225 symbol->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
226 symbol->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
227 |
|
228 symbol->setType(control()->integerType(IntegerType::Int)); |
|
229 symbol->setType(declTy); |
|
230 |
|
231 if (_templateParameters && it == ast->declarator_list && ty && ! ty->isClassType()) |
|
232 symbol->setTemplateParameters(_templateParameters); |
|
233 |
|
234 symbol->setVisibility(semantic()->currentVisibility()); |
|
235 |
|
236 if (ty.isFriend()) |
|
237 symbol->setStorage(Symbol::Friend); |
|
238 else if (ty.isRegister()) |
|
239 symbol->setStorage(Symbol::Register); |
|
240 else if (ty.isStatic()) |
|
241 symbol->setStorage(Symbol::Static); |
|
242 else if (ty.isExtern()) |
|
243 symbol->setStorage(Symbol::Extern); |
|
244 else if (ty.isMutable()) |
|
245 symbol->setStorage(Symbol::Mutable); |
|
246 else if (ty.isTypedef()) |
|
247 symbol->setStorage(Symbol::Typedef); |
|
248 |
|
249 if (it->value && it->value->initializer) { |
|
250 FullySpecifiedType initTy = semantic()->check(it->value->initializer, _scope); |
|
251 } |
|
252 |
|
253 *decl_it = new (translationUnit()->memoryPool()) List<Declaration *>(); |
|
254 (*decl_it)->value = symbol; |
|
255 decl_it = &(*decl_it)->next; |
|
256 |
|
257 _scope->enterSymbol(symbol); |
|
258 } |
|
259 return false; |
|
260 } |
|
261 |
|
262 bool CheckDeclaration::visit(EmptyDeclarationAST *) |
|
263 { |
|
264 return false; |
|
265 } |
|
266 |
|
267 bool CheckDeclaration::visit(AccessDeclarationAST *ast) |
|
268 { |
|
269 int accessSpecifier = tokenKind(ast->access_specifier_token); |
|
270 int visibility = semantic()->visibilityForAccessSpecifier(accessSpecifier); |
|
271 semantic()->switchVisibility(visibility); |
|
272 if (ast->slots_token) |
|
273 semantic()->switchMethodKey(Function::SlotMethod); |
|
274 else if (accessSpecifier == T_Q_SIGNALS) |
|
275 semantic()->switchMethodKey(Function::SignalMethod); |
|
276 else |
|
277 semantic()->switchMethodKey(Function::NormalMethod); |
|
278 return false; |
|
279 } |
|
280 |
|
281 #ifdef ICHECK_BUILD |
|
282 bool CheckDeclaration::visit(QPropertyDeclarationAST *) |
|
283 { |
|
284 return false; |
|
285 } |
|
286 |
|
287 bool CheckDeclaration::visit(QEnumDeclarationAST *) |
|
288 { |
|
289 return false; |
|
290 } |
|
291 |
|
292 bool CheckDeclaration::visit(QFlagsDeclarationAST *) |
|
293 { |
|
294 return false; |
|
295 } |
|
296 |
|
297 bool CheckDeclaration::visit(QDeclareFlagsDeclarationAST *) |
|
298 { |
|
299 return false; |
|
300 } |
|
301 #endif |
|
302 |
|
303 bool CheckDeclaration::visit(AsmDefinitionAST *) |
|
304 { |
|
305 return false; |
|
306 } |
|
307 |
|
308 bool CheckDeclaration::visit(ExceptionDeclarationAST *ast) |
|
309 { |
|
310 FullySpecifiedType ty = semantic()->check(ast->type_specifier_list, _scope); |
|
311 FullySpecifiedType qualTy = ty.qualifiedType(); |
|
312 |
|
313 const Name *name = 0; |
|
314 FullySpecifiedType declTy = semantic()->check(ast->declarator, qualTy, |
|
315 _scope, &name); |
|
316 |
|
317 unsigned location = locationOfDeclaratorId(ast->declarator); |
|
318 if (! location) { |
|
319 if (ast->declarator) |
|
320 location = ast->declarator->firstToken(); |
|
321 else |
|
322 location = ast->firstToken(); |
|
323 } |
|
324 |
|
325 Declaration *symbol = control()->newDeclaration(location, name); |
|
326 symbol->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
327 symbol->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
328 symbol->setType(declTy); |
|
329 _scope->enterSymbol(symbol); |
|
330 |
|
331 return false; |
|
332 } |
|
333 |
|
334 bool CheckDeclaration::visit(FunctionDefinitionAST *ast) |
|
335 { |
|
336 FullySpecifiedType ty = semantic()->check(ast->decl_specifier_list, _scope); |
|
337 FullySpecifiedType qualTy = ty.qualifiedType(); |
|
338 const Name *name = 0; |
|
339 FullySpecifiedType funTy = semantic()->check(ast->declarator, qualTy, |
|
340 _scope, &name); |
|
341 if (! (funTy && funTy->isFunctionType())) { |
|
342 translationUnit()->error(ast->firstToken(), |
|
343 "expected a function prototype"); |
|
344 return false; |
|
345 } |
|
346 |
|
347 Function *fun = funTy->asFunctionType(); |
|
348 fun->setVirtual(ty.isVirtual()); |
|
349 fun->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
350 fun->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
351 if (ast->declarator) |
|
352 fun->setSourceLocation(ast->declarator->firstToken()); |
|
353 fun->setName(name); |
|
354 fun->setTemplateParameters(_templateParameters); |
|
355 fun->setVisibility(semantic()->currentVisibility()); |
|
356 fun->setMethodKey(semantic()->currentMethodKey()); |
|
357 |
|
358 const bool isQ_SLOT = ast->qt_invokable_token && tokenKind(ast->qt_invokable_token) == T_Q_SLOT; |
|
359 const bool isQ_SIGNAL = ast->qt_invokable_token && tokenKind(ast->qt_invokable_token) == T_Q_SIGNAL; |
|
360 #ifdef ICHECK_BUILD |
|
361 const bool isQ_INVOKABLE = (ast->invoke_token > 0); |
|
362 #endif |
|
363 |
|
364 if (isQ_SIGNAL) |
|
365 fun->setMethodKey(Function::SignalMethod); |
|
366 else if (isQ_SLOT) |
|
367 fun->setMethodKey(Function::SlotMethod); |
|
368 #ifdef ICHECK_BUILD |
|
369 else if (isQ_INVOKABLE) |
|
370 fun->setInvokable(true); |
|
371 #endif |
|
372 |
|
373 checkFunctionArguments(fun); |
|
374 |
|
375 ast->symbol = fun; |
|
376 _scope->enterSymbol(fun); |
|
377 |
|
378 if (! semantic()->skipFunctionBodies()) { |
|
379 if (ast->ctor_initializer) { |
|
380 bool looksLikeCtor = false; |
|
381 if (ty.isValid() || ! fun->identity()) |
|
382 looksLikeCtor = false; |
|
383 else if (fun->identity()->isNameId() || fun->identity()->isTemplateNameId()) |
|
384 looksLikeCtor = true; |
|
385 |
|
386 if (! looksLikeCtor) { |
|
387 translationUnit()->error(ast->ctor_initializer->firstToken(), |
|
388 "only constructors take base initializers"); |
|
389 } |
|
390 accept(ast->ctor_initializer); |
|
391 } |
|
392 |
|
393 const int previousVisibility = semantic()->switchVisibility(Symbol::Public); |
|
394 const int previousMethodKey = semantic()->switchMethodKey(Function::NormalMethod); |
|
395 |
|
396 semantic()->check(ast->function_body, fun->members()); |
|
397 |
|
398 semantic()->switchMethodKey(previousMethodKey); |
|
399 semantic()->switchVisibility(previousVisibility); |
|
400 } |
|
401 |
|
402 return false; |
|
403 } |
|
404 |
|
405 bool CheckDeclaration::visit(MemInitializerAST *ast) |
|
406 { |
|
407 (void) semantic()->check(ast->name, _scope); |
|
408 for (ExpressionListAST *it = ast->expression_list; it; it = it->next) { |
|
409 FullySpecifiedType ty = semantic()->check(it->value, _scope); |
|
410 } |
|
411 return false; |
|
412 } |
|
413 |
|
414 bool CheckDeclaration::visit(LinkageBodyAST *ast) |
|
415 { |
|
416 for (DeclarationListAST *decl = ast->declaration_list; decl; decl = decl->next) { |
|
417 semantic()->check(decl->value, _scope); |
|
418 } |
|
419 return false; |
|
420 } |
|
421 |
|
422 bool CheckDeclaration::visit(LinkageSpecificationAST *ast) |
|
423 { |
|
424 semantic()->check(ast->declaration, _scope); |
|
425 return false; |
|
426 } |
|
427 |
|
428 bool CheckDeclaration::visit(NamespaceAST *ast) |
|
429 { |
|
430 const Name *namespaceName = 0; |
|
431 if (const Identifier *id = identifier(ast->identifier_token)) |
|
432 namespaceName = control()->nameId(id); |
|
433 |
|
434 unsigned sourceLocation = ast->firstToken(); |
|
435 |
|
436 if (ast->identifier_token) |
|
437 sourceLocation = ast->identifier_token; |
|
438 |
|
439 Namespace *ns = control()->newNamespace(sourceLocation, namespaceName); |
|
440 ns->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
441 ns->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
442 ast->symbol = ns; |
|
443 _scope->enterSymbol(ns); |
|
444 semantic()->check(ast->linkage_body, ns->members()); // ### we'll do the merge later. |
|
445 |
|
446 return false; |
|
447 } |
|
448 |
|
449 bool CheckDeclaration::visit(NamespaceAliasDefinitionAST *) |
|
450 { |
|
451 return false; |
|
452 } |
|
453 |
|
454 bool CheckDeclaration::visit(ParameterDeclarationAST *ast) |
|
455 { |
|
456 unsigned sourceLocation = locationOfDeclaratorId(ast->declarator); |
|
457 if (! sourceLocation) { |
|
458 if (ast->declarator) |
|
459 sourceLocation = ast->declarator->firstToken(); |
|
460 else |
|
461 sourceLocation = ast->firstToken(); |
|
462 } |
|
463 |
|
464 const Name *argName = 0; |
|
465 FullySpecifiedType ty = semantic()->check(ast->type_specifier_list, _scope); |
|
466 FullySpecifiedType argTy = semantic()->check(ast->declarator, ty.qualifiedType(), |
|
467 _scope, &argName); |
|
468 FullySpecifiedType exprTy = semantic()->check(ast->expression, _scope); |
|
469 Argument *arg = control()->newArgument(sourceLocation, argName); |
|
470 ast->symbol = arg; |
|
471 if (ast->expression) { |
|
472 unsigned startOfExpression = ast->expression->firstToken(); |
|
473 unsigned endOfExpression = ast->expression->lastToken(); |
|
474 std::string buffer; |
|
475 for (unsigned index = startOfExpression; index != endOfExpression; ++index) { |
|
476 const Token &tk = tokenAt(index); |
|
477 if (tk.whitespace() || tk.newline()) |
|
478 buffer += ' '; |
|
479 buffer += tk.spell(); |
|
480 } |
|
481 const StringLiteral *initializer = control()->findOrInsertStringLiteral(buffer.c_str(), buffer.size()); |
|
482 arg->setInitializer(initializer); |
|
483 } |
|
484 arg->setType(argTy); |
|
485 _scope->enterSymbol(arg); |
|
486 return false; |
|
487 } |
|
488 |
|
489 bool CheckDeclaration::visit(TemplateDeclarationAST *ast) |
|
490 { |
|
491 Scope *scope = new Scope(_scope->owner()); |
|
492 |
|
493 for (DeclarationListAST *param = ast->template_parameter_list; param; param = param->next) { |
|
494 semantic()->check(param->value, scope); |
|
495 } |
|
496 |
|
497 semantic()->check(ast->declaration, _scope, |
|
498 new TemplateParameters(_templateParameters, scope)); |
|
499 |
|
500 return false; |
|
501 } |
|
502 |
|
503 bool CheckDeclaration::visit(TypenameTypeParameterAST *ast) |
|
504 { |
|
505 unsigned sourceLocation = ast->firstToken(); |
|
506 if (ast->name) |
|
507 sourceLocation = ast->name->firstToken(); |
|
508 |
|
509 const Name *name = semantic()->check(ast->name, _scope); |
|
510 TypenameArgument *arg = control()->newTypenameArgument(sourceLocation, name); |
|
511 FullySpecifiedType ty = semantic()->check(ast->type_id, _scope); |
|
512 arg->setType(ty); |
|
513 ast->symbol = arg; |
|
514 _scope->enterSymbol(arg); |
|
515 return false; |
|
516 } |
|
517 |
|
518 bool CheckDeclaration::visit(TemplateTypeParameterAST *ast) |
|
519 { |
|
520 unsigned sourceLocation = ast->firstToken(); |
|
521 if (ast->name) |
|
522 sourceLocation = ast->name->firstToken(); |
|
523 |
|
524 const Name *name = semantic()->check(ast->name, _scope); |
|
525 TypenameArgument *arg = control()->newTypenameArgument(sourceLocation, name); |
|
526 FullySpecifiedType ty = semantic()->check(ast->type_id, _scope); |
|
527 arg->setType(ty); |
|
528 ast->symbol = arg; |
|
529 _scope->enterSymbol(arg); |
|
530 return false; |
|
531 } |
|
532 |
|
533 bool CheckDeclaration::visit(UsingAST *ast) |
|
534 { |
|
535 const Name *name = semantic()->check(ast->name, _scope); |
|
536 |
|
537 unsigned sourceLocation = ast->firstToken(); |
|
538 if (ast->name) |
|
539 sourceLocation = ast->name->firstToken(); |
|
540 |
|
541 UsingDeclaration *u = control()->newUsingDeclaration(sourceLocation, name); |
|
542 ast->symbol = u; |
|
543 _scope->enterSymbol(u); |
|
544 return false; |
|
545 } |
|
546 |
|
547 bool CheckDeclaration::visit(UsingDirectiveAST *ast) |
|
548 { |
|
549 const Name *name = semantic()->check(ast->name, _scope); |
|
550 |
|
551 unsigned sourceLocation = ast->firstToken(); |
|
552 if (ast->name) |
|
553 sourceLocation = ast->name->firstToken(); |
|
554 |
|
555 UsingNamespaceDirective *u = control()->newUsingNamespaceDirective(sourceLocation, name); |
|
556 ast->symbol = u; |
|
557 _scope->enterSymbol(u); |
|
558 |
|
559 if (! (_scope->isBlockScope() || _scope->isNamespaceScope())) |
|
560 translationUnit()->error(ast->firstToken(), |
|
561 "using-directive not within namespace or block scope"); |
|
562 |
|
563 return false; |
|
564 } |
|
565 |
|
566 bool CheckDeclaration::visit(ObjCProtocolForwardDeclarationAST *ast) |
|
567 { |
|
568 const unsigned sourceLocation = ast->firstToken(); |
|
569 |
|
570 List<ObjCForwardProtocolDeclaration *> **symbolIter = &ast->symbols; |
|
571 for (ObjCIdentifierListAST *it = ast->identifier_list; it; it = it->next) { |
|
572 unsigned declarationLocation; |
|
573 if (it->value) |
|
574 declarationLocation = it->value->firstToken(); |
|
575 else |
|
576 declarationLocation = sourceLocation; |
|
577 |
|
578 const Name *protocolName = semantic()->check(it->value, _scope); |
|
579 ObjCForwardProtocolDeclaration *fwdProtocol = control()->newObjCForwardProtocolDeclaration(sourceLocation, protocolName); |
|
580 fwdProtocol->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
581 fwdProtocol->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
582 |
|
583 _scope->enterSymbol(fwdProtocol); |
|
584 |
|
585 *symbolIter = new (translationUnit()->memoryPool()) List<ObjCForwardProtocolDeclaration *>(); |
|
586 (*symbolIter)->value = fwdProtocol; |
|
587 symbolIter = &(*symbolIter)->next; |
|
588 } |
|
589 |
|
590 return false; |
|
591 } |
|
592 |
|
593 bool CheckDeclaration::visit(ObjCProtocolDeclarationAST *ast) |
|
594 { |
|
595 unsigned sourceLocation; |
|
596 if (ast->name) |
|
597 sourceLocation = ast->name->firstToken(); |
|
598 else |
|
599 sourceLocation = ast->firstToken(); |
|
600 |
|
601 const Name *protocolName = semantic()->check(ast->name, _scope); |
|
602 ObjCProtocol *protocol = control()->newObjCProtocol(sourceLocation, protocolName); |
|
603 protocol->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
604 protocol->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
605 |
|
606 if (ast->protocol_refs && ast->protocol_refs->identifier_list) { |
|
607 for (ObjCIdentifierListAST *iter = ast->protocol_refs->identifier_list; iter; iter = iter->next) { |
|
608 NameAST* name = iter->value; |
|
609 const Name *protocolName = semantic()->check(name, _scope); |
|
610 ObjCBaseProtocol *baseProtocol = control()->newObjCBaseProtocol(name->firstToken(), protocolName); |
|
611 protocol->addProtocol(baseProtocol); |
|
612 } |
|
613 } |
|
614 |
|
615 int previousObjCVisibility = semantic()->switchObjCVisibility(Function::Public); |
|
616 for (DeclarationListAST *it = ast->member_declaration_list; it; it = it->next) { |
|
617 semantic()->check(it->value, protocol->members()); |
|
618 } |
|
619 (void) semantic()->switchObjCVisibility(previousObjCVisibility); |
|
620 |
|
621 ast->symbol = protocol; |
|
622 _scope->enterSymbol(protocol); |
|
623 |
|
624 return false; |
|
625 } |
|
626 |
|
627 bool CheckDeclaration::visit(ObjCClassForwardDeclarationAST *ast) |
|
628 { |
|
629 const unsigned sourceLocation = ast->firstToken(); |
|
630 |
|
631 List<ObjCForwardClassDeclaration *> **symbolIter = &ast->symbols; |
|
632 for (ObjCIdentifierListAST *it = ast->identifier_list; it; it = it->next) { |
|
633 unsigned declarationLocation; |
|
634 if (it->value) |
|
635 declarationLocation = it->value->firstToken(); |
|
636 else |
|
637 declarationLocation = sourceLocation; |
|
638 |
|
639 const Name *className = semantic()->check(it->value, _scope); |
|
640 ObjCForwardClassDeclaration *fwdClass = control()->newObjCForwardClassDeclaration(sourceLocation, className); |
|
641 fwdClass->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
642 fwdClass->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
643 |
|
644 _scope->enterSymbol(fwdClass); |
|
645 |
|
646 *symbolIter = new (translationUnit()->memoryPool()) List<ObjCForwardClassDeclaration *>(); |
|
647 (*symbolIter)->value = fwdClass; |
|
648 symbolIter = &(*symbolIter)->next; |
|
649 } |
|
650 |
|
651 return false; |
|
652 } |
|
653 |
|
654 bool CheckDeclaration::visit(ObjCClassDeclarationAST *ast) |
|
655 { |
|
656 unsigned sourceLocation; |
|
657 if (ast->class_name) |
|
658 sourceLocation = ast->class_name->firstToken(); |
|
659 else |
|
660 sourceLocation = ast->firstToken(); |
|
661 |
|
662 const Name *className = semantic()->check(ast->class_name, _scope); |
|
663 ObjCClass *klass = control()->newObjCClass(sourceLocation, className); |
|
664 klass->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
665 klass->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
666 ast->symbol = klass; |
|
667 |
|
668 klass->setInterface(ast->interface_token != 0); |
|
669 |
|
670 if (ast->category_name) { |
|
671 const Name *categoryName = semantic()->check(ast->category_name, _scope); |
|
672 klass->setCategoryName(categoryName); |
|
673 } |
|
674 |
|
675 if (ast->superclass) { |
|
676 const Name *superClassName = semantic()->check(ast->superclass, _scope); |
|
677 ObjCBaseClass *superKlass = control()->newObjCBaseClass(ast->superclass->firstToken(), superClassName); |
|
678 klass->setBaseClass(superKlass); |
|
679 } |
|
680 |
|
681 if (ast->protocol_refs && ast->protocol_refs->identifier_list) { |
|
682 for (ObjCIdentifierListAST *iter = ast->protocol_refs->identifier_list; iter; iter = iter->next) { |
|
683 NameAST* name = iter->value; |
|
684 const Name *protocolName = semantic()->check(name, _scope); |
|
685 ObjCBaseProtocol *baseProtocol = control()->newObjCBaseProtocol(name->firstToken(), protocolName); |
|
686 klass->addProtocol(baseProtocol); |
|
687 } |
|
688 } |
|
689 |
|
690 _scope->enterSymbol(klass); |
|
691 |
|
692 int previousObjCVisibility = semantic()->switchObjCVisibility(Function::Protected); |
|
693 |
|
694 if (ast->inst_vars_decl) { |
|
695 for (DeclarationListAST *it = ast->inst_vars_decl->instance_variable_list; it; it = it->next) { |
|
696 semantic()->check(it->value, klass->members()); |
|
697 } |
|
698 } |
|
699 |
|
700 (void) semantic()->switchObjCVisibility(Function::Public); |
|
701 |
|
702 for (DeclarationListAST *it = ast->member_declaration_list; it; it = it->next) { |
|
703 semantic()->check(it->value, klass->members()); |
|
704 } |
|
705 |
|
706 (void) semantic()->switchObjCVisibility(previousObjCVisibility); |
|
707 |
|
708 return false; |
|
709 } |
|
710 |
|
711 bool CheckDeclaration::visit(ObjCMethodDeclarationAST *ast) |
|
712 { |
|
713 if (!ast->method_prototype) |
|
714 return false; |
|
715 |
|
716 FullySpecifiedType ty = semantic()->check(ast->method_prototype, _scope); |
|
717 ObjCMethod *methodTy = ty.type()->asObjCMethodType(); |
|
718 if (!methodTy) |
|
719 return false; |
|
720 |
|
721 Symbol *symbol; |
|
722 if (ast->function_body) { |
|
723 if (!semantic()->skipFunctionBodies()) { |
|
724 semantic()->check(ast->function_body, methodTy->members()); |
|
725 } |
|
726 |
|
727 symbol = methodTy; |
|
728 } else { |
|
729 Declaration *decl = control()->newDeclaration(ast->firstToken(), methodTy->name()); |
|
730 decl->setType(methodTy); |
|
731 symbol = decl; |
|
732 symbol->setStorage(methodTy->storage()); |
|
733 } |
|
734 |
|
735 symbol->setStartOffset(tokenAt(ast->firstToken()).offset); |
|
736 symbol->setEndOffset(tokenAt(ast->lastToken()).offset); |
|
737 symbol->setVisibility(semantic()->currentVisibility()); |
|
738 |
|
739 _scope->enterSymbol(symbol); |
|
740 |
|
741 return false; |
|
742 } |
|
743 |
|
744 bool CheckDeclaration::visit(ObjCVisibilityDeclarationAST *ast) |
|
745 { |
|
746 int accessSpecifier = tokenKind(ast->visibility_token); |
|
747 int visibility = semantic()->visibilityForObjCAccessSpecifier(accessSpecifier); |
|
748 semantic()->switchObjCVisibility(visibility); |
|
749 return false; |
|
750 } |
|
751 |
|
752 bool CheckDeclaration::checkPropertyAttribute(ObjCPropertyAttributeAST *attrAst, |
|
753 int &flags, |
|
754 int attr) |
|
755 { |
|
756 if (flags & attr) { |
|
757 translationUnit()->warning(attrAst->attribute_identifier_token, |
|
758 "duplicate property attribute \"%s\"", |
|
759 spell(attrAst->attribute_identifier_token)); |
|
760 return false; |
|
761 } else { |
|
762 flags |= attr; |
|
763 return true; |
|
764 } |
|
765 } |
|
766 |
|
767 bool CheckDeclaration::visit(ObjCPropertyDeclarationAST *ast) |
|
768 { |
|
769 semantic()->check(ast->simple_declaration, _scope); |
|
770 SimpleDeclarationAST *simpleDecl = ast->simple_declaration->asSimpleDeclaration(); |
|
771 |
|
772 if (!simpleDecl) { |
|
773 translationUnit()->warning(ast->simple_declaration->firstToken(), |
|
774 "invalid type for property declaration"); |
|
775 return false; |
|
776 } |
|
777 |
|
778 int propAttrs = ObjCPropertyDeclaration::None; |
|
779 const Name *getterName = 0, *setterName = 0; |
|
780 |
|
781 for (ObjCPropertyAttributeListAST *iter= ast->property_attribute_list; iter; iter = iter->next) { |
|
782 ObjCPropertyAttributeAST *attrAst = iter->value; |
|
783 if (!attrAst) |
|
784 continue; |
|
785 |
|
786 const Identifier *attrId = identifier(attrAst->attribute_identifier_token); |
|
787 if (attrId == control()->objcGetterId()) { |
|
788 if (checkPropertyAttribute(attrAst, propAttrs, ObjCPropertyDeclaration::Getter)) { |
|
789 getterName = semantic()->check(attrAst->method_selector, _scope); |
|
790 } |
|
791 } else if (attrId == control()->objcSetterId()) { |
|
792 if (checkPropertyAttribute(attrAst, propAttrs, ObjCPropertyDeclaration::Setter)) { |
|
793 setterName = semantic()->check(attrAst->method_selector, _scope); |
|
794 } |
|
795 } else if (attrId == control()->objcReadwriteId()) { |
|
796 checkPropertyAttribute(attrAst, propAttrs, ObjCPropertyDeclaration::ReadWrite); |
|
797 } else if (attrId == control()->objcReadonlyId()) { |
|
798 checkPropertyAttribute(attrAst, propAttrs, ObjCPropertyDeclaration::ReadOnly); |
|
799 } else if (attrId == control()->objcAssignId()) { |
|
800 checkPropertyAttribute(attrAst, propAttrs, ObjCPropertyDeclaration::Assign); |
|
801 } else if (attrId == control()->objcRetainId()) { |
|
802 checkPropertyAttribute(attrAst, propAttrs, ObjCPropertyDeclaration::Retain); |
|
803 } else if (attrId == control()->objcCopyId()) { |
|
804 checkPropertyAttribute(attrAst, propAttrs, ObjCPropertyDeclaration::Copy); |
|
805 } else if (attrId == control()->objcNonatomicId()) { |
|
806 checkPropertyAttribute(attrAst, propAttrs, ObjCPropertyDeclaration::NonAtomic); |
|
807 } |
|
808 } |
|
809 |
|
810 if (propAttrs & ObjCPropertyDeclaration::ReadOnly && |
|
811 propAttrs & ObjCPropertyDeclaration::ReadWrite) |
|
812 // Should this be an error instead of only a warning? |
|
813 translationUnit()->warning(ast->property_token, |
|
814 "property can have at most one attribute \"readonly\" or \"readwrite\" specified"); |
|
815 int setterSemAttrs = propAttrs & ObjCPropertyDeclaration::SetterSemanticsMask; |
|
816 if (setterSemAttrs |
|
817 && setterSemAttrs != ObjCPropertyDeclaration::Assign |
|
818 && setterSemAttrs != ObjCPropertyDeclaration::Retain |
|
819 && setterSemAttrs != ObjCPropertyDeclaration::Copy) { |
|
820 // Should this be an error instead of only a warning? |
|
821 translationUnit()->warning(ast->property_token, |
|
822 "property can have at most one attribute \"assign\", \"retain\", or \"copy\" specified"); |
|
823 } |
|
824 |
|
825 List<ObjCPropertyDeclaration *> **lastSymbols = &ast->symbols; |
|
826 for (List<Declaration*> *iter = simpleDecl->symbols; iter; iter = iter->next) { |
|
827 ObjCPropertyDeclaration *propDecl = control()->newObjCPropertyDeclaration(ast->firstToken(), |
|
828 iter->value->name()); |
|
829 propDecl->setType(iter->value->type()); |
|
830 propDecl->setAttributes(propAttrs); |
|
831 propDecl->setGetterName(getterName); |
|
832 propDecl->setSetterName(setterName); |
|
833 _scope->enterSymbol(propDecl); |
|
834 |
|
835 *lastSymbols = new (translationUnit()->memoryPool()) List<ObjCPropertyDeclaration *>(); |
|
836 (*lastSymbols)->value = propDecl; |
|
837 lastSymbols = &(*lastSymbols)->next; |
|
838 } |
|
839 |
|
840 return false; |
|
841 } |