cppchecksymbols.cpp 44.5 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** Alternatively, 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29

30
#include "cppchecksymbols.h"
31

32 33
#include "cpplocalsymbols.h"

34 35
#include <utils/qtcassert.h>

36 37
#include <QCoreApplication>
#include <QDebug>
38

39 40 41 42
// This is for experimeting highlighting ctors/dtors as functions (instead of types).
// Whenever this feature is considered "accepted" the switch below should be permanently
// removed, unless we decide to actually make this a user setting - that is why it's
// currently a bool instead of a define.
43
static const bool highlightCtorDtorAsType = true;
44

45
using namespace CPlusPlus;
46
using namespace CppTools;
47

48 49
namespace {

50 51 52 53 54 55
class FriendlyThread: public QThread
{
public:
    using QThread::msleep;
};

Roberto Raggi's avatar
Roberto Raggi committed
56
class CollectSymbols: protected SymbolVisitor
57 58 59 60
{
    Document::Ptr _doc;
    Snapshot _snapshot;
    QSet<QByteArray> _types;
61
    QSet<QByteArray> _fields;
62
    QSet<QByteArray> _functions;
63
    QSet<QByteArray> _statics;
64 65 66
    bool _mainDocument;

public:
Roberto Raggi's avatar
Roberto Raggi committed
67
    CollectSymbols(Document::Ptr doc, const Snapshot &snapshot)
68 69 70 71 72 73 74 75 76 77 78
        : _doc(doc), _snapshot(snapshot), _mainDocument(false)
    {
        QSet<Namespace *> processed;
        process(doc, &processed);
    }

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

79
    const QSet<QByteArray> &fields() const
80
    {
81
        return _fields;
82 83
    }

84
    const QSet<QByteArray> &functions() const
85
    {
86
        return _functions;
87 88
    }

89 90 91 92 93
    const QSet<QByteArray> &statics() const
    {
        return _statics;
    }

94 95 96
protected:
    void process(Document::Ptr doc, QSet<Namespace *> *processed)
    {
97
        if (!doc)
98
            return;
99
        if (!processed->contains(doc->globalNamespace())) {
100 101
            processed->insert(doc->globalNamespace());

102
            foreach (const Document::Include &i, doc->resolvedIncludes())
103
                process(_snapshot.document(i.resolvedFileName()), processed);
104 105 106 107 108 109 110 111 112 113 114 115 116 117

            _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)
    {
118
        if (!name) {
119 120 121
            return;

        } else if (const QualifiedNameId *q = name->asQualifiedNameId()) {
122 123
            addType(q->base());
            addType(q->name());
124 125 126 127 128 129 130

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

        }
    }

131
    void addField(const Name *name)
132
    {
133
        if (!name) {
134 135 136 137
            return;

        } else if (name->isNameId()) {
            const Identifier *id = name->identifier();
138
            _fields.insert(QByteArray::fromRawData(id->chars(), id->size()));
139 140 141 142

        }
    }

143
    void addFunction(const Name *name)
144
    {
145
        if (!name) {
146 147 148 149
            return;

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

154 155
    void addStatic(const Name *name)
    {
156
        if (!name) {
157 158 159 160 161 162 163 164 165
            return;

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

        }
    }

166 167 168 169 170 171 172 173
    // 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)
    {
174
        addFunction(symbol->name());
175 176 177
        return true;
    }

Roberto Raggi's avatar
Roberto Raggi committed
178
    virtual bool visit(Block *)
179 180 181 182 183 184 185 186 187 188 189 190
    {
        return true;
    }

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

    virtual bool visit(Declaration *symbol)
    {
191
        if (symbol->enclosingEnum() != 0)
192 193
            addStatic(symbol->name());

194 195
        if (symbol->type()->isFunctionType())
            addFunction(symbol->name());
196

197 198
        if (symbol->isTypedef())
            addType(symbol->name());
199
        else if (!symbol->type()->isFunctionType() && symbol->enclosingScope()->isClass())
200
            addField(symbol->name());
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

        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
223 224 225 226 227
    virtual bool visit(Template *)
    {
        return true;
    }

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
    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
244
    virtual bool visit(ObjCMethod *) { return true; }
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

    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

Erik Verbruggen's avatar
Erik Verbruggen committed
273
static bool sortByLinePredicate(const CheckSymbols::Result &lhs, const CheckSymbols::Result &rhs)
274
{
275 276 277 278
    if (lhs.line == rhs.line)
        return lhs.column < rhs.column;
    else
        return lhs.line < rhs.line;
279 280
}

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

static bool acceptName(NameAST *ast, unsigned *referenceToken)
{
    *referenceToken = ast->firstToken();
    DestructorNameAST *dtor = ast->asDestructorName();
    if (dtor)
        *referenceToken = dtor->unqualified_name->firstToken();

    if (highlightCtorDtorAsType)
        return true;

    return !dtor
            && !ast->asConversionFunctionId()
            && !ast->asOperatorFunctionId();
}

Erik Verbruggen's avatar
Erik Verbruggen committed
297
CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, const LookupContext &context, const QList<CheckSymbols::Result> &macroUses)
298
{
299
    QTC_ASSERT(doc, return Future());
300

301
    return (new CheckSymbols(doc, context, macroUses))->start();
302 303
}

Erik Verbruggen's avatar
Erik Verbruggen committed
304
CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context, const QList<CheckSymbols::Result> &macroUses)
305
    : ASTVisitor(doc->translationUnit()), _doc(doc), _context(context)
306
    , _lineOfLastUsage(0), _macroUses(macroUses)
307
{
308 309
    unsigned line = 0;
    getTokenEndPosition(translationUnit()->ast()->lastToken(), &line, 0);
310
    _chunkSize = qMax(50U, line / 200);
311 312 313 314
    _usages.reserve(_chunkSize);

    _astStack.reserve(200);

Roberto Raggi's avatar
Roberto Raggi committed
315
    typeOfExpression.init(_doc, _context.snapshot(), _context.bindings());
316 317
    // make possible to instantiate templates
    typeOfExpression.setExpandTemplates(true);
318 319
}

320
CheckSymbols::~CheckSymbols()
321
{ }
322

323
void CheckSymbols::run()
324
{
Erik Verbruggen's avatar
Erik Verbruggen committed
325 326 327 328 329 330 331 332
    CollectSymbols collectTypes(_doc, _context.snapshot());

    _fileName = _doc->fileName();
    _potentialTypes = collectTypes.types();
    _potentialFields = collectTypes.fields();
    _potentialFunctions = collectTypes.functions();
    _potentialStatics = collectTypes.statics();

333
    qSort(_macroUses.begin(), _macroUses.end(), sortByLinePredicate);
334
    _doc->clearDiagnosticMessages();
335

336
    if (!isCanceled()) {
337 338
        if (_doc->translationUnit()) {
            accept(_doc->translationUnit()->ast());
Erik Verbruggen's avatar
Erik Verbruggen committed
339
            _usages << QVector<Result>::fromList(_macroUses);
340 341
            flush();
        }
Roberto Raggi's avatar
Roberto Raggi committed
342
    }
343 344

    reportFinished();
345 346
}

347
bool CheckSymbols::warning(unsigned line, unsigned column, const QString &text, unsigned length)
348
{
349
    Document::DiagnosticMessage m(Document::DiagnosticMessage::Warning, _fileName, line, column, text, length);
350
    _doc->addDiagnosticMessage(m);
351 352 353
    return false;
}

354
bool CheckSymbols::warning(AST *ast, const QString &text)
355
{
356 357
    const Token &firstToken = tokenAt(ast->firstToken());
    const Token &lastToken = tokenAt(ast->lastToken() - 1);
358

359 360 361
    const unsigned length = lastToken.end() - firstToken.begin();
    unsigned line = 1, column = 1;
    getTokenStartPosition(ast->firstToken(), &line, &column);
362

363 364
    warning(line, column, text, length);
    return false;
365 366
}

367
FunctionDefinitionAST *CheckSymbols::enclosingFunctionDefinition(bool skipTopOfStack) const
Roberto Raggi's avatar
Roberto Raggi committed
368
{
369 370 371 372
    int index = _astStack.size() - 1;
    if (skipTopOfStack && !_astStack.isEmpty())
        --index;
    for (; index != -1; --index) {
Roberto Raggi's avatar
Roberto Raggi committed
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
        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)
401
                return ns->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
402 403 404

        } else if (ClassSpecifierAST *classSpec = ast->asClassSpecifier()) {
            if (classSpec->symbol)
405
                return classSpec->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
406 407 408

        } else if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition()) {
            if (funDef->symbol)
409
                return funDef->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
410

411 412 413 414 415 416 417 418
        } else if (TemplateDeclarationAST *templateDeclaration = ast->asTemplateDeclaration()) {
            if (DeclarationAST *decl = templateDeclaration->declaration) {
                if (FunctionDefinitionAST *funDef = decl->asFunctionDefinition()) {
                    if (funDef->symbol)
                        return funDef->symbol;
                }
            }

Roberto Raggi's avatar
Roberto Raggi committed
419 420
        } else if (CompoundStatementAST *blockStmt = ast->asCompoundStatement()) {
            if (blockStmt->symbol)
421
                return blockStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
422 423 424

        } else if (IfStatementAST *ifStmt = ast->asIfStatement()) {
            if (ifStmt->symbol)
425
                return ifStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
426 427 428

        } else if (WhileStatementAST *whileStmt = ast->asWhileStatement()) {
            if (whileStmt->symbol)
429
                return whileStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
430 431 432

        } else if (ForStatementAST *forStmt = ast->asForStatement()) {
            if (forStmt->symbol)
433
                return forStmt->symbol;
Roberto Raggi's avatar
Roberto Raggi committed
434 435 436

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

439 440 441 442
        } else if (RangeBasedForStatementAST *rangeBasedForStmt = ast->asRangeBasedForStatement()) {
            if (rangeBasedForStmt->symbol)
                return rangeBasedForStmt->symbol;

443 444
        } else if (SwitchStatementAST *switchStmt = ast->asSwitchStatement()) {
            if (switchStmt->symbol)
445
                return switchStmt->symbol;
446 447 448

        } else if (CatchClauseAST *catchClause = ast->asCatchClause()) {
            if (catchClause->symbol)
449
                return catchClause->symbol;
450

Roberto Raggi's avatar
Roberto Raggi committed
451 452 453
        }
    }

454
    return _doc->globalNamespace();
Roberto Raggi's avatar
Roberto Raggi committed
455 456 457
}

bool CheckSymbols::preVisit(AST *ast)
458
{
Roberto Raggi's avatar
Roberto Raggi committed
459 460
    _astStack.append(ast);

461
    if (isCanceled())
462 463 464 465 466
        return false;

    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
467 468 469 470 471
void CheckSymbols::postVisit(AST *)
{
    _astStack.takeLast();
}

472
bool CheckSymbols::visit(NamespaceAST *ast)
473
{
Roberto Raggi's avatar
Roberto Raggi committed
474 475
    if (ast->identifier_token) {
        const Token &tok = tokenAt(ast->identifier_token);
476
        if (!tok.generated()) {
Roberto Raggi's avatar
Roberto Raggi committed
477 478
            unsigned line, column;
            getTokenStartPosition(ast->identifier_token, &line, &column);
Erik Verbruggen's avatar
Erik Verbruggen committed
479
            Result use(line, column, tok.length(), CppHighlightingSupport::TypeUse);
Roberto Raggi's avatar
Roberto Raggi committed
480
            addUse(use);
Roberto Raggi's avatar
Roberto Raggi committed
481 482 483 484
        }
    }

    return true;
485 486
}

487
bool CheckSymbols::visit(UsingDirectiveAST *)
488 489 490 491
{
    return true;
}

492 493
bool CheckSymbols::visit(EnumeratorAST *ast)
{
Erik Verbruggen's avatar
Erik Verbruggen committed
494
    addUse(ast->identifier_token, CppHighlightingSupport::EnumerationUse);
495 496 497
    return true;
}

498 499
bool CheckSymbols::visit(SimpleDeclarationAST *ast)
{
500
    NameAST *declrIdNameAST = 0;
501
    if (ast->declarator_list && !ast->declarator_list->next) {
502
        if (ast->symbols && !ast->symbols->next && !ast->symbols->value->isGenerated()) {
503
            Symbol *decl = ast->symbols->value;
504
            if (NameAST *nameAST = declaratorId(ast->declarator_list->value)) {
505
                if (Function *funTy = decl->type()->asFunctionType()) {
506 507 508
                    if (funTy->isVirtual()
                            || (nameAST->asDestructorName()
                                && hasVirtualDestructor(_context.lookupType(funTy->enclosingScope())))) {
Erik Verbruggen's avatar
Erik Verbruggen committed
509
                        addUse(nameAST, CppHighlightingSupport::VirtualMethodUse);
510 511 512 513 514
                        declrIdNameAST = nameAST;
                    } else if (maybeAddFunction(_context.lookup(decl->name(),
                                                                decl->enclosingScope()),
                                                nameAST, funTy->argumentCount())) {
                        declrIdNameAST = nameAST;
515 516

                        // Add a diagnostic message if non-virtual function has override/final marker
Erik Verbruggen's avatar
Erik Verbruggen committed
517
                        if ((_usages.back().kind != CppHighlightingSupport::VirtualMethodUse)) {
518
                            if (funTy->isOverride())
Orgad Shaneh's avatar
Orgad Shaneh committed
519
                                warning(declrIdNameAST, QCoreApplication::translate(
520
                                            "CPlusplus::CheckSymbols", "Only virtual functions can be marked 'override'"));
521
                            else if (funTy->isFinal())
Orgad Shaneh's avatar
Orgad Shaneh committed
522
                                warning(declrIdNameAST, QCoreApplication::translate(
523
                                            "CPlusPlus::CheckSymbols", "Only virtual functions can be marked 'final'"));
524
                        }
525 526 527 528 529 530
                    }
                }
            }
        }
    }

531
    accept(ast->decl_specifier_list);
532

533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
    for (DeclaratorListAST *it = ast->declarator_list; it ; it = it->next) {
        DeclaratorAST *declr = it->value;
        if (declrIdNameAST
                && declr->core_declarator
                && declr->core_declarator->asDeclaratorId()
                && declr->core_declarator->asDeclaratorId()->name == declrIdNameAST) {
            accept(declr->attribute_list);
            accept(declr->postfix_declarator_list);
            accept(declr->post_attribute_list);
            accept(declr->initializer);
        } else {
            accept(declr);
        }
    }

    return false;
549
}
550

551 552 553 554
bool CheckSymbols::visit(ElaboratedTypeSpecifierAST *ast)
{
    accept(ast->attribute_list);
    accept(ast->name);
Erik Verbruggen's avatar
Erik Verbruggen committed
555
    addUse(ast->name, CppHighlightingSupport::TypeUse);
556 557 558
    return false;
}

559 560 561
bool CheckSymbols::visit(MemberAccessAST *ast)
{
    accept(ast->base_expression);
562
    if (!ast->member_name)
Roberto Raggi's avatar
Roberto Raggi committed
563 564 565 566 567
        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());
568
            if (_potentialFields.contains(id)) {
Roberto Raggi's avatar
Roberto Raggi committed
569 570
                const Token start = tokenAt(ast->firstToken());
                const Token end = tokenAt(ast->lastToken() - 1);
571
                const QByteArray expression = _doc->utf8Source().mid(start.begin(), end.end() - start.begin());
Roberto Raggi's avatar
Roberto Raggi committed
572

573
                const QList<LookupItem> candidates =
574
                    typeOfExpression(expression, enclosingScope(), TypeOfExpression::Preprocess);
575
                maybeAddField(candidates, ast->member_name);
Roberto Raggi's avatar
Roberto Raggi committed
576 577 578 579
            }
        }
    }

580 581 582
    return false;
}

583 584 585 586 587 588 589
bool CheckSymbols::visit(CallAST *ast)
{
    if (ast->base_expression) {
        unsigned argumentCount = 0;
        for (ExpressionListAST *it = ast->expression_list; it; it = it->next)
            ++argumentCount;

590
        ExpressionAST *expr = ast->base_expression;
591 592
        if (MemberAccessAST *access = ast->base_expression->asMemberAccess()) {
            if (access->member_name && access->member_name->name) {
593
                if (maybeFunction(access->member_name->name)) {
594
                    expr = access->base_expression;
595

596
                    const QByteArray expression = textOf(access);
597
                    const QList<LookupItem> candidates =
598 599
                        typeOfExpression(expression, enclosingScope(),
                                         TypeOfExpression::Preprocess);
600 601

                    NameAST *memberName = access->member_name;
602 603
                    if (QualifiedNameAST *q = memberName->asQualifiedName()) {
                        checkNestedName(q);
604
                        memberName = q->unqualified_name;
605 606
                    } else if (TemplateIdAST *tId = memberName->asTemplateId()) {
                        accept(tId->template_argument_list);
607
                    }
608

609 610 611 612
                    if (!maybeAddFunction(candidates, memberName, argumentCount)
                            && highlightCtorDtorAsType) {
                        expr = ast->base_expression;
                    }
613 614 615 616
                }
            }
        } else if (IdExpressionAST *idExpr = ast->base_expression->asIdExpression()) {
            if (const Name *name = idExpr->name->name) {
617
                if (maybeFunction(name)) {
618 619
                    expr = 0;

620
                    NameAST *exprName = idExpr->name;
621 622
                    if (QualifiedNameAST *q = exprName->asQualifiedName()) {
                        checkNestedName(q);
623
                        exprName = q->unqualified_name;
624 625
                    } else if (TemplateIdAST *tId = exprName->asTemplateId()) {
                        accept(tId->template_argument_list);
626
                    }
627

628
                    const QList<LookupItem> candidates =
629
                        typeOfExpression(textOf(idExpr), enclosingScope(),
630
                                         TypeOfExpression::Preprocess);
631 632 633 634 635

                    if (!maybeAddFunction(candidates, exprName, argumentCount)
                            && highlightCtorDtorAsType) {
                        expr = ast->base_expression;
                    }
636 637 638 639
                }
            }
        }

640
        accept(expr);
641 642 643 644 645 646
        accept(ast->expression_list);
    }

    return false;
}

647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
bool CheckSymbols::visit(NewExpressionAST *ast)
{
    accept(ast->new_placement);
    accept(ast->type_id);

    if (highlightCtorDtorAsType) {
        accept(ast->new_type_id);
    } else {
        ClassOrNamespace *binding = 0;
        NameAST *nameAST = 0;
        if (ast->new_type_id) {
            for (SpecifierListAST *it = ast->new_type_id->type_specifier_list; it; it = it->next) {
                if (NamedTypeSpecifierAST *spec = it->value->asNamedTypeSpecifier()) {
                    nameAST = spec->name;
                    if (QualifiedNameAST *qNameAST = nameAST->asQualifiedName()) {
                        binding = checkNestedName(qNameAST);
                        if (binding)
                            binding = binding->findType(qNameAST->unqualified_name->name);
                        nameAST = qNameAST->unqualified_name;
                    } else if (maybeType(nameAST->name)) {
                        binding = _context.lookupType(nameAST->name, enclosingScope());
                    }

                    break;
                }
            }
        }

        if (binding && nameAST) {
            int arguments = 0;
            if (ast->new_initializer) {
678
                ExpressionListAST *list = 0;
679
                if (ExpressionListParenAST *exprListParen = ast->new_initializer->asExpressionListParen())
680
                    list = exprListParen->expression_list;
681
                else if (BracedInitializerAST *braceInit = ast->new_initializer->asBracedInitializer())
682 683 684
                    list = braceInit->expression_list;
                for (ExpressionListAST *it = list; it; it = it->next)
                    ++arguments;
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
            }

            Scope *scope = enclosingScope();
            foreach (Symbol *s, binding->symbols()) {
                if (Class *klass = s->asClass()) {
                    scope = klass;
                    break;
                }
            }

            maybeAddFunction(_context.lookup(nameAST->name, scope), nameAST, arguments);
        }
    }

    accept(ast->new_initializer);

    return false;
}

704 705 706 707
QByteArray CheckSymbols::textOf(AST *ast) const
{
    const Token start = tokenAt(ast->firstToken());
    const Token end = tokenAt(ast->lastToken() - 1);
708
    const QByteArray text = _doc->utf8Source().mid(start.begin(), end.end() - start.begin());
709 710 711
    return text;
}

712
void CheckSymbols::checkNamespace(NameAST *name)
713
{
714
    if (!name)
715
        return;
716

717 718
    unsigned line, column;
    getTokenStartPosition(name->firstToken(), &line, &column);
719

Roberto Raggi's avatar
Roberto Raggi committed
720
    if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope())) {
721 722 723
        foreach (Symbol *s, b->symbols()) {
            if (s->isNamespace())
                return;
724 725 726
        }
    }

727
    const unsigned length = tokenAt(name->lastToken() - 1).end() - tokenAt(name->firstToken()).begin();
728
    warning(line, column, QCoreApplication::translate("CPlusPlus::CheckSymbols", "Expected a namespace-name"), length);
729
}
730

731 732
bool CheckSymbols::hasVirtualDestructor(Class *klass) const
{
733
    if (!klass)
734 735
        return false;
    const Identifier *id = klass->identifier();
736
    if (!id)
737
        return false;
738
    for (Symbol *s = klass->find(id); s; s = s->next()) {
739
        if (!s->name())
740
            continue;
741
        if (s->name()->isDestructorNameId()) {
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
            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);

757
    while (!todo.isEmpty()) {
758
        ClassOrNamespace *b = todo.takeFirst();
759
        if (b && !processed.contains(b)) {
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
            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
775
void CheckSymbols::checkName(NameAST *ast, Scope *scope)
776
{
777
    if (ast && ast->name) {
778
        if (!scope)
Roberto Raggi's avatar
Roberto Raggi committed
779 780
            scope = enclosingScope();

781
        if (ast->asDestructorName() != 0) {
782
            Class *klass = scope->asClass();
783 784 785 786 787
            if (!klass && scope->asFunction())
                klass = scope->asFunction()->enclosingScope()->asClass();

            if (klass) {
                if (hasVirtualDestructor(_context.lookupType(klass))) {
Erik Verbruggen's avatar
Erik Verbruggen committed
788
                    addUse(ast, CppHighlightingSupport::VirtualMethodUse);
789 790 791 792 793 794
                } else {
                    bool added = false;
                    if (highlightCtorDtorAsType && maybeType(ast->name))
                        added = maybeAddTypeOrStatic(_context.lookup(ast->name, klass), ast);

                    if (!added)
Erik Verbruggen's avatar
Erik Verbruggen committed
795
                        addUse(ast, CppHighlightingSupport::FunctionUse);
796 797
                }
            }
798
        } else if (maybeType(ast->name) || maybeStatic(ast->name)) {
799
            if (!maybeAddTypeOrStatic(_context.lookup(ast->name, scope), ast)) {
800 801 802 803
                // it can be a local variable
                if (maybeField(ast->name))
                    maybeAddField(_context.lookup(ast->name, scope), ast);
            }
804 805
        } else if (maybeField(ast->name)) {
            maybeAddField(_context.lookup(ast->name, scope), ast);
806 807
        }
    }
Roberto Raggi's avatar
Roberto Raggi committed
808
}
809

810
bool CheckSymbols::visit(SimpleNameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
811 812
{
    checkName(ast);
813 814 815
    return true;
}

816
bool CheckSymbols::visit(TemplateIdAST *ast)
817
{
Roberto Raggi's avatar
Roberto Raggi committed
818
    checkName(ast);
819 820 821
    return true;
}

822
bool CheckSymbols::visit(DestructorNameAST *ast)
823
{
824
    checkName(ast);
825 826 827
    return true;
}

828 829 830 831 832 833 834 835
bool CheckSymbols::visit(ParameterDeclarationAST *ast)
{
    accept(ast->type_specifier_list);
    // Skip parameter name, it does not need to be colored
    accept(ast->expression);
    return false;
}

836
bool CheckSymbols::visit(QualifiedNameAST *ast)
837 838
{
    if (ast->name) {
839 840 841 842 843 844

        ClassOrNamespace *binding = checkNestedName(ast);

        if (binding && ast->unqualified_name) {
            if (ast->unqualified_name->asDestructorName() != 0) {
                if (hasVirtualDestructor(binding)) {
Erik Verbruggen's avatar
Erik Verbruggen committed
845
                    addUse(ast->unqualified_name, CppHighlightingSupport::VirtualMethodUse);
846 847 848 849 850 851
                } else {
                    bool added = false;
                    if (highlightCtorDtorAsType && maybeType(ast->name))
                        added = maybeAddTypeOrStatic(binding->find(ast->unqualified_name->name),
                                                     ast->unqualified_name);
                    if (!added)
Erik Verbruggen's avatar
Erik Verbruggen committed
852
                        addUse(ast->unqualified_name, CppHighlightingSupport::FunctionUse);
853 854
                }
            } else {
855 856 857 858
                QList<LookupItem> items = binding->find(ast->unqualified_name->name);
                if (items.empty())
                    items = _context.lookup(ast->name, enclosingScope());
                maybeAddTypeOrStatic(items, ast->unqualified_name);
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
            }

            if (TemplateIdAST *template_id = ast->unqualified_name->asTemplateId())
                accept(template_id->template_argument_list);
        }
    }

    return false;
}

ClassOrNamespace *CheckSymbols::checkNestedName(QualifiedNameAST *ast)
{
    ClassOrNamespace *binding = 0;

    if (ast->name) {
874 875
        if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) {
            NestedNameSpecifierAST *nested_name_specifier = it->value;
876
            if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { // ### remove shadowing
877

878 879 880
                if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
                    accept(template_id->template_argument_list);

881
                const Name *name = class_or_namespace_name->name;
882
                binding = _context.lookupType(name, enclosingScope());
883 884 885 886 887 888
                if (binding)
                    addType(binding, class_or_namespace_name);
                else
                    // for the case when we use template parameter as qualifier
                    // e.g.: template <typename T> void fun() { T::type type; }
                    accept(nested_name_specifier->class_or_namespace_name);
889

890
                for (it = it->next; it; it = it->next) {
891
                    NestedNameSpecifierAST *nested_name_specifier = it->value;
892

893
                    if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) {
894 895
                        if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) {
                            if (template_id->template_token) {
Erik Verbruggen's avatar
Erik Verbruggen committed
896
                                addUse(template_id, CppHighlightingSupport::TypeUse);
897 898
                                binding = 0; // there's no way we can find a binding.
                            }
899

900
                            accept(template_id->template_argument_list);
901
                            if (!binding)
902 903 904 905 906 907 908
                                continue;
                        }

                        if (binding) {
                            binding = binding->findType(class_or_namespace_name->name);
                            addType(binding, class_or_namespace_name);
                        }
909
                    }
910 911 912 913 914
                }
            }
        }
    }

915
    return binding;
916 917
}

918
bool CheckSymbols::visit(TypenameTypeParameterAST *ast)
919
{
Erik Verbruggen's avatar
Erik Verbruggen committed
920
    addUse(ast->name, CppHighlightingSupport::TypeUse);
Roberto Raggi's avatar
Roberto Raggi committed
921 922
    accept(ast->type_id);
    return false;
923 924
}

925
bool CheckSymbols::visit(TemplateTypeParameterAST *ast)
926
{
Roberto Raggi's avatar
Roberto Raggi committed
927
    accept(ast->template_parameter_list);
Erik Verbruggen's avatar
Erik Verbruggen committed
928
    addUse(ast->name, CppHighlightingSupport::TypeUse);
Roberto Raggi's avatar
Roberto Raggi committed
929 930
    accept(ast->type_id);
    return false;
931 932
}

Roberto Raggi's avatar
Roberto Raggi committed
933 934
bool CheckSymbols::visit(MemInitializerAST *ast)
{
Roberto Raggi's avatar
Roberto Raggi committed
935 936 937 938
    if (FunctionDefinitionAST *enclosingFunction = enclosingFunctionDefinition()) {
        if (ast->name && enclosingFunction->symbol) {
            if (ClassOrNamespace *binding = _context.lookupType(enclosingFunction->symbol)) {
                foreach (Symbol *s, binding->symbols()) {
939 940 941 942 943 944 945 946 947 948 949 950
                    if (Class *klass = s->asClass()) {
                        NameAST *nameAST = ast->name;
                        if (QualifiedNameAST *q = nameAST->asQualifiedName()) {
                            checkNestedName(q);
                            nameAST = q->unqualified_name;
                        }

                        if (highlightCtorDtorAsType && maybeType(nameAST->name)) {
                            checkName(nameAST, klass);
                        } else if (maybeField(nameAST->name)) {
                            maybeAddField(_context.lookup(nameAST->name, klass), nameAST);
                        } else {
951
                            // It's a constructor, count the number of arguments
952
                            unsigned arguments = 0;
953 954 955 956 957 958 959 960 961
                            if (ast->expression) {
                                ExpressionListAST *expr_list = 0;
                                if (ExpressionListParenAST *parenExprList = ast->expression->asExpressionListParen())
                                    expr_list = parenExprList->expression_list;
                                else if (BracedInitializerAST *bracedInitList = ast->expression->asBracedInitializer())
                                    expr_list = bracedInitList->expression_list;
                                for (ExpressionListAST *it = expr_list; it; it = it->next)
                                    ++arguments;
                            }
962 963 964
                            maybeAddFunction(_context.lookup(nameAST->name, klass), nameAST, arguments);
                        }

Roberto Raggi's avatar
Roberto Raggi committed
965 966
                        break;
                    }
Roberto Raggi's avatar
Roberto Raggi committed
967 968 969 970
                }
            }
        }

971
        accept(ast->expression);
Roberto Raggi's avatar
Roberto Raggi committed
972
    }
Roberto Raggi's avatar
Roberto Raggi committed
973 974 975 976

    return false;
}

977 978 979
bool CheckSymbols::visit(GotoStatementAST *ast)
{
    if (ast->identifier_token)
Erik Verbruggen's avatar
Erik Verbruggen committed
980
        addUse(ast->identifier_token, CppHighlightingSupport::LabelUse);
981 982 983 984 985 986

    return false;
}

bool CheckSymbols::visit(LabeledStatementAST *ast)
{
987
    if (ast->label_token && !tokenAt(ast->label_token).isKeyword())
Erik Verbruggen's avatar
Erik Verbruggen committed
988
        addUse(ast->label_token, CppHighlightingSupport::LabelUse);
989 990 991 992 993

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

994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008

/**
 * \brief Highlights "override" and "final" pseudokeywords like true keywords
 */
bool CheckSymbols::visit(SimpleSpecifierAST *ast)
{
    if (ast->specifier_token)
    {
        const Token &tk = tokenAt(ast->specifier_token);
        if (tk.is(T_IDENTIFIER))
        {
            const Identifier &id = *(tk.identifier);
            if (id.equalTo(_doc->control()->cpp11Override())
                    || id.equalTo(_doc->control()->cpp11Final()))
            {
Erik Verbruggen's avatar
Erik Verbruggen committed
1009
                addUse(ast->specifier_token, CppHighlightingSupport::PseudoKeywordUse);
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
            }
        }
    }

    return false;
}

bool CheckSymbols::visit(ClassSpecifierAST *ast)
{
    if (ast->final_token)
Erik Verbruggen's avatar
Erik Verbruggen committed
1020
        addUse(ast->final_token, CppHighlightingSupport::PseudoKeywordUse);
1021 1022 1023 1024

    return true;
}

1025 1026
bool CheckSymbols::visit(FunctionDefinitionAST *ast)
{
1027
    AST *thisFunction = _astStack.takeLast();
1028
    accept(ast->decl_specifier_list);
1029
    _astStack.append(thisFunction);
1030

1031
    bool processEntireDeclr = true;
1032
    if (ast->declarator && ast->symbol && !ast->symbol->isGenerated()) {
1033 1034
        Function *fun = ast->symbol;
        if (NameAST *declId = declaratorId(ast->declarator)) {
1035 1036 1037 1038
            processEntireDeclr = false;

            if (QualifiedNameAST *q = declId->asQualifiedName()) {
                checkNestedName(q);
1039
                declId = q->unqualified_name;
1040
            }
1041

1042 1043 1044
            if (fun->isVirtual()
                    || (declId->asDestructorName()
                        && hasVirtualDestructor(_context.lookupType(fun->enclosingScope())))) {
Erik Verbruggen's avatar
Erik Verbruggen committed
1045
                addUse(declId, CppHighlightingSupport::VirtualMethodUse);
1046 1047 1048 1049
            } else if (!maybeAddFunction(_context.lookup(fun->name(),
                                                         fun->enclosingScope()),
                                         declId, fun->argumentCount())) {
                processEntireDeclr = true;
1050 1051 1052 1053
            }
        }
    }

1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
    if (ast->declarator) {
        if (processEntireDeclr) {
            accept(ast->declarator);
        } else {
            accept(ast->declarator->attribute_list);
            accept(ast->declarator->postfix_declarator_list);
            accept(ast->declarator->post_attribute_list);
            accept(ast->declarator->initializer);
        }
    }

1065 1066 1067
    accept(ast->ctor_initializer);
    accept(ast->function_body);

1068
    const LocalSymbols locals(_doc, ast);
Erik Verbruggen's avatar
Erik Verbruggen committed
1069 1070
    foreach (const QList<Result> &uses, locals.uses) {
        foreach (const Result &u, uses)
Roberto Raggi's avatar
Roberto Raggi committed
1071
            addUse(u);
1072 1073
    }

1074
    if (!enclosingFunctionDefinition(true))
1075 1076
        if (_usages.size() >= _chunkSize)
            flush();
1077

1078 1079 1080
    return false;
}

Erik Verbruggen's avatar
Erik Verbruggen committed
1081
void CheckSymbols::addUse(NameAST *ast, Kind kind)
Roberto Raggi's avatar
Roberto Raggi committed
1082
{
1083
    if (!ast)
Roberto Raggi's avatar
Roberto Raggi committed
1084 1085 1086 1087
        return;

    if (QualifiedNameAST *q = ast->asQualifiedName())
        ast = q->unqualified_name;
1088 1089
    if (DestructorNameAST *dtor = ast->asDestructorName())
        ast = dtor->unqualified_name;
Roberto Raggi's avatar
Roberto Raggi committed
1090

1091
    if (!ast)
Roberto Raggi's avatar
Roberto Raggi committed
1092 1093 1094 1095 1096 1097
        return; // nothing to do
    else if (ast->asOperatorFunctionId() != 0 || ast->asConversionFunctionId() != 0)