| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | /**************************************************************************
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-06-17 00:01:27 +10:00
										 |  |  | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** Commercial Usage | 
					
						
							| 
									
										
										
										
											2008-12-02 14:17:16 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** 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. | 
					
						
							| 
									
										
										
										
											2008-12-02 14:17:16 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** GNU Lesser General Public License Usage | 
					
						
							| 
									
										
										
										
											2008-12-02 14:17:16 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** 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.
 | 
					
						
							| 
									
										
										
										
											2008-12-02 14:17:16 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | ** If you are unsure which license is appropriate for your use, please | 
					
						
							| 
									
										
										
										
											2009-08-14 09:30:56 +02:00
										 |  |  | ** contact the sales department at http://qt.nokia.com/contact.
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2009-02-25 09:15:00 +01:00
										 |  |  | **************************************************************************/ | 
					
						
							| 
									
										
										
										
											2008-12-02 15:08:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include "cppcodecompletion.h"
 | 
					
						
							|  |  |  | #include "cppmodelmanager.h"
 | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  | #include "cppdoxygen.h"
 | 
					
						
							| 
									
										
										
										
											2009-06-09 13:52:27 +02:00
										 |  |  | #include "cpptoolseditorsupport.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #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>
 | 
					
						
							| 
									
										
										
										
											2008-12-09 15:25:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include <cplusplus/ResolveExpression.h>
 | 
					
						
							|  |  |  | #include <cplusplus/LookupContext.h>
 | 
					
						
							| 
									
										
										
										
											2009-09-22 16:52:27 +02:00
										 |  |  | #include <cplusplus/MatchingText.h>
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include <cplusplus/Overview.h>
 | 
					
						
							|  |  |  | #include <cplusplus/ExpressionUnderCursor.h>
 | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  | #include <cplusplus/BackwardsScanner.h>
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include <cplusplus/TokenUnderCursor.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <coreplugin/icore.h>
 | 
					
						
							|  |  |  | #include <coreplugin/editormanager/editormanager.h>
 | 
					
						
							|  |  |  | #include <texteditor/itexteditor.h>
 | 
					
						
							|  |  |  | #include <texteditor/itexteditable.h>
 | 
					
						
							|  |  |  | #include <texteditor/basetexteditor.h>
 | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  | #include <projectexplorer/projectexplorer.h>
 | 
					
						
							|  |  |  | #include <utils/qtcassert.h>
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <QtCore/QDebug>
 | 
					
						
							|  |  |  | #include <QtCore/QMap>
 | 
					
						
							|  |  |  | #include <QtCore/QFile>
 | 
					
						
							|  |  |  | #include <QtGui/QAction>
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | #include <QtGui/QApplication>
 | 
					
						
							| 
									
										
										
										
											2009-03-26 15:12:31 +01:00
										 |  |  | #include <QtGui/QDesktopWidget>
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include <QtGui/QKeyEvent>
 | 
					
						
							|  |  |  | #include <QtGui/QLabel>
 | 
					
						
							| 
									
										
										
										
											2009-06-19 15:18:36 +02:00
										 |  |  | #include <QtGui/QStyleOption>
 | 
					
						
							|  |  |  | #include <QtGui/QStylePainter>
 | 
					
						
							|  |  |  | #include <QtGui/QTextDocument> // Qt::escape()
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | #include <QtGui/QToolButton>
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include <QtGui/QVBoxLayout>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace CPlusPlus; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace CppTools { | 
					
						
							|  |  |  | namespace Internal { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-19 15:18:36 +02:00
										 |  |  | class FakeToolTipFrame : public QWidget | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     FakeToolTipFrame(QWidget *parent = 0) : | 
					
						
							|  |  |  |         QWidget(parent, Qt::ToolTip | Qt::WindowStaysOnTopHint) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setFocusPolicy(Qt::NoFocus); | 
					
						
							|  |  |  |         setAttribute(Qt::WA_DeleteOnClose); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							|  |  |  |     void paintEvent(QPaintEvent *e); | 
					
						
							|  |  |  |     void resizeEvent(QResizeEvent *e); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-28 13:56:10 +01:00
										 |  |  | class FunctionArgumentWidget : public QLabel | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     Q_OBJECT | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2009-01-28 13:56:10 +01:00
										 |  |  |     FunctionArgumentWidget(); | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     void showFunctionHint(QList<Function *> functionSymbols, | 
					
						
							|  |  |  |                           const LookupContext &context, | 
					
						
							|  |  |  |                           int startPosition); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							|  |  |  |     bool eventFilter(QObject *obj, QEvent *e); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | private slots: | 
					
						
							|  |  |  |     void nextPage(); | 
					
						
							|  |  |  |     void previousPage(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |     void updateArgumentHighlight(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     void updateHintText(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     Function *currentFunction() const | 
					
						
							|  |  |  |     { return m_items.at(m_current); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     int m_startpos; | 
					
						
							|  |  |  |     int m_currentarg; | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     int m_current; | 
					
						
							| 
									
										
										
										
											2009-04-08 10:26:56 +02:00
										 |  |  |     bool m_escapePressed; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     TextEditor::ITextEditor *m_editor; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     QWidget *m_pager; | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |     QLabel *m_numberLabel; | 
					
						
							| 
									
										
										
										
											2009-06-19 15:18:36 +02:00
										 |  |  |     FakeToolTipFrame *m_popupFrame; | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     QList<Function *> m_items; | 
					
						
							| 
									
										
										
										
											2009-02-16 11:20:11 +01:00
										 |  |  |     LookupContext m_context; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |             _item.data = QVariant::fromValue(symbol); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         (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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TextEditor::CompletionItem newCompletionItem(Name *name) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         TextEditor::CompletionItem item(_collector); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |         item.text = overview.prettyName(name); | 
					
						
							|  |  |  |         item.icon = _collector->iconForSymbol(_symbol); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         return item; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void visit(NameId *name) | 
					
						
							|  |  |  |     { _item = newCompletionItem(name); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void visit(TemplateNameId *name) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         _item = newCompletionItem(name); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |         _item.text = QLatin1String(name->identifier()->chars()); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void visit(DestructorNameId *name) | 
					
						
							|  |  |  |     { _item = newCompletionItem(name); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void visit(OperatorNameId *name) | 
					
						
							|  |  |  |     { _item = newCompletionItem(name); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void visit(ConversionNameId *name) | 
					
						
							|  |  |  |     { _item = newCompletionItem(name); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void visit(QualifiedNameId *name) | 
					
						
							|  |  |  |     { _item = newCompletionItem(name->unqualifiedNameId()); } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-02 10:31:44 +01:00
										 |  |  | struct CompleteFunctionDeclaration | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     explicit CompleteFunctionDeclaration(Function *f = 0) | 
					
						
							|  |  |  |         : function(f) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Function *function; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | } // namespace Internal
 | 
					
						
							|  |  |  | } // namespace CppTools
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace CppTools::Internal; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-02 10:31:44 +01:00
										 |  |  | Q_DECLARE_METATYPE(CompleteFunctionDeclaration) | 
					
						
							| 
									
										
										
										
											2009-06-19 15:18:36 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-23 12:16:20 +02:00
										 |  |  | void FakeToolTipFrame::paintEvent(QPaintEvent *) | 
					
						
							| 
									
										
										
										
											2009-06-19 15:18:36 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QStylePainter p(this); | 
					
						
							|  |  |  |     QStyleOptionFrame opt; | 
					
						
							|  |  |  |     opt.init(this); | 
					
						
							|  |  |  |     p.drawPrimitive(QStyle::PE_PanelTipLabel, opt); | 
					
						
							|  |  |  |     p.end(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-23 12:16:20 +02:00
										 |  |  | void FakeToolTipFrame::resizeEvent(QResizeEvent *) | 
					
						
							| 
									
										
										
										
											2009-06-19 15:18:36 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QStyleHintReturnMask frameMask; | 
					
						
							|  |  |  |     QStyleOption option; | 
					
						
							|  |  |  |     option.init(this); | 
					
						
							|  |  |  |     if (style()->styleHint(QStyle::SH_ToolTip_Mask, &option, this, &frameMask)) | 
					
						
							|  |  |  |         setMask(frameMask.region); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | FunctionArgumentWidget::FunctionArgumentWidget(): | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     m_startpos(-1), | 
					
						
							| 
									
										
										
										
											2009-04-08 10:26:56 +02:00
										 |  |  |     m_current(0), | 
					
						
							|  |  |  |     m_escapePressed(false) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-13 15:20:48 +01:00
										 |  |  |     QObject *editorObject = Core::EditorManager::instance()->currentEditor(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     m_editor = qobject_cast<TextEditor::ITextEditor *>(editorObject); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-19 15:18:36 +02:00
										 |  |  |     m_popupFrame = new FakeToolTipFrame(m_editor->widget()); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-13 11:05:39 +02:00
										 |  |  |     QToolButton *downArrow = new QToolButton; | 
					
						
							|  |  |  |     downArrow->setArrowType(Qt::DownArrow); | 
					
						
							|  |  |  |     downArrow->setFixedSize(16, 16); | 
					
						
							|  |  |  |     downArrow->setAutoRaise(true); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-13 11:05:39 +02:00
										 |  |  |     QToolButton *upArrow = new QToolButton; | 
					
						
							|  |  |  |     upArrow->setArrowType(Qt::UpArrow); | 
					
						
							|  |  |  |     upArrow->setFixedSize(16, 16); | 
					
						
							|  |  |  |     upArrow->setAutoRaise(true); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     setParent(m_popupFrame); | 
					
						
							|  |  |  |     setFocusPolicy(Qt::NoFocus); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     m_pager = new QWidget; | 
					
						
							|  |  |  |     QHBoxLayout *hbox = new QHBoxLayout(m_pager); | 
					
						
							|  |  |  |     hbox->setMargin(0); | 
					
						
							|  |  |  |     hbox->setSpacing(0); | 
					
						
							| 
									
										
										
										
											2009-05-13 11:05:39 +02:00
										 |  |  |     hbox->addWidget(upArrow); | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |     m_numberLabel = new QLabel; | 
					
						
							|  |  |  |     hbox->addWidget(m_numberLabel); | 
					
						
							| 
									
										
										
										
											2009-05-13 11:05:39 +02:00
										 |  |  |     hbox->addWidget(downArrow); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |     QHBoxLayout *layout = new QHBoxLayout; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     layout->setMargin(0); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     layout->setSpacing(0); | 
					
						
							|  |  |  |     layout->addWidget(m_pager); | 
					
						
							|  |  |  |     layout->addWidget(this); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     m_popupFrame->setLayout(layout); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-13 11:05:39 +02:00
										 |  |  |     connect(upArrow, SIGNAL(clicked()), SLOT(previousPage())); | 
					
						
							|  |  |  |     connect(downArrow, SIGNAL(clicked()), SLOT(nextPage())); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     setTextFormat(Qt::RichText); | 
					
						
							|  |  |  |     setMargin(1); | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     qApp->installEventFilter(this); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | void FunctionArgumentWidget::showFunctionHint(QList<Function *> functionSymbols, | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |                                               const LookupContext &context, | 
					
						
							|  |  |  |                                               int startPosition) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     Q_ASSERT(!functionSymbols.isEmpty()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     if (m_startpos == startPosition) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |     m_pager->setVisible(functionSymbols.size() > 1); | 
					
						
							| 
									
										
										
										
											2009-02-17 15:11:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     m_items = functionSymbols; | 
					
						
							| 
									
										
										
										
											2009-02-16 11:20:11 +01:00
										 |  |  |     m_context = context; | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     m_startpos = startPosition; | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     m_current = 0; | 
					
						
							| 
									
										
										
										
											2009-04-08 10:26:56 +02:00
										 |  |  |     m_escapePressed = false; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // update the text
 | 
					
						
							|  |  |  |     m_currentarg = -1; | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |     updateArgumentHighlight(); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     m_popupFrame->show(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | 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(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  | void FunctionArgumentWidget::updateArgumentHighlight() | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     int curpos = m_editor->position(); | 
					
						
							|  |  |  |     if (curpos < m_startpos) { | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |         m_popupFrame->close(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         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) | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |         m_popupFrame->close(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (e->type()) { | 
					
						
							| 
									
										
										
										
											2009-04-08 10:26:56 +02:00
										 |  |  |     case QEvent::ShortcutOverride: | 
					
						
							|  |  |  |         if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) { | 
					
						
							|  |  |  |             m_escapePressed = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |     case QEvent::KeyPress: | 
					
						
							| 
									
										
										
										
											2009-04-08 10:26:56 +02:00
										 |  |  |         if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) { | 
					
						
							|  |  |  |             m_escapePressed = true; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |         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; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case QEvent::KeyRelease: | 
					
						
							| 
									
										
										
										
											2009-04-08 10:26:56 +02:00
										 |  |  |         if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && m_escapePressed) { | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |             m_popupFrame->close(); | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |         updateArgumentHighlight(); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     case QEvent::WindowDeactivate: | 
					
						
							|  |  |  |     case QEvent::FocusOut: | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |         if (obj != m_editor->widget()) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         m_popupFrame->close(); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     case QEvent::MouseButtonPress: | 
					
						
							|  |  |  |     case QEvent::MouseButtonRelease: | 
					
						
							|  |  |  |     case QEvent::MouseButtonDblClick: | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     case QEvent::Wheel: { | 
					
						
							|  |  |  |             QWidget *widget = qobject_cast<QWidget *>(obj); | 
					
						
							|  |  |  |             if (! (widget == this || m_popupFrame->isAncestorOf(widget))) { | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |                 m_popupFrame->close(); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void FunctionArgumentWidget::updateHintText() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Overview overview; | 
					
						
							|  |  |  |     overview.setShowReturnTypes(true); | 
					
						
							|  |  |  |     overview.setShowArgumentNames(true); | 
					
						
							| 
									
										
										
										
											2009-05-27 17:02:35 +02:00
										 |  |  |     overview.setMarkedArgument(m_currentarg + 1); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     Function *f = currentFunction(); | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-27 17:02:35 +02:00
										 |  |  |     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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 14:46:03 +01:00
										 |  |  |     m_numberLabel->setText(tr("%1 of %2").arg(m_current + 1).arg(m_items.size())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_popupFrame->setFixedWidth(m_popupFrame->minimumSizeHint().width()); | 
					
						
							| 
									
										
										
										
											2009-03-26 15:12:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const QDesktopWidget *desktop = QApplication::desktop(); | 
					
						
							| 
									
										
										
										
											2009-06-03 20:45:49 +02:00
										 |  |  | #ifdef Q_WS_MAC
 | 
					
						
							| 
									
										
										
										
											2009-04-06 17:11:32 +02:00
										 |  |  |     const QRect screen = desktop->availableGeometry(desktop->screenNumber(m_editor->widget())); | 
					
						
							| 
									
										
										
										
											2009-03-26 15:12:31 +01:00
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2009-04-06 17:11:32 +02:00
										 |  |  |     const QRect screen = desktop->screenGeometry(desktop->screenNumber(m_editor->widget())); | 
					
						
							| 
									
										
										
										
											2009-03-26 15:12:31 +01:00
										 |  |  | #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); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-09 13:52:27 +02:00
										 |  |  | CppQuickFixCollector::CppQuickFixCollector(CppModelManager *modelManager) | 
					
						
							|  |  |  |     : _modelManager(modelManager), _editor(0) | 
					
						
							|  |  |  | { } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | CppQuickFixCollector::~CppQuickFixCollector() | 
					
						
							|  |  |  | { } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool CppQuickFixCollector::supportsEditor(TextEditor::ITextEditable *editor) | 
					
						
							|  |  |  | { return _modelManager->isCppEditor(editor); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool CppQuickFixCollector::triggersCompletion(TextEditor::ITextEditable *) | 
					
						
							|  |  |  | { return false; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CppQuickFixCollector::startCompletion(TextEditor::ITextEditable *editor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _editor = editor; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (CppEditorSupport *extra = _modelManager->editorSupport(editor)) { | 
					
						
							|  |  |  |         const QList<QuickFixOperationPtr> quickFixes = extra->quickFixes(); | 
					
						
							|  |  |  |         if (! quickFixes.isEmpty()) { | 
					
						
							|  |  |  |             int i = 0; | 
					
						
							|  |  |  |             foreach (QuickFixOperationPtr op, quickFixes) { | 
					
						
							|  |  |  |                 TextEditor::CompletionItem item(this); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                 item.text = op->description(); | 
					
						
							|  |  |  |                 item.data = QVariant::fromValue(i); | 
					
						
							| 
									
										
										
										
											2009-06-09 13:52:27 +02:00
										 |  |  |                 _completions.append(item); | 
					
						
							|  |  |  |                 ++i; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return editor->position(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppQuickFixCollector::completions(QList<TextEditor::CompletionItem> *completions) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     completions->append(_completions); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppQuickFixCollector::complete(const TextEditor::CompletionItem &item) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CppEditorSupport *extra = _modelManager->editorSupport(_editor); | 
					
						
							|  |  |  |     const QList<QuickFixOperationPtr> quickFixes = extra->quickFixes(); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |     QuickFixOperationPtr quickFix = quickFixes.at(item.data.toInt()); | 
					
						
							| 
									
										
										
										
											2009-06-09 13:52:27 +02:00
										 |  |  |     TextEditor::BaseTextEditor *ed = qobject_cast<TextEditor::BaseTextEditor *>(_editor->widget()); | 
					
						
							|  |  |  |     quickFix->apply(ed->textCursor()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppQuickFixCollector::cleanup() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _completions.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-28 13:56:10 +01:00
										 |  |  | CppCodeCompletion::CppCodeCompletion(CppModelManager *manager) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     : ICompletionCollector(manager), | 
					
						
							|  |  |  |       m_manager(manager), | 
					
						
							| 
									
										
										
										
											2009-10-21 16:51:54 +02:00
										 |  |  |       m_editor(0), | 
					
						
							|  |  |  |       m_startPosition(-1), | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  |       m_caseSensitivity(Qt::CaseSensitive), | 
					
						
							| 
									
										
										
										
											2009-10-05 18:42:46 +02:00
										 |  |  |       m_autoInsertBrackets(true), | 
					
						
							| 
									
										
										
										
											2009-10-21 16:51:54 +02:00
										 |  |  |       m_partialCompletionEnabled(true), | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |       m_forcedCompletion(false), | 
					
						
							|  |  |  |       m_completionOperator(T_EOF_SYMBOL) | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | QIcon CppCodeCompletion::iconForSymbol(Symbol *symbol) const | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return m_icons.iconForSymbol(symbol); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Qt::CaseSensitivity CppCodeCompletion::caseSensitivity() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_caseSensitivity; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_caseSensitivity = caseSensitivity; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-26 11:10:22 +02:00
										 |  |  | bool CppCodeCompletion::autoInsertBrackets() const | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-10-05 18:42:46 +02:00
										 |  |  |     return m_autoInsertBrackets; | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-26 11:10:22 +02:00
										 |  |  | void CppCodeCompletion::setAutoInsertBrackets(bool autoInsertBrackets) | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-10-05 18:42:46 +02:00
										 |  |  |     m_autoInsertBrackets = autoInsertBrackets; | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-16 16:55:44 +01:00
										 |  |  | bool CppCodeCompletion::isPartialCompletionEnabled() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_partialCompletionEnabled; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::setPartialCompletionEnabled(bool partialCompletionEnabled) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_partialCompletionEnabled = partialCompletionEnabled; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |   Searches backwards for an access operator. | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | */ | 
					
						
							|  |  |  | static int startOfOperator(TextEditor::ITextEditable *editor, | 
					
						
							|  |  |  |                            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; | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |     int completionKind = T_EOF_SYMBOL; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |     switch (ch.toLatin1()) { | 
					
						
							|  |  |  |     case '.': | 
					
						
							|  |  |  |         if (ch2 != QLatin1Char('.')) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_DOT; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |             --start; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case ',': | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |         completionKind = T_COMMA; | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |         --start; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case '(': | 
					
						
							|  |  |  |         if (wantFunctionCall) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_LPAREN; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |             --start; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case ':': | 
					
						
							|  |  |  |         if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':')) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_COLON_COLON; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |             start -= 2; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case '>': | 
					
						
							|  |  |  |         if (ch2 == QLatin1Char('-')) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_ARROW; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |             start -= 2; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case '*': | 
					
						
							|  |  |  |         if (ch2 == QLatin1Char('.')) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_DOT_STAR; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |             start -= 2; | 
					
						
							|  |  |  |         } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>')) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_ARROW_STAR; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |             start -= 3; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case '\\': | 
					
						
							|  |  |  |     case '@': | 
					
						
							|  |  |  |         if (ch2.isNull() || ch2.isSpace()) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_DOXY_COMMENT; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |             --start; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case '<': | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |         completionKind = T_ANGLE_STRING_LITERAL; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |         --start; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case '"': | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |         completionKind = T_STRING_LITERAL; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |         --start; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case '/': | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |         completionKind = T_SLASH; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |         --start; | 
					
						
							| 
									
										
										
										
											2009-08-28 13:43:06 +02:00
										 |  |  |         break; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |     if (start == pos) | 
					
						
							|  |  |  |         return start; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget()); | 
					
						
							|  |  |  |     QTextCursor tc(edit->textCursor()); | 
					
						
							|  |  |  |     tc.setPosition(pos); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     // Include completion: make sure the quote character is the first one on the line
 | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |     if (completionKind == T_STRING_LITERAL) { | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |         QTextCursor s = tc; | 
					
						
							|  |  |  |         s.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); | 
					
						
							|  |  |  |         QString sel = s.selectedText(); | 
					
						
							|  |  |  |         if (sel.indexOf(QLatin1Char('"')) < sel.length() - 1) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_EOF_SYMBOL; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |             start = pos; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |     if (completionKind == T_COMMA) { | 
					
						
							| 
									
										
										
										
											2009-10-08 15:32:12 +02:00
										 |  |  |         ExpressionUnderCursor expressionUnderCursor; | 
					
						
							|  |  |  |         if (expressionUnderCursor.startOfFunctionCall(tc) == -1) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_EOF_SYMBOL; | 
					
						
							| 
									
										
										
										
											2009-10-08 15:32:12 +02:00
										 |  |  |             start = pos; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |     static CPlusPlus::TokenUnderCursor tokenUnderCursor; | 
					
						
							|  |  |  |     const SimpleToken tk = tokenUnderCursor(tc); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |     if (completionKind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) { | 
					
						
							|  |  |  |         completionKind = T_EOF_SYMBOL; | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         start = pos; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     // Don't complete in comments or strings, but still check for include completion
 | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |         start = pos; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Include completion: can be triggered by slash, but only in a string
 | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |     else if (completionKind == T_SLASH && (tk.isNot(T_STRING_LITERAL) && tk.isNot(T_ANGLE_STRING_LITERAL))) { | 
					
						
							|  |  |  |         completionKind = T_EOF_SYMBOL; | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         start = pos; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |     else if (completionKind == T_LPAREN) { | 
					
						
							| 
									
										
										
										
											2009-05-27 11:12:06 +02:00
										 |  |  |         const QList<SimpleToken> &tokens = tokenUnderCursor.tokens(); | 
					
						
							|  |  |  |         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); | 
					
						
							| 
									
										
										
										
											2009-05-27 13:10:38 +02:00
										 |  |  |                 if (previousToken.is(T_IDENTIFIER) || previousToken.is(T_GREATER) | 
					
						
							|  |  |  |                     || previousToken.is(T_SIGNAL) || previousToken.is(T_SLOT)) | 
					
						
							| 
									
										
										
										
											2009-05-27 11:12:06 +02:00
										 |  |  |                     break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (i == tokens.size()) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_EOF_SYMBOL; | 
					
						
							| 
									
										
										
										
											2009-05-27 11:12:06 +02:00
										 |  |  |             start = pos; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     // Check for include preprocessor directive
 | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |     else if (completionKind == T_STRING_LITERAL || completionKind == T_ANGLE_STRING_LITERAL || completionKind == T_SLASH) { | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |         bool include = false; | 
					
						
							| 
									
										
										
										
											2009-10-08 15:59:43 +02:00
										 |  |  |         const QList<SimpleToken> &tokens = tokenUnderCursor.tokens(); | 
					
						
							|  |  |  |         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))) { | 
					
						
							|  |  |  |                 QStringRef directive = tokens.at(1).text(); | 
					
						
							|  |  |  |                 if (directive == QLatin1String("include") || | 
					
						
							|  |  |  |                     directive == QLatin1String("include_next") || | 
					
						
							|  |  |  |                     directive == QLatin1String("import")) { | 
					
						
							|  |  |  |                     include = true; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!include) { | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |             completionKind = T_EOF_SYMBOL; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |             start = pos; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |     if (kind) | 
					
						
							| 
									
										
										
										
											2009-10-20 16:37:01 +02:00
										 |  |  |         *kind = completionKind; | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     return start; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-07 15:56:02 +02:00
										 |  |  | bool CppCodeCompletion::supportsEditor(TextEditor::ITextEditable *editor) | 
					
						
							| 
									
										
										
										
											2009-04-02 10:19:23 +02:00
										 |  |  | { return m_manager->isCppEditor(editor); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | bool CppCodeCompletion::triggersCompletion(TextEditor::ITextEditable *editor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const int pos = editor->position(); | 
					
						
							|  |  |  |     if (startOfOperator(editor, pos, /*token =*/ 0, | 
					
						
							|  |  |  |                         /*want function call=*/ true) != pos) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(editor->widget()); | 
					
						
							|  |  |  |     if (! edit) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_editor = editor; | 
					
						
							| 
									
										
										
										
											2009-03-26 15:12:12 +01:00
										 |  |  |     const int startOfName = findStartOfName(); | 
					
						
							|  |  |  |     m_startPosition = startOfName; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     m_completionOperator = T_EOF_SYMBOL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-26 15:51:14 +01:00
										 |  |  |     int endOfOperator = m_startPosition; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Skip whitespace preceding this position
 | 
					
						
							| 
									
										
										
										
											2009-01-26 15:51:14 +01:00
										 |  |  |     while (editor->characterAt(endOfOperator - 1).isSpace()) | 
					
						
							|  |  |  |         --endOfOperator; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-26 15:51:14 +01:00
										 |  |  |     int endOfExpression = startOfOperator(editor, endOfOperator, | 
					
						
							|  |  |  |                                           &m_completionOperator, | 
					
						
							|  |  |  |                                           /*want function call =*/ true); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |     if (m_completionOperator == T_DOXY_COMMENT) { | 
					
						
							|  |  |  |         for (int i = 1; i < T_DOXY_LAST_TAG; ++i) { | 
					
						
							|  |  |  |             TextEditor::CompletionItem item(this); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |             item.text.append(QString::fromLatin1(doxygenTagSpell(i))); | 
					
						
							|  |  |  |             item.icon = m_icons.keywordIcon(); | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |             m_completions.append(item); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return m_startPosition; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     // 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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     ExpressionUnderCursor expressionUnderCursor; | 
					
						
							|  |  |  |     QTextCursor tc(edit->document()); | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     if (m_completionOperator == T_COMMA) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         tc.setPosition(endOfExpression); | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |         const int start = expressionUnderCursor.startOfFunctionCall(tc); | 
					
						
							| 
									
										
										
										
											2009-10-08 15:32:12 +02:00
										 |  |  |         if (start == -1) { | 
					
						
							|  |  |  |             m_completionOperator = T_EOF_SYMBOL; | 
					
						
							|  |  |  |             return -1; | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-10-08 15:32:12 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         endOfExpression = start; | 
					
						
							|  |  |  |         m_startPosition = start + 1; | 
					
						
							|  |  |  |         m_completionOperator = T_LPAREN; | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString expression; | 
					
						
							|  |  |  |     tc.setPosition(endOfExpression); | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     if (m_completionOperator) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         expression = expressionUnderCursor(tc); | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         if (m_completionOperator == T_LPAREN) { | 
					
						
							|  |  |  |             if (expression.endsWith(QLatin1String("SIGNAL"))) | 
					
						
							|  |  |  |                 m_completionOperator = T_SIGNAL; | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             else if (expression.endsWith(QLatin1String("SLOT"))) | 
					
						
							|  |  |  |                 m_completionOperator = T_SLOT; | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-26 15:51:14 +01:00
										 |  |  |             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; | 
					
						
							| 
									
										
										
										
											2009-03-26 15:12:12 +01:00
										 |  |  |                 m_startPosition = startOfName; | 
					
						
							| 
									
										
										
										
											2009-01-26 15:51:14 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     //qDebug() << "***** expression:" << expression;
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-12 10:07:58 +01:00
										 |  |  |     const Snapshot snapshot = m_manager->snapshot(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (Document::Ptr thisDocument = snapshot.value(fileName)) { | 
					
						
							| 
									
										
										
										
											2009-09-29 12:46:42 +02:00
										 |  |  |         Symbol *lastVisibleSymbol = thisDocument->findSymbolAt(line, column); | 
					
						
							| 
									
										
										
										
											2008-12-12 10:07:58 +01:00
										 |  |  |         typeOfExpression.setSnapshot(m_manager->snapshot()); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-29 12:46:42 +02:00
										 |  |  |         QList<TypeOfExpression::Result> resolvedTypes = typeOfExpression(expression, thisDocument, lastVisibleSymbol, | 
					
						
							| 
									
										
										
										
											2008-12-11 11:27:07 +01:00
										 |  |  |                                                                          TypeOfExpression::Preprocess); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         LookupContext context = typeOfExpression.lookupContext(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!typeOfExpression.expressionAST() && (! m_completionOperator || | 
					
						
							|  |  |  |                                                     m_completionOperator == T_COLON_COLON)) { | 
					
						
							|  |  |  |             if (!m_completionOperator) { | 
					
						
							|  |  |  |                 addKeywords(); | 
					
						
							|  |  |  |                 addMacros(context); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const QList<Scope *> scopes = context.expand(context.visibleScopes()); | 
					
						
							|  |  |  |             foreach (Scope *scope, scopes) { | 
					
						
							|  |  |  |                 for (unsigned i = 0; i < scope->symbolCount(); ++i) { | 
					
						
							|  |  |  |                     addCompletionItem(scope->symbolAt(i)); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return m_startPosition; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // qDebug() << "found" << resolvedTypes.count() << "symbols for expression:" << expression;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (resolvedTypes.isEmpty() && (m_completionOperator == T_SIGNAL || | 
					
						
							|  |  |  |                                         m_completionOperator == T_SLOT)) { | 
					
						
							|  |  |  |             // Apply signal/slot completion on 'this'
 | 
					
						
							|  |  |  |             expression = QLatin1String("this"); | 
					
						
							| 
									
										
										
										
											2009-09-29 12:46:42 +02:00
										 |  |  |             resolvedTypes = typeOfExpression(expression, thisDocument, lastVisibleSymbol); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             context = typeOfExpression.lookupContext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 12:12:14 +01:00
										 |  |  |         if (! resolvedTypes.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  |             if (m_completionOperator == T_LPAREN && | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |                 completeConstructorOrFunction(resolvedTypes, context, endOfExpression, false)) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 return m_startPosition; | 
					
						
							| 
									
										
										
										
											2009-02-17 12:12:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-04 16:40:42 +01:00
										 |  |  |             } else if ((m_completionOperator == T_DOT || m_completionOperator == T_ARROW) && | 
					
						
							| 
									
										
										
										
											2008-12-30 11:45:41 +01:00
										 |  |  |                       completeMember(resolvedTypes, context)) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 return m_startPosition; | 
					
						
							| 
									
										
										
										
											2009-02-17 12:12:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 11:35:30 +01:00
										 |  |  |             } else if (m_completionOperator == T_COLON_COLON && completeScope(resolvedTypes, context)) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 return m_startPosition; | 
					
						
							| 
									
										
										
										
											2009-02-17 12:12:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             } else if (m_completionOperator == T_SIGNAL      && completeSignal(resolvedTypes, context)) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 return m_startPosition; | 
					
						
							| 
									
										
										
										
											2009-02-17 12:12:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             } else if (m_completionOperator == T_SLOT        && completeSlot(resolvedTypes, context)) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 return m_startPosition; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-02-04 16:40:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (m_completionOperator == T_LPAREN) { | 
					
						
							|  |  |  |             // 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); | 
					
						
							| 
									
										
										
										
											2009-10-16 12:22:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             const QString baseExpression = expressionUnderCursor(tc); | 
					
						
							| 
									
										
										
										
											2009-02-04 16:40:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Resolve the type of this expression
 | 
					
						
							| 
									
										
										
										
											2009-10-16 12:22:33 +02:00
										 |  |  |             const QList<TypeOfExpression::Result> results = | 
					
						
							|  |  |  |                     typeOfExpression(baseExpression, thisDocument, | 
					
						
							|  |  |  |                                      lastVisibleSymbol, | 
					
						
							|  |  |  |                                      TypeOfExpression::Preprocess); | 
					
						
							| 
									
										
										
										
											2009-02-04 16:40:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // If it's a class, add completions for the constructors
 | 
					
						
							|  |  |  |             foreach (const TypeOfExpression::Result &result, results) { | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |                 if (result.first->isClassType()) { | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |                     if (completeConstructorOrFunction(results, context, endOfExpression, true)) | 
					
						
							| 
									
										
										
										
											2009-02-04 16:40:42 +01:00
										 |  |  |                         return m_startPosition; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // nothing to do.
 | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-16 12:22:33 +02:00
										 |  |  | bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpression::Result> &results, | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  |                                                       const LookupContext &context, | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |                                                       int endOfExpression, bool toolTipOnly) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     QList<Function *> functions; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 11:50:56 +01:00
										 |  |  |     foreach (const TypeOfExpression::Result &result, results) { | 
					
						
							| 
									
										
										
										
											2009-10-16 12:22:33 +02:00
										 |  |  |         FullySpecifiedType exprTy = result.first.simplified(); | 
					
						
							| 
									
										
										
										
											2009-02-17 11:50:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (Class *klass = exprTy->asClassType()) { | 
					
						
							| 
									
										
										
										
											2009-05-19 12:15:30 +02:00
										 |  |  |             Name *className = klass->name(); | 
					
						
							|  |  |  |             if (! className) | 
					
						
							|  |  |  |                 continue; // nothing to do for anonymoous classes.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 11:50:56 +01:00
										 |  |  |             for (unsigned i = 0; i < klass->memberCount(); ++i) { | 
					
						
							|  |  |  |                 Symbol *member = klass->memberAt(i); | 
					
						
							| 
									
										
										
										
											2009-05-19 12:15:30 +02:00
										 |  |  |                 Name *memberName = member->name(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 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); | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2009-02-17 11:50:56 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2009-02-12 11:41:52 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-02-17 11:50:56 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2009-02-12 11:41:52 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-02-17 11:50:56 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     if (functions.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2009-10-16 12:22:33 +02:00
										 |  |  |         foreach (const TypeOfExpression::Result &result, results) { | 
					
						
							|  |  |  |             FullySpecifiedType ty = result.first.simplified(); | 
					
						
							| 
									
										
										
										
											2009-02-17 11:50:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |             if (Function *fun = ty->asFunctionType()) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-19 12:15:30 +02:00
										 |  |  |                 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; | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2009-05-19 12:15:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 if (newOverload) | 
					
						
							|  |  |  |                     functions.append(fun); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-10-16 12:22:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (functions.isEmpty()) { | 
					
						
							|  |  |  |         ResolveExpression resolveExpression(context); | 
					
						
							|  |  |  |         ResolveClass resolveClass; | 
					
						
							|  |  |  |         Name *functionCallOp = context.control()->operatorNameId(OperatorNameId::FunctionCallOp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach (const TypeOfExpression::Result &result, results) { | 
					
						
							|  |  |  |             FullySpecifiedType ty = result.first.simplified(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (NamedType *namedTy = ty->asNamedType()) { | 
					
						
							|  |  |  |                 const QList<Symbol *> classObjectCandidates = resolveClass(namedTy->name(), result, context); | 
					
						
							| 
									
										
										
										
											2009-05-19 12:15:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-16 12:22:33 +02:00
										 |  |  |                 foreach (Symbol *classObjectCandidate, classObjectCandidates) { | 
					
						
							|  |  |  |                     if (Class *klass = classObjectCandidate->asClass()) { | 
					
						
							|  |  |  |                         const QList<TypeOfExpression::Result> overloads = | 
					
						
							|  |  |  |                                 resolveExpression.resolveMember(functionCallOp, klass, | 
					
						
							|  |  |  |                                                                 namedTy->name()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         foreach (const TypeOfExpression::Result &overloadResult, overloads) { | 
					
						
							|  |  |  |                             FullySpecifiedType overloadTy = overloadResult.first.simplified(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             if (Function *funTy = overloadTy->asFunctionType()) | 
					
						
							|  |  |  |                                 functions.append(funTy); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |     // 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.
 | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |     // check if function signature autocompletion is appropriate
 | 
					
						
							|  |  |  |     if (! functions.isEmpty() && ! toolTipOnly) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // function definitions will only happen in class or namespace scope,
 | 
					
						
							|  |  |  |         // so get the current location's enclosing scope.
 | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // get current line and column
 | 
					
						
							|  |  |  |         TextEditor::BaseTextEditor *edit = qobject_cast<TextEditor::BaseTextEditor *>(m_editor->widget()); | 
					
						
							|  |  |  |         int lineSigned = 0, columnSigned = 0; | 
					
						
							|  |  |  |         edit->convertPosition(m_editor->position(), &lineSigned, &columnSigned); | 
					
						
							|  |  |  |         unsigned line = lineSigned, column = columnSigned; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // find a scope that encloses the current location, starting from the lastVisibileSymbol
 | 
					
						
							|  |  |  |         // and moving outwards
 | 
					
						
							| 
									
										
										
										
											2009-10-20 17:17:11 +02:00
										 |  |  |         Scope *sc = 0; | 
					
						
							|  |  |  |         if (context.symbol()) | 
					
						
							|  |  |  |             sc = context.symbol()->scope(); | 
					
						
							|  |  |  |         else if (context.thisDocument()) | 
					
						
							|  |  |  |             sc = context.thisDocument()->globalSymbols(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         while (sc && sc->enclosingScope()) { | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  |             unsigned startLine, startColumn; | 
					
						
							|  |  |  |             context.thisDocument()->translationUnit()->getPosition(sc->owner()->startOffset(), &startLine, &startColumn); | 
					
						
							|  |  |  |             unsigned endLine, endColumn; | 
					
						
							|  |  |  |             context.thisDocument()->translationUnit()->getPosition(sc->owner()->endOffset(), &endLine, &endColumn); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |             if (startLine <= line && line <= endLine) { | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  |                 if ((startLine != line || startColumn <= column) | 
					
						
							|  |  |  |                     && (endLine != line || column <= endColumn)) | 
					
						
							|  |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             sc = sc->enclosingScope(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |         if (sc && (sc->isClassScope() || sc->isNamespaceScope())) { | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  |             // It may still be a function call. If the whole line parses as a function
 | 
					
						
							|  |  |  |             // declaration, we should be certain that it isn't.
 | 
					
						
							|  |  |  |             bool autocompleteSignature = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             QTextCursor tc(edit->document()); | 
					
						
							|  |  |  |             tc.setPosition(endOfExpression); | 
					
						
							|  |  |  |             BackwardsScanner bs(tc); | 
					
						
							|  |  |  |             QString possibleDecl = bs.mid(bs.startOfLine(bs.startToken())).trimmed().append("();"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Document::Ptr doc = Document::create(QLatin1String("<completion>")); | 
					
						
							|  |  |  |             doc->setSource(possibleDecl.toLatin1()); | 
					
						
							|  |  |  |             if (doc->parse(Document::ParseDeclaration)) { | 
					
						
							|  |  |  |                 doc->check(); | 
					
						
							|  |  |  |                 if (SimpleDeclarationAST *sd = doc->translationUnit()->ast()->asSimpleDeclaration()) { | 
					
						
							| 
									
										
										
										
											2009-11-19 17:23:53 +01:00
										 |  |  |                     if (sd->declarators && | 
					
						
							|  |  |  |                         sd->declarators->declarator->postfix_declarators | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  |                         && sd->declarators->declarator->postfix_declarators->asFunctionDeclarator()) { | 
					
						
							|  |  |  |                         autocompleteSignature = true; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (autocompleteSignature) { | 
					
						
							|  |  |  |                 // set up signature autocompletion
 | 
					
						
							|  |  |  |                 foreach (Function *f, functions) { | 
					
						
							|  |  |  |                     Overview overview; | 
					
						
							|  |  |  |                     overview.setShowArgumentNames(true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-02 10:31:44 +01:00
										 |  |  |                     // gets: "parameter list) cv-spec",
 | 
					
						
							|  |  |  |                     QString completion = overview(f->type()).mid(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     TextEditor::CompletionItem item(this); | 
					
						
							|  |  |  |                     item.text = completion; | 
					
						
							|  |  |  |                     item.data = QVariant::fromValue(CompleteFunctionDeclaration(f)); | 
					
						
							|  |  |  |                     m_completions.append(item); | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-09 10:10:31 +01:00
										 |  |  |     if (! functions.empty()) { | 
					
						
							| 
									
										
										
										
											2009-10-19 14:14:28 +02:00
										 |  |  |         // set up function call tooltip
 | 
					
						
							| 
									
										
										
										
											2009-05-19 12:15:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |         // Recreate if necessary
 | 
					
						
							|  |  |  |         if (!m_functionArgumentWidget) | 
					
						
							|  |  |  |             m_functionArgumentWidget = new FunctionArgumentWidget; | 
					
						
							| 
									
										
										
										
											2009-02-12 11:41:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |         m_functionArgumentWidget->showFunctionHint(functions, | 
					
						
							|  |  |  |                                                    typeOfExpression.lookupContext(), | 
					
						
							|  |  |  |                                                    m_startPosition); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-16 11:08:06 +02:00
										 |  |  | bool CppCodeCompletion::completeMember(const QList<TypeOfExpression::Result> &baseResults, | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                                        const LookupContext &context) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-10-16 11:08:06 +02:00
										 |  |  |     if (baseResults.isEmpty()) | 
					
						
							| 
									
										
										
										
											2008-12-29 11:53:40 +01:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-16 11:08:06 +02:00
										 |  |  |     ResolveExpression resolveExpression(context); | 
					
						
							|  |  |  |     ResolveClass resolveClass; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool replacedDotOperator = false; | 
					
						
							|  |  |  |     const QList<TypeOfExpression::Result> classObjectResults = | 
					
						
							|  |  |  |             resolveExpression.resolveBaseExpression(baseResults, | 
					
						
							|  |  |  |                                                     m_completionOperator, | 
					
						
							|  |  |  |                                                     &replacedDotOperator); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QList<Symbol *> classObjectCandidates; | 
					
						
							|  |  |  |     foreach (const TypeOfExpression::Result &r, classObjectResults) { | 
					
						
							|  |  |  |         FullySpecifiedType ty = r.first.simplified(); | 
					
						
							| 
									
										
										
										
											2009-01-05 15:23:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-16 11:08:06 +02:00
										 |  |  |         if (Class *klass = ty->asClassType()) | 
					
						
							|  |  |  |             classObjectCandidates.append(klass); | 
					
						
							| 
									
										
										
										
											2009-01-05 15:23:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-16 11:08:06 +02:00
										 |  |  |         else if (NamedType *namedTy = ty->asNamedType()) { | 
					
						
							|  |  |  |             Name *className = namedTy->name(); | 
					
						
							|  |  |  |             const QList<Symbol *> classes = resolveClass(className, r, context); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-16 11:08:06 +02:00
										 |  |  |             foreach (Symbol *c, classes) { | 
					
						
							|  |  |  |                 if (Class *klass = c->asClass()) | 
					
						
							| 
									
										
										
										
											2008-12-29 11:53:40 +01:00
										 |  |  |                     classObjectCandidates.append(klass); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-04 18:21:35 +01:00
										 |  |  |     if (replacedDotOperator && ! classObjectCandidates.isEmpty()) { | 
					
						
							|  |  |  |         // Replace . with ->
 | 
					
						
							|  |  |  |         int length = m_editor->position() - m_startPosition + 1; | 
					
						
							|  |  |  |         m_editor->setCurPos(m_startPosition - 1); | 
					
						
							|  |  |  |         m_editor->replace(length, QLatin1String("->")); | 
					
						
							|  |  |  |         ++m_startPosition; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     completeClass(classObjectCandidates, context, /*static lookup = */ false); | 
					
						
							|  |  |  |     if (! m_completions.isEmpty()) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 11:35:30 +01:00
										 |  |  | bool CppCodeCompletion::completeScope(const QList<TypeOfExpression::Result> &results, | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                                       const LookupContext &context) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-18 15:56:59 +01:00
										 |  |  |     QList<Symbol *> classes, namespaces; | 
					
						
							| 
									
										
										
										
											2008-12-30 11:35:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-18 15:56:59 +01:00
										 |  |  |     foreach (TypeOfExpression::Result result, results) { | 
					
						
							| 
									
										
										
										
											2008-12-30 11:35:30 +01:00
										 |  |  |         FullySpecifiedType ty = result.first; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-18 15:56:59 +01:00
										 |  |  |         if (Class *classTy = ty->asClassType()) | 
					
						
							|  |  |  |             classes.append(classTy); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-18 15:56:59 +01:00
										 |  |  |         else if (Namespace *namespaceTy = ty->asNamespaceType()) | 
					
						
							|  |  |  |             namespaces.append(namespaceTy); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-18 15:56:59 +01:00
										 |  |  |     if (! classes.isEmpty()) | 
					
						
							|  |  |  |         completeClass(classes, context); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     else if (! namespaces.isEmpty() && m_completions.isEmpty()) | 
					
						
							|  |  |  |         completeNamespace(namespaces, context); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     return ! m_completions.isEmpty(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::addKeywords() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // keyword completion items.
 | 
					
						
							| 
									
										
										
										
											2009-01-14 12:35:22 +01:00
										 |  |  |     for (int i = T_FIRST_KEYWORD; i < T_FIRST_OBJC_AT_KEYWORD; ++i) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         TextEditor::CompletionItem item(this); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |         item.text = QLatin1String(Token::name(i)); | 
					
						
							|  |  |  |         item.icon = m_icons.keywordIcon(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         m_completions.append(item); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::addMacros(const LookupContext &context) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QSet<QString> processed; | 
					
						
							| 
									
										
										
										
											2009-02-17 11:09:07 +01:00
										 |  |  |     QSet<QString> definedMacros; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     addMacros_helper(context, context.thisDocument()->fileName(), | 
					
						
							|  |  |  |                      &processed, &definedMacros); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 11:09:07 +01:00
										 |  |  |     foreach (const QString ¯oName, definedMacros) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         TextEditor::CompletionItem item(this); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |         item.text = macroName; | 
					
						
							|  |  |  |         item.icon = m_icons.macroIcon(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         m_completions.append(item); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 11:09:07 +01:00
										 |  |  | void CppCodeCompletion::addMacros_helper(const LookupContext &context, | 
					
						
							|  |  |  |                                          const QString &fileName, | 
					
						
							|  |  |  |                                          QSet<QString> *processed, | 
					
						
							|  |  |  |                                          QSet<QString> *definedMacros) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Document::Ptr doc = context.document(fileName); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (! doc || processed->contains(doc->fileName())) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     processed->insert(doc->fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     foreach (const Document::Include &i, doc->includes()) { | 
					
						
							|  |  |  |         addMacros_helper(context, i.fileName(), processed, definedMacros); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     foreach (const Macro ¯o, doc->definedMacros()) { | 
					
						
							|  |  |  |         const QString macroName = QString::fromUtf8(macro.name().constData(), macro.name().length()); | 
					
						
							|  |  |  |         if (! macro.isHidden()) | 
					
						
							|  |  |  |             definedMacros->insert(macroName); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             definedMacros->remove(macroName); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | void CppCodeCompletion::addCompletionItem(Symbol *symbol) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ConvertToCompletionItem toCompletionItem(this); | 
					
						
							|  |  |  |     if (TextEditor::CompletionItem item = toCompletionItem(symbol)) | 
					
						
							|  |  |  |         m_completions.append(item); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  | bool CppCodeCompletion::completeInclude(const QTextCursor &cursor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QString directoryPrefix; | 
					
						
							|  |  |  |     if (m_completionOperator == T_SLASH) { | 
					
						
							|  |  |  |         QTextCursor c = cursor; | 
					
						
							|  |  |  |         c.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); | 
					
						
							|  |  |  |         QString sel = c.selectedText(); | 
					
						
							|  |  |  |         int startCharPos = sel.indexOf(QLatin1Char('"')); | 
					
						
							|  |  |  |         if (startCharPos == -1) { | 
					
						
							|  |  |  |             startCharPos = sel.indexOf(QLatin1Char('<')); | 
					
						
							|  |  |  |             m_completionOperator = T_ANGLE_STRING_LITERAL; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             m_completionOperator = T_STRING_LITERAL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (startCharPos != -1) | 
					
						
							|  |  |  |             directoryPrefix = sel.mid(startCharPos + 1, sel.length() - 1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Make completion for all relevant includes
 | 
					
						
							|  |  |  |     if (ProjectExplorer::Project *project = ProjectExplorer::ProjectExplorerPlugin::instance()->currentProject()) { | 
					
						
							|  |  |  |         QStringList includePaths = m_manager->projectInfo(project).includePaths; | 
					
						
							|  |  |  |         const QString currentFilePath = QFileInfo(m_editor->file()->fileName()).path(); | 
					
						
							|  |  |  |         if (!includePaths.contains(currentFilePath)) | 
					
						
							|  |  |  |             includePaths.append(currentFilePath); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach (const QString &includePath, includePaths) { | 
					
						
							|  |  |  |             QString realPath = includePath; | 
					
						
							|  |  |  |             if (!directoryPrefix.isEmpty()) { | 
					
						
							|  |  |  |                 realPath += QLatin1Char('/'); | 
					
						
							|  |  |  |                 realPath += directoryPrefix; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-07-24 13:48:21 +02:00
										 |  |  |             foreach (const QString &itemText, m_manager->includesInPath(realPath)) { | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |                 TextEditor::CompletionItem item(this); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                 item.text += itemText; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |                 // TODO: Icon for include files
 | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                 item.icon = m_icons.keywordIcon(); | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |                 m_completions.append(item); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-10-01 17:01:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         QStringList frameworkPaths = m_manager->projectInfo(project).frameworkPaths; | 
					
						
							|  |  |  |         foreach (const QString &frameworkPath, frameworkPaths) { | 
					
						
							|  |  |  |             QString realPath = frameworkPath; | 
					
						
							|  |  |  |             if (!directoryPrefix.isEmpty()) { | 
					
						
							|  |  |  |                 realPath += QLatin1Char('/'); | 
					
						
							|  |  |  |                 realPath += directoryPrefix; | 
					
						
							|  |  |  |                 realPath += QLatin1String(".framework/Headers"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             foreach (const QString &itemText, m_manager->includesInPath(realPath)) { | 
					
						
							|  |  |  |                 TextEditor::CompletionItem item(this); | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                 item.text += itemText; | 
					
						
							| 
									
										
										
										
											2009-10-01 17:01:13 +02:00
										 |  |  |                 // TODO: Icon for include files
 | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                 item.icon = m_icons.keywordIcon(); | 
					
						
							| 
									
										
										
										
											2009-10-01 17:01:13 +02:00
										 |  |  |                 m_completions.append(item); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-24 13:48:21 +02:00
										 |  |  |     return !m_completions.isEmpty(); | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | void CppCodeCompletion::completeNamespace(const QList<Symbol *> &candidates, | 
					
						
							|  |  |  |                                           const LookupContext &context) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QList<Scope *> todo; | 
					
						
							|  |  |  |     QList<Scope *> visibleScopes = context.visibleScopes(); | 
					
						
							|  |  |  |     foreach (Symbol *candidate, candidates) { | 
					
						
							|  |  |  |         if (Namespace *ns = candidate->asNamespace()) | 
					
						
							|  |  |  |             context.expand(ns->members(), visibleScopes, &todo); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     foreach (Scope *scope, todo) { | 
					
						
							|  |  |  |         addCompletionItem(scope->owner()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (unsigned i = 0; i < scope->symbolCount(); ++i) { | 
					
						
							|  |  |  |             addCompletionItem(scope->symbolAt(i)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::completeClass(const QList<Symbol *> &candidates, | 
					
						
							|  |  |  |                                       const LookupContext &context, | 
					
						
							|  |  |  |                                       bool staticLookup) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (candidates.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Class *klass = candidates.first()->asClass(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QList<Scope *> todo; | 
					
						
							|  |  |  |     context.expand(klass->members(), context.visibleScopes(), &todo); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     foreach (Scope *scope, todo) { | 
					
						
							|  |  |  |         addCompletionItem(scope->owner()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (unsigned i = 0; i < scope->symbolCount(); ++i) { | 
					
						
							|  |  |  |             Symbol *symbol = scope->symbolAt(i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (symbol->type().isFriend()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             else if (! staticLookup && (symbol->isTypedef() || | 
					
						
							|  |  |  |                                         symbol->isEnum()    || | 
					
						
							|  |  |  |                                         symbol->isClass())) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             addCompletionItem(symbol); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 12:12:14 +01:00
										 |  |  | bool CppCodeCompletion::completeQtMethod(const QList<TypeOfExpression::Result> &results, | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                                          const LookupContext &context, | 
					
						
							|  |  |  |                                          bool wantSignals) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (results.isEmpty()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 12:03:49 +01:00
										 |  |  |     ResolveClass resolveClass; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     ConvertToCompletionItem toCompletionItem(this); | 
					
						
							|  |  |  |     Overview o; | 
					
						
							|  |  |  |     o.setShowReturnTypes(false); | 
					
						
							|  |  |  |     o.setShowArgumentNames(false); | 
					
						
							|  |  |  |     o.setShowFunctionSignatures(true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QSet<QString> signatures; | 
					
						
							| 
									
										
										
										
											2009-02-17 12:12:14 +01:00
										 |  |  |     foreach (const TypeOfExpression::Result &p, results) { | 
					
						
							| 
									
										
										
										
											2009-09-30 11:24:00 +02:00
										 |  |  |         FullySpecifiedType ty = p.first.simplified(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         if (PointerType *ptrTy = ty->asPointerType()) | 
					
						
							| 
									
										
										
										
											2009-10-05 11:38:54 +02:00
										 |  |  |             ty = ptrTy->elementType().simplified(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         else | 
					
						
							|  |  |  |             continue; // not a pointer or a reference to a pointer.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         NamedType *namedTy = ty->asNamedType(); | 
					
						
							|  |  |  |         if (! namedTy) // not a class name.
 | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const QList<Symbol *> classObjects = | 
					
						
							| 
									
										
										
										
											2009-10-05 11:38:54 +02:00
										 |  |  |                 resolveClass(namedTy->name(), p, context); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (classObjects.isEmpty()) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Class *klass = classObjects.first()->asClass(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QList<Scope *> todo; | 
					
						
							| 
									
										
										
										
											2008-12-30 12:03:49 +01:00
										 |  |  |         const QList<Scope *> visibleScopes = context.visibleScopes(p); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         context.expand(klass->members(), visibleScopes, &todo); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach (Scope *scope, todo) { | 
					
						
							|  |  |  |             if (! scope->isClassScope()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (unsigned i = 0; i < scope->symbolCount(); ++i) { | 
					
						
							|  |  |  |                 Symbol *member = scope->symbolAt(i); | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |                 Function *fun = member->type()->asFunctionType(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 if (! fun) | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 if (wantSignals && ! fun->isSignal()) | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 else if (! wantSignals && ! fun->isSlot()) | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 if (TextEditor::CompletionItem item = toCompletionItem(fun)) { | 
					
						
							|  |  |  |                     unsigned count = fun->argumentCount(); | 
					
						
							|  |  |  |                     while (true) { | 
					
						
							| 
									
										
										
										
											2009-01-13 17:55:02 +01:00
										 |  |  |                         TextEditor::CompletionItem ci = item; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                         QString signature; | 
					
						
							|  |  |  |                         signature += overview.prettyName(fun->name()); | 
					
						
							|  |  |  |                         signature += QLatin1Char('('); | 
					
						
							|  |  |  |                         for (unsigned i = 0; i < count; ++i) { | 
					
						
							|  |  |  |                             Symbol *arg = fun->argumentAt(i); | 
					
						
							|  |  |  |                             if (i != 0) | 
					
						
							|  |  |  |                                 signature += QLatin1Char(','); | 
					
						
							|  |  |  |                             signature += o.prettyType(arg->type()); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         signature += QLatin1Char(')'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         const QByteArray normalized = | 
					
						
							|  |  |  |                                 QMetaObject::normalizedSignature(signature.toLatin1()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         signature = QString::fromLatin1(normalized, normalized.size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (! signatures.contains(signature)) { | 
					
						
							|  |  |  |                             signatures.insert(signature); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                             ci.text = signature; // fix the completion item.
 | 
					
						
							| 
									
										
										
										
											2009-01-13 17:55:02 +01:00
										 |  |  |                             m_completions.append(ci); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         if (count && fun->argumentAt(count - 1)->asArgument()->hasInitializer()) | 
					
						
							|  |  |  |                             --count; | 
					
						
							|  |  |  |                         else | 
					
						
							|  |  |  |                             break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ! m_completions.isEmpty(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *completions) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const int length = m_editor->position() - m_startPosition; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (length == 0) | 
					
						
							|  |  |  |         *completions = m_completions; | 
					
						
							|  |  |  |     else if (length > 0) { | 
					
						
							|  |  |  |         const QString key = m_editor->textAt(m_startPosition, length); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-24 14:32:39 +02:00
										 |  |  |         /* Close on the trailing slash for include completion, to enable the slash to
 | 
					
						
							|  |  |  |          * trigger a new completion list. */ | 
					
						
							|  |  |  |         if ((m_completionOperator == T_STRING_LITERAL || | 
					
						
							|  |  |  |              m_completionOperator == T_ANGLE_STRING_LITERAL) && key.endsWith(QLatin1Char('/'))) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         if (m_completionOperator != T_LPAREN) { | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * This code builds a regular expression in order to more intelligently match | 
					
						
							|  |  |  |              * camel-case style. This means upper-case characters will be rewritten as follows: | 
					
						
							|  |  |  |              * | 
					
						
							|  |  |  |              *   A => [a-z0-9_]*A (for any but the first capital letter) | 
					
						
							|  |  |  |              * | 
					
						
							|  |  |  |              * Meaning it allows any sequence of lower-case characters to preceed an | 
					
						
							|  |  |  |              * upper-case character. So for example gAC matches getActionController. | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             QString keyRegExp; | 
					
						
							|  |  |  |             keyRegExp += QLatin1Char('^'); | 
					
						
							|  |  |  |             bool first = true; | 
					
						
							|  |  |  |             foreach (const QChar &c, key) { | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  |                 if (c.isUpper() && !first) { | 
					
						
							|  |  |  |                     keyRegExp += QLatin1String("[a-z0-9_]*"); | 
					
						
							|  |  |  |                     keyRegExp += c; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  |                     keyRegExp += QRegExp::escape(c); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 first = false; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-06-10 16:08:23 +02:00
										 |  |  |             const QRegExp regExp(keyRegExp, m_caseSensitivity); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             foreach (TextEditor::CompletionItem item, m_completions) { | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                 if (regExp.indexIn(item.text) == 0) { | 
					
						
							|  |  |  |                     item.relevance = (key.length() > 0 && | 
					
						
							|  |  |  |                                          item.text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                     (*completions) << item; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (m_completionOperator == T_LPAREN || | 
					
						
							|  |  |  |                    m_completionOperator == T_SIGNAL || | 
					
						
							|  |  |  |                    m_completionOperator == T_SLOT) { | 
					
						
							|  |  |  |             foreach (TextEditor::CompletionItem item, m_completions) { | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                 if (item.text.startsWith(key, Qt::CaseInsensitive)) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                     (*completions) << item; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Symbol *symbol = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |     if (item.data.isValid()) | 
					
						
							|  |  |  |         symbol = item.data.value<Symbol *>(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     QString toInsert; | 
					
						
							| 
									
										
										
										
											2009-07-24 13:48:21 +02:00
										 |  |  |     QString extraChars; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     int extraLength = 0; | 
					
						
							| 
									
										
										
										
											2009-09-16 16:48:14 +02:00
										 |  |  |     int cursorOffset = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-17 12:36:40 +02:00
										 |  |  |     bool autoParenthesesEnabled = true; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |         toInsert = item.text; | 
					
						
							| 
									
										
										
										
											2009-07-24 13:48:21 +02:00
										 |  |  |         extraChars += QLatin1Char(')'); | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     } else if (m_completionOperator == T_STRING_LITERAL || m_completionOperator == T_ANGLE_STRING_LITERAL) { | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |         toInsert = item.text; | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |         if (!toInsert.endsWith(QLatin1Char('/'))) | 
					
						
							| 
									
										
										
										
											2009-07-24 13:48:21 +02:00
										 |  |  |             extraChars += QLatin1Char((m_completionOperator == T_ANGLE_STRING_LITERAL) ? '>' : '"'); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |         toInsert = item.text; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         //qDebug() << "current symbol:" << overview.prettyName(symbol->name())
 | 
					
						
							|  |  |  |         //<< overview.prettyType(symbol->type());
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-05 18:42:46 +02:00
										 |  |  |         if (m_autoInsertBrackets && symbol && symbol->type()) { | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |             if (Function *function = symbol->type()->asFunctionType()) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 // If the member is a function, automatically place the opening parenthesis,
 | 
					
						
							|  |  |  |                 // except when it might take template parameters.
 | 
					
						
							| 
									
										
										
										
											2009-03-26 16:43:38 +01:00
										 |  |  |                 if (! function->hasReturnType() && (function->identity() && !function->identity()->isDestructorNameId())) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                     // Don't insert any magic, since the user might have just wanted to select the class
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 } else if (function->templateParameterCount() != 0) { | 
					
						
							|  |  |  |                     // If there are no arguments, then we need the template specification
 | 
					
						
							|  |  |  |                     if (function->argumentCount() == 0) { | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01:00
										 |  |  |                         extraChars += QLatin1Char('<'); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2009-03-17 14:46:35 +01:00
										 |  |  |                 } else if (! function->isAmbiguous()) { | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01:00
										 |  |  |                     extraChars += QLatin1Char('('); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-16 16:48:14 +02:00
										 |  |  |                     // If the function doesn't return anything, automatically place the semicolon,
 | 
					
						
							|  |  |  |                     // unless we're doing a scope completion (then it might be function definition).
 | 
					
						
							|  |  |  |                     bool endWithSemicolon = function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                     // If the function takes no arguments, automatically place the closing parenthesis
 | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |                     if (item.duplicateCount == 0 && ! function->hasArguments()) { | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01:00
										 |  |  |                         extraChars += QLatin1Char(')'); | 
					
						
							| 
									
										
										
										
											2009-09-16 16:48:14 +02:00
										 |  |  |                         if (endWithSemicolon) | 
					
						
							|  |  |  |                             extraChars += QLatin1Char(';'); | 
					
						
							|  |  |  |                     } else if (autoParenthesesEnabled) { | 
					
						
							| 
									
										
										
										
											2009-09-22 16:52:27 +02:00
										 |  |  |                         const QChar lookAhead = m_editor->characterAt(m_editor->position() + 1); | 
					
						
							|  |  |  |                         if (MatchingText::shouldInsertMatchingText(lookAhead)) { | 
					
						
							|  |  |  |                             extraChars += QLatin1Char(')'); | 
					
						
							| 
									
										
										
										
											2009-09-16 16:48:14 +02:00
										 |  |  |                             --cursorOffset; | 
					
						
							| 
									
										
										
										
											2009-09-22 16:52:27 +02:00
										 |  |  |                             if (endWithSemicolon) { | 
					
						
							|  |  |  |                                 extraChars += QLatin1Char(';'); | 
					
						
							|  |  |  |                                 --cursorOffset; | 
					
						
							|  |  |  |                             } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-11-02 10:31:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (m_autoInsertBrackets && item.data.canConvert<CompleteFunctionDeclaration>()) { | 
					
						
							|  |  |  |             // everything from the closing parenthesis on are extra chars, to
 | 
					
						
							|  |  |  |             // make sure an auto-inserted ")" gets replaced by ") const" if necessary
 | 
					
						
							|  |  |  |             int closingParen = toInsert.lastIndexOf(QLatin1Char(')')); | 
					
						
							|  |  |  |             extraChars = toInsert.mid(closingParen); | 
					
						
							|  |  |  |             toInsert.truncate(closingParen); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2009-07-24 13:48:21 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-24 13:48:21 +02:00
										 |  |  |     // Avoid inserting characters that are already there
 | 
					
						
							|  |  |  |     for (int i = 0; i < extraChars.length(); ++i) { | 
					
						
							|  |  |  |         const QChar a = extraChars.at(i); | 
					
						
							|  |  |  |         const QChar b = m_editor->characterAt(m_editor->position() + i); | 
					
						
							|  |  |  |         if (a == b) | 
					
						
							|  |  |  |             ++extraLength; | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-24 13:48:21 +02:00
										 |  |  |     toInsert += extraChars; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-23 16:46:30 +02:00
										 |  |  |     // Insert the remainder of the name
 | 
					
						
							|  |  |  |     int length = m_editor->position() - m_startPosition + extraLength; | 
					
						
							|  |  |  |     m_editor->setCurPos(m_startPosition); | 
					
						
							|  |  |  |     m_editor->replace(length, toInsert); | 
					
						
							| 
									
										
										
										
											2009-09-16 16:48:14 +02:00
										 |  |  |     if (cursorOffset) | 
					
						
							|  |  |  |         m_editor->setCurPos(m_editor->position() + cursorOffset); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool CppCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } else if (completionItems.count() == 1) { | 
					
						
							|  |  |  |         complete(completionItems.first()); | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2008-12-16 16:55:44 +01:00
										 |  |  |     } else if (m_partialCompletionEnabled && m_completionOperator != T_LPAREN) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         // Compute common prefix
 | 
					
						
							| 
									
										
										
										
											2009-10-05 18:32:08 +02:00
										 |  |  |         QString firstKey = completionItems.first().text; | 
					
						
							|  |  |  |         QString lastKey = completionItems.last().text; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         const int length = qMin(firstKey.length(), lastKey.length()); | 
					
						
							|  |  |  |         firstKey.truncate(length); | 
					
						
							|  |  |  |         lastKey.truncate(length); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         while (firstKey != lastKey) { | 
					
						
							|  |  |  |             firstKey.chop(1); | 
					
						
							|  |  |  |             lastKey.chop(1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int typedLength = m_editor->position() - m_startPosition; | 
					
						
							|  |  |  |         if (!firstKey.isEmpty() && firstKey.length() > typedLength) { | 
					
						
							|  |  |  |             m_editor->setCurPos(m_startPosition); | 
					
						
							|  |  |  |             m_editor->replace(typedLength, firstKey); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::cleanup() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     m_completions.clear(); | 
					
						
							| 
									
										
										
										
											2008-12-08 13:01:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Set empty map in order to avoid referencing old versions of the documents
 | 
					
						
							|  |  |  |     // until the next completion
 | 
					
						
							| 
									
										
										
										
											2008-12-12 10:07:58 +01:00
										 |  |  |     typeOfExpression.setSnapshot(Snapshot()); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-04 16:40:42 +01:00
										 |  |  | int CppCodeCompletion::findStartOfName(int pos) const | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-04 16:40:42 +01:00
										 |  |  |     if (pos == -1) | 
					
						
							|  |  |  |         pos = m_editor->position(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     QChar chr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Skip to the start of a name
 | 
					
						
							|  |  |  |     do { | 
					
						
							| 
									
										
										
										
											2009-02-04 16:40:42 +01:00
										 |  |  |         chr = m_editor->characterAt(--pos); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } while (chr.isLetterOrNumber() || chr == QLatin1Char('_')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return pos + 1; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "cppcodecompletion.moc"
 |