cppchecksymbols.cpp 31.9 KB
Newer Older
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
8 9 10 11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
30 31 32
**
**************************************************************************/

Roberto Raggi's avatar
Roberto Raggi committed
33
#include "cppchecksymbols.h"
34 35
#include "cpplocalsymbols.h"

36
#include <cplusplus/Overview.h>
37 38 39 40 41 42 43

#include <Names.h>
#include <Literals.h>
#include <Symbols.h>
#include <TranslationUnit.h>
#include <Scope.h>
#include <AST.h>
Roberto Raggi's avatar
Roberto Raggi committed
44
#include <SymbolVisitor.h>
45

46 47
#include <utils/qtcassert.h>

48 49 50
#include <QCoreApplication>
#include <QThreadPool>
#include <QDebug>
51

52
#include <utils/runextensions.h>
53

54
using namespace CPlusPlus;
55
using namespace CppTools;
56

Roberto Raggi's avatar
Roberto Raggi committed
57 58
namespace {

59 60 61 62 63 64
class FriendlyThread: public QThread
{
public:
    using QThread::msleep;
};

Roberto Raggi's avatar
Roberto Raggi committed
65
class CollectSymbols: protected SymbolVisitor
Roberto Raggi's avatar
Roberto Raggi committed
66 67 68 69
{
    Document::Ptr _doc;
    Snapshot _snapshot;
    QSet<QByteArray> _types;
70
    QSet<QByteArray> _members;
Roberto Raggi's avatar
Roberto Raggi committed
71
    QSet<QByteArray> _virtualMethods;
72
    QSet<QByteArray> _statics;
Roberto Raggi's avatar
Roberto Raggi committed
73 74 75
    bool _mainDocument;

public:
Roberto Raggi's avatar
Roberto Raggi committed
76
    CollectSymbols(Document::Ptr doc, const Snapshot &snapshot)
Roberto Raggi's avatar
Roberto Raggi committed
77 78 79 80 81 82 83 84 85 86 87
        : _doc(doc), _snapshot(snapshot), _mainDocument(false)
    {
        QSet<Namespace *> processed;
        process(doc, &processed);
    }

    const QSet<QByteArray> &types() const
    {
        return _types;
    }

88 89 90 91 92
    const QSet<QByteArray> &members() const
    {
        return _members;
    }

Roberto Raggi's avatar
Roberto Raggi committed
93 94 95 96 97
    const QSet<QByteArray> &virtualMethods() const
    {
        return _virtualMethods;
    }

98 99 100 101 102
    const QSet<QByteArray> &statics() const
    {
        return _statics;
    }

Roberto Raggi's avatar
Roberto Raggi committed
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
protected:
    void process(Document::Ptr doc, QSet<Namespace *> *processed)
    {
        if (! doc)
            return;
        else if (! processed->contains(doc->globalNamespace())) {
            processed->insert(doc->globalNamespace());

            foreach (const Document::Include &i, doc->includes())
                process(_snapshot.document(i.fileName()), processed);

            _mainDocument = (doc == _doc); // ### improve
            accept(doc->globalNamespace());
        }
    }

    void addType(const Identifier *id)
    {
        if (id)
            _types.insert(QByteArray::fromRawData(id->chars(), id->size()));
    }

    void addType(const Name *name)
    {
        if (! name) {
            return;

        } else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
131 132
            addType(q->base());
            addType(q->name());
Roberto Raggi's avatar
Roberto Raggi committed
133 134 135 136 137 138 139

        } else if (name->isNameId() || name->isTemplateNameId()) {
            addType(name->identifier());

        }
    }

140 141 142 143 144 145 146 147 148 149 150 151
    void addMember(const Name *name)
    {
        if (! name) {
            return;

        } else if (name->isNameId()) {
            const Identifier *id = name->identifier();
            _members.insert(QByteArray::fromRawData(id->chars(), id->size()));

        }
    }

Roberto Raggi's avatar
Roberto Raggi committed
152 153 154 155 156 157 158 159 160 161 162 163
    void addVirtualMethod(const Name *name)
    {
        if (! name) {
            return;

        } else if (name->isNameId()) {
            const Identifier *id = name->identifier();
            _virtualMethods.insert(QByteArray::fromRawData(id->chars(), id->size()));

        }
    }

164 165 166 167 168 169 170 171 172 173 174 175
    void addStatic(const Name *name)
    {
        if (! name) {
            return;

        } else if (name->isNameId() || name->isTemplateNameId()) {
            const Identifier *id = name->identifier();
            _statics.insert(QByteArray::fromRawData(id->chars(), id->size()));

        }
    }

Roberto Raggi's avatar
Roberto Raggi committed
176 177 178 179 180 181 182 183
    // nothing to do
    virtual bool visit(UsingNamespaceDirective *) { return true; }
    virtual bool visit(UsingDeclaration *) { return true; }
    virtual bool visit(Argument *) { return true; }
    virtual bool visit(BaseClass *) { return true; }

    virtual bool visit(Function *symbol)
    {
Roberto Raggi's avatar
Roberto Raggi committed
184 185 186
        if (symbol->isVirtual())
            addVirtualMethod(symbol->name());

Roberto Raggi's avatar
Roberto Raggi committed
187 188 189
        return true;
    }

Roberto Raggi's avatar
Roberto Raggi committed
190
    virtual bool visit(Block *)
Roberto Raggi's avatar
Roberto Raggi committed
191 192 193 194 195 196 197 198 199 200 201 202
    {
        return true;
    }

    virtual bool visit(NamespaceAlias *symbol)
    {
        addType(symbol->name());
        return true;
    }

    virtual bool visit(Declaration *symbol)
    {
Roberto Raggi's avatar
Roberto Raggi committed
203
        if (symbol->enclosingEnum() != 0)
204 205
            addStatic(symbol->name());

Roberto Raggi's avatar
Roberto Raggi committed
206 207 208 209 210
        if (Function *funTy = symbol->type()->asFunctionType()) {
            if (funTy->isVirtual())
                addVirtualMethod(symbol->name());
        }

Roberto Raggi's avatar
Roberto Raggi committed
211 212
        if (symbol->isTypedef())
            addType(symbol->name());
213
        else if (! symbol->type()->isFunctionType() && symbol->enclosingScope()->isClass())
214
            addMember(symbol->name());
Roberto Raggi's avatar
Roberto Raggi committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236

        return true;
    }

    virtual bool visit(TypenameArgument *symbol)
    {
        addType(symbol->name());
        return true;
    }

    virtual bool visit(Enum *symbol)
    {
        addType(symbol->name());
        return true;
    }

    virtual bool visit(Namespace *symbol)
    {
        addType(symbol->name());
        return true;
    }

Roberto Raggi's avatar
Roberto Raggi committed
237 238 239 240 241
    virtual bool visit(Template *)
    {
        return true;
    }

Roberto Raggi's avatar
Roberto Raggi committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
    virtual bool visit(Class *symbol)
    {
        addType(symbol->name());
        return true;
    }

    virtual bool visit(ForwardClassDeclaration *symbol)
    {
        addType(symbol->name());
        return true;
    }

    // Objective-C
    virtual bool visit(ObjCBaseClass *) { return true; }
    virtual bool visit(ObjCBaseProtocol *) { return true; }
    virtual bool visit(ObjCPropertyDeclaration *) { return true; }
Roberto Raggi's avatar
Roberto Raggi committed
258
    virtual bool visit(ObjCMethod *) { return true; }
Roberto Raggi's avatar
Roberto Raggi committed
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

    virtual bool visit(ObjCClass *symbol)
    {
        addType(symbol->name());
        return true;
    }

    virtual bool visit(ObjCForwardClassDeclaration *symbol)
    {
        addType(symbol->name());
        return true;
    }

    virtual bool visit(ObjCProtocol *symbol)
    {
        addType(symbol->name());
        return true;
    }

    virtual bool visit(ObjCForwardProtocolDeclaration *symbol)
    {
        addType(symbol->name());
        return true;
    }
};

} // end of anonymous namespace

Roberto Raggi's avatar
Roberto Raggi committed
287
CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, const LookupContext &context)
288
{
289
    QTC_ASSERT(doc, return Future());
290

Roberto Raggi's avatar
Roberto Raggi committed
291
    return (new CheckSymbols(doc, context))->start();
292 293
}

Roberto Raggi's avatar
Roberto Raggi committed
294
CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context)
295
    : ASTVisitor(doc->translationUnit()), _doc(doc), _context(context)
296
    , _lineOfLastUsage(0)
297
{
Roberto Raggi's avatar
Roberto Raggi committed
298
    CollectSymbols collectTypes(doc, context.snapshot());
Roberto Raggi's avatar
Roberto Raggi committed
299 300

    _fileName = doc->fileName();
Roberto Raggi's avatar
Roberto Raggi committed
301
    _potentialTypes = collectTypes.types();
302
    _potentialMembers = collectTypes.members();
Roberto Raggi's avatar
Roberto Raggi committed
303
    _potentialVirtualMethods = collectTypes.virtualMethods();
304
    _potentialStatics = collectTypes.statics();
Roberto Raggi's avatar
Roberto Raggi committed
305 306

    typeOfExpression.init(_doc, _context.snapshot(), _context.bindings());
307 308
}

Roberto Raggi's avatar
Roberto Raggi committed
309
CheckSymbols::~CheckSymbols()
310
{ }
311

Roberto Raggi's avatar
Roberto Raggi committed
312
void CheckSymbols::run()
313
{
314
    _diagnosticMessages.clear();
315

316 317 318 319 320
    if (! isCanceled()) {
        if (_doc->translationUnit()) {
            accept(_doc->translationUnit()->ast());
            flush();
        }
Roberto Raggi's avatar
Roberto Raggi committed
321
    }
322 323

    reportFinished();
324 325
}

Roberto Raggi's avatar
Roberto Raggi committed
326
bool CheckSymbols::warning(unsigned line, unsigned column, const QString &text, unsigned length)
327
{
328 329
    Document::DiagnosticMessage m(Document::DiagnosticMessage::Warning, _fileName, line, column, text, length);
    _diagnosticMessages.append(m);
330 331 332
    return false;
}

Roberto Raggi's avatar
Roberto Raggi committed
333
bool CheckSymbols::warning(AST *ast, const QString &text)
334
{
335 336
    const Token &firstToken = tokenAt(ast->firstToken());
    const Token &lastToken = tokenAt(ast->lastToken() - 1);
337

338 339 340
    const unsigned length = lastToken.end() - firstToken.begin();
    unsigned line = 1, column = 1;
    getTokenStartPosition(ast->firstToken(), &line, &column);
341

342 343
    warning(line, column, text, length);
    return false;
344 345
}

346
FunctionDefinitionAST *CheckSymbols::enclosingFunctionDefinition(bool skipTopOfStack) const
Roberto Raggi's avatar
Roberto Raggi committed
347
{
348 349 350 351
    int index = _astStack.size() - 1;
    if (skipTopOfStack && !_astStack.isEmpty())
        --index;
    for (; index != -1; --index) {
Roberto Raggi's avatar
Roberto Raggi committed
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
        AST *ast = _astStack.at(index);

        if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition())
            return funDef;
    }

    return 0;
}

TemplateDeclarationAST *CheckSymbols::enclosingTemplateDeclaration() const
{
    for (int index = _astStack.size() - 1; index != -1; --index) {
        AST *ast = _astStack.at(index);

        if (TemplateDeclarationAST *funDef = ast->asTemplateDeclaration())
            return funDef;
    }

    return 0;
}

Scope *CheckSymbols::enclosingScope() const
{
    for (int index = _astStack.size() - 1; index != -1; --index) {
        AST *ast = _astStack.at(index);

        if (NamespaceAST *ns = ast->asNamespace()) {
            if (ns->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
380
                return ns->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
381 382 383

        } else if (ClassSpecifierAST *classSpec = ast->asClassSpecifier()) {
            if (classSpec->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
384
                return classSpec->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
385 386 387

        } else if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition()) {
            if (funDef->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
388
                return funDef->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
389 390 391

        } else if (CompoundStatementAST *blockStmt = ast->asCompoundStatement()) {
            if (blockStmt->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
392
                return blockStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
393 394 395

        } else if (IfStatementAST *ifStmt = ast->asIfStatement()) {
            if (ifStmt->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
396
                return ifStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
397 398 399

        } else if (WhileStatementAST *whileStmt = ast->asWhileStatement()) {
            if (whileStmt->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
400
                return whileStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
401 402 403

        } else if (ForStatementAST *forStmt = ast->asForStatement()) {
            if (forStmt->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
404
                return forStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
405 406 407

        } else if (ForeachStatementAST *foreachStmt = ast->asForeachStatement()) {
            if (foreachStmt->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
408
                return foreachStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
409

410 411 412 413
        } else if (RangeBasedForStatementAST *rangeBasedForStmt = ast->asRangeBasedForStatement()) {
            if (rangeBasedForStmt->symbol)
                return rangeBasedForStmt->symbol;

414 415
        } else if (SwitchStatementAST *switchStmt = ast->asSwitchStatement()) {
            if (switchStmt->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
416
                return switchStmt->symbol;
417 418 419

        } else if (CatchClauseAST *catchClause = ast->asCatchClause()) {
            if (catchClause->symbol)
Roberto Raggi's avatar
Roberto Raggi committed
420
                return catchClause->symbol;
421

Roberto Raggi's avatar
Roberto Raggi committed
422 423 424
        }
    }

Roberto Raggi's avatar
Roberto Raggi committed
425
    return _doc->globalNamespace();
Roberto Raggi's avatar
Roberto Raggi committed
426 427 428
}

bool CheckSymbols::preVisit(AST *ast)
429
{
Roberto Raggi's avatar
Roberto Raggi committed
430 431
    _astStack.append(ast);

432
    if (isCanceled())
433 434 435 436 437
        return false;

    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
438 439 440 441 442
void CheckSymbols::postVisit(AST *)
{
    _astStack.takeLast();
}

Roberto Raggi's avatar
Roberto Raggi committed
443
bool CheckSymbols::visit(NamespaceAST *ast)
444
{
Roberto Raggi's avatar
Roberto Raggi committed
445 446 447 448 449
    if (ast->identifier_token) {
        const Token &tok = tokenAt(ast->identifier_token);
        if (! tok.generated()) {
            unsigned line, column;
            getTokenStartPosition(ast->identifier_token, &line, &column);
450
            Use use(line, column, tok.length(), SemanticInfo::TypeUse);
Roberto Raggi's avatar
Roberto Raggi committed
451
            addUse(use);
Roberto Raggi's avatar
Roberto Raggi committed
452 453 454 455
        }
    }

    return true;
456 457
}

Roberto Raggi's avatar
Roberto Raggi committed
458
bool CheckSymbols::visit(UsingDirectiveAST *)
459 460 461 462
{
    return true;
}

463 464
bool CheckSymbols::visit(EnumeratorAST *ast)
{
465
    addUse(ast->identifier_token, SemanticInfo::StaticUse);
466 467 468
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
469 470 471 472 473 474 475 476
bool CheckSymbols::visit(SimpleDeclarationAST *ast)
{
    if (ast->declarator_list && !ast->declarator_list->next) {
        if (ast->symbols && ! ast->symbols->next && !ast->symbols->value->isGenerated()) {
            Symbol *decl = ast->symbols->value;
            if (NameAST *declId = declaratorId(ast->declarator_list->value)) {
                if (Function *funTy = decl->type()->asFunctionType()) {
                    if (funTy->isVirtual()) {
477
                        addUse(declId, SemanticInfo::VirtualMethodUse);
Roberto Raggi's avatar
Roberto Raggi committed
478
                    } else if (maybeVirtualMethod(decl->name())) {
479
                        addVirtualMethod(_context.lookup(decl->name(), decl->enclosingScope()), declId, funTy->argumentCount());
Roberto Raggi's avatar
Roberto Raggi committed
480 481 482 483 484 485
                    }
                }
            }
        }
    }

Roberto Raggi's avatar
Roberto Raggi committed
486 487
    return true;
}
488

Roberto Raggi's avatar
Roberto Raggi committed
489
bool CheckSymbols::visit(NamedTypeSpecifierAST *)
Roberto Raggi's avatar
Roberto Raggi committed
490
{
Roberto Raggi's avatar
Roberto Raggi committed
491
    return true;
492
}
493

494 495 496 497
bool CheckSymbols::visit(ElaboratedTypeSpecifierAST *ast)
{
    accept(ast->attribute_list);
    accept(ast->name);
498
    addUse(ast->name, SemanticInfo::TypeUse);
499 500 501
    return false;
}

502 503 504
bool CheckSymbols::visit(MemberAccessAST *ast)
{
    accept(ast->base_expression);
Roberto Raggi's avatar
Roberto Raggi committed
505 506 507 508 509 510 511 512 513
    if (! ast->member_name)
        return false;

    if (const Name *name = ast->member_name->name) {
        if (const Identifier *ident = name->identifier()) {
            const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
            if (_potentialMembers.contains(id)) {
                const Token start = tokenAt(ast->firstToken());
                const Token end = tokenAt(ast->lastToken() - 1);
514
                const QByteArray expression = _doc->utf8Source().mid(start.begin(), end.end() - start.begin());
Roberto Raggi's avatar
Roberto Raggi committed
515

516
                const QList<LookupItem> candidates =
517
                    typeOfExpression(expression, enclosingScope(), TypeOfExpression::Preprocess);
Roberto Raggi's avatar
Roberto Raggi committed
518
                addClassMember(candidates, ast->member_name);
Roberto Raggi's avatar
Roberto Raggi committed
519 520 521 522
            }
        }
    }

523 524 525
    return false;
}

Roberto Raggi's avatar
Roberto Raggi committed
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
bool CheckSymbols::visit(CallAST *ast)
{
    if (ast->base_expression) {
        accept(ast->base_expression);

        unsigned argumentCount = 0;

        for (ExpressionListAST *it = ast->expression_list; it; it = it->next)
            ++argumentCount;

        if (MemberAccessAST *access = ast->base_expression->asMemberAccess()) {
            if (access->member_name && access->member_name->name) {
                if (maybeVirtualMethod(access->member_name->name)) {
                    const QByteArray expression = textOf(access);

541
                    const QList<LookupItem> candidates =
542 543
                        typeOfExpression(expression, enclosingScope(),
                                         TypeOfExpression::Preprocess);
544 545 546 547 548

                    NameAST *memberName = access->member_name;
                    if (QualifiedNameAST *q = memberName->asQualifiedName())
                        memberName = q->unqualified_name;

Roberto Raggi's avatar
Roberto Raggi committed
549
                    addVirtualMethod(candidates, memberName, argumentCount);
Roberto Raggi's avatar
Roberto Raggi committed
550 551 552 553 554
                }
            }
        } else if (IdExpressionAST *idExpr = ast->base_expression->asIdExpression()) {
            if (const Name *name = idExpr->name->name) {
                if (maybeVirtualMethod(name)) {
555 556 557 558
                    NameAST *exprName = idExpr->name;
                    if (QualifiedNameAST *q = exprName->asQualifiedName())
                        exprName = q->unqualified_name;

559
                    const QList<LookupItem> candidates =
560
                        typeOfExpression(textOf(idExpr), enclosingScope(),
561
                                         TypeOfExpression::Preprocess);
Roberto Raggi's avatar
Roberto Raggi committed
562
                    addVirtualMethod(candidates, exprName, argumentCount);
Roberto Raggi's avatar
Roberto Raggi committed
563 564 565 566 567 568 569 570 571 572 573 574 575 576
                }
            }
        }

        accept(ast->expression_list);
    }

    return false;
}

QByteArray CheckSymbols::textOf(AST *ast) const
{
    const Token start = tokenAt(ast->firstToken());
    const Token end = tokenAt(ast->lastToken() - 1);
577
    const QByteArray text = _doc->utf8Source().mid(start.begin(), end.end() - start.begin());
Roberto Raggi's avatar
Roberto Raggi committed
578 579 580
    return text;
}

Roberto Raggi's avatar
Roberto Raggi committed
581
void CheckSymbols::checkNamespace(NameAST *name)
582
{
583 584
    if (! name)
        return;
585

586 587
    unsigned line, column;
    getTokenStartPosition(name->firstToken(), &line, &column);
588

Roberto Raggi's avatar
Roberto Raggi committed
589
    if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope())) {
590 591 592
        foreach (Symbol *s, b->symbols()) {
            if (s->isNamespace())
                return;
593 594 595
        }
    }

596 597
    const unsigned length = tokenAt(name->lastToken() - 1).end() - tokenAt(name->firstToken()).begin();
    warning(line, column, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a namespace-name"), length);
598
}
Roberto Raggi's avatar
Roberto Raggi committed
599

Roberto Raggi's avatar
Roberto Raggi committed
600 601 602 603 604 605 606
bool CheckSymbols::hasVirtualDestructor(Class *klass) const
{
    if (! klass)
        return false;
    const Identifier *id = klass->identifier();
    if (! id)
        return false;
Roberto Raggi's avatar
Roberto Raggi committed
607
    for (Symbol *s = klass->find(id); s; s = s->next()) {
Roberto Raggi's avatar
Roberto Raggi committed
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
        if (! s->name())
            continue;
        else if (s->name()->isDestructorNameId()) {
            if (Function *funTy = s->type()->asFunctionType()) {
                if (funTy->isVirtual() && id->isEqualTo(s->identifier()))
                    return true;
            }
        }
    }
    return false;
}

bool CheckSymbols::hasVirtualDestructor(ClassOrNamespace *binding) const
{
    QSet<ClassOrNamespace *> processed;
    QList<ClassOrNamespace *> todo;
    todo.append(binding);

    while (! todo.isEmpty()) {
        ClassOrNamespace *b = todo.takeFirst();
        if (b && ! processed.contains(b)) {
            processed.insert(b);
            foreach (Symbol *s, b->symbols()) {
                if (Class *k = s->asClass()) {
                    if (hasVirtualDestructor(k))
                        return true;
                }
            }

            todo += b->usings();
        }
    }

    return false;
}

Roberto Raggi's avatar
Roberto Raggi committed
644
void CheckSymbols::checkName(NameAST *ast, Scope *scope)
Roberto Raggi's avatar
Roberto Raggi committed
645
{
646
    if (ast && ast->name) {
Roberto Raggi's avatar
Roberto Raggi committed
647
        if (! scope)
Roberto Raggi's avatar
Roberto Raggi committed
648 649
            scope = enclosingScope();

650
        if (ast->asDestructorName() != 0) {
Roberto Raggi's avatar
Roberto Raggi committed
651
            Class *klass = scope->asClass();
Roberto Raggi's avatar
Roberto Raggi committed
652
            if (hasVirtualDestructor(_context.lookupType(klass)))
653
                addUse(ast, SemanticInfo::VirtualMethodUse);
654
        } else if (maybeType(ast->name) || maybeStatic(ast->name)) {
Roberto Raggi's avatar
Roberto Raggi committed
655
            const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
656
            addTypeOrStatic(candidates, ast);
Roberto Raggi's avatar
Roberto Raggi committed
657 658 659
        } else if (maybeMember(ast->name)) {
            const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
            addClassMember(candidates, ast);
Roberto Raggi's avatar
Roberto Raggi committed
660 661
        }
    }
Roberto Raggi's avatar
Roberto Raggi committed
662
}
Roberto Raggi's avatar
Roberto Raggi committed
663

Roberto Raggi's avatar
Roberto Raggi committed
664
bool CheckSymbols::visit(SimpleNameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
665 666
{
    checkName(ast);
Roberto Raggi's avatar
Roberto Raggi committed
667 668 669
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
670
bool CheckSymbols::visit(TemplateIdAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
671
{
Roberto Raggi's avatar
Roberto Raggi committed
672
    checkName(ast);
Roberto Raggi's avatar
Roberto Raggi committed
673 674 675
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
676
bool CheckSymbols::visit(DestructorNameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
677
{
678
    checkName(ast);
Roberto Raggi's avatar
Roberto Raggi committed
679 680 681
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
682
bool CheckSymbols::visit(QualifiedNameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
683 684
{
    if (ast->name) {
685
        ClassOrNamespace *binding = 0;
Roberto Raggi's avatar
Roberto Raggi committed
686 687
        if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) {
            NestedNameSpecifierAST *nested_name_specifier = it->value;
688
            if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { // ### remove shadowing
Roberto Raggi's avatar
Roberto Raggi committed
689

690 691 692
                if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
                    accept(template_id->template_argument_list);

693
                const Name *name = class_or_namespace_name->name;
694 695
                binding = _context.lookupType(name, enclosingScope());
                addType(binding, class_or_namespace_name);
Roberto Raggi's avatar
Roberto Raggi committed
696

697
                for (it = it->next; it; it = it->next) {
698
                    NestedNameSpecifierAST *nested_name_specifier = it->value;
Roberto Raggi's avatar
Roberto Raggi committed
699

700
                    if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) {
701 702
                        if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) {
                            if (template_id->template_token) {
703
                                addUse(template_id, SemanticInfo::TypeUse);
704 705
                                binding = 0; // there's no way we can find a binding.
                            }
706

707 708 709 710 711 712 713 714 715
                            accept(template_id->template_argument_list);
                            if (! binding)
                                continue;
                        }

                        if (binding) {
                            binding = binding->findType(class_or_namespace_name->name);
                            addType(binding, class_or_namespace_name);
                        }
716
                    }
Roberto Raggi's avatar
Roberto Raggi committed
717 718 719 720
                }
            }
        }

721
        if (binding && ast->unqualified_name) {
Roberto Raggi's avatar
Roberto Raggi committed
722
            if (ast->unqualified_name->asDestructorName() != 0) {
723
                if (hasVirtualDestructor(binding))
724
                    addUse(ast->unqualified_name, SemanticInfo::VirtualMethodUse);
Roberto Raggi's avatar
Roberto Raggi committed
725
            } else {
726
                addTypeOrStatic(binding->find(ast->unqualified_name->name), ast->unqualified_name);
Roberto Raggi's avatar
Roberto Raggi committed
727
            }
728 729 730

            if (TemplateIdAST *template_id = ast->unqualified_name->asTemplateId())
                accept(template_id->template_argument_list);
Roberto Raggi's avatar
Roberto Raggi committed
731
        }
Roberto Raggi's avatar
Roberto Raggi committed
732 733 734 735 736
    }

    return false;
}

Roberto Raggi's avatar
Roberto Raggi committed
737
bool CheckSymbols::visit(TypenameTypeParameterAST *ast)
738
{
739
    addUse(ast->name, SemanticInfo::TypeUse);
Roberto Raggi's avatar
Roberto Raggi committed
740 741
    accept(ast->type_id);
    return false;
742 743
}

Roberto Raggi's avatar
Roberto Raggi committed
744
bool CheckSymbols::visit(TemplateTypeParameterAST *ast)
745
{
Roberto Raggi's avatar
Roberto Raggi committed
746
    accept(ast->template_parameter_list);
747
    addUse(ast->name, SemanticInfo::TypeUse);
Roberto Raggi's avatar
Roberto Raggi committed
748 749
    accept(ast->type_id);
    return false;
750 751
}

Roberto Raggi's avatar
Roberto Raggi committed
752 753
bool CheckSymbols::visit(MemInitializerAST *ast)
{
Roberto Raggi's avatar
Roberto Raggi committed
754 755 756 757 758
    if (FunctionDefinitionAST *enclosingFunction = enclosingFunctionDefinition()) {
        if (ast->name && enclosingFunction->symbol) {
            if (ClassOrNamespace *binding = _context.lookupType(enclosingFunction->symbol)) {
                foreach (Symbol *s, binding->symbols()) {
                    if (Class *klass = s->asClass()){
Roberto Raggi's avatar
Roberto Raggi committed
759
                        checkName(ast->name, klass);
Roberto Raggi's avatar
Roberto Raggi committed
760 761
                        break;
                    }
Roberto Raggi's avatar
Roberto Raggi committed
762 763 764 765
                }
            }
        }

Roberto Raggi's avatar
Roberto Raggi committed
766 767
        accept(ast->expression_list);
    }
Roberto Raggi's avatar
Roberto Raggi committed
768 769 770 771

    return false;
}

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
bool CheckSymbols::visit(GotoStatementAST *ast)
{
    if (ast->identifier_token)
        addUse(ast->identifier_token, SemanticInfo::LabelUse);

    return false;
}

bool CheckSymbols::visit(LabeledStatementAST *ast)
{
    if (ast->label_token)
        addUse(ast->label_token, SemanticInfo::LabelUse);

    accept(ast->statement);
    return false;
}

789 790
bool CheckSymbols::visit(FunctionDefinitionAST *ast)
{
791
    AST *thisFunction = _astStack.takeLast();
792
    accept(ast->decl_specifier_list);
793
    _astStack.append(thisFunction);
Roberto Raggi's avatar
Roberto Raggi committed
794

Roberto Raggi's avatar
Roberto Raggi committed
795
    if (ast->declarator && ast->symbol && ! ast->symbol->isGenerated()) {
Roberto Raggi's avatar
Roberto Raggi committed
796 797 798 799 800 801
        Function *fun = ast->symbol;
        if (NameAST *declId = declaratorId(ast->declarator)) {
            if (QualifiedNameAST *q = declId->asQualifiedName())
                declId = q->unqualified_name;

            if (fun->isVirtual()) {
802
                addUse(declId, SemanticInfo::VirtualMethodUse);
Roberto Raggi's avatar
Roberto Raggi committed
803
            } else if (maybeVirtualMethod(fun->name())) {
804
                addVirtualMethod(_context.lookup(fun->name(), fun->enclosingScope()), declId, fun->argumentCount());
Roberto Raggi's avatar
Roberto Raggi committed
805 806 807 808
            }
        }
    }

809 810 811 812
    accept(ast->declarator);
    accept(ast->ctor_initializer);
    accept(ast->function_body);

813
    const LocalSymbols locals(_doc, ast);
Friedemann Kleint's avatar
Friedemann Kleint committed
814
    foreach (const QList<SemanticInfo::Use> &uses, locals.uses) {
815
        foreach (const SemanticInfo::Use &u, uses)
Roberto Raggi's avatar
Roberto Raggi committed
816
            addUse(u);
817 818
    }

819 820 821
    if (!enclosingFunctionDefinition(true))
        flush();

822 823 824
    return false;
}

825
void CheckSymbols::addUse(NameAST *ast, UseKind kind)
Roberto Raggi's avatar
Roberto Raggi committed
826 827 828 829 830 831
{
    if (! ast)
        return;

    if (QualifiedNameAST *q = ast->asQualifiedName())
        ast = q->unqualified_name;
832 833
    if (DestructorNameAST *dtor = ast->asDestructorName())
        ast = dtor->unqualified_name;
Roberto Raggi's avatar
Roberto Raggi committed
834 835 836 837 838 839 840 841

    if (! ast)
        return; // nothing to do
    else if (ast->asOperatorFunctionId() != 0 || ast->asConversionFunctionId() != 0)
        return; // nothing to do

    unsigned startToken = ast->firstToken();

842
    if (TemplateIdAST *templ = ast->asTemplateId())
843 844
        startToken = templ->identifier_token;

845 846 847
    addUse(startToken, kind);
}

848
void CheckSymbols::addUse(unsigned tokenIndex, UseKind kind)
849 850 851 852 853
{
    if (! tokenIndex)
        return;

    const Token &tok = tokenAt(tokenIndex);
Roberto Raggi's avatar
Roberto Raggi committed
854 855 856 857
    if (tok.generated())
        return;

    unsigned line, column;
858
    getTokenStartPosition(tokenIndex, &line, &column);
Roberto Raggi's avatar
Roberto Raggi committed
859 860 861 862 863 864
    const unsigned length = tok.length();

    const Use use(line, column, length, kind);
    addUse(use);
}

865 866
static const int chunkSize = 50;

Roberto Raggi's avatar
Roberto Raggi committed
867
void CheckSymbols::addUse(const Use &use)
868
{
869 870 871
    if (!use.line)
        return;

Roberto Raggi's avatar
Roberto Raggi committed
872
    if (! enclosingFunctionDefinition()) {
873
        if (_usages.size() >= chunkSize) {
874
            if (use.line > _lineOfLastUsage)
875
                flush();
876 877
        }
    }
Roberto Raggi's avatar
Roberto Raggi committed
878

879
    _lineOfLastUsage = qMax(_lineOfLastUsage, use.line);
880
    _usages.append(use);
881 882
}

Roberto Raggi's avatar
Roberto Raggi committed
883
void CheckSymbols::addType(ClassOrNamespace *b, NameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
884 885 886 887
{
    if (! b)
        return;

888 889
    unsigned startToken = ast->firstToken();
    if (DestructorNameAST *dtor = ast->asDestructorName())
890 891
        if (dtor->unqualified_name)
            startToken = dtor->unqualified_name->firstToken();
892 893

    const Token &tok = tokenAt(startToken);
Roberto Raggi's avatar
Roberto Raggi committed
894 895 896 897
    if (tok.generated())
        return;

    unsigned line, column;
898
    getTokenStartPosition(startToken, &line, &column);
Roberto Raggi's avatar
Roberto Raggi committed
899
    const unsigned length = tok.length();
900
    const Use use(line, column, length, SemanticInfo::TypeUse);
Roberto Raggi's avatar
Roberto Raggi committed
901
    addUse(use);
Roberto Raggi's avatar
Roberto Raggi committed
902 903 904
    //qDebug() << "added use" << oo(ast->name) << line << column << length;
}

Roberto Raggi's avatar
Roberto Raggi committed
905 906 907 908 909
bool CheckSymbols::isTemplateClass(Symbol *symbol) const
{
    if (symbol) {
        if (Template *templ = symbol->asTemplate()) {
            if (Symbol *declaration = templ->declaration()) {
910
                if (declaration->isClass() || declaration->isForwardClassDeclaration())
Roberto Raggi's avatar
Roberto Raggi committed
911 912 913 914 915 916 917
                    return true;
            }
        }
    }
    return false;
}

918
void CheckSymbols::addTypeOrStatic(const QList<LookupItem> &candidates, NameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
919
{
920 921
    unsigned startToken = ast->firstToken();
    if (DestructorNameAST *dtor = ast->asDestructorName())
922 923
        if (dtor->unqualified_name)
            startToken = dtor->unqualified_name->firstToken();
924 925

    const Token &tok = tokenAt(startToken);
Roberto Raggi's avatar
Roberto Raggi committed
926 927 928
    if (tok.generated())
        return;

929 930
    foreach (const LookupItem &r, candidates) {
        Symbol *c = r.declaration();
Roberto Raggi's avatar
Roberto Raggi committed
931 932 933 934 935
        if (c->isUsingDeclaration()) // skip using declarations...
            continue;
        else if (c->isUsingNamespaceDirective()) // ... and using namespace directives.
            continue;
        else if (c->isTypedef() || c->isNamespace() ||
Roberto Raggi's avatar
Roberto Raggi committed
936
                 c->isClass() || c->isEnum() || isTemplateClass(c) ||
Roberto Raggi's avatar
Roberto Raggi committed
937
                 c->isForwardClassDeclaration() || c->isTypenameArgument() || c->enclosingEnum() != 0) {
938 939 940 941 942

            unsigned line, column;
            getTokenStartPosition(startToken, &line, &column);
            const unsigned length = tok.length();

943
            UseKind kind = SemanticInfo::TypeUse;
944

Roberto Raggi's avatar
Roberto Raggi committed
945
            if (c->enclosingEnum() != 0)
946
                kind = SemanticInfo::StaticUse;
947 948

            const Use use(line, column, length, kind);
Roberto Raggi's avatar
Roberto Raggi committed
949
            addUse(use);
Roberto Raggi's avatar
Roberto Raggi committed
950 951 952
            //qDebug() << "added use" << oo(ast->name) << line << column << length;
            break;
        }
953 954 955
    }
}

Roberto Raggi's avatar
Roberto Raggi committed
956
void CheckSymbols::addClassMember(const QList<LookupItem> &candidates, NameAST *ast)
957 958 959
{
    unsigned startToken = ast->firstToken();
    if (DestructorNameAST *dtor = ast->asDestructorName())
960 961
        if (dtor->unqualified_name)
            startToken = dtor->unqualified_name->firstToken();
962 963 964 965 966

    const Token &tok = tokenAt(startToken);
    if (tok.generated())
        return;

967 968 969 970 971
    foreach (const LookupItem &r, candidates) {
        Symbol *c = r.declaration();
        if (! c)
            continue;
        else if (! c->isDeclaration())
Roberto Raggi's avatar
Roberto Raggi committed
972
            return;
973
        else if (! (c->enclosingScope() && c->enclosingScope()->isClass()))
Roberto Raggi's avatar
Roberto Raggi committed
974 975 976
            return; // shadowed
        else if (c->isTypedef() || c->type()->isFunctionType())
            return; // shadowed
977

978 979 980 981
        unsigned line, column;
        getTokenStartPosition(startToken, &line, &column);
        const unsigned length = tok.length();

982
        const Use use(line, column, length, SemanticInfo::FieldUse);
Roberto Raggi's avatar
Roberto Raggi committed
983
        addUse(use);
Roberto Raggi's avatar
Roberto Raggi committed
984 985 986 987
        break;
    }
}

988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
void CheckSymbols::addStatic(const QList<LookupItem> &candidates, NameAST *ast)
{
    if (ast->asDestructorName() != 0)
        return;

    unsigned startToken = ast->firstToken();
    const Token &tok = tokenAt(startToken);
    if (tok.generated())
        return;

    foreach (const LookupItem &r, candidates) {
        Symbol *c = r.declaration();
        if (! c)
            return;
1002
        if (c->enclosingScope()->isEnum()) {
1003 1004 1005 1006
            unsigned line, column;
            getTokenStartPosition(startToken, &line, &column);
            const unsigned length = tok.length();

1007
            const Use use(line, column, length, SemanticInfo::StaticUse);
1008 1009 1010 1011 1012 1013 1014
            addUse(use);
            //qDebug() << "added use" << oo(ast->name) << line << column << length;
            break;
        }
    }
}

Roberto Raggi's avatar
Roberto Raggi committed
1015
void CheckSymbols::addVirtualMethod(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount)
Roberto Raggi's avatar
Roberto Raggi committed
1016 1017 1018
{
    unsigned startToken = ast->firstToken();
    if (DestructorNameAST *dtor = ast->asDestructorName())
1019 1020
        if (dtor->unqualified_name)
            startToken = dtor->unqualified_name->firstToken();