cppchecksymbols.cpp 18.7 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
27
28
29
**
**************************************************************************/

Roberto Raggi's avatar
Roberto Raggi committed
30
#include "cppchecksymbols.h"
31
32
#include "cpplocalsymbols.h"

33
#include <cplusplus/Overview.h>
34
35
36
37
38
39
40

#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
41
#include <SymbolVisitor.h>
42

43
44
45
46
47
#include <QtCore/QCoreApplication>
#include <QtCore/QThreadPool>
#include <QtCore/QDebug>

#include <qtconcurrent/runextensions.h>
48

49
using namespace CPlusPlus;
50
using namespace CppEditor::Internal;
51

Roberto Raggi's avatar
Roberto Raggi committed
52
53
namespace {

54
55
56
57
58
59
class FriendlyThread: public QThread
{
public:
    using QThread::msleep;
};

Roberto Raggi's avatar
Roberto Raggi committed
60
61
62
63
64
class CollectTypes: protected SymbolVisitor
{
    Document::Ptr _doc;
    Snapshot _snapshot;
    QSet<QByteArray> _types;
65
    QSet<QByteArray> _members;
Roberto Raggi's avatar
Roberto Raggi committed
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    QList<ScopedSymbol *> _scopes;
    QList<NameAST *> _names;
    bool _mainDocument;

public:
    CollectTypes(Document::Ptr doc, const Snapshot &snapshot)
        : _doc(doc), _snapshot(snapshot), _mainDocument(false)
    {
        QSet<Namespace *> processed;
        process(doc, &processed);
    }

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

83
84
85
86
87
    const QSet<QByteArray> &members() const
    {
        return _members;
    }

Roberto Raggi's avatar
Roberto Raggi committed
88
89
90
91
92
93
94
95
    const QList<ScopedSymbol *> &scopes() const
    {
        return _scopes;
    }

    static Scope *findScope(unsigned tokenOffset, const QList<ScopedSymbol *> &scopes)
    {
        for (int i = scopes.size() - 1; i != -1; --i) {
96
97
98
            Scope *scope = scopes.at(i)->members();
            const unsigned start = scope->startOffset();
            const unsigned end = scope->endOffset();
Roberto Raggi's avatar
Roberto Raggi committed
99
100

            if (tokenOffset >= start && tokenOffset < end)
101
                return scope;
Roberto Raggi's avatar
Roberto Raggi committed
102
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
131
132
133
134
        }

        return 0;
    }

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()) {
135
136
            addType(q->base());
            addType(q->name());
Roberto Raggi's avatar
Roberto Raggi committed
137
138
139
140
141
142
143

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

        }
    }

144
145
146
147
148
149
150
151
152
153
154
155
    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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
    void addScope(ScopedSymbol *symbol)
    {
        if (_mainDocument)
            _scopes.append(symbol);
    }

    // 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)
    {
170
171
172
173
174
175
        for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
            Scope *scope = p->scope();
            for (unsigned i = 0; i < scope->symbolCount(); ++i)
                accept(scope->symbolAt(i));
        }

Roberto Raggi's avatar
Roberto Raggi committed
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
        addScope(symbol);
        return true;
    }

    virtual bool visit(Block *symbol)
    {
        addScope(symbol);
        return true;
    }

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

    virtual bool visit(Declaration *symbol)
    {
        if (symbol->isTypedef())
            addType(symbol->name());
196
197
        else if (! symbol->type()->isFunctionType() && symbol->enclosingSymbol()->isClass())
            addMember(symbol->name());
Roberto Raggi's avatar
Roberto Raggi committed
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

        return true;
    }

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

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

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

    virtual bool visit(Class *symbol)
    {
224
225
226
227
228
229
        for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
            Scope *scope = p->scope();
            for (unsigned i = 0; i < scope->symbolCount(); ++i)
                accept(scope->symbolAt(i));
        }

Roberto Raggi's avatar
Roberto Raggi committed
230
231
232
233
234
235
236
        addScope(symbol);
        addType(symbol->name());
        return true;
    }

    virtual bool visit(ForwardClassDeclaration *symbol)
    {
237
238
239
240
241
242
        for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) {
            Scope *scope = p->scope();
            for (unsigned i = 0; i < scope->symbolCount(); ++i)
                accept(scope->symbolAt(i));
        }

Roberto Raggi's avatar
Roberto Raggi committed
243
244
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
        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; }

    virtual bool visit(ObjCMethod *symbol)
    {
        addScope(symbol);
        return true;
    }

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

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

    virtual bool visit(ObjCProtocol *symbol)
    {
        addScope(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
{
    Q_ASSERT(doc);
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
{
297
298
    _fileName = doc->fileName();
    CollectTypes collectTypes(doc, context.snapshot());
Roberto Raggi's avatar
Roberto Raggi committed
299
    _potentialTypes = collectTypes.types();
300
    _potentialMembers = collectTypes.members();
Roberto Raggi's avatar
Roberto Raggi committed
301
    _scopes = collectTypes.scopes();
302
303
    _flushRequested = false;
    _flushLine = 0;
304
305
}

Roberto Raggi's avatar
Roberto Raggi committed
306
CheckSymbols::~CheckSymbols()
307
{ }
308

Roberto Raggi's avatar
Roberto Raggi committed
309
void CheckSymbols::run()
310
{
311
    _diagnosticMessages.clear();
312

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

    reportFinished();
321
322
}

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

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

335
336
337
    const unsigned length = lastToken.end() - firstToken.begin();
    unsigned line = 1, column = 1;
    getTokenStartPosition(ast->firstToken(), &line, &column);
338

339
340
    warning(line, column, text, length);
    return false;
341
342
}

Roberto Raggi's avatar
Roberto Raggi committed
343
bool CheckSymbols::preVisit(AST *)
344
{
345
    if (isCanceled())
346
347
348
349
350
        return false;

    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
351
bool CheckSymbols::visit(NamespaceAST *ast)
352
{
Roberto Raggi's avatar
Roberto Raggi committed
353
354
355
356
357
358
    if (ast->identifier_token) {
        const Token &tok = tokenAt(ast->identifier_token);
        if (! tok.generated()) {
            unsigned line, column;
            getTokenStartPosition(ast->identifier_token, &line, &column);
            Use use(line, column, tok.length());
359
            addUsage(use);
Roberto Raggi's avatar
Roberto Raggi committed
360
361
362
363
        }
    }

    return true;
364
365
}

Roberto Raggi's avatar
Roberto Raggi committed
366
bool CheckSymbols::visit(UsingDirectiveAST *)
367
368
369
370
{
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
371
bool CheckSymbols::visit(SimpleDeclarationAST *)
372
{
Roberto Raggi's avatar
Roberto Raggi committed
373
374
    return true;
}
375

Roberto Raggi's avatar
Roberto Raggi committed
376
bool CheckSymbols::visit(NamedTypeSpecifierAST *)
Roberto Raggi's avatar
Roberto Raggi committed
377
{
Roberto Raggi's avatar
Roberto Raggi committed
378
    return true;
379
}
380

381
382
383
384
385
386
bool CheckSymbols::visit(MemberAccessAST *ast)
{
    accept(ast->base_expression);
    return false;
}

Roberto Raggi's avatar
Roberto Raggi committed
387
void CheckSymbols::checkNamespace(NameAST *name)
388
{
389
390
    if (! name)
        return;
391

392
393
    unsigned line, column;
    getTokenStartPosition(name->firstToken(), &line, &column);
394

395
    Scope *enclosingScope = _doc->scopeAt(line, column);
396
397
398
399
    if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope)) {
        foreach (Symbol *s, b->symbols()) {
            if (s->isNamespace())
                return;
400
401
402
        }
    }

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

Roberto Raggi's avatar
Roberto Raggi committed
407
void CheckSymbols::checkName(NameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
408
{
409
    if (ast && ast->name) {
410
411
412
413
        if (const Identifier *ident = ast->name->identifier()) {
            const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
            if (_potentialTypes.contains(id)) {
                Scope *scope = findScope(ast);
414
                const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
415
                addUsage(candidates, ast);
416
417
            } else if (_potentialMembers.contains(id)) {
                Scope *scope = findScope(ast);
418
                const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
419
420
421
422
423
424
425
426
427
428
429
430
431
                addMemberUsage(candidates, ast);
            }
        }
    }
}

void CheckSymbols::checkMemberName(NameAST *ast)
{
    if (ast && ast->name) {
        if (const Identifier *ident = ast->name->identifier()) {
            const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size());
            if (_potentialMembers.contains(id)) {
                Scope *scope = findScope(ast);
432
                const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
433
434
435
                addMemberUsage(candidates, ast);
            } else if (_potentialMembers.contains(id)) {
                Scope *scope = findScope(ast);
436
                const QList<LookupItem> candidates = _context.lookup(ast->name, scope);
437
                addMemberUsage(candidates, ast);
438
            }
Roberto Raggi's avatar
Roberto Raggi committed
439
440
        }
    }
Roberto Raggi's avatar
Roberto Raggi committed
441
}
Roberto Raggi's avatar
Roberto Raggi committed
442

Roberto Raggi's avatar
Roberto Raggi committed
443
bool CheckSymbols::visit(SimpleNameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
444
445
{
    checkName(ast);
Roberto Raggi's avatar
Roberto Raggi committed
446
447
448
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
449
bool CheckSymbols::visit(TemplateIdAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
450
{
Roberto Raggi's avatar
Roberto Raggi committed
451
    checkName(ast);
Roberto Raggi's avatar
Roberto Raggi committed
452
453
454
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
455
bool CheckSymbols::visit(DestructorNameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
456
{
457
    checkName(ast);
Roberto Raggi's avatar
Roberto Raggi committed
458
459
460
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
461
bool CheckSymbols::visit(QualifiedNameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
462
463
{
    if (ast->name) {
464
        Scope *scope = findScope(ast);
Roberto Raggi's avatar
Roberto Raggi committed
465
466
467
468

        ClassOrNamespace *b = 0;
        if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) {
            NestedNameSpecifierAST *nested_name_specifier = it->value;
469
            if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { // ### remove shadowing
Roberto Raggi's avatar
Roberto Raggi committed
470

471
472
473
                if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
                    accept(template_id->template_argument_list);

474
475
                const Name *name = class_or_namespace_name->name;
                b = _context.lookupType(name, scope);
476
                addUsage(b, class_or_namespace_name);
Roberto Raggi's avatar
Roberto Raggi committed
477

478
479
                for (it = it->next; b && it; it = it->next) {
                    NestedNameSpecifierAST *nested_name_specifier = it->value;
Roberto Raggi's avatar
Roberto Raggi committed
480

481
482
483
                    if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) {
                        if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId())
                            accept(template_id->template_argument_list);
484

485
                        b = b->findType(class_or_namespace_name->name);
486
                        addUsage(b, class_or_namespace_name);
487
                    }
Roberto Raggi's avatar
Roberto Raggi committed
488
489
490
491
492
                }
            }
        }

        if (b && ast->unqualified_name)
493
            addUsage(b->find(ast->unqualified_name->name), ast->unqualified_name);
Roberto Raggi's avatar
Roberto Raggi committed
494
495
496
497
498
    }

    return false;
}

Roberto Raggi's avatar
Roberto Raggi committed
499
bool CheckSymbols::visit(TypenameTypeParameterAST *ast)
500
{
501
    if (ast->name && ast->name->name) {
502
503
504
505
        if (const Identifier *templId = ast->name->name->identifier()) {
            const QByteArray id = QByteArray::fromRawData(templId->chars(), templId->size());
            if (_potentialTypes.contains(id)) {
                Scope *scope = findScope(_templateDeclarationStack.back());
506
                const QList<LookupItem> candidates = _context.lookup(ast->name->name, scope);
507
                addUsage(candidates, ast->name);
508
509
510
511
512
513
            }
        }
    }
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
514
bool CheckSymbols::visit(TemplateTypeParameterAST *ast)
515
516
517
518
519
{
    checkName(ast->name);
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
520
bool CheckSymbols::visit(TemplateDeclarationAST *ast)
521
522
523
524
525
{
    _templateDeclarationStack.append(ast);
    return true;
}

Roberto Raggi's avatar
Roberto Raggi committed
526
void CheckSymbols::endVisit(TemplateDeclarationAST *)
527
528
529
530
{
    _templateDeclarationStack.takeFirst();
}

531
532
533
bool CheckSymbols::visit(FunctionDefinitionAST *ast)
{
    _functionDefinitionStack.append(ast);
534
535
536
537
538
539

    accept(ast->decl_specifier_list);
    accept(ast->declarator);
    accept(ast->ctor_initializer);
    accept(ast->function_body);

540
541
542
543
    const LocalSymbols locals(_doc, ast);
    QList<SemanticInfo::Use> uses;
    foreach (uses, locals.uses) {
        foreach (const SemanticInfo::Use &u, uses)
544
            addUsage(u);
545
546
547
    }

    _functionDefinitionStack.removeLast();
548
549

    flush();
550
551
552
    return false;
}

553
void CheckSymbols::addUsage(const Use &use)
554
{
555
    if (_functionDefinitionStack.isEmpty()) {
556
        if (_usages.size() >= 50) {
557
558
559
560
561
562
            if (_flushRequested && use.line != _flushLine)
                flush();
            else if (! _flushRequested) {
                _flushRequested = true;
                _flushLine = use.line;
            }
563
564
        }
    }
Roberto Raggi's avatar
Roberto Raggi committed
565

566
    _usages.append(use);
567
568
}

569
void CheckSymbols::addUsage(ClassOrNamespace *b, NameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
570
571
572
573
{
    if (! b)
        return;

574
575
576
577
578
    unsigned startToken = ast->firstToken();
    if (DestructorNameAST *dtor = ast->asDestructorName())
        startToken = dtor->identifier_token;

    const Token &tok = tokenAt(startToken);
Roberto Raggi's avatar
Roberto Raggi committed
579
580
581
582
    if (tok.generated())
        return;

    unsigned line, column;
583
    getTokenStartPosition(startToken, &line, &column);
Roberto Raggi's avatar
Roberto Raggi committed
584
    const unsigned length = tok.length();
585
    const Use use(line, column, length);
586
    addUsage(use);
Roberto Raggi's avatar
Roberto Raggi committed
587
588
589
    //qDebug() << "added use" << oo(ast->name) << line << column << length;
}

590
void CheckSymbols::addUsage(const QList<LookupItem> &candidates, NameAST *ast)
Roberto Raggi's avatar
Roberto Raggi committed
591
{
592
593
594
595
596
    unsigned startToken = ast->firstToken();
    if (DestructorNameAST *dtor = ast->asDestructorName())
        startToken = dtor->identifier_token;

    const Token &tok = tokenAt(startToken);
Roberto Raggi's avatar
Roberto Raggi committed
597
598
599
600
    if (tok.generated())
        return;

    unsigned line, column;
601
    getTokenStartPosition(startToken, &line, &column);
Roberto Raggi's avatar
Roberto Raggi committed
602
603
    const unsigned length = tok.length();

604
605
    foreach (const LookupItem &r, candidates) {
        Symbol *c = r.declaration();
Roberto Raggi's avatar
Roberto Raggi committed
606
607
608
609
610
611
612
        if (c->isUsingDeclaration()) // skip using declarations...
            continue;
        else if (c->isUsingNamespaceDirective()) // ... and using namespace directives.
            continue;
        else if (c->isTypedef() || c->isNamespace() ||
                 c->isClass() || c->isEnum() ||
                 c->isForwardClassDeclaration() || c->isTypenameArgument()) {
613
            const Use use(line, column, length);
614
            addUsage(use);
Roberto Raggi's avatar
Roberto Raggi committed
615
616
617
            //qDebug() << "added use" << oo(ast->name) << line << column << length;
            break;
        }
618
619
620
    }
}

621
void CheckSymbols::addMemberUsage(const QList<LookupItem> &candidates, NameAST *ast)
622
623
624
625
626
627
628
629
630
631
632
633
634
{
    unsigned startToken = ast->firstToken();
    if (DestructorNameAST *dtor = ast->asDestructorName())
        startToken = dtor->identifier_token;

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

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

635
636
637
638
639
    foreach (const LookupItem &r, candidates) {
        Symbol *c = r.declaration();
        if (! c)
            continue;
        else if (! c->isDeclaration())
640
641
642
643
644
645
646
647
648
            continue;
        else if (c->isTypedef())
            continue;
        else if (c->type()->isFunctionType())
            continue;
        else if (! c->enclosingSymbol()->isClass())
            continue;

        const Use use(line, column, length, Use::Field);
649
        addUsage(use);
650
        //qDebug() << "added use" << oo(ast->name) << line << column << length;
Roberto Raggi's avatar
Roberto Raggi committed
651
652
653
    }
}

Roberto Raggi's avatar
Roberto Raggi committed
654
unsigned CheckSymbols::startOfTemplateDeclaration(TemplateDeclarationAST *ast) const
655
656
657
658
659
660
661
662
663
664
665
{
    if (ast->declaration) {
        if (TemplateDeclarationAST *templ = ast->declaration->asTemplateDeclaration())
            return startOfTemplateDeclaration(templ);

        return ast->declaration->firstToken();
    }

    return ast->firstToken();
}

Roberto Raggi's avatar
Roberto Raggi committed
666
Scope *CheckSymbols::findScope(AST *ast) const
667
668
669
670
671
672
673
674
675
676
677
678
679
{
    Scope *scope = 0;

    if (ast) {
        unsigned startToken = ast->firstToken();
        if (TemplateDeclarationAST *templ = ast->asTemplateDeclaration())
            startToken = startOfTemplateDeclaration(templ);

        const unsigned tokenOffset = tokenAt(startToken).offset;
        scope = CollectTypes::findScope(tokenOffset, _scopes);
    }

    if (! scope)
680
        scope = _doc->globalSymbols();
681
682
683

    return scope;
}
Roberto Raggi's avatar
Roberto Raggi committed
684

Roberto Raggi's avatar
Roberto Raggi committed
685
void CheckSymbols::flush()
Roberto Raggi's avatar
Roberto Raggi committed
686
{
687
688
689
    _flushRequested = false;
    _flushLine = 0;

690
    if (_usages.isEmpty())
Roberto Raggi's avatar
Roberto Raggi committed
691
692
        return;

693
694
    reportResults(_usages);
    _usages.clear();
Roberto Raggi's avatar
Roberto Raggi committed
695
}