cppcodecompletion.cpp 57.7 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
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
31
#include "cppcodecompletion.h"
#include "cppmodelmanager.h"
32
#include "cppdoxygen.h"
33
#include "cpptoolsconstants.h"
Roberto Raggi's avatar
Roberto Raggi committed
34
#include "cpptoolseditorsupport.h"
con's avatar
con committed
35
36
37
38
39
40
41
42
43
44
45
46

#include <Control.h>
#include <AST.h>
#include <ASTVisitor.h>
#include <CoreTypes.h>
#include <Literals.h>
#include <Names.h>
#include <NameVisitor.h>
#include <Symbols.h>
#include <SymbolVisitor.h>
#include <Scope.h>
#include <TranslationUnit.h>
hjk's avatar
hjk committed
47

con's avatar
con committed
48
#include <cplusplus/ResolveExpression.h>
49
#include <cplusplus/MatchingText.h>
con's avatar
con committed
50
51
#include <cplusplus/Overview.h>
#include <cplusplus/ExpressionUnderCursor.h>
52
#include <cplusplus/BackwardsScanner.h>
53
#include <cplusplus/LookupContext.h>
con's avatar
con committed
54
55

#include <coreplugin/icore.h>
56
#include <coreplugin/mimedatabase.h>
con's avatar
con committed
57
#include <coreplugin/editormanager/editormanager.h>
58
#include <texteditor/completionsettings.h>
con's avatar
con committed
59
60
61
#include <texteditor/itexteditor.h>
#include <texteditor/itexteditable.h>
#include <texteditor/basetexteditor.h>
62
#include <projectexplorer/projectexplorer.h>
63
64

#include <utils/faketooltip.h>
65
#include <utils/qtcassert.h>
con's avatar
con committed
66
67
68
69

#include <QtCore/QMap>
#include <QtCore/QFile>
#include <QtGui/QAction>
70
#include <QtGui/QApplication>
71
#include <QtGui/QDesktopWidget>
con's avatar
con committed
72
73
#include <QtGui/QKeyEvent>
#include <QtGui/QLabel>
74
#include <QtGui/QStyle>
75
#include <QtGui/QTextDocument> // Qt::escape()
76
#include <QtGui/QToolButton>
con's avatar
con committed
77
78
#include <QtGui/QVBoxLayout>

79
80
81
82
namespace {
    const bool debug = ! qgetenv("CPLUSPLUS_DEBUG").isEmpty();
}

con's avatar
con committed
83
84
85
86
87
using namespace CPlusPlus;

namespace CppTools {
namespace Internal {

88
89
class FunctionArgumentWidget : public QLabel
{
90
91
    Q_OBJECT

con's avatar
con committed
92
public:
93
    FunctionArgumentWidget();
94
    void showFunctionHint(QList<Function *> functionSymbols,
95
                          const LookupContext &context,
96
                          int startPosition);
con's avatar
con committed
97
98
99
100

protected:
    bool eventFilter(QObject *obj, QEvent *e);

101
102
103
104
private slots:
    void nextPage();
    void previousPage();

con's avatar
con committed
105
private:
106
    void updateArgumentHighlight();
con's avatar
con committed
107
108
    void updateHintText();

109
110
111
    Function *currentFunction() const
    { return m_items.at(m_current); }

con's avatar
con committed
112
113
    int m_startpos;
    int m_currentarg;
114
    int m_current;
115
    bool m_escapePressed;
con's avatar
con committed
116
117
118

    TextEditor::ITextEditor *m_editor;

119
    QWidget *m_pager;
120
    QLabel *m_numberLabel;
121
    Utils::FakeToolTip *m_popupFrame;
122
    QList<Function *> m_items;
123
    LookupContext m_context;
con's avatar
con committed
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
};

class ConvertToCompletionItem: protected NameVisitor
{
    // The completion collector.
    CppCodeCompletion *_collector;

    // The completion item.
    TextEditor::CompletionItem _item;

    // The current symbol.
    Symbol *_symbol;

    // The pretty printer.
    Overview overview;

public:
    ConvertToCompletionItem(CppCodeCompletion *collector)
        : _collector(collector),
          _item(0),
          _symbol(0)
    { }

    TextEditor::CompletionItem operator()(Symbol *symbol)
    {
        if (! symbol || ! symbol->name() || symbol->name()->isQualifiedNameId())
            return 0;

        TextEditor::CompletionItem previousItem = switchCompletionItem(0);
        Symbol *previousSymbol = switchSymbol(symbol);
        accept(symbol->identity());
        if (_item)
156
            _item.data = QVariant::fromValue(symbol);
con's avatar
con committed
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
        (void) switchSymbol(previousSymbol);
        return switchCompletionItem(previousItem);
    }

protected:
    Symbol *switchSymbol(Symbol *symbol)
    {
        Symbol *previousSymbol = _symbol;
        _symbol = symbol;
        return previousSymbol;
    }

    TextEditor::CompletionItem switchCompletionItem(TextEditor::CompletionItem item)
    {
        TextEditor::CompletionItem previousItem = _item;
        _item = item;
        return previousItem;
    }

Roberto Raggi's avatar
Roberto Raggi committed
176
    TextEditor::CompletionItem newCompletionItem(const Name *name)
con's avatar
con committed
177
178
    {
        TextEditor::CompletionItem item(_collector);
179
180
        item.text = overview.prettyName(name);
        item.icon = _collector->iconForSymbol(_symbol);
con's avatar
con committed
181
182
183
        return item;
    }

Roberto Raggi's avatar
Roberto Raggi committed
184
    virtual void visit(const NameId *name)
con's avatar
con committed
185
186
    { _item = newCompletionItem(name); }

Roberto Raggi's avatar
Roberto Raggi committed
187
    virtual void visit(const TemplateNameId *name)
con's avatar
con committed
188
189
    {
        _item = newCompletionItem(name);
190
        _item.text = QLatin1String(name->identifier()->chars());
con's avatar
con committed
191
192
    }

Roberto Raggi's avatar
Roberto Raggi committed
193
    virtual void visit(const DestructorNameId *name)
con's avatar
con committed
194
195
    { _item = newCompletionItem(name); }

Roberto Raggi's avatar
Roberto Raggi committed
196
    virtual void visit(const OperatorNameId *name)
con's avatar
con committed
197
198
    { _item = newCompletionItem(name); }

Roberto Raggi's avatar
Roberto Raggi committed
199
    virtual void visit(const ConversionNameId *name)
con's avatar
con committed
200
201
    { _item = newCompletionItem(name); }

Roberto Raggi's avatar
Roberto Raggi committed
202
    virtual void visit(const QualifiedNameId *name)
con's avatar
con committed
203
204
205
    { _item = newCompletionItem(name->unqualifiedNameId()); }
};

206
207
208
209
210
211
212
213
struct CompleteFunctionDeclaration
{
    explicit CompleteFunctionDeclaration(Function *f = 0)
        : function(f)
    {}

    Function *function;
};
con's avatar
con committed
214
215
216
217
218
219

} // namespace Internal
} // namespace CppTools

using namespace CppTools::Internal;

220
Q_DECLARE_METATYPE(CompleteFunctionDeclaration)
221
222


223
FunctionArgumentWidget::FunctionArgumentWidget():
224
    m_startpos(-1),
225
226
    m_current(0),
    m_escapePressed(false)
con's avatar
con committed
227
{
228
    QObject *editorObject = Core::EditorManager::instance()->currentEditor();
con's avatar
con committed
229
230
    m_editor = qobject_cast<TextEditor::ITextEditor *>(editorObject);

231
    m_popupFrame = new Utils::FakeToolTip(m_editor->widget());
con's avatar
con committed
232

233
234
235
236
    QToolButton *downArrow = new QToolButton;
    downArrow->setArrowType(Qt::DownArrow);
    downArrow->setFixedSize(16, 16);
    downArrow->setAutoRaise(true);
237

238
239
240
241
    QToolButton *upArrow = new QToolButton;
    upArrow->setArrowType(Qt::UpArrow);
    upArrow->setFixedSize(16, 16);
    upArrow->setAutoRaise(true);
242

con's avatar
con committed
243
244
245
    setParent(m_popupFrame);
    setFocusPolicy(Qt::NoFocus);

246
247
248
249
    m_pager = new QWidget;
    QHBoxLayout *hbox = new QHBoxLayout(m_pager);
    hbox->setMargin(0);
    hbox->setSpacing(0);
250
    hbox->addWidget(upArrow);
251
252
    m_numberLabel = new QLabel;
    hbox->addWidget(m_numberLabel);
253
    hbox->addWidget(downArrow);
254

255
    QHBoxLayout *layout = new QHBoxLayout;
con's avatar
con committed
256
    layout->setMargin(0);
257
258
259
    layout->setSpacing(0);
    layout->addWidget(m_pager);
    layout->addWidget(this);
con's avatar
con committed
260
261
    m_popupFrame->setLayout(layout);

262
263
    connect(upArrow, SIGNAL(clicked()), SLOT(previousPage()));
    connect(downArrow, SIGNAL(clicked()), SLOT(nextPage()));
264

con's avatar
con committed
265
    setTextFormat(Qt::RichText);
266
267

    qApp->installEventFilter(this);
con's avatar
con committed
268
269
}

270
void FunctionArgumentWidget::showFunctionHint(QList<Function *> functionSymbols,
271
                                              const LookupContext &context,
272
                                              int startPosition)
con's avatar
con committed
273
{
274
275
    Q_ASSERT(!functionSymbols.isEmpty());

276
277
278
    if (m_startpos == startPosition)
        return;

279
    m_pager->setVisible(functionSymbols.size() > 1);
280

281
    m_items = functionSymbols;
282
    m_context = context;
283
    m_startpos = startPosition;
284
    m_current = 0;
285
    m_escapePressed = false;
con's avatar
con committed
286
287
288

    // update the text
    m_currentarg = -1;
289
    updateArgumentHighlight();
290

con's avatar
con committed
291
292
293
    m_popupFrame->show();
}

294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
void FunctionArgumentWidget::nextPage()
{
    m_current = (m_current + 1) % m_items.size();
    updateHintText();
}

void FunctionArgumentWidget::previousPage()
{
    if (m_current == 0)
        m_current = m_items.size() - 1;
    else
        --m_current;

    updateHintText();
}

310
void FunctionArgumentWidget::updateArgumentHighlight()
con's avatar
con committed
311
312
313
{
    int curpos = m_editor->position();
    if (curpos < m_startpos) {
314
        m_popupFrame->close();
con's avatar
con committed
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
        return;
    }

    QString str = m_editor->textAt(m_startpos, curpos - m_startpos);
    int argnr = 0;
    int parcount = 0;
    SimpleLexer tokenize;
    QList<SimpleToken> tokens = tokenize(str);
    for (int i = 0; i < tokens.count(); ++i) {
        const SimpleToken &tk = tokens.at(i);
        if (tk.is(T_LPAREN))
            ++parcount;
        else if (tk.is(T_RPAREN))
            --parcount;
        else if (! parcount && tk.is(T_COMMA))
            ++argnr;
    }

    if (m_currentarg != argnr) {
        m_currentarg = argnr;
        updateHintText();
    }

    if (parcount < 0)
339
        m_popupFrame->close();
con's avatar
con committed
340
341
342
343
344
}

bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e)
{
    switch (e->type()) {
345
346
347
348
349
    case QEvent::ShortcutOverride:
        if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
            m_escapePressed = true;
        }
        break;
350
    case QEvent::KeyPress:
351
352
353
        if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
            m_escapePressed = true;
        }
354
355
356
357
358
359
360
361
        if (m_items.size() > 1) {
            QKeyEvent *ke = static_cast<QKeyEvent*>(e);
            if (ke->key() == Qt::Key_Up) {
                previousPage();
                return true;
            } else if (ke->key() == Qt::Key_Down) {
                nextPage();
                return true;
con's avatar
con committed
362
            }
363
364
365
366
            return false;
        }
        break;
    case QEvent::KeyRelease:
367
        if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && m_escapePressed) {
368
369
            m_popupFrame->close();
            return false;
con's avatar
con committed
370
        }
371
372
        updateArgumentHighlight();
        break;
con's avatar
con committed
373
374
    case QEvent::WindowDeactivate:
    case QEvent::FocusOut:
375
376
377
        if (obj != m_editor->widget())
            break;
        m_popupFrame->close();
378
        break;
con's avatar
con committed
379
380
381
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
    case QEvent::MouseButtonDblClick:
382
383
384
    case QEvent::Wheel: {
            QWidget *widget = qobject_cast<QWidget *>(obj);
            if (! (widget == this || m_popupFrame->isAncestorOf(widget))) {
385
                m_popupFrame->close();
386
387
            }
        }
con's avatar
con committed
388
389
390
391
392
393
394
395
396
397
398
399
        break;
    default:
        break;
    }
    return false;
}

void FunctionArgumentWidget::updateHintText()
{
    Overview overview;
    overview.setShowReturnTypes(true);
    overview.setShowArgumentNames(true);
400
    overview.setMarkedArgument(m_currentarg + 1);
401
    Function *f = currentFunction();
402

403
404
405
406
407
408
409
410
411
412
413
414
    const QString prettyMethod = overview(f->type(), f->name());
    const int begin = overview.markedArgumentBegin();
    const int end = overview.markedArgumentEnd();

    QString hintText;
    hintText += Qt::escape(prettyMethod.left(begin));
    hintText += "<b>";
    hintText += Qt::escape(prettyMethod.mid(begin, end - begin));
    hintText += "</b>";
    hintText += Qt::escape(prettyMethod.mid(end));
    setText(hintText);

415
416
417
    m_numberLabel->setText(tr("%1 of %2").arg(m_current + 1).arg(m_items.size()));

    m_popupFrame->setFixedWidth(m_popupFrame->minimumSizeHint().width());
418
419

    const QDesktopWidget *desktop = QApplication::desktop();
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
420
#ifdef Q_WS_MAC
421
    const QRect screen = desktop->availableGeometry(desktop->screenNumber(m_editor->widget()));
422
#else
423
    const QRect screen = desktop->screenGeometry(desktop->screenNumber(m_editor->widget()));
424
425
426
427
428
429
430
431
432
433
#endif

    const QSize sz = m_popupFrame->sizeHint();
    QPoint pos = m_editor->cursorRect(m_startpos).topLeft();
    pos.setY(pos.y() - sz.height() - 1);

    if (pos.x() + sz.width() > screen.right())
        pos.setX(screen.right() - sz.width());

    m_popupFrame->move(pos);
con's avatar
con committed
434
435
}

436
CppCodeCompletion::CppCodeCompletion(CppModelManager *manager)
con's avatar
con committed
437
438
    : ICompletionCollector(manager),
      m_manager(manager),
439
440
      m_editor(0),
      m_startPosition(-1),
con's avatar
con committed
441
      m_forcedCompletion(false),
442
443
      m_completionOperator(T_EOF_SYMBOL),
      m_objcEnabled(true)
444
445
{
}
con's avatar
con committed
446
447

QIcon CppCodeCompletion::iconForSymbol(Symbol *symbol) const
448
449
450
451
{
    return m_icons.iconForSymbol(symbol);
}

con's avatar
con committed
452
/*
453
  Searches backwards for an access operator.
con's avatar
con committed
454
*/
455
456
static int startOfOperator(TokenCache *tokenCache,
                           TextEditor::ITextEditable *editor,
con's avatar
con committed
457
458
459
460
461
462
463
464
                           int pos, unsigned *kind,
                           bool wantFunctionCall)
{
    const QChar ch  = pos > -1 ? editor->characterAt(pos - 1) : QChar();
    const QChar ch2 = pos >  0 ? editor->characterAt(pos - 2) : QChar();
    const QChar ch3 = pos >  1 ? editor->characterAt(pos - 3) : QChar();

    int start = pos;
465
    int completionKind = T_EOF_SYMBOL;
con's avatar
con committed
466

467
468
469
    switch (ch.toLatin1()) {
    case '.':
        if (ch2 != QLatin1Char('.')) {
470
            completionKind = T_DOT;
471
472
473
474
            --start;
        }
        break;
    case ',':
475
        completionKind = T_COMMA;
476
        --start;
477
478
479
        break;
    case '(':
        if (wantFunctionCall) {
480
            completionKind = T_LPAREN;
481
482
483
484
485
            --start;
        }
        break;
    case ':':
        if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':')) {
486
            completionKind = T_COLON_COLON;
487
488
489
490
491
            start -= 2;
        }
        break;
    case '>':
        if (ch2 == QLatin1Char('-')) {
492
            completionKind = T_ARROW;
493
494
495
496
497
            start -= 2;
        }
        break;
    case '*':
        if (ch2 == QLatin1Char('.')) {
498
            completionKind = T_DOT_STAR;
499
500
            start -= 2;
        } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>')) {
501
            completionKind = T_ARROW_STAR;
502
503
504
505
506
507
            start -= 3;
        }
        break;
    case '\\':
    case '@':
        if (ch2.isNull() || ch2.isSpace()) {
508
            completionKind = T_DOXY_COMMENT;
509
510
511
512
            --start;
        }
        break;
    case '<':
513
        completionKind = T_ANGLE_STRING_LITERAL;
514
        --start;
515
516
        break;
    case '"':
517
        completionKind = T_STRING_LITERAL;
518
        --start;
519
520
        break;
    case '/':
521
        completionKind = T_SLASH;
522
        --start;
523
        break;
524
525
526
527
    case '#':
        completionKind = T_POUND;
        --start;
        break;
con's avatar
con committed
528
529
    }

530
531
532
533
534
535
536
    if (start == pos)
        return start;

    TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
    QTextCursor tc(edit->textCursor());
    tc.setPosition(pos);

537
    // Include completion: make sure the quote character is the first one on the line
538
    if (completionKind == T_STRING_LITERAL) {
539
540
541
542
        QTextCursor s = tc;
        s.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
        QString sel = s.selectedText();
        if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) {
543
            completionKind = T_EOF_SYMBOL;
544
545
546
547
            start = pos;
        }
    }

548
    if (completionKind == T_COMMA) {
549
        ExpressionUnderCursor expressionUnderCursor(tokenCache);
550
        if (expressionUnderCursor.startOfFunctionCall(tc) == -1) {
551
            completionKind = T_EOF_SYMBOL;
552
553
554
555
            start = pos;
        }
    }

556
    const SimpleToken tk = tokenCache->tokenUnderCursor(tc);
557

558
559
    if (completionKind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) {
        completionKind = T_EOF_SYMBOL;
560
        start = pos;
con's avatar
con committed
561
    }
562
    // Don't complete in comments or strings, but still check for include completion
563
564
565
566
567
    else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT) ||
             (tk.isLiteral() && (completionKind != T_STRING_LITERAL
                                 && completionKind != T_ANGLE_STRING_LITERAL
                                 && completionKind != T_SLASH))) {
        completionKind = T_EOF_SYMBOL;
568
569
570
        start = pos;
    }
    // Include completion: can be triggered by slash, but only in a string
571
572
    else if (completionKind == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) {
        completionKind = T_EOF_SYMBOL;
573
574
        start = pos;
    }
575
    else if (completionKind == T_LPAREN) {
576
        const QList<SimpleToken> &tokens = tokenCache->tokensForBlock(tc.block());
577
578
579
580
581
582
583
        int i = 0;
        for (; i < tokens.size(); ++i) {
            const SimpleToken &token = tokens.at(i);
            if (token.position() == tk.position()) {
                if (i == 0) // no token on the left, but might be on a previous line
                    break;
                const SimpleToken &previousToken = tokens.at(i - 1);
584
585
                if (previousToken.is(T_IDENTIFIER) || previousToken.is(T_GREATER)
                    || previousToken.is(T_SIGNAL) || previousToken.is(T_SLOT))
586
587
588
589
590
                    break;
            }
        }

        if (i == tokens.size()) {
591
            completionKind = T_EOF_SYMBOL;
592
593
594
            start = pos;
        }
    }
595
    // Check for include preprocessor directive
596
    else if (completionKind == T_STRING_LITERAL || completionKind == T_ANGLE_STRING_LITERAL || completionKind == T_SLASH) {
597
        bool include = false;
598
        const QList<SimpleToken> &tokens = tokenCache->tokensForBlock(tc.block());
599
600
601
        if (tokens.size() >= 3) {
            if (tokens.at(0).is(T_POUND) && tokens.at(1).is(T_IDENTIFIER) && (tokens.at(2).is(T_STRING_LITERAL) ||
                                                                              tokens.at(2).is(T_ANGLE_STRING_LITERAL))) {
602
                QString directive = tokenCache->text(tc.block(), 1);
603
604
605
606
                if (directive == QLatin1String("include") ||
                    directive == QLatin1String("include_next") ||
                    directive == QLatin1String("import")) {
                    include = true;
607
608
609
610
611
                }
            }
        }

        if (!include) {
612
            completionKind = T_EOF_SYMBOL;
613
614
615
616
            start = pos;
        }
    }

617
    if (kind)
618
        *kind = completionKind;
619

con's avatar
con committed
620
621
622
    return start;
}

623
bool CppCodeCompletion::supportsEditor(TextEditor::ITextEditable *editor)
624
625
{ return m_manager->isCppEditor(editor); }

626
627
628
629
630
631
TextEditor::ITextEditable *CppCodeCompletion::editor() const
{ return m_editor; }

int CppCodeCompletion::startPosition() const
{ return m_startPosition; }

con's avatar
con committed
632
633
634
bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditable *editor)
{
    const int pos = editor->position();
635
    TokenCache *tokenCache = m_manager->tokenCache(editor);
636
637
    unsigned token = T_EOF_SYMBOL;

638
    if (startOfOperator(tokenCache, editor, pos, &token, /*want function call=*/ true) != pos) {
639
        if (token == T_POUND) {
640
641
642
            if (TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget())) {
                QTextCursor tc(edit->document());
                tc.setPosition(pos);
643
                return tc.positionInBlock() == 1;
644
645
646
647
648
            }

            return false;
        }

con's avatar
con committed
649
        return true;
650
    }
con's avatar
con committed
651
652
653
654
655
656

    return false;
}

int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
{
657
    int index = startCompletionHelper(editor);
Roberto Raggi's avatar
Roberto Raggi committed
658
659
    if (index != -1) {
        if (m_completionOperator != T_EOF_SYMBOL)
660
661
662
663
            qSort(m_completions.begin(), m_completions.end(), completionItemLessThan);

        // always remove duplicates
        m_completions = removeDuplicates(m_completions);
Roberto Raggi's avatar
Roberto Raggi committed
664
    }
665
666
667
668
669
    return index;
}

int CppCodeCompletion::startCompletionHelper(TextEditor::ITextEditable *editor)
{
con's avatar
con committed
670
671
672
673
674
    TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget());
    if (! edit)
        return -1;

    m_editor = editor;
675

676
677
    const int startOfName = findStartOfName();
    m_startPosition = startOfName;
con's avatar
con committed
678
679
    m_completionOperator = T_EOF_SYMBOL;

680
    int endOfOperator = m_startPosition;
con's avatar
con committed
681
682

    // Skip whitespace preceding this position
683
684
    while (editor->characterAt(endOfOperator - 1).isSpace())
        --endOfOperator;
con's avatar
con committed
685

686
687
    TokenCache *tokenCache = m_manager->tokenCache(editor);
    int endOfExpression = startOfOperator(tokenCache, editor, endOfOperator,
688
689
                                          &m_completionOperator,
                                          /*want function call =*/ true);
con's avatar
con committed
690
691
692
693
694
695
696
697

    Core::IFile *file = editor->file();
    QString fileName = file->fileName();

    int line = 0, column = 0;
    edit->convertPosition(editor->position(), &line, &column);
    // qDebug() << "line:" << line << "column:" << column;

698
699
700
    if (m_completionOperator == T_DOXY_COMMENT) {
        for (int i = 1; i < T_DOXY_LAST_TAG; ++i) {
            TextEditor::CompletionItem item(this);
701
702
            item.text.append(QString::fromLatin1(doxygenTagSpell(i)));
            item.icon = m_icons.keywordIcon();
703
704
705
706
707
708
            m_completions.append(item);
        }

        return m_startPosition;
    }

709
710
711
712
713
714
715
    // Pre-processor completion
    if (m_completionOperator == T_POUND) {
        completePreprocessor();
        m_startPosition = startOfName;
        return m_startPosition;
    }

716
717
718
719
720
721
722
723
724
725
726
727
    // Include completion
    if (m_completionOperator == T_STRING_LITERAL
        || m_completionOperator == T_ANGLE_STRING_LITERAL
        || m_completionOperator == T_SLASH) {

        QTextCursor c = edit->textCursor();
        c.setPosition(endOfExpression);
        if (completeInclude(c))
            m_startPosition = startOfName;
        return m_startPosition;
    }

728
    ExpressionUnderCursor expressionUnderCursor(m_manager->tokenCache(editor));
729
    QTextCursor tc(edit->document());
730

731
    if (m_completionOperator == T_COMMA) {
con's avatar
con committed
732
        tc.setPosition(endOfExpression);
733
        const int start = expressionUnderCursor.startOfFunctionCall(tc);
734
735
736
        if (start == -1) {
            m_completionOperator = T_EOF_SYMBOL;
            return -1;
737
        }
738
739
740
741

        endOfExpression = start;
        m_startPosition = start + 1;
        m_completionOperator = T_LPAREN;
742
743
744
745
    }

    QString expression;
    tc.setPosition(endOfExpression);
746

747
    if (m_completionOperator) {
con's avatar
con committed
748
        expression = expressionUnderCursor(tc);
749

con's avatar
con committed
750
751
752
        if (m_completionOperator == T_LPAREN) {
            if (expression.endsWith(QLatin1String("SIGNAL")))
                m_completionOperator = T_SIGNAL;
753

con's avatar
con committed
754
755
            else if (expression.endsWith(QLatin1String("SLOT")))
                m_completionOperator = T_SLOT;
756

757
758
759
760
            else if (editor->position() != endOfOperator) {
                // We don't want a function completion when the cursor isn't at the opening brace
                expression.clear();
                m_completionOperator = T_EOF_SYMBOL;
761
                m_startPosition = startOfName;
762
            }
con's avatar
con committed
763
764
765
        }
    }

766
    //qDebug() << "***** expression:" << expression;
767
768
    return startCompletionInternal(edit, fileName, line, column, expression, endOfExpression);
}
con's avatar
con committed
769

770
771
772
773
774
775
776
int CppCodeCompletion::startCompletionInternal(TextEditor::BaseTextEditor *edit,
                                               const QString fileName,
                                               unsigned line, unsigned column,
                                               const QString &expr,
                                               int endOfExpression)
{
    QString expression = expr.trimmed();
777
778
    const Snapshot snapshot = m_manager->snapshot();

779
780
781
    Document::Ptr thisDocument = snapshot.document(fileName);
    if (! thisDocument)
        return -1;
con's avatar
con committed
782

783
    typeOfExpression.init(thisDocument, snapshot);
784
785
786

    Scope *scope = thisDocument->scopeAt(line, column);
    Q_ASSERT(scope != 0);
con's avatar
con committed
787

788
    if (expression.isEmpty()) {
789
790
791
792
793
794
795
        if (m_completionOperator == T_EOF_SYMBOL || m_completionOperator == T_COLON_COLON) {
            (void) typeOfExpression(expression, scope);
            globalCompletion(scope);
            if (m_completions.isEmpty())
                return -1;
            return m_startPosition;
        }
con's avatar
con committed
796

797
        else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
con's avatar
con committed
798
799
800
            // Apply signal/slot completion on 'this'
            expression = QLatin1String("this");
        }
801
    }
con's avatar
con committed
802

803
    QList<LookupItem> results = typeOfExpression(expression, scope, TypeOfExpression::Preprocess);
804

805
806
807
808
    if (results.isEmpty()) {
        if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) {
            if (! (expression.isEmpty() || expression == QLatin1String("this"))) {
                expression = QLatin1String("this");
809
                results = typeOfExpression(expression, scope);
810
            }
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
811

812
813
            if (results.isEmpty())
                return -1;
Roberto Raggi's avatar
Cleanup    
Roberto Raggi committed
814

815
        } else if (m_completionOperator == T_LPAREN) {
816
817
818
819
820
821
822
823
            // Find the expression that precedes the current name
            int index = endOfExpression;
            while (m_editor->characterAt(index - 1).isSpace())
                --index;
            index = findStartOfName(index);

            QTextCursor tc(edit->document());
            tc.setPosition(index);
824

825
826
            TokenCache *tokenCache = m_manager->tokenCache(edit->editableInterface());
            ExpressionUnderCursor expressionUnderCursor(tokenCache);
827
            const QString baseExpression = expressionUnderCursor(tc);
828
829

            // Resolve the type of this expression
830
            const QList<LookupItem> results =
831
                    typeOfExpression(baseExpression, scope,
832
                                     TypeOfExpression::Preprocess);
833
834

            // If it's a class, add completions for the constructors
835
836
            foreach (const LookupItem &result, results) {
                if (result.type()->isClassType()) {
837
                    if (completeConstructorOrFunction(results, endOfExpression, true))
838
                        return m_startPosition;
839

840
841
842
                    break;
                }
            }
843
844
845
846
847
848
            return -1;

        } else {
            // nothing to do.
            return -1;

849
        }
con's avatar
con committed
850
851
    }

852
853
    switch (m_completionOperator) {
    case T_LPAREN:
854
        if (completeConstructorOrFunction(results, endOfExpression, false))
855
856
857
858
859
            return m_startPosition;
        break;

    case T_DOT:
    case T_ARROW:
860
        if (completeMember(results))
861
862
863
864
            return m_startPosition;
        break;

    case T_COLON_COLON:
865
        if (completeScope(results))
866
867
868
869
            return m_startPosition;
        break;

    case T_SIGNAL:
870
        if (completeSignal(results))
871
872
873
874
            return m_startPosition;
        break;

    case T_SLOT:
875
        if (completeSlot(results))
876
877
878
879
880
881
882
            return m_startPosition;
        break;

    default:
        break;
    } // end of switch

con's avatar
con committed
883
884
885
886
    // nothing to do.
    return -1;
}

887
void CppCodeCompletion::globalCompletion(Scope *currentScope)
888
{
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
    const LookupContext &context = typeOfExpression.context();

    if (m_completionOperator == T_COLON_COLON) {
        completeNamespace(context.globalNamespace());
        return;
    }

    QList<ClassOrNamespace *> usingBindings;
    ClassOrNamespace *currentBinding = 0;

    for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) {
        if (scope->isBlockScope()) {
            if (ClassOrNamespace *binding = context.lookupType(scope->owner())) {
                for (unsigned i = 0; i < scope->symbolCount(); ++i) {
                    Symbol *member = scope->symbolAt(i);
                    if (! member->name())
                        continue;
                    else if (UsingNamespaceDirective *u = member->asUsingNamespaceDirective()) {
                        if (ClassOrNamespace *b = binding->lookupType(u->name()))
                            usingBindings.append(b);
                    }
                }
            }
        } else if (scope->isFunctionScope() || scope->isClassScope() || scope->isNamespaceScope()) {
            currentBinding = context.lookupType(scope->owner());
            break;
        }
916
917
    }

918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
    for (Scope *scope = currentScope; scope; scope = scope->enclosingScope()) {
        if (scope->isBlockScope()) {
            for (unsigned i = 0; i < scope->symbolCount(); ++i) {
                addCompletionItem(scope->symbolAt(i));
            }
        } else if (scope->isFunctionScope()) {
            Scope *arguments = scope->owner()->asFunction()->arguments();
            for (unsigned i = 0; i < arguments->symbolCount(); ++i) {
                addCompletionItem(arguments->symbolAt(i));
            }
            break;
        } else {
            break;
        }
    }
Roberto Raggi's avatar
Roberto Raggi committed
933
934
935
936
937
938
939
940

    for (; currentBinding; currentBinding = currentBinding->parent()) {
        const QList<Symbol *> symbols = currentBinding->symbols();

        if (! symbols.isEmpty()) {
            if (symbols.first()->isNamespace())
                completeNamespace(currentBinding);
            else
941
                completeClass(currentBinding);
Roberto Raggi's avatar
Roberto Raggi committed
942
943
944
945
946
947
948
949
        }
    }

    foreach (ClassOrNamespace *b, usingBindings)
        completeNamespace(b);

    addKeywords();
    addMacros(context.thisDocument()->fileName(), context.snapshot());
950
951
}

952
bool CppCodeCompletion::completeConstructorOrFunction(const QList<LookupItem> &results,
953
                                                      int endOfExpression, bool toolTipOnly)
con's avatar
con committed
954
{
955
    const LookupContext &context = typeOfExpression.context();
956
957
    QList<Function *> functions;

958
959
    foreach (const LookupItem &result, results) {
        FullySpecifiedType exprTy = result.type().simplified();
Roberto Raggi's avatar
Roberto Raggi committed
960
961

        if (Class *klass = exprTy->asClassType()) {
Roberto Raggi's avatar
Roberto Raggi committed
962
            const Name *className = klass->name();
963
964
965
            if (! className)
                continue; // nothing to do for anonymoous classes.

Roberto Raggi's avatar
Roberto Raggi committed
966
967
            for (unsigned i = 0; i < klass->memberCount(); ++i) {
                Symbol *member = klass->memberAt(i);
Roberto Raggi's avatar
Roberto Raggi committed
968
                const Name *memberName = member->name();
969
970
971
972
973
974
975
976
977
978
979
980

                if (! memberName)
                    continue; // skip anonymous member.

                else if (memberName->isQualifiedNameId())
                    continue; // skip

                if (Function *funTy = member->type()->asFunctionType()) {
                    if (memberName->isEqualTo(className)) {
                        // it's a ctor.
                        functions.append(funTy);
                    }
Roberto Raggi's avatar
Roberto Raggi committed
981
                }
982
            }
Roberto Raggi's avatar
Roberto Raggi committed
983
984

            break;
985
        }
Roberto Raggi's avatar
Roberto Raggi committed
986
987
    }

988
    if (functions.isEmpty()) {
989
990
        foreach (const LookupItem &result, results) {
            FullySpecifiedType ty = result.type().simplified();
Roberto Raggi's avatar
Roberto Raggi committed
991

992
            if (Function *fun = ty->asFunctionType()) {
con's avatar
con committed
993

994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
                if (! fun->name())
                    continue;
                else if (! functions.isEmpty() && functions.first()->scope() != fun->scope())
                    continue; // skip fun, it's an hidden declaration.

                bool newOverload = true;

                foreach (Function *f, functions) {
                    if (fun->isEqualTo(f)) {
                        newOverload = false;
                        break;
                    }
con's avatar
con committed
1006
                }
1007
1008
1009

                if (newOverload)
                    functions.append(fun);
con's avatar
con committed
1010
1011
            }
        }
1012
1013
1014
    }

    if (functions.isEmpty()) {
Roberto Raggi's avatar
Roberto Raggi committed
1015
        const Name *functionCallOp = context.control()->operatorNameId(OperatorNameId::FunctionCallOp);
1016

1017
1018
        foreach (const LookupItem &result, results) {
            FullySpecifiedType ty = result.type().simplified();
1019
            Scope *scope = result.scope();
1020
1021

            if (NamedType *namedTy = ty->asNamedType()) {
1022
                if (ClassOrNamespace *b = context.lookupType(namedTy->name(), scope)) {
1023
1024
                    foreach (Symbol *overload, b->lookup(functionCallOp)) {
                        FullySpecifiedType overloadTy = overload->type().simplified();
1025

1026
1027
                        if (Function *funTy = overloadTy->asFunctionType())
                            functions.append(funTy);
1028
1029
1030
1031
                    }
                }
            }
        }
con's avatar
con committed
1032
1033
    }

1034
1035
1036
1037
1038
    // There are two different kinds of completion we want to provide:
    // 1. If this is a function call, we want to pop up a tooltip that shows the user
    // the possible overloads with their argument types and names.
    // 2. If this is a function definition, we want to offer autocompletion of
    // the function signature.
1039

1040
1041
1042
1043
1044
    // check if function signature autocompletion is appropriate
    if (! functions.isEmpty() && ! toolTipOnly) {

        // function definitions will o