LookupContext.cpp 16.4 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
5
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
7
8
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
9
** Commercial Usage
10
**
11
12
13
14
** 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.
15
**
16
** GNU Lesser General Public License Usage
17
**
18
19
20
21
22
23
** 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.
24
**
25
26
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
con's avatar
con committed
27
**
28
**************************************************************************/
con's avatar
con committed
29
30

#include "LookupContext.h"
31
32
33
#include "ResolveExpression.h"
#include "Overview.h"

con's avatar
con committed
34
35
36
37
38
39
#include <CoreTypes.h>
#include <Symbols.h>
#include <Literals.h>
#include <Names.h>
#include <Scope.h>
#include <Control.h>
hjk's avatar
hjk committed
40

con's avatar
con committed
41
42
43
44
#include <QtDebug>

using namespace CPlusPlus;

Roberto Raggi's avatar
Roberto Raggi committed
45
bool LookupContext::isNameCompatibleWithIdentifier(Name *name, Identifier *id)
con's avatar
con committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
{
    if (! name) {
        return false;
    } else if (NameId *nameId = name->asNameId()) {
        Identifier *identifier = nameId->identifier();
        return identifier->isEqualTo(id);
    } else if (DestructorNameId *nameId = name->asDestructorNameId()) {
        Identifier *identifier = nameId->identifier();
        return identifier->isEqualTo(id);
    } else if (TemplateNameId *templNameId = name->asTemplateNameId()) {
        Identifier *identifier = templNameId->identifier();
        return identifier->isEqualTo(id);
    }

    return false;
}

63
64
65
66
67
68
69
70
71
72
73
#ifndef CPLUSPLUS_WITH_NO_DEBUG
static void printScopes(const QList<Scope *> &scopes)
{
    qDebug() << "===========";
    foreach (Scope *scope, scopes) {
        qDebug() << "scope:" << scope << scope->owner()->name() << scope->owner()->fileName()
                << scope->owner()->line() << scope->owner()->column();
    }
}
#endif

con's avatar
con committed
74
75
76
77
78
79
80
81
82
83
84
/////////////////////////////////////////////////////////////////////
// LookupContext
/////////////////////////////////////////////////////////////////////
LookupContext::LookupContext(Control *control)
    : _control(control),
      _symbol(0)
{ }

LookupContext::LookupContext(Symbol *symbol,
                             Document::Ptr expressionDocument,
                             Document::Ptr thisDocument,
Roberto Raggi's avatar
Roberto Raggi committed
85
                             const Snapshot &snapshot)
con's avatar
con committed
86
87
88
    : _symbol(symbol),
      _expressionDocument(expressionDocument),
      _thisDocument(thisDocument),
Roberto Raggi's avatar
Roberto Raggi committed
89
      _snapshot(snapshot)
con's avatar
con committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
{
    _control = _expressionDocument->control();
    _visibleScopes = buildVisibleScopes();
}

bool LookupContext::isValid() const
{ return _control != 0; }

Control *LookupContext::control() const
{ return _control; }

Symbol *LookupContext::symbol() const
{ return _symbol; }

Document::Ptr LookupContext::expressionDocument() const
{ return _expressionDocument; }

Document::Ptr LookupContext::thisDocument() const
{ return _thisDocument; }

Document::Ptr LookupContext::document(const QString &fileName) const
Roberto Raggi's avatar
Roberto Raggi committed
111
{ return _snapshot.value(fileName); }
con's avatar
con committed
112

Roberto Raggi's avatar
Roberto Raggi committed
113
114
Snapshot LookupContext::snapshot() const
{ return _snapshot; }
con's avatar
con committed
115

116
117
118
119
120
121
122
123
124
125
126
127
128
bool LookupContext::maybeValidSymbol(Symbol *symbol,
                                     ResolveMode mode,
                                     const QList<Symbol *> &candidates)
{
    if (((mode & ResolveNamespace) && symbol->isNamespace()) ||
        ((mode & ResolveClass)     && symbol->isClass())     ||
         (mode & ResolveSymbol)) {
        return ! candidates.contains(symbol);
    }

    return false;
}

129
130
131
QList<Symbol *> LookupContext::resolveQualifiedNameId(QualifiedNameId *q,
                                                      const QList<Scope *> &visibleScopes,
                                                      ResolveMode mode) const
con's avatar
con committed
132
{
133
    QList<Scope *> scopes = visibleScopes;
134
135
    QList<Symbol *> candidates;

136
137
    for (unsigned i = 0; i < q->nameCount(); ++i) {
        Name *name = q->nameAt(i);
138

139
140
141
142
        if (i + 1 == q->nameCount())
            candidates = resolve(name, scopes, mode);
        else
            candidates = resolveClassOrNamespace(name, scopes);
143

144
145
        if (candidates.isEmpty() || i + 1 == q->nameCount())
            break;
146

147
148
149
150
        scopes.clear();
        foreach (Symbol *candidate, candidates) {
            if (ScopedSymbol *scoped = candidate->asScopedSymbol()) {
                scopes.append(scoped->members());
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
    Identifier *id = q->identifier();
    foreach (Scope *scope, visibleScopes) {
        Symbol *symbol = scope->lookat(id);
        for (; symbol; symbol = symbol->next()) {
            if (! symbol->name())
                continue;
            else if (! maybeValidSymbol(symbol, mode, candidates))
                continue;
            QualifiedNameId *qq = symbol->name()->asQualifiedNameId();
            if (! qq)
                continue;
            if (q->nameCount() > qq->nameCount())
                continue;

            for (int i = q->nameCount() - 1; i != -1; --i) {
                Name *a = q->nameAt(i);
                Name *b = qq->nameAt(i);

                if (! a->isEqualTo(b))
                    break;
                else if (i == 0)
                    candidates.append(symbol);
177
178
            }
        }
179
180
181
182
    }

    return candidates;
}
183

184
185
186
187
188
189
QList<Symbol *> LookupContext::resolve(Name *name, const QList<Scope *> &visibleScopes,
                                       ResolveMode mode) const
{
    QList<Symbol *> candidates;

    if (!name)
190
        return candidates;
191
192
193

    if (QualifiedNameId *q = name->asQualifiedNameId())
        return resolveQualifiedNameId(q, visibleScopes, mode);
con's avatar
con committed
194
195
196
197
198

    if (Identifier *id = identifier(name)) {
        for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
            Scope *scope = visibleScopes.at(scopeIndex);
            for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
199
                if (! symbol->name()) {
con's avatar
con committed
200
                    continue;
201
                } else if (! maybeValidSymbol(symbol, mode, candidates)) {
con's avatar
con committed
202
                    continue;
203
204
205
206
207
                } else if (QualifiedNameId *q = symbol->name()->asQualifiedNameId()) {
                    if (! q->unqualifiedNameId()->isEqualTo(name))
                        continue;

                    if (q->nameCount() > 1) {
208
209
                        Name *classOrNamespaceName = control()->qualifiedNameId(q->names(),
                                                                                q->nameCount() - 1);
210

211
212
213
214
                        if (Identifier *classOrNamespaceNameId = identifier(classOrNamespaceName)) {
                            if (classOrNamespaceNameId->isEqualTo(id))
                                continue;
                        }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231

                        const QList<Symbol *> resolvedClassOrNamespace =
                                resolveClassOrNamespace(classOrNamespaceName, visibleScopes);

                        bool good = false;
                        foreach (Symbol *classOrNamespace, resolvedClassOrNamespace) {
                            ScopedSymbol *scoped = classOrNamespace->asScopedSymbol();
                            if (visibleScopes.contains(scoped->members())) {
                                good = true;
                                break;
                            }
                        }

                        if (! good)
                            continue;
                    }
                } else if (! isNameCompatibleWithIdentifier(symbol->name(), id)) {
con's avatar
con committed
232
                    continue;
233
                } else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId()) {
con's avatar
con committed
234
235
                    continue;
                }
236
237

                candidates.append(symbol);
con's avatar
con committed
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
            }
        }
    } else if (OperatorNameId *opId = name->asOperatorNameId()) {
        for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
            Scope *scope = visibleScopes.at(scopeIndex);
            for (Symbol *symbol = scope->lookat(opId->kind()); symbol; symbol = symbol->next()) {
                if (! opId->isEqualTo(symbol->name()))
                    continue;
                else if (! candidates.contains(symbol))
                    candidates.append(symbol);
            }
        }
    }

    return candidates;
}

Roberto Raggi's avatar
Roberto Raggi committed
255
256
257
258
259
260
261
262
Identifier *LookupContext::identifier(const Name *name) const
{
    if (name)
        return name->identifier();

    return 0;
}

263
264
265
266
267
268
269
270
271
272
void LookupContext::buildVisibleScopes_helper(Document::Ptr doc, QList<Scope *> *scopes,
                                              QSet<QString> *processed)
{
    if (doc && ! processed->contains(doc->fileName())) {
        processed->insert(doc->fileName());

        if (doc->globalSymbolCount())
            scopes->append(doc->globalSymbols());

        foreach (const Document::Include &incl, doc->includes()) {
Roberto Raggi's avatar
Roberto Raggi committed
273
            buildVisibleScopes_helper(_snapshot.value(incl.fileName()),
274
275
276
277
278
                                      scopes, processed);
        }
    }
}

con's avatar
con committed
279
280
281
282
283
284
QList<Scope *> LookupContext::buildVisibleScopes()
{
    QList<Scope *> scopes;

    if (_symbol) {
        for (Scope *scope = _symbol->scope(); scope; scope = scope->enclosingScope()) {
285
286
287
            if (scope == _thisDocument->globalSymbols())
                break;

con's avatar
con committed
288
289
290
291
292
            scopes.append(scope);
        }
    }

    QSet<QString> processed;
293
    buildVisibleScopes_helper(_thisDocument, &scopes, &processed);
con's avatar
con committed
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

    while (true) {
        QList<Scope *> expandedScopes;
        expand(scopes, &expandedScopes);

        if (expandedScopes.size() == scopes.size())
            return expandedScopes;

        scopes = expandedScopes;
    }

    return scopes;
}

QList<Scope *> LookupContext::visibleScopes(const QPair<FullySpecifiedType, Symbol *> &result) const
{
    Symbol *symbol = result.second;
    QList<Scope *> scopes;
    for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
        scopes.append(scope);
    scopes += visibleScopes();
    scopes = expand(scopes);
    return scopes;
}

QList<Scope *> LookupContext::expand(const QList<Scope *> &scopes) const
{
    QList<Scope *> expanded;
    expand(scopes, &expanded);
    return expanded;
}

void LookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const
{
    for (int i = 0; i < scopes.size(); ++i) {
        expand(scopes.at(i), scopes, expandedScopes);
    }
}

333
void LookupContext::expandNamespace(Namespace *ns,
334
335
                                    const QList<Scope *> &visibleScopes,
                                    QList<Scope *> *expandedScopes) const
con's avatar
con committed
336
{
337
338
339
340
341
342
343
344
    if (Name *nsName = ns->name()) {
        const QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes);
        foreach (Symbol *otherNs, namespaceList) {
            if (otherNs == ns)
                continue;
            expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes);
        }
    }
con's avatar
con committed
345

346
347
348
349
    for (unsigned i = 0; i < ns->memberCount(); ++i) { // ### make me fast
        Symbol *symbol = ns->memberAt(i);
        if (Namespace *otherNs = symbol->asNamespace()) {
            if (! otherNs->name()) {
350
                expand(ns->members(), visibleScopes, expandedScopes);
con's avatar
con committed
351
            }
352
353
354
355
356
        } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
            const QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
            for (int j = 0; j < candidates.size(); ++j) {
                expand(candidates.at(j)->asNamespace()->members(),
                       visibleScopes, expandedScopes);
con's avatar
con committed
357
            }
358
359
        } else if (Enum *e = symbol->asEnum()) {
            expand(e->members(), visibleScopes, expandedScopes);
con's avatar
con committed
360
        }
361
362
363
    }
}

364
void LookupContext::expandClass(Class *klass,
365
366
367
                                const QList<Scope *> &visibleScopes,
                                QList<Scope *> *expandedScopes) const
{
368
369
    for (unsigned i = 0; i < klass->memberCount(); ++i) {
        Symbol *symbol = klass->memberAt(i);
370
371
372
        if (Class *nestedClass = symbol->asClass()) {
            if (! nestedClass->name()) {
                expand(nestedClass->members(), visibleScopes, expandedScopes);
con's avatar
con committed
373
            }
374
375
        } else if (Enum *e = symbol->asEnum()) {
            expand(e->members(), visibleScopes, expandedScopes);
con's avatar
con committed
376
        }
377
    }
con's avatar
con committed
378

379
380
381
382
383
384
385
386
387
388
389
    if (klass->baseClassCount()) {
        QList<Scope *> classVisibleScopes = visibleScopes;
        for (Scope *scope = klass->scope(); scope; scope = scope->enclosingScope()) {
            if (scope->isNamespaceScope()) {
                Namespace *enclosingNamespace = scope->owner()->asNamespace();
                if (enclosingNamespace->name()) {
                    const QList<Symbol *> nsList = resolveNamespace(enclosingNamespace->name(),
                                                                    visibleScopes);
                    foreach (Symbol *ns, nsList) {
                        expand(ns->asNamespace()->members(), classVisibleScopes,
                               &classVisibleScopes);
con's avatar
con committed
390
391
392
393
                    }
                }
            }
        }
394
395
396
397
398
399

        for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
            BaseClass *baseClass = klass->baseClassAt(i);
            Name *baseClassName = baseClass->name();
            const QList<Symbol *> baseClassCandidates = resolveClass(baseClassName,
                                                                     classVisibleScopes);
400

401
            for (int j = 0; j < baseClassCandidates.size(); ++j) {
402
403
                if (Class *baseClassSymbol = baseClassCandidates.at(j)->asClass())
                    expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
404
            }
con's avatar
con committed
405
        }
406
407
408
    }
}

409
void LookupContext::expandBlock(Block *blockSymbol,
410
411
412
                                const QList<Scope *> &visibleScopes,
                                QList<Scope *> *expandedScopes) const
{
413
414
    for (unsigned i = 0; i < blockSymbol->memberCount(); ++i) {
        Symbol *symbol = blockSymbol->memberAt(i);
415
416
417
        if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
            const QList<Symbol *> candidates = resolveNamespace(u->name(),
                                                                visibleScopes);
con's avatar
con committed
418
            for (int j = 0; j < candidates.size(); ++j) {
419
                expand(candidates.at(j)->asNamespace()->members(),
con's avatar
con committed
420
421
422
                       visibleScopes, expandedScopes);
            }
        }
423
424
425
426

    }
}

427
void LookupContext::expandFunction(Function *function,
428
429
430
431
432
                                   const QList<Scope *> &visibleScopes,
                                   QList<Scope *> *expandedScopes) const
{
    if (! expandedScopes->contains(function->arguments()))
        expandedScopes->append(function->arguments());
433

434
435
    if (QualifiedNameId *q = function->name()->asQualifiedNameId()) {
        Name *nestedNameSpec = 0;
436
        if (q->nameCount() == 1)
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
            nestedNameSpec = q->nameAt(0);
        else
            nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1,
                                                        q->isGlobal());
        const QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes);
        for (int j = 0; j < candidates.size(); ++j) {
            expand(candidates.at(j)->asScopedSymbol()->members(),
                   visibleScopes, expandedScopes);
        }
    }
}

void LookupContext::expand(Scope *scope,
                           const QList<Scope *> &visibleScopes,
                           QList<Scope *> *expandedScopes) const
{
    if (expandedScopes->contains(scope))
        return;

    expandedScopes->append(scope);

458
459
460
461
462
463
464
465
    if (Namespace *ns = scope->owner()->asNamespace()) {
        expandNamespace(ns, visibleScopes, expandedScopes);
    } else if (Class *klass = scope->owner()->asClass()) {
        expandClass(klass, visibleScopes, expandedScopes);
    } else if (Block *block = scope->owner()->asBlock()) {
        expandBlock(block, visibleScopes, expandedScopes);
    } else if (Function *fun = scope->owner()->asFunction()) {
        expandFunction(fun, visibleScopes, expandedScopes);
con's avatar
con committed
466
467
    }
}