CppDocument.cpp 22.3 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
con's avatar
con committed
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
con's avatar
con committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
con's avatar
con committed
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
****************************************************************************/
con's avatar
con committed
29
30

#include "CppDocument.h"
31
#include "FastPreprocessor.h"
32
33
#include "LookupContext.h"
#include "Overview.h"
hjk's avatar
hjk committed
34

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <cplusplus/Bind.h>
#include <cplusplus/Control.h>
#include <cplusplus/TranslationUnit.h>
#include <cplusplus/DiagnosticClient.h>
#include <cplusplus/Literals.h>
#include <cplusplus/Symbols.h>
#include <cplusplus/Names.h>
#include <cplusplus/AST.h>
#include <cplusplus/ASTPatternBuilder.h>
#include <cplusplus/ASTMatcher.h>
#include <cplusplus/Scope.h>
#include <cplusplus/SymbolVisitor.h>
#include <cplusplus/NameVisitor.h>
#include <cplusplus/TypeVisitor.h>
#include <cplusplus/CoreTypes.h>
hjk's avatar
hjk committed
50

51
52
53
#include <QByteArray>
#include <QBitArray>
#include <QDir>
hjk's avatar
hjk committed
54
#include <QDebug>
con's avatar
con committed
55

Christian Kamm's avatar
Christian Kamm committed
56
57
58
59
60
/*!
    \namespace CPlusPlus
    The namespace for C++ related tools.
*/

con's avatar
con committed
61
62
63
64
using namespace CPlusPlus;

namespace {

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
class LastVisibleSymbolAt: protected SymbolVisitor
{
    Symbol *root;
    unsigned line;
    unsigned column;
    Symbol *symbol;

public:
    LastVisibleSymbolAt(Symbol *root)
        : root(root), line(0), column(0), symbol(0) {}

    Symbol *operator()(unsigned line, unsigned column)
    {
        this->line = line;
        this->column = column;
        this->symbol = 0;
        accept(root);
        if (! symbol)
            symbol = root;
        return symbol;
    }

protected:
    bool preVisit(Symbol *s)
    {
        if (s->asBlock()) {
91
            if (s->line() < line || (s->line() == line && s->column() <= column))
92
93
94
95
96
97
98
99
100
101
102
                return true;
            // skip blocks
        } if (s->line() < line || (s->line() == line && s->column() <= column)) {
            symbol = s;
            return true;
        }

        return false;
    }
};

103
104
105
106
107
108
109
110
class FindScopeAt: protected SymbolVisitor
{
    TranslationUnit *_unit;
    unsigned _line;
    unsigned _column;
    Scope *_scope;

public:
Erik Verbruggen's avatar
Erik Verbruggen committed
111
    /** line and column should be 1-based */
112
113
114
115
116
117
118
119
120
121
    FindScopeAt(TranslationUnit *unit, unsigned line, unsigned column)
        : _unit(unit), _line(line), _column(column), _scope(0) {}

    Scope *operator()(Symbol *symbol)
    {
        accept(symbol);
        return _scope;
    }

protected:
Roberto Raggi's avatar
Roberto Raggi committed
122
    bool process(Scope *symbol)
123
124
    {
        if (! _scope) {
Roberto Raggi's avatar
Roberto Raggi committed
125
            Scope *scope = symbol;
126

Roberto Raggi's avatar
Roberto Raggi committed
127
128
            for (unsigned i = 0; i < scope->memberCount(); ++i) {
                accept(scope->memberAt(i));
129
130
131
132
133
134

                if (_scope)
                    return false;
            }

            unsigned startLine, startColumn;
135
            _unit->getPosition(scope->startOffset(), &startLine, &startColumn);
136
137
138

            if (_line > startLine || (_line == startLine && _column >= startColumn)) {
                unsigned endLine, endColumn;
139
                _unit->getPosition(scope->endOffset(), &endLine, &endColumn);
140

141
                if (_line < endLine || (_line == endLine && _column < endColumn))
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
                    _scope = scope;
            }
        }

        return false;
    }

    using SymbolVisitor::visit;

    virtual bool preVisit(Symbol *)
    { return ! _scope; }

    virtual bool visit(UsingNamespaceDirective *) { return false; }
    virtual bool visit(UsingDeclaration *) { return false; }
    virtual bool visit(NamespaceAlias *) { return false; }
    virtual bool visit(Declaration *) { return false; }
    virtual bool visit(Argument *) { return false; }
    virtual bool visit(TypenameArgument *) { return false; }
    virtual bool visit(BaseClass *) { return false; }
    virtual bool visit(ForwardClassDeclaration *) { return false; }

    virtual bool visit(Enum *symbol)
    { return process(symbol); }

    virtual bool visit(Function *symbol)
    { return process(symbol); }

    virtual bool visit(Namespace *symbol)
    { return process(symbol); }

    virtual bool visit(Class *symbol)
    { return process(symbol); }

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

178
179
    virtual bool visit(Template *symbol)
    {
180
181
182
183
184
        if (Symbol *decl = symbol->declaration()) {
            if (decl->isFunction() || decl->isClass())
                return process(symbol);
        }
        return true;
185
186
    }

187
188
189
190
191
192
    // Objective-C
    virtual bool visit(ObjCBaseClass *) { return false; }
    virtual bool visit(ObjCBaseProtocol *) { return false; }
    virtual bool visit(ObjCForwardClassDeclaration *) { return false; }
    virtual bool visit(ObjCForwardProtocolDeclaration *) { return false; }
    virtual bool visit(ObjCPropertyDeclaration *) { return false; }
Erik Verbruggen's avatar
Erik Verbruggen committed
193
194
195
196
197
198
199
200
201

    virtual bool visit(ObjCClass *symbol)
    { return process(symbol); }

    virtual bool visit(ObjCProtocol *symbol)
    { return process(symbol); }

    virtual bool visit(ObjCMethod *symbol)
    { return process(symbol); }
202
203
};

204

205
206
#define DO_NOT_DUMP_ALL_PARSER_ERRORS

hjk's avatar
hjk committed
207
208
209
210
211
212
213
class DocumentDiagnosticClient : public DiagnosticClient
{
    enum { MAX_MESSAGE_COUNT = 10 };

public:
    DocumentDiagnosticClient(Document *doc, QList<Document::DiagnosticMessage> *messages)
        : doc(doc),
Roberto Raggi's avatar
Roberto Raggi committed
214
215
          messages(messages),
          errorCount(0)
hjk's avatar
hjk committed
216
217
218
    { }

    virtual void report(int level,
Roberto Raggi's avatar
Roberto Raggi committed
219
                        const StringLiteral *fileId,
hjk's avatar
hjk committed
220
221
222
                        unsigned line, unsigned column,
                        const char *format, va_list ap)
    {
Roberto Raggi's avatar
Roberto Raggi committed
223
224
225
        if (level == Error) {
            ++errorCount;

226
#ifdef DO_NOT_DUMP_ALL_PARSER_ERRORS
Roberto Raggi's avatar
Roberto Raggi committed
227
228
            if (errorCount >= MAX_MESSAGE_COUNT)
                return; // ignore the error
229
#endif // DO_NOT_DUMP_ALL_PARSER_ERRORS
Roberto Raggi's avatar
Roberto Raggi committed
230
        }
con's avatar
con committed
231

hjk's avatar
hjk committed
232
        const QString fileName = QString::fromUtf8(fileId->chars(), fileId->size());
con's avatar
con committed
233

hjk's avatar
hjk committed
234
235
        if (fileName != doc->fileName())
            return;
con's avatar
con committed
236

hjk's avatar
hjk committed
237
238
        QString message;
        message.vsprintf(format, ap);
con's avatar
con committed
239

240
241
242
243
244
245
246
247
248
249
#ifndef DO_NOT_DUMP_ALL_PARSER_ERRORS
        {
            const char *levelStr = "Unknown level";
            if (level == Document::DiagnosticMessage::Warning) levelStr = "Warning";
            if (level == Document::DiagnosticMessage::Error) levelStr = "Error";
            if (level == Document::DiagnosticMessage::Fatal) levelStr = "Fatal";
            qDebug("%s:%u:%u: %s: %s", fileId->chars(), line, column, levelStr, message.toUtf8().constData());
        }
#endif // DO_NOT_DUMP_ALL_PARSER_ERRORS

hjk's avatar
hjk committed
250
251
252
253
        Document::DiagnosticMessage m(convertLevel(level), doc->fileName(),
                                      line, column, message);
        messages->append(m);
    }
con's avatar
con committed
254

hjk's avatar
hjk committed
255
256
257
258
259
260
    static int convertLevel(int level) {
        switch (level) {
            case Warning: return Document::DiagnosticMessage::Warning;
            case Error:   return Document::DiagnosticMessage::Error;
            case Fatal:   return Document::DiagnosticMessage::Fatal;
            default:      return Document::DiagnosticMessage::Error;
con's avatar
con committed
261
        }
hjk's avatar
hjk committed
262
    }
con's avatar
con committed
263

Roberto Raggi's avatar
Roberto Raggi committed
264
private:
hjk's avatar
hjk committed
265
266
    Document *doc;
    QList<Document::DiagnosticMessage> *messages;
Roberto Raggi's avatar
Roberto Raggi committed
267
    int errorCount;
hjk's avatar
hjk committed
268
};
con's avatar
con committed
269

hjk's avatar
hjk committed
270
} // anonymous namespace
con's avatar
con committed
271

Christian Kamm's avatar
Christian Kamm committed
272

con's avatar
con committed
273
Document::Document(const QString &fileName)
274
    : _fileName(QDir::cleanPath(fileName)),
275
      _globalNamespace(0),
276
      _revision(0),
277
278
      _editorRevision(0),
      _checkMode(0)
con's avatar
con committed
279
280
281
282
283
284
{
    _control = new Control();

    _control->setDiagnosticClient(new DocumentDiagnosticClient(this, &_diagnosticMessages));

    const QByteArray localFileName = fileName.toUtf8();
285
    const StringLiteral *fileId = _control->stringLiteral(localFileName.constData(),
Roberto Raggi's avatar
Roberto Raggi committed
286
                                                                      localFileName.size());
287
288
289
290
291
292
    LanguageFeatures features;
    features.qtEnabled = true;
    features.qtMocRunEnabled = true;
    features.qtKeywordsEnabled = true;
    features.cxx11Enabled = true;
    features.objCEnabled = true;
con's avatar
con committed
293
    _translationUnit = new TranslationUnit(_control, fileId);
294
    _translationUnit->setLanguageFeatures(features);
con's avatar
con committed
295
296
297
298
299
300
301
302
303
304
305
    (void) _control->switchTranslationUnit(_translationUnit);
}

Document::~Document()
{
    delete _translationUnit;
    delete _control->diagnosticClient();
    delete _control;
}

Control *Document::control() const
hjk's avatar
hjk committed
306
307
308
{
    return _control;
}
con's avatar
con committed
309

310
311
312
313
314
315
316
317
318
319
unsigned Document::revision() const
{
    return _revision;
}

void Document::setRevision(unsigned revision)
{
    _revision = revision;
}

320
321
322
323
324
325
326
327
328
329
unsigned Document::editorRevision() const
{
    return _editorRevision;
}

void Document::setEditorRevision(unsigned editorRevision)
{
    _editorRevision = editorRevision;
}

330
331
332
333
334
335
336
337
338
339
QDateTime Document::lastModified() const
{
    return _lastModified;
}

void Document::setLastModified(const QDateTime &lastModified)
{
    _lastModified = lastModified;
}

con's avatar
con committed
340
QString Document::fileName() const
hjk's avatar
hjk committed
341
342
343
{
    return _fileName;
}
con's avatar
con committed
344
345

QStringList Document::includedFiles() const
hjk's avatar
hjk committed
346
{
347
    QStringList files;
348
    foreach (const Include &i, _resolvedIncludes)
349
        files.append(i.resolvedFileName());
350
351
    files.removeDuplicates();
    return files;
hjk's avatar
hjk committed
352
}
con's avatar
con committed
353

354
// This assumes to be called with a QDir::cleanPath cleaned fileName.
355
void Document::addIncludeFile(const Document::Include &include)
hjk's avatar
hjk committed
356
{
357
358
359
360
    if (include.resolvedFileName().isEmpty())
        _unresolvedIncludes.append(include);
    else
        _resolvedIncludes.append(include);
hjk's avatar
hjk committed
361
}
con's avatar
con committed
362

Roberto Raggi's avatar
Roberto Raggi committed
363
void Document::appendMacro(const Macro &macro)
hjk's avatar
hjk committed
364
{
Roberto Raggi's avatar
Roberto Raggi committed
365
    _definedMacros.append(macro);
con's avatar
con committed
366
367
}

368
369
370
void Document::addMacroUse(const Macro &macro,
                           unsigned bytesOffset, unsigned bytesLength,
                           unsigned utf16charsOffset, unsigned utf16charLength,
371
                           unsigned beginLine,
372
                           const QVector<MacroArgumentReference> &actuals)
373
{
374
375
376
377
    MacroUse use(macro,
                 bytesOffset, bytesOffset + bytesLength,
                 utf16charsOffset, utf16charsOffset + utf16charLength,
                 beginLine);
378
379

    foreach (const MacroArgumentReference &actual, actuals) {
380
381
        const Block arg(0, 0, actual.utf16charsOffset(),
                        actual.utf16charsOffset() + actual.utf16charsLength());
382
383
384
385
        use.addArgument(arg);
    }

    _macroUses.append(use);
386
387
}

388
389
void Document::addUndefinedMacroUse(const QByteArray &name,
                                    unsigned bytesOffset, unsigned utf16charsOffset)
Christian Kamm's avatar
Christian Kamm committed
390
391
{
    QByteArray copy(name.data(), name.size());
392
    UndefinedMacroUse use(copy, bytesOffset, utf16charsOffset);
Christian Kamm's avatar
Christian Kamm committed
393
394
395
396
397
    _undefinedMacroUses.append(use);
}

/*!
    \class Document::MacroUse
398
399
    \brief The MacroUse class represents the usage of a macro in a
    \l {Document}.
Christian Kamm's avatar
Christian Kamm committed
400
401
402
403
404
    \sa Document::UndefinedMacroUse
*/

/*!
    \class Document::UndefinedMacroUse
405
406
    \brief The UndefinedMacroUse class represents a macro that was looked for,
    but not found.
Christian Kamm's avatar
Christian Kamm committed
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444

    Holds data about the reference to a macro in an \tt{#ifdef} or \tt{#ifndef}
    or argument to the \tt{defined} operator inside an \tt{#if} or \tt{#elif} that does
    not exist.

    \sa Document::undefinedMacroUses(), Document::MacroUse, Macro
*/

/*!
    \fn QByteArray Document::UndefinedMacroUse::name() const

    Returns the name of the macro that was not found.
*/

/*!
    \fn QList<UndefinedMacroUse> Document::undefinedMacroUses() const

    Returns a list of referenced but undefined macros.

    \sa Document::macroUses(), Document::definedMacros(), Macro
*/

/*!
    \fn QList<MacroUse> Document::macroUses() const

    Returns a list of macros used.

    \sa Document::undefinedMacroUses(), Document::definedMacros(), Macro
*/

/*!
    \fn QList<Macro> Document::definedMacros() const

    Returns the list of macros defined.

    \sa Document::macroUses(), Document::undefinedMacroUses()
*/

con's avatar
con committed
445
TranslationUnit *Document::translationUnit() const
hjk's avatar
hjk committed
446
447
448
{
    return _translationUnit;
}
con's avatar
con committed
449
450

bool Document::skipFunctionBody() const
hjk's avatar
hjk committed
451
452
453
{
    return _translationUnit->skipFunctionBody();
}
con's avatar
con committed
454
455

void Document::setSkipFunctionBody(bool skipFunctionBody)
hjk's avatar
hjk committed
456
457
458
{
    _translationUnit->setSkipFunctionBody(skipFunctionBody);
}
con's avatar
con committed
459
460
461
462
463
464
465
466
467
468

unsigned Document::globalSymbolCount() const
{
    if (! _globalNamespace)
        return 0;

    return _globalNamespace->memberCount();
}

Symbol *Document::globalSymbolAt(unsigned index) const
hjk's avatar
hjk committed
469
470
471
{
    return _globalNamespace->memberAt(index);
}
con's avatar
con committed
472
473

Namespace *Document::globalNamespace() const
hjk's avatar
hjk committed
474
475
476
{
    return _globalNamespace;
}
con's avatar
con committed
477

478
479
480
481
482
void Document::setGlobalNamespace(Namespace *globalNamespace)
{
    _globalNamespace = globalNamespace;
}

483
484
485
486
/*!
 * Extract the function name including scope at the given position.
 *
 * Note that a function (scope) starts at the name of that function, not at the return type. The
487
 * implication is that this function will return an empty string when the line/column is on the
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
 * return type.
 *
 * \param line the line number, starting with line 1
 * \param column the column number, starting with column 1
 */
QString Document::functionAt(int line, int column) const
{
    if (line < 1 || column < 1)
        return QString();

    CPlusPlus::Symbol *symbol = lastVisibleSymbolAt(line, column);
    if (!symbol)
        return QString();

    // Find the enclosing function scope (which might be several levels up, or we might be standing
    // on it)
    Scope *scope;
    if (symbol->isScope())
        scope = symbol->asScope();
    else
        scope = symbol->enclosingScope();

    while (scope && !scope->isFunction() )
        scope = scope->enclosingScope();

    if (!scope)
        return QString();

    // We found the function scope, extract its name.
    const Overview o;
    QString rc = o.prettyName(scope->name());

    // Prepend namespace "Foo::Foo::foo()" up to empty root namespace
    for (const Symbol *owner = scope->enclosingNamespace();
         owner; owner = owner->enclosingNamespace()) {
        const QString name = o.prettyName(owner->name());
        if (name.isEmpty()) {
            break;
        } else {
            rc.prepend(QLatin1String("::"));
            rc.prepend(name);
        }
    }
    return rc;
}

534
535
536
Scope *Document::scopeAt(unsigned line, unsigned column)
{
    FindScopeAt findScopeAt(_translationUnit, line, column);
537
538
    if (Scope *scope = findScopeAt(_globalNamespace))
        return scope;
Roberto Raggi's avatar
Roberto Raggi committed
539
    return globalNamespace();
540
541
}

542
Symbol *Document::lastVisibleSymbolAt(unsigned line, unsigned column) const
hjk's avatar
hjk committed
543
{
544
545
    LastVisibleSymbolAt lastVisibleSymbolAt(globalNamespace());
    return lastVisibleSymbolAt(line, column);
con's avatar
con committed
546
547
}

548
549
550
551
552
553
554
555
556
const Macro *Document::findMacroDefinitionAt(unsigned line) const
{
    foreach (const Macro &macro, _definedMacros) {
        if (macro.line() == line)
            return &macro;
    }
    return 0;
}

557
const Document::MacroUse *Document::findMacroUseAt(unsigned utf16charsOffset) const
558
559
{
    foreach (const Document::MacroUse &use, _macroUses) {
560
561
        if (use.containsUtf16charOffset(utf16charsOffset)
                && (utf16charsOffset < use.utf16charsBegin() + use.macro().nameToQString().size())) {
562
            return &use;
563
        }
564
565
566
567
    }
    return 0;
}

568
const Document::UndefinedMacroUse *Document::findUndefinedMacroUseAt(unsigned utf16charsOffset) const
569
570
{
    foreach (const Document::UndefinedMacroUse &use, _undefinedMacroUses) {
571
572
573
        if (use.containsUtf16charOffset(utf16charsOffset)
                && (utf16charsOffset < use.utf16charsBegin()
                    + QString::fromUtf8(use.name(), use.name().size()).length()))
574
575
576
577
578
            return &use;
    }
    return 0;
}

con's avatar
con committed
579
580
581
582
583
584
Document::Ptr Document::create(const QString &fileName)
{
    Document::Ptr doc(new Document(fileName));
    return doc;
}

585
QByteArray Document::utf8Source() const
Roberto Raggi's avatar
Roberto Raggi committed
586
587
{ return _source; }

588
void Document::setUtf8Source(const QByteArray &source)
hjk's avatar
hjk committed
589
{
590
591
    _source = source;
    _translationUnit->setSource(_source.constBegin(), _source.size());
hjk's avatar
hjk committed
592
}
con's avatar
con committed
593

594
void Document::startSkippingBlocks(unsigned utf16charsOffset)
hjk's avatar
hjk committed
595
{
596
    _skippedBlocks.append(Block(0, 0, utf16charsOffset, 0));
hjk's avatar
hjk committed
597
}
con's avatar
con committed
598

599
void Document::stopSkippingBlocks(unsigned utf16charsOffset)
con's avatar
con committed
600
{
Roberto Raggi's avatar
Roberto Raggi committed
601
602
603
    if (_skippedBlocks.isEmpty())
        return;

604
605
    unsigned start = _skippedBlocks.back().utf16charsBegin();
    if (start > utf16charsOffset)
con's avatar
con committed
606
607
        _skippedBlocks.removeLast(); // Ignore this block, it's invalid.
    else
608
        _skippedBlocks.back() = Block(0, 0, start, utf16charsOffset);
con's avatar
con committed
609
610
}

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
bool Document::isTokenized() const
{
    return _translationUnit->isTokenized();
}

void Document::tokenize()
{
    _translationUnit->tokenize();
}

bool Document::isParsed() const
{
    return _translationUnit->isParsed();
}

626
bool Document::parse(ParseMode mode)
hjk's avatar
hjk committed
627
{
628
629
630
631
632
633
634
635
636
637
638
639
640
641
    TranslationUnit::ParseMode m = TranslationUnit::ParseTranlationUnit;
    switch (mode) {
    case ParseTranlationUnit:
        m = TranslationUnit::ParseTranlationUnit;
        break;

    case ParseDeclaration:
        m = TranslationUnit::ParseDeclaration;
        break;

    case ParseExpression:
        m = TranslationUnit::ParseExpression;
        break;

642
643
644
645
    case ParseDeclarator:
        m = TranslationUnit::ParseDeclarator;
        break;

646
647
648
649
650
651
652
653
654
    case ParseStatement:
        m = TranslationUnit::ParseStatement;
        break;

    default:
        break;
    }

    return _translationUnit->parse(m);
hjk's avatar
hjk committed
655
}
con's avatar
con committed
656

657
void Document::check(CheckMode mode)
con's avatar
con committed
658
{
659
    Q_ASSERT(!_globalNamespace);
con's avatar
con committed
660

661
662
    _checkMode = mode;

663
664
665
    if (! isParsed())
        parse();

Roberto Raggi's avatar
Roberto Raggi committed
666
667
    _globalNamespace = _control->newNamespace(0);
    Bind semantic(_translationUnit);
668
    if (mode == FastCheck)
669
        semantic.setSkipFunctionBodies(true);
con's avatar
con committed
670

671
672
673
    if (! _translationUnit->ast())
        return; // nothing to do.

674
    if (TranslationUnitAST *ast = _translationUnit->ast()->asTranslationUnit())
Roberto Raggi's avatar
Roberto Raggi committed
675
        semantic(ast, _globalNamespace);
676
677
    else if (StatementAST *ast = _translationUnit->ast()->asStatement())
        semantic(ast, _globalNamespace);
678
    else if (ExpressionAST *ast = _translationUnit->ast()->asExpression())
Roberto Raggi's avatar
Roberto Raggi committed
679
        semantic(ast, _globalNamespace);
680
    else if (DeclarationAST *ast = translationUnit()->ast()->asDeclaration())
681
        semantic(ast, _globalNamespace);
con's avatar
con committed
682
683
}

684
void Document::keepSourceAndAST()
685
{
686
    _keepSourceAndASTCount.ref();
687
688
}

689
void Document::releaseSourceAndAST()
hjk's avatar
hjk committed
690
{
691
692
693
    if (!_keepSourceAndASTCount.deref()) {
        _source.clear();
        _translationUnit->release();
694
        _control->squeeze();
695
    }
hjk's avatar
hjk committed
696
}
697

698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
bool Document::DiagnosticMessage::operator==(const Document::DiagnosticMessage &other) const
{
    return
            _line == other._line &&
            _column == other._column &&
            _length == other._length &&
            _level == other._level &&
            _fileName == other._fileName &&
            _text == other._text;
}

bool Document::DiagnosticMessage::operator!=(const Document::DiagnosticMessage &other) const
{
    return !operator==(other);
}

714
715
716
717
718
719
720
721
Snapshot::Snapshot()
{
}

Snapshot::~Snapshot()
{
}

722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
int Snapshot::size() const
{
    return _documents.size();
}

bool Snapshot::isEmpty() const
{
    return _documents.isEmpty();
}

Snapshot::const_iterator Snapshot::find(const QString &fileName) const
{
    return _documents.find(fileName);
}

void Snapshot::remove(const QString &fileName)
{
    _documents.remove(fileName);
}

bool Snapshot::contains(const QString &fileName) const
{
    return _documents.contains(fileName);
}

747
748
749
void Snapshot::insert(Document::Ptr doc)
{
    if (doc)
750
        _documents.insert(doc->fileName(), doc);
751
752
}

753
754
Document::Ptr Snapshot::preprocessedDocument(const QByteArray &source,
                                             const QString &fileName) const
755
{
756
757
758
759
760
    Document::Ptr newDoc = Document::create(fileName);
    if (Document::Ptr thisDocument = document(fileName)) {
        newDoc->_revision = thisDocument->_revision;
        newDoc->_editorRevision = thisDocument->_editorRevision;
        newDoc->_lastModified = thisDocument->_lastModified;
761
762
        newDoc->_resolvedIncludes = thisDocument->_resolvedIncludes;
        newDoc->_unresolvedIncludes = thisDocument->_unresolvedIncludes;
763
764
    }

765
    FastPreprocessor pp(*this);
766
767
768
    const QByteArray preprocessedCode = pp.run(newDoc, source);
    newDoc->setUtf8Source(preprocessedCode);
    return newDoc;
769
770
771
772
773
}

Document::Ptr Snapshot::documentFromSource(const QByteArray &preprocessedCode,
                                           const QString &fileName) const
{
Roberto Raggi's avatar
Roberto Raggi committed
774
    Document::Ptr newDoc = Document::create(fileName);
775

776
    if (Document::Ptr thisDocument = document(fileName)) {
777
        newDoc->_revision = thisDocument->_revision;
778
        newDoc->_editorRevision = thisDocument->_editorRevision;
779
        newDoc->_lastModified = thisDocument->_lastModified;
780
781
        newDoc->_resolvedIncludes = thisDocument->_resolvedIncludes;
        newDoc->_unresolvedIncludes = thisDocument->_unresolvedIncludes;
782
        newDoc->_definedMacros = thisDocument->_definedMacros;
783
        newDoc->_macroUses = thisDocument->_macroUses;
784
785
    }

786
    newDoc->setUtf8Source(preprocessedCode);
Roberto Raggi's avatar
Roberto Raggi committed
787
    return newDoc;
788
789
}

790
QSet<QString> Snapshot::allIncludesForDocument(const QString &fileName) const
791
{
792
793
794
    QSet<QString> result;
    allIncludesForDocument_helper(fileName, result);
    return result;
795
796
}

797
void Snapshot::allIncludesForDocument_helper(const QString &fileName, QSet<QString> &result) const
798
{
799
800
801
802
803
804
805
806
    if (Document::Ptr doc = document(fileName)) {
        foreach (const QString &inc, doc->includedFiles()) {
            if (!result.contains(inc)) {
                result.insert(inc);
                allIncludesForDocument_helper(inc, result);
            }
        }
    }
807
808
}

809
Document::Ptr Snapshot::document(const QString &fileName) const
810
{
811
812
    return _documents.value(fileName);
}
813

814
815
816
Snapshot Snapshot::simplified(Document::Ptr doc) const
{
    Snapshot snapshot;
817

818
819
820
821
822
    if (doc) {
        snapshot.insert(doc);
        foreach (const QString &fileName, allIncludesForDocument(doc->fileName()))
            if (Document::Ptr inc = document(fileName))
                snapshot.insert(inc);
823
    }
824

825
826
    return snapshot;
}