ResolveExpression.cpp 20.5 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
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).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
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
** 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.
con's avatar
con committed
27
**
28
**************************************************************************/
con's avatar
con committed
29
30

#include "ResolveExpression.h"
31
#include "LookupContext.h"
con's avatar
con committed
32
#include "Overview.h"
33
#include "DeprecatedGenTemplateInstance.h"
con's avatar
con committed
34
35
36
37
38
39
40
41
42
43

#include <Control.h>
#include <AST.h>
#include <Scope.h>
#include <Names.h>
#include <Symbols.h>
#include <Literals.h>
#include <CoreTypes.h>
#include <TypeVisitor.h>
#include <NameVisitor.h>
hjk's avatar
hjk committed
44

hjk's avatar
hjk committed
45
46
#include <QtCore/QList>
#include <QtCore/QtDebug>
con's avatar
con committed
47
48
49

using namespace CPlusPlus;

hjk's avatar
hjk committed
50
namespace {
con's avatar
con committed
51

52
53
const bool debug = ! qgetenv("CPLUSPLUS_DEBUG").isEmpty();

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
template <typename _Tp>
static QList<_Tp> removeDuplicates(const QList<_Tp> &results)
{
    QList<_Tp> uniqueList;
    QSet<_Tp> processed;
    foreach (const _Tp &r, results) {
        if (processed.contains(r))
            continue;

        processed.insert(r);
        uniqueList.append(r);
    }

    return uniqueList;
}

con's avatar
con committed
70
71
72
73
74
} // end of anonymous namespace

/////////////////////////////////////////////////////////////////////
// ResolveExpression
/////////////////////////////////////////////////////////////////////
75
ResolveExpression::ResolveExpression(const LookupContext &context)
Roberto Raggi's avatar
Roberto Raggi committed
76
    : ASTVisitor(context.expressionDocument()->translationUnit()),
77
      _scope(0),
con's avatar
con committed
78
      _context(context),
Roberto Raggi's avatar
Roberto Raggi committed
79
      sem(context.expressionDocument()->translationUnit())
80
{ }
con's avatar
con committed
81
82
83
84

ResolveExpression::~ResolveExpression()
{ }

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
QList<LookupItem> ResolveExpression::operator()(ExpressionAST *ast, Scope *scope)
{ return resolve(ast, scope); }

QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast, Scope *scope)
{
    Q_ASSERT(scope != 0);

    Scope *previousVisibleSymbol = _scope;
    _scope = scope;
    const QList<LookupItem> result = resolve(ast);
    _scope = previousVisibleSymbol;
    return result;
}

QList<LookupItem> ResolveExpression::resolve(ExpressionAST *ast)
con's avatar
con committed
100
{
101
    const QList<LookupItem> previousResults = switchResults(QList<LookupItem>());
con's avatar
con committed
102
    accept(ast);
103
    return removeDuplicates(switchResults(previousResults));
con's avatar
con committed
104
105
}

106
QList<LookupItem> ResolveExpression::switchResults(const QList<LookupItem> &results)
con's avatar
con committed
107
{
108
    const QList<LookupItem> previousResults = _results;
con's avatar
con committed
109
110
111
112
    _results = results;
    return previousResults;
}

113
void ResolveExpression::addResults(const QList<Symbol *> &symbols)
con's avatar
con committed
114
{
115
116
117
118
119
    foreach (Symbol *symbol, symbols) {
        LookupItem item;
        item.setType(symbol->type());
        item.setScope(symbol->scope());
        item.setDeclaration(symbol);
120
121
        _results.append(item);
    }
con's avatar
con committed
122
123
}

124
void ResolveExpression::addResult(const FullySpecifiedType &ty, Scope *scope)
con's avatar
con committed
125
{
126
127
128
    LookupItem item;
    item.setType(ty);
    item.setScope(scope);
con's avatar
con committed
129

130
    _results.append(item);
131
}
con's avatar
con committed
132

133
bool ResolveExpression::visit(BinaryExpressionAST *ast)
con's avatar
con committed
134
{
135
136
137
138
139
140
141
142
143
144
    if (tokenKind(ast->binary_op_token) == T_COMMA && ast->right_expression && ast->right_expression->asQtMethod() != 0) {

        if (ast->left_expression && ast->left_expression->asQtMethod() != 0)
            thisObject();
        else
            accept(ast->left_expression);

        QtMethodAST *qtMethod = ast->right_expression->asQtMethod();
        if (DeclaratorAST *d = qtMethod->declarator) {
            if (d->core_declarator) {
145
146
147
148
149
150
151
152
                if (DeclaratorIdAST *declaratorId = d->core_declarator->asDeclaratorId()) {
                    if (NameAST *nameAST = declaratorId->name) {
                        if (ClassOrNamespace *binding = baseExpression(_results, T_ARROW)) {
                            _results.clear();
                            addResults(binding->lookup(nameAST->name));
                        }
                    }
                }
153
154
155
156
157
158
            }
        }

        return false;
    }

159
    accept(ast->left_expression);
con's avatar
con committed
160
161
162
163
164
    return false;
}

bool ResolveExpression::visit(CastExpressionAST *ast)
{
165
166
167
    Scope *dummyScope = _context.expressionDocument()->globalSymbols();
    FullySpecifiedType ty = sem.check(ast->type_id, dummyScope);
    addResult(ty, _scope);
con's avatar
con committed
168
169
170
171
172
173
174
175
176
    return false;
}

bool ResolveExpression::visit(ConditionAST *)
{
    // nothing to do.
    return false;
}

177
bool ResolveExpression::visit(ConditionalExpressionAST *ast)
con's avatar
con committed
178
{
179
180
181
182
183
184
    if (ast->left_expression)
        accept(ast->left_expression);

    else if (ast->right_expression)
        accept(ast->right_expression);

con's avatar
con committed
185
186
187
188
189
    return false;
}

bool ResolveExpression::visit(CppCastExpressionAST *ast)
{
190
191
192
    Scope *dummyScope = _context.expressionDocument()->globalSymbols();
    FullySpecifiedType ty = sem.check(ast->type_id, dummyScope);
    addResult(ty, _scope);
con's avatar
con committed
193
194
195
196
197
    return false;
}

bool ResolveExpression::visit(DeleteExpressionAST *)
{
198
    FullySpecifiedType ty(control()->voidType());
199
    addResult(ty, _scope);
con's avatar
con committed
200
201
202
203
204
205
206
207
208
    return false;
}

bool ResolveExpression::visit(ArrayInitializerAST *)
{
    // nothing to do.
    return false;
}

209
bool ResolveExpression::visit(NewExpressionAST *ast)
con's avatar
con committed
210
{
211
    if (ast->new_type_id) {
212
213
214
        Scope *dummyScope = _context.expressionDocument()->globalSymbols();
        FullySpecifiedType ty = sem.check(ast->new_type_id->type_specifier_list, dummyScope);
        ty = sem.check(ast->new_type_id->ptr_operator_list, ty, dummyScope);
215
        FullySpecifiedType ptrTy(control()->pointerType(ty));
216
        addResult(ptrTy, _scope);
217
    }
con's avatar
con committed
218
219
220
221
222
223
    // nothing to do.
    return false;
}

bool ResolveExpression::visit(TypeidExpressionAST *)
{
Roberto Raggi's avatar
Roberto Raggi committed
224
    const Name *std_type_info[2];
con's avatar
con committed
225
226
227
    std_type_info[0] = control()->nameId(control()->findOrInsertIdentifier("std"));
    std_type_info[1] = control()->nameId(control()->findOrInsertIdentifier("type_info"));

Roberto Raggi's avatar
Roberto Raggi committed
228
    const Name *q = control()->qualifiedNameId(std_type_info, 2, /*global=*/ true);
con's avatar
con committed
229
    FullySpecifiedType ty(control()->namedType(q));
230
    addResult(ty, _scope);
con's avatar
con committed
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

    return false;
}

bool ResolveExpression::visit(TypenameCallExpressionAST *)
{
    // nothing to do
    return false;
}

bool ResolveExpression::visit(TypeConstructorCallAST *)
{
    // nothing to do.
    return false;
}

bool ResolveExpression::visit(PostfixExpressionAST *ast)
{
    accept(ast->base_expression);

251
    for (PostfixListAST *it = ast->postfix_expression_list; it; it = it->next)
Roberto Raggi's avatar
Roberto Raggi committed
252
        accept(it->value);
con's avatar
con committed
253
254
255
256
257
258
259
260

    return false;
}

bool ResolveExpression::visit(SizeofExpressionAST *)
{
    FullySpecifiedType ty(control()->integerType(IntegerType::Int));
    ty.setUnsigned(true);
261
    addResult(ty, _scope);
con's avatar
con committed
262
263
264
    return false;
}

265
bool ResolveExpression::visit(NumericLiteralAST *ast)
con's avatar
con committed
266
{
267
    Type *type = 0;
Roberto Raggi's avatar
Roberto Raggi committed
268
    const NumericLiteral *literal = numericLiteral(ast->literal_token);
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292

    if (literal->isChar())
        type = control()->integerType(IntegerType::Char);
    else if (literal->isWideChar())
        type = control()->integerType(IntegerType::WideChar);
    else if (literal->isInt())
        type = control()->integerType(IntegerType::Int);
    else if (literal->isLong())
        type = control()->integerType(IntegerType::Long);
    else if (literal->isLongLong())
        type = control()->integerType(IntegerType::LongLong);
    else if (literal->isFloat())
        type = control()->floatType(FloatType::Float);
    else if (literal->isDouble())
        type = control()->floatType(FloatType::Double);
    else if (literal->isLongDouble())
        type = control()->floatType(FloatType::LongDouble);
    else
        type = control()->integerType(IntegerType::Int);

    FullySpecifiedType ty(type);
    if (literal->isUnsigned())
        ty.setUnsigned(true);

293
    addResult(ty, _scope);
con's avatar
con committed
294
295
296
297
298
299
    return false;
}

bool ResolveExpression::visit(BoolLiteralAST *)
{
    FullySpecifiedType ty(control()->integerType(IntegerType::Bool));
300
    addResult(ty, _scope);
con's avatar
con committed
301
302
303
304
    return false;
}

bool ResolveExpression::visit(ThisExpressionAST *)
305
306
307
308
309
310
{
    thisObject();
    return false;
}

void ResolveExpression::thisObject()
con's avatar
con committed
311
{
312
    Scope *scope = _scope;
con's avatar
con committed
313
314
315
316
317
318
319
    for (; scope; scope = scope->enclosingScope()) {
        if (scope->isFunctionScope()) {
            Function *fun = scope->owner()->asFunction();
            if (Scope *cscope = scope->enclosingClassScope()) {
                Class *klass = cscope->owner()->asClass();
                FullySpecifiedType classTy(control()->namedType(klass->name()));
                FullySpecifiedType ptrTy(control()->pointerType(classTy));
320
                addResult(ptrTy, fun->scope());
con's avatar
con committed
321
                break;
Roberto Raggi's avatar
Roberto Raggi committed
322
323
            } else if (const QualifiedNameId *q = fun->name()->asQualifiedNameId()) {
                const Name *nestedNameSpecifier = 0;
con's avatar
con committed
324
325
326
327
328
329
                if (q->nameCount() == 1 && q->isGlobal())
                    nestedNameSpecifier = q->nameAt(0);
                else
                    nestedNameSpecifier = control()->qualifiedNameId(q->names(), q->nameCount() - 1);
                FullySpecifiedType classTy(control()->namedType(nestedNameSpecifier));
                FullySpecifiedType ptrTy(control()->pointerType(classTy));
330
                addResult(ptrTy, fun->scope());
con's avatar
con committed
331
332
333
334
335
336
                break;
            }
        }
    }
}

337
338
bool ResolveExpression::visit(CompoundExpressionAST *ast)
{
339
    CompoundStatementAST *cStmt = ast->statement;
340
341
342
343
    if (cStmt && cStmt->statement_list) {
        accept(cStmt->statement_list->lastValue());
    }
    return false;
344
345
}

con's avatar
con committed
346
347
348
349
350
351
352
353
354
355
356
bool ResolveExpression::visit(NestedExpressionAST *ast)
{
    accept(ast->expression);
    return false;
}

bool ResolveExpression::visit(StringLiteralAST *)
{
    FullySpecifiedType charTy = control()->integerType(IntegerType::Char);
    charTy.setConst(true);
    FullySpecifiedType ty(control()->pointerType(charTy));
357
    addResult(ty, _scope);
con's avatar
con committed
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
    return false;
}

bool ResolveExpression::visit(ThrowExpressionAST *)
{
    return false;
}

bool ResolveExpression::visit(TypeIdAST *)
{
    return false;
}

bool ResolveExpression::visit(UnaryExpressionAST *ast)
{
    accept(ast->expression);
    unsigned unaryOp = tokenKind(ast->unary_op_token);
    if (unaryOp == T_AMPER) {
376
        QMutableListIterator<LookupItem > it(_results);
con's avatar
con committed
377
        while (it.hasNext()) {
378
379
380
381
            LookupItem p = it.next();
            FullySpecifiedType ty = p.type();
            ty.setType(control()->pointerType(ty));
            p.setType(ty);
con's avatar
con committed
382
383
384
            it.setValue(p);
        }
    } else if (unaryOp == T_STAR) {
385
        QMutableListIterator<LookupItem > it(_results);
con's avatar
con committed
386
        while (it.hasNext()) {
387
388
389
            LookupItem p = it.next();
            if (PointerType *ptrTy = p.type()->asPointerType()) {
                p.setType(ptrTy->elementType());
con's avatar
con committed
390
391
392
393
394
395
396
397
398
                it.setValue(p);
            } else {
                it.remove();
            }
        }
    }
    return false;
}

399
400
401
402
403
404
bool ResolveExpression::visit(CompoundLiteralAST *ast)
{
    accept(ast->type_id);
    return false;
}

con's avatar
con committed
405
406
bool ResolveExpression::visit(QualifiedNameAST *ast)
{
407
408
    if (const Name *name = ast->name) {
        const QList<Symbol *> candidates = _context.lookup(name, _scope);
409
        addResults(candidates);
con's avatar
con committed
410
411
412
413
414
    }

    return false;
}

415
bool ResolveExpression::visit(SimpleNameAST *ast)
con's avatar
con committed
416
{
417
418
    const QList<Symbol *> candidates = _context.lookup(ast->name, _scope);
    addResults(candidates);
con's avatar
con committed
419
420
421
    return false;
}

422
bool ResolveExpression::visit(TemplateIdAST *ast)
con's avatar
con committed
423
{
424
425
    const QList<Symbol *> candidates = _context.lookup(ast->name, _scope);
    addResults(candidates);
con's avatar
con committed
426
427
428
429
430
431
    return false;
}

bool ResolveExpression::visit(DestructorNameAST *)
{
    FullySpecifiedType ty(control()->voidType());
432
    addResult(ty, _scope);
con's avatar
con committed
433
434
435
    return false;
}

436
bool ResolveExpression::visit(OperatorFunctionIdAST *)
con's avatar
con committed
437
{
438
439
    return false;
}
con's avatar
con committed
440

441
442
bool ResolveExpression::visit(ConversionFunctionIdAST *)
{
con's avatar
con committed
443
444
445
    return false;
}

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
bool ResolveExpression::maybeValidPrototype(Function *funTy, unsigned actualArgumentCount) const
{
    unsigned minNumberArguments = 0;

    for (; minNumberArguments < funTy->argumentCount(); ++minNumberArguments) {
        Argument *arg = funTy->argumentAt(minNumberArguments)->asArgument();

        if (arg->hasInitializer())
            break;
    }

    if (actualArgumentCount < minNumberArguments) {
        // not enough arguments.
        return false;

    } else if (! funTy->isVariadic() && actualArgumentCount > funTy->argumentCount()) {
        // too many arguments.
        return false;
    }

    return true;
}

con's avatar
con committed
469
470
bool ResolveExpression::visit(CallAST *ast)
{
471
    const QList<LookupItem> baseResults = _results;
472
473
    _results.clear();

con's avatar
con committed
474
    // Compute the types of the actual arguments.
475
    int actualArgumentCount = 0;
con's avatar
con committed
476

477
478
    //QList< QList<Result> > arguments;
    for (ExpressionListAST *exprIt = ast->expression_list; exprIt; exprIt = exprIt->next) {
479
        //arguments.append(resolve(exprIt->expression));
480
481
        ++actualArgumentCount;
    }
con's avatar
con committed
482

Roberto Raggi's avatar
Roberto Raggi committed
483
    const Name *functionCallOp = control()->operatorNameId(OperatorNameId::FunctionCallOp);
484

485
486
    foreach (const LookupItem &result, baseResults) {
        FullySpecifiedType ty = result.type().simplified();
487
        Scope *scope = result.scope();
488
489

        if (NamedType *namedTy = ty->asNamedType()) {
490
            if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
491
                foreach (Symbol *overload, b->find(functionCallOp)) {
492
493
494
                    if (Function *funTy = overload->type()->asFunctionType()) {
                        if (maybeValidPrototype(funTy, actualArgumentCount)) {
                            Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType();
495
                            addResult(proto->returnType().simplified(), scope);
496
                        }
497
498
                    }
                }
con's avatar
con committed
499
            }
500

501
        } else if (Function *funTy = ty->asFunctionType()) {
502
            if (maybeValidPrototype(funTy, actualArgumentCount))
503
                addResult(funTy->returnType().simplified(), scope);
504
505

        } else if (Class *classTy = ty->asClassType()) {
con's avatar
con committed
506
            // Constructor call
507
            FullySpecifiedType ctorTy = control()->namedType(classTy->name());
508
            addResult(ctorTy, scope);
con's avatar
con committed
509
510
511
512
513
514
515
516
        }
    }

    return false;
}

bool ResolveExpression::visit(ArrayAccessAST *ast)
{
517
    const QList<LookupItem> baseResults = _results;
con's avatar
con committed
518
519
    _results.clear();

520
    const QList<LookupItem> indexResults = resolve(ast->expression);
con's avatar
con committed
521

Roberto Raggi's avatar
Roberto Raggi committed
522
    const Name *arrayAccessOp = control()->operatorNameId(OperatorNameId::ArrayAccessOp);
con's avatar
con committed
523

524
525
    foreach (const LookupItem &result, baseResults) {
        FullySpecifiedType ty = result.type().simplified();
526
        Scope *scope = result.scope();
con's avatar
con committed
527
528

        if (PointerType *ptrTy = ty->asPointerType()) {
529
            addResult(ptrTy->elementType().simplified(), scope);
530

con's avatar
con committed
531
        } else if (ArrayType *arrTy = ty->asArrayType()) {
532
            addResult(arrTy->elementType().simplified(), scope);
533

con's avatar
con committed
534
        } else if (NamedType *namedTy = ty->asNamedType()) {
535
            if (ClassOrNamespace *b = _context.lookupType(namedTy->name(), scope)) {
536
                foreach (Symbol *overload, b->find(arrayAccessOp)) {
537
538
539
                    if (Function *funTy = overload->type()->asFunctionType()) {
                        Function *proto = instantiate(namedTy->name(), funTy)->asFunctionType();
                        // ### TODO: check the actual arguments
540
                        addResult(proto->returnType().simplified(), scope);
541
                    }
con's avatar
con committed
542
                }
543

con's avatar
con committed
544
545
546
547
548
549
550
551
552
553
            }
        }
    }
    return false;
}

bool ResolveExpression::visit(MemberAccessAST *ast)
{
    // The candidate types for the base expression are stored in
    // _results.
554
    const QList<LookupItem> baseResults = _results;
555
    _results.clear();
con's avatar
con committed
556
557

    // Evaluate the expression-id that follows the access operator.
Roberto Raggi's avatar
Roberto Raggi committed
558
    const Name *memberName = 0;
559
560
    if (ast->member_name)
        memberName = ast->member_name->name;
con's avatar
con committed
561
562

    // Remember the access operator.
563
    const int accessOp = tokenKind(ast->access_token);
con's avatar
con committed
564

565
566
    if (ClassOrNamespace *binding = baseExpression(baseResults, accessOp))
        addResults(binding->lookup(memberName));
con's avatar
con committed
567
568
569
570

    return false;
}

571
572
573
ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &originalTy, Scope *scope) const
{
    FullySpecifiedType ty = originalTy.simplified();
574
    ClassOrNamespace *binding = 0;
575
576

    if (Class *klass = ty->asClassType())
577
        binding = _context.lookupType(klass);
578
579

    else if (NamedType *namedTy = ty->asNamedType())
580
        binding = _context.lookupType(namedTy->name(), scope);
581

582
583
584
    else if (Function *funTy = ty->asFunctionType())
        return findClass(funTy->returnType(), scope);

585
586
587
    return binding;
}

588
589
590
591
592
593
ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults,
                                                    int accessOp,
                                                    bool *replacedDotOperator) const
{
    foreach (const LookupItem &r, baseResults) {
        FullySpecifiedType ty = r.type().simplified();
594
        Scope *scope = r.scope();
595

596
        if (accessOp == T_ARROW) {
597
            if (PointerType *ptrTy = ty->asPointerType()) {
598
599
600
                if (ClassOrNamespace *binding = findClass(ptrTy->elementType(), scope))
                    return binding;

601
            } else if (ClassOrNamespace *binding = findClass(ty, scope)) {
602
603
                // lookup for overloads of operator->
                const OperatorNameId *arrowOp = control()->operatorNameId(OperatorNameId::ArrowOp);
604

605
                foreach (Symbol *overload, binding->find(arrowOp)) {
Roberto Raggi's avatar
Roberto Raggi committed
606
                    if (overload->type()->isFunctionType()) {
607
                        FullySpecifiedType overloadTy = DeprecatedGenTemplateInstance::instantiate(binding->templateId(), overload, control());
608
609
610
611
612
613
614
615
                        Function *instantiatedFunction = overloadTy->asFunctionType();
                        Q_ASSERT(instantiatedFunction != 0);

                        FullySpecifiedType retTy = instantiatedFunction->returnType().simplified();

                        if (PointerType *ptrTy = retTy->asPointerType()) {
                            if (ClassOrNamespace *retBinding = findClass(ptrTy->elementType(), overload->scope()))
                                return retBinding;
616

617
618
619
620
621
622
                            else if (debug) {
                                Overview oo;
                                qDebug() << "no class for:" << oo(ptrTy->elementType());
                            }
                        }
                    }
623
                }
624
            }
625
626
627
628
629
630
631
        } else if (accessOp == T_DOT) {
            if (replacedDotOperator) {
                if (PointerType *ptrTy = ty->asPointerType()) {
                    // replace . with ->
                    ty = ptrTy->elementType();
                    *replacedDotOperator = true;
                }
632
633
            }

634
635
636
            if (ClassOrNamespace *binding = findClass(ty, scope))
                return binding;
        }
637
638
639
640
641
    }

    return 0;
}

642
643
FullySpecifiedType ResolveExpression::instantiate(const Name *className, Symbol *candidate) const
{
644
    return DeprecatedGenTemplateInstance::instantiate(className, candidate, _context.control());
645
646
}

con's avatar
con committed
647
648
649
650
bool ResolveExpression::visit(PostIncrDecrAST *)
{
    return false;
}
Roberto Raggi's avatar
Roberto Raggi committed
651

652
bool ResolveExpression::visit(ObjCMessageExpressionAST *ast)
653
{
654
    const QList<LookupItem> receiverResults = resolve(ast->receiver_expression);
655

656
    foreach (const LookupItem &result, receiverResults) {
657
        FullySpecifiedType ty = result.type().simplified();
658
        ClassOrNamespace *binding = 0;
659

660
        if (ObjCClass *clazz = ty->asObjCClassType()) {
661
            // static access, e.g.:
662
663
664
665
            //   [NSObject description];
            binding = _context.lookupType(clazz);
        } else if (PointerType *ptrTy = ty->asPointerType()) {
            if (NamedType *namedTy = ptrTy->asNamedType()) {
666
                // dynamic access, e.g.:
667
668
                //   NSObject *obj = ...; [obj release];
                binding = _context.lookupType(namedTy->name(), result.scope());
669
670
671
            }
        }

672
673
        if (binding)
            addResults(binding->lookup(ast->selector->name));
674
675
676
677
678
    }

    return false;
}