| 
									
										
										
										
											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
										 |  |  | ** | 
					
						
							|  |  |  | ** Contact:  Qt Software Information (qt-info@nokia.com) | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | ** contact the sales department at qt-sales@nokia.com. | 
					
						
							| 
									
										
										
										
											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"
 | 
					
						
							| 
									
										
										
										
											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>
 | 
					
						
							|  |  |  | #include <cplusplus/Overview.h>
 | 
					
						
							|  |  |  | #include <cplusplus/ExpressionUnderCursor.h>
 | 
					
						
							|  |  |  | #include <cplusplus/TokenUnderCursor.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <coreplugin/icore.h>
 | 
					
						
							|  |  |  | #include <coreplugin/editormanager/editormanager.h>
 | 
					
						
							|  |  |  | #include <texteditor/itexteditor.h>
 | 
					
						
							|  |  |  | #include <texteditor/itexteditable.h>
 | 
					
						
							| 
									
										
										
										
											2008-12-09 15:25:01 +01:00
										 |  |  | #include <utils/qtcassert.h>
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include <texteditor/basetexteditor.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #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-03-26 11:14:05 +01:00
										 |  |  | #include <QtGui/QToolButton>
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | #include <QtGui/QVBoxLayout>
 | 
					
						
							| 
									
										
										
										
											2009-05-27 17:02:35 +02:00
										 |  |  | #include <QtGui/QTextDocument> // Qt::escape()
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | using namespace CPlusPlus; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace CppTools { | 
					
						
							|  |  |  | namespace Internal { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     QFrame *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) | 
					
						
							|  |  |  |             _item.m_data = QVariant::fromValue(symbol); | 
					
						
							|  |  |  |         (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); | 
					
						
							|  |  |  |         item.m_text = overview.prettyName(name); | 
					
						
							|  |  |  |         item.m_icon = _collector->iconForSymbol(_symbol); | 
					
						
							|  |  |  |         return item; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void visit(NameId *name) | 
					
						
							|  |  |  |     { _item = newCompletionItem(name); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     virtual void visit(TemplateNameId *name) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         _item = newCompletionItem(name); | 
					
						
							|  |  |  |         _item.m_text = QLatin1String(name->identifier()->chars()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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()); } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace Internal
 | 
					
						
							|  |  |  | } // namespace CppTools
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace CppTools::Internal; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-03-26 11:14:05 +01:00
										 |  |  |     m_popupFrame = new QFrame(m_editor->widget(), Qt::ToolTip | Qt::WindowStaysOnTopHint); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     m_popupFrame->setFocusPolicy(Qt::NoFocus); | 
					
						
							|  |  |  |     m_popupFrame->setAttribute(Qt::WA_DeleteOnClose); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  |     m_popupFrame->setFrameStyle(QFrame::Box); | 
					
						
							|  |  |  |     m_popupFrame->setFrameShadow(QFrame::Plain); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  |     QPalette pal = m_popupFrame->palette(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     setAutoFillBackground(true); | 
					
						
							|  |  |  |     pal.setColor(QPalette::Background, QColor(255, 255, 220)); | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     m_popupFrame->setPalette(pal); | 
					
						
							| 
									
										
										
										
											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(); | 
					
						
							|  |  |  | #ifdef Q_OS_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-01-28 13:56:10 +01:00
										 |  |  | CppCodeCompletion::CppCodeCompletion(CppModelManager *manager) | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     : ICompletionCollector(manager), | 
					
						
							|  |  |  |       m_manager(manager), | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  |       m_caseSensitivity(Qt::CaseSensitive), | 
					
						
							| 
									
										
										
										
											2009-05-26 11:10:22 +02:00
										 |  |  |       m_autoInsertBrackets(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-05-26 11:10:22 +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-05-26 11:10:22 +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
										 |  |  | /*
 | 
					
						
							|  |  |  |   Searches beckward for an access operator. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 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-02-20 12:55:01 +01:00
										 |  |  |     int k = T_EOF_SYMBOL; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if        (ch2 != QLatin1Char('.') && ch == QLatin1Char('.')) { | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         k = T_DOT; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         --start; | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     } else if (ch == QLatin1Char(',')) { | 
					
						
							|  |  |  |         k = T_COMMA; | 
					
						
							|  |  |  |         --start; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } else if (wantFunctionCall        && ch == QLatin1Char('(')) { | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         k = T_LPAREN; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         --start; | 
					
						
							| 
									
										
										
										
											2009-03-26 11:22:47 +01:00
										 |  |  |     } else if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':') && ch == QLatin1Char(':')) { | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         k = T_COLON_COLON; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         start -= 2; | 
					
						
							|  |  |  |     } else if (ch2 == QLatin1Char('-') && ch == QLatin1Char('>')) { | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         k = T_ARROW; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         start -= 2; | 
					
						
							|  |  |  |     } else if (ch2 == QLatin1Char('.') && ch == QLatin1Char('*')) { | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         k = T_DOT_STAR; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         start -= 2; | 
					
						
							|  |  |  |     } else if (ch3 == QLatin1Char('-') && ch2 == QLatin1Char('>') && ch == QLatin1Char('*')) { | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         k = T_ARROW_STAR; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         start -= 3; | 
					
						
							| 
									
										
										
										
											2009-02-23 17:54:08 +01:00
										 |  |  |     } else if ((ch2.isNull() || ch2.isSpace()) && (ch == QLatin1Char('@') || ch == QLatin1Char('\\'))) { | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |         k = T_DOXY_COMMENT; | 
					
						
							|  |  |  |         --start; | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static CPlusPlus::TokenUnderCursor tokenUnderCursor; | 
					
						
							|  |  |  |     const SimpleToken tk = tokenUnderCursor(tc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (k == T_DOXY_COMMENT && tk.isNot(T_DOXY_COMMENT)) { | 
					
						
							|  |  |  |         k = T_EOF_SYMBOL; | 
					
						
							|  |  |  |         start = pos; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |     else if (tk.is(T_COMMENT) || tk.isLiteral()) { | 
					
						
							|  |  |  |         k = T_EOF_SYMBOL; | 
					
						
							|  |  |  |         start = pos; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-27 11:12:06 +02:00
										 |  |  |     if (k == T_LPAREN) { | 
					
						
							|  |  |  |         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()) { | 
					
						
							|  |  |  |             k = T_EOF_SYMBOL; | 
					
						
							|  |  |  |             start = pos; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |     if (kind) | 
					
						
							|  |  |  |         *kind = k; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  |             item.m_text.append(QString::fromLatin1(doxygenTagSpell(i))); | 
					
						
							| 
									
										
										
										
											2009-02-20 12:57:16 +01:00
										 |  |  |             item.m_icon = m_icons.keywordIcon(); | 
					
						
							| 
									
										
										
										
											2009-02-20 12:55:01 +01:00
										 |  |  |             m_completions.append(item); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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); | 
					
						
							|  |  |  |         if (start != -1) { | 
					
						
							|  |  |  |             endOfExpression = start; | 
					
						
							|  |  |  |             m_startPosition = start + 1; | 
					
						
							|  |  |  |             m_completionOperator = T_LPAREN; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     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)) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         Symbol *symbol = 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-11 11:27:07 +01:00
										 |  |  |         QList<TypeOfExpression::Result> resolvedTypes = typeOfExpression(expression, thisDocument, symbol, | 
					
						
							|  |  |  |                                                                          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"); | 
					
						
							|  |  |  |             resolvedTypes = typeOfExpression(expression, thisDocument, symbol); | 
					
						
							|  |  |  |             context = typeOfExpression.lookupContext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-17 12:12:14 +01:00
										 |  |  |         if (! resolvedTypes.isEmpty()) { | 
					
						
							|  |  |  |             if (m_completionOperator == T_LPAREN && completeConstructorOrFunction(resolvedTypes)) { | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  |             QString baseExpression = expressionUnderCursor(tc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Resolve the type of this expression
 | 
					
						
							|  |  |  |             QList<TypeOfExpression::Result> results = | 
					
						
							|  |  |  |                     typeOfExpression(baseExpression, thisDocument, symbol, TypeOfExpression::Preprocess); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // 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-02-17 12:12:14 +01:00
										 |  |  |                     if (completeConstructorOrFunction(results)) | 
					
						
							| 
									
										
										
										
											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-02-17 12:12:14 +01:00
										 |  |  | bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpression::Result> &results) | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							|  |  |  |         FullySpecifiedType exprTy = result.first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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-02-17 11:50:56 +01:00
										 |  |  |         foreach (const TypeOfExpression::Result &p, results) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             FullySpecifiedType ty = p.first; | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 Name *name = fun->name(); | 
					
						
							|  |  |  |                 if (QualifiedNameId *q = fun->name()->asQualifiedNameId()) | 
					
						
							|  |  |  |                     name = q->unqualifiedNameId(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 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-05-19 12:15:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 11:14:05 +01:00
										 |  |  |     if (! functions.isEmpty()) { | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-30 11:45:41 +01:00
										 |  |  | bool CppCodeCompletion::completeMember(const QList<TypeOfExpression::Result> &results, | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                                        const LookupContext &context) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-02-10 17:37:18 +01:00
										 |  |  |     if (results.isEmpty()) | 
					
						
							| 
									
										
										
										
											2008-12-29 11:53:40 +01:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |     TypeOfExpression::Result result = results.first(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |     QList<Symbol *> classObjectCandidates; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (m_completionOperator == T_ARROW)  { | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |         FullySpecifiedType ty = result.first; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (ReferenceType *refTy = ty->asReferenceType()) | 
					
						
							|  |  |  |             ty = refTy->elementType(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |         if (Class *classTy = ty->asClassType()) { | 
					
						
							| 
									
										
										
										
											2009-02-04 10:57:32 +01:00
										 |  |  |             Symbol *symbol = result.second; | 
					
						
							|  |  |  |             if (symbol && ! symbol->isClass()) | 
					
						
							|  |  |  |                 classObjectCandidates.append(classTy); | 
					
						
							| 
									
										
										
										
											2009-02-03 12:50:53 +01:00
										 |  |  |         } else if (NamedType *namedTy = ty->asNamedType()) { | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |             // ### This code is pretty slow.
 | 
					
						
							|  |  |  |             const QList<Symbol *> candidates = context.resolve(namedTy->name()); | 
					
						
							|  |  |  |             foreach (Symbol *candidate, candidates) { | 
					
						
							|  |  |  |                 if (candidate->isTypedef()) { | 
					
						
							|  |  |  |                     ty = candidate->type(); | 
					
						
							|  |  |  |                     const ResolveExpression::Result r(ty, candidate); | 
					
						
							|  |  |  |                     result = r; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         if (NamedType *namedTy = ty->asNamedType()) { | 
					
						
							|  |  |  |             ResolveExpression resolveExpression(context); | 
					
						
							| 
									
										
										
										
											2008-12-30 12:03:49 +01:00
										 |  |  |             ResolveClass resolveClass; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |             const QList<Symbol *> candidates = resolveClass(result, context); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             foreach (Symbol *classObject, candidates) { | 
					
						
							|  |  |  |                 const QList<TypeOfExpression::Result> overloads = | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |                         resolveExpression.resolveArrowOperator(result, namedTy, | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                                                                classObject->asClass()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 foreach (TypeOfExpression::Result r, overloads) { | 
					
						
							|  |  |  |                     FullySpecifiedType ty = r.first; | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |                     Function *funTy = ty->asFunctionType(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                     if (! funTy) | 
					
						
							|  |  |  |                         continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     ty = funTy->returnType(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (ReferenceType *refTy = ty->asReferenceType()) | 
					
						
							|  |  |  |                         ty = refTy->elementType(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     if (PointerType *ptrTy = ty->asPointerType()) { | 
					
						
							|  |  |  |                         if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) { | 
					
						
							|  |  |  |                             const QList<Symbol *> classes = | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |                                     resolveClass(namedTy, result, context); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                             foreach (Symbol *c, classes) { | 
					
						
							|  |  |  |                                 if (! classObjectCandidates.contains(c)) | 
					
						
							|  |  |  |                                     classObjectCandidates.append(c); | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (PointerType *ptrTy = ty->asPointerType()) { | 
					
						
							|  |  |  |             if (NamedType *namedTy = ptrTy->elementType()->asNamedType()) { | 
					
						
							| 
									
										
										
										
											2008-12-30 12:03:49 +01:00
										 |  |  |                 ResolveClass resolveClass; | 
					
						
							| 
									
										
										
										
											2008-12-30 11:45:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |                 const QList<Symbol *> classes = resolveClass(namedTy, result, | 
					
						
							|  |  |  |                                                              context); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 foreach (Symbol *c, classes) { | 
					
						
							|  |  |  |                     if (! classObjectCandidates.contains(c)) | 
					
						
							|  |  |  |                         classObjectCandidates.append(c); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |             } else if (Class *classTy = ptrTy->elementType()->asClassType()) { | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |                 // typedef struct { int x } *Ptr;
 | 
					
						
							|  |  |  |                 // Ptr p;
 | 
					
						
							|  |  |  |                 // p->
 | 
					
						
							|  |  |  |                 classObjectCandidates.append(classTy); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else if (m_completionOperator == T_DOT) { | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |         FullySpecifiedType ty = result.first; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (ReferenceType *refTy = ty->asReferenceType()) | 
					
						
							|  |  |  |             ty = refTy->elementType(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         NamedType *namedTy = 0; | 
					
						
							| 
									
										
										
										
											2009-01-05 15:23:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (ArrayType *arrayTy = ty->asArrayType()) { | 
					
						
							|  |  |  |             // Replace . with [0]. when `ty' is an array type.
 | 
					
						
							|  |  |  |             FullySpecifiedType elementTy = arrayTy->elementType(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (ReferenceType *refTy = elementTy->asReferenceType()) | 
					
						
							|  |  |  |                 elementTy = refTy->elementType(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (elementTy->isNamedType() || elementTy->isPointerType()) { | 
					
						
							|  |  |  |                 ty = elementTy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const int length = m_editor->position() - m_startPosition + 1; | 
					
						
							|  |  |  |                 m_editor->setCurPos(m_startPosition - 1); | 
					
						
							|  |  |  |                 m_editor->replace(length, QLatin1String("[0].")); | 
					
						
							|  |  |  |                 m_startPosition += 3; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         if (PointerType *ptrTy = ty->asPointerType()) { | 
					
						
							| 
									
										
										
										
											2009-02-03 11:37:38 +01:00
										 |  |  |             if (ptrTy->elementType()->isNamedType()) { | 
					
						
							|  |  |  |                 // Replace . with ->
 | 
					
						
							|  |  |  |                 int length = m_editor->position() - m_startPosition + 1; | 
					
						
							|  |  |  |                 m_editor->setCurPos(m_startPosition - 1); | 
					
						
							|  |  |  |                 m_editor->replace(length, QLatin1String("->")); | 
					
						
							|  |  |  |                 ++m_startPosition; | 
					
						
							|  |  |  |                 namedTy = ptrTy->elementType()->asNamedType(); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |         } else if (Class *classTy = ty->asClassType()) { | 
					
						
							| 
									
										
										
										
											2009-02-04 10:57:32 +01:00
										 |  |  |             Symbol *symbol = result.second; | 
					
						
							|  |  |  |             if (symbol && ! symbol->isClass()) | 
					
						
							|  |  |  |                 classObjectCandidates.append(classTy); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             namedTy = ty->asNamedType(); | 
					
						
							|  |  |  |             if (! namedTy) { | 
					
						
							| 
									
										
										
										
											2009-02-09 17:44:06 +01:00
										 |  |  |                 Function *fun = ty->asFunctionType(); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                 if (fun && (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope())) | 
					
						
							|  |  |  |                     namedTy = fun->returnType()->asNamedType(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (namedTy) { | 
					
						
							| 
									
										
										
										
											2008-12-30 12:03:49 +01:00
										 |  |  |             ResolveClass resolveClass; | 
					
						
							| 
									
										
										
										
											2008-12-31 10:57:27 +01:00
										 |  |  |             const QList<Symbol *> symbols = resolveClass(namedTy, result, | 
					
						
							|  |  |  |                                                          context); | 
					
						
							| 
									
										
										
										
											2008-12-29 11:53:40 +01:00
										 |  |  |             foreach (Symbol *symbol, symbols) { | 
					
						
							|  |  |  |                 if (classObjectCandidates.contains(symbol)) | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 if (Class *klass = symbol->asClass()) | 
					
						
							|  |  |  |                     classObjectCandidates.append(klass); | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  |         item.m_text = QLatin1String(Token::name(i)); | 
					
						
							|  |  |  |         item.m_icon = m_icons.keywordIcon(); | 
					
						
							|  |  |  |         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-02-17 11:09:07 +01:00
										 |  |  |         item.m_text = macroName; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         item.m_icon = m_icons.macroIcon(); | 
					
						
							|  |  |  |         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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         FullySpecifiedType ty = p.first; | 
					
						
							|  |  |  |         if (ReferenceType *refTy = ty->asReferenceType()) | 
					
						
							|  |  |  |             ty = refTy->elementType(); | 
					
						
							|  |  |  |         if (PointerType *ptrTy = ty->asPointerType()) | 
					
						
							|  |  |  |             ty = ptrTy->elementType(); | 
					
						
							|  |  |  |         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 = | 
					
						
							| 
									
										
										
										
											2008-12-30 12:03:49 +01:00
										 |  |  |                 resolveClass(namedTy, 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-01-13 17:55:02 +01:00
										 |  |  |                             ci.m_text = signature; // fix the completion item.
 | 
					
						
							|  |  |  |                             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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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; | 
					
						
							|  |  |  |                 } else if (m_caseSensitivity == Qt::CaseInsensitive && c.isLower()) { | 
					
						
							|  |  |  |                     keyRegExp += QLatin1Char('['); | 
					
						
							|  |  |  |                     keyRegExp += c; | 
					
						
							|  |  |  |                     keyRegExp += c.toUpper(); | 
					
						
							|  |  |  |                     keyRegExp += QLatin1Char(']'); | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-12-12 16:36:33 +01:00
										 |  |  |             const QRegExp regExp(keyRegExp, Qt::CaseSensitive); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             foreach (TextEditor::CompletionItem item, m_completions) { | 
					
						
							|  |  |  |                 if (regExp.indexIn(item.m_text) == 0) { | 
					
						
							|  |  |  |                     item.m_relevance = (key.length() > 0 && | 
					
						
							|  |  |  |                                          item.m_text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0; | 
					
						
							|  |  |  |                     (*completions) << item; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (m_completionOperator == T_LPAREN || | 
					
						
							|  |  |  |                    m_completionOperator == T_SIGNAL || | 
					
						
							|  |  |  |                    m_completionOperator == T_SLOT) { | 
					
						
							|  |  |  |             foreach (TextEditor::CompletionItem item, m_completions) { | 
					
						
							|  |  |  |                 if (item.m_text.startsWith(key, Qt::CaseInsensitive)) { | 
					
						
							|  |  |  |                     (*completions) << item; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Symbol *symbol = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (item.m_data.isValid()) | 
					
						
							|  |  |  |         symbol = item.m_data.value<Symbol *>(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-26 12:37:40 +01:00
										 |  |  |     if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         QString toInsert = item.m_text; | 
					
						
							|  |  |  |         toInsert += QLatin1Char(')'); | 
					
						
							|  |  |  |         // Insert the remainder of the name
 | 
					
						
							|  |  |  |         int length = m_editor->position() - m_startPosition; | 
					
						
							|  |  |  |         m_editor->setCurPos(m_startPosition); | 
					
						
							|  |  |  |         m_editor->replace(length, toInsert); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         QString toInsert = item.m_text; | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01:00
										 |  |  |         int extraLength = 0; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         //qDebug() << "current symbol:" << overview.prettyName(symbol->name())
 | 
					
						
							|  |  |  |         //<< overview.prettyType(symbol->type());
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-26 11:10:22 +02:00
										 |  |  |         if (m_autoInsertBrackets && symbol && symbol->type()) { | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01:00
										 |  |  |             QString extraChars; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  |                     // If the function takes no arguments, automatically place the closing parenthesis
 | 
					
						
							| 
									
										
										
										
											2009-03-26 16:43:38 +01:00
										 |  |  |                     if (item.m_duplicateCount == 0 && ! function->hasArguments()) { | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01:00
										 |  |  |                         extraChars += QLatin1Char(')'); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01: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).
 | 
					
						
							| 
									
										
										
										
											2009-02-10 17:37:18 +01:00
										 |  |  |                         if (function->returnType()->isVoidType() && m_completionOperator != T_COLON_COLON) { | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01:00
										 |  |  |                             extraChars += QLatin1Char(';'); | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01: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; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             toInsert += extraChars; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Insert the remainder of the name
 | 
					
						
							| 
									
										
										
										
											2009-02-10 12:51:42 +01:00
										 |  |  |         int length = m_editor->position() - m_startPosition + extraLength; | 
					
						
							| 
									
										
										
										
											2008-12-02 12:01:29 +01:00
										 |  |  |         m_editor->setCurPos(m_startPosition); | 
					
						
							|  |  |  |         m_editor->replace(length, toInsert); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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
 | 
					
						
							|  |  |  |         QString firstKey = completionItems.first().m_text; | 
					
						
							|  |  |  |         QString lastKey = completionItems.last().m_text; | 
					
						
							|  |  |  |         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"
 |