| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | /**************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Commercial Usage | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** 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. | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** GNU Lesser General Public License Usage | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** 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.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** If you are unsure which license is appropriate for your use, please | 
					
						
							|  |  |  | ** contact the sales department at http://qt.nokia.com/contact.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | **************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "InsertionPointLocator.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <AST.h>
 | 
					
						
							|  |  |  | #include <ASTVisitor.h>
 | 
					
						
							|  |  |  | #include <TranslationUnit.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace CPlusPlus; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static QString generate(InsertionPointLocator::AccessSpec xsSpec) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (xsSpec) { | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |     case InsertionPointLocator::Public: | 
					
						
							|  |  |  |         return QLatin1String("public:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case InsertionPointLocator::Protected: | 
					
						
							|  |  |  |         return QLatin1String("protected:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case InsertionPointLocator::Private: | 
					
						
							|  |  |  |         return QLatin1String("private:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case InsertionPointLocator::PublicSlot: | 
					
						
							|  |  |  |         return QLatin1String("public slots:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case InsertionPointLocator::ProtectedSlot: | 
					
						
							|  |  |  |         return QLatin1String("protected slots:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case InsertionPointLocator::PrivateSlot: | 
					
						
							| 
									
										
										
										
											2010-07-27 17:02:12 +02:00
										 |  |  |         return QLatin1String("private slots:\n"); | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     case InsertionPointLocator::Signals: | 
					
						
							|  |  |  |         return QLatin1String("signals:\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  | static int ordering(InsertionPointLocator::AccessSpec xsSpec) | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |     static QList<InsertionPointLocator::AccessSpec> order = QList<InsertionPointLocator::AccessSpec>() | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |             << InsertionPointLocator::Public | 
					
						
							|  |  |  |             << InsertionPointLocator::PublicSlot | 
					
						
							|  |  |  |             << InsertionPointLocator::Signals | 
					
						
							|  |  |  |             << InsertionPointLocator::Protected | 
					
						
							|  |  |  |             << InsertionPointLocator::ProtectedSlot | 
					
						
							|  |  |  |             << InsertionPointLocator::PrivateSlot | 
					
						
							|  |  |  |             << InsertionPointLocator::Private | 
					
						
							|  |  |  |             ; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |     return order.indexOf(xsSpec); | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct AccessRange | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned start; | 
					
						
							|  |  |  |     unsigned end; | 
					
						
							|  |  |  |     InsertionPointLocator::AccessSpec xsSpec; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     AccessRange() | 
					
						
							|  |  |  |         : start(0) | 
					
						
							|  |  |  |         , end(0) | 
					
						
							|  |  |  |         , xsSpec(InsertionPointLocator::Invalid) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     AccessRange(unsigned start, unsigned end, InsertionPointLocator::AccessSpec xsSpec) | 
					
						
							|  |  |  |         : start(start) | 
					
						
							|  |  |  |         , end(end) | 
					
						
							|  |  |  |         , xsSpec(xsSpec) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FindInClass: public ASTVisitor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     FindInClass(const Document::Ptr &doc, const Class *clazz, InsertionPointLocator::AccessSpec xsSpec) | 
					
						
							|  |  |  |         : ASTVisitor(doc->translationUnit()) | 
					
						
							|  |  |  |         , _doc(doc) | 
					
						
							|  |  |  |         , _clazz(clazz) | 
					
						
							|  |  |  |         , _xsSpec(xsSpec) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InsertionLocation operator()() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         _result = InsertionLocation(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         AST *ast = translationUnit()->ast(); | 
					
						
							|  |  |  |         accept(ast); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return _result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							|  |  |  |     using ASTVisitor::visit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(ClassSpecifierAST *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!ast->lbrace_token || !ast->rbrace_token) | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         if (!ast->symbol || !ast->symbol->isEqualTo(_clazz)) | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QList<AccessRange> ranges = collectAccessRanges( | 
					
						
							|  |  |  |                     ast->member_specifier_list, | 
					
						
							|  |  |  |                     tokenKind(ast->classkey_token) == T_CLASS ? InsertionPointLocator::Private : InsertionPointLocator::Public, | 
					
						
							|  |  |  |                     ast->lbrace_token, | 
					
						
							|  |  |  |                     ast->rbrace_token); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         unsigned beforeToken = 0; | 
					
						
							|  |  |  |         bool needsPrefix = false; | 
					
						
							|  |  |  |         bool needsSuffix = false; | 
					
						
							|  |  |  |         findMatch(ranges, _xsSpec, beforeToken, needsPrefix, needsSuffix); | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         unsigned line = 0, column = 0; | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         getTokenStartPosition(beforeToken, &line, &column); | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         QString prefix; | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         if (needsPrefix) | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |             prefix = generate(_xsSpec); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         QString suffix; | 
					
						
							|  |  |  |         if (needsSuffix) | 
					
						
							|  |  |  |             suffix = QLatin1Char('\n'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         _result = InsertionLocation(prefix, suffix, line, column); | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |     static void findMatch(const QList<AccessRange> &ranges, | 
					
						
							|  |  |  |                           InsertionPointLocator::AccessSpec xsSpec, | 
					
						
							|  |  |  |                           unsigned &beforeToken, | 
					
						
							|  |  |  |                           bool &needsPrefix, | 
					
						
							|  |  |  |                           bool &needsSuffix) | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         Q_ASSERT(!ranges.isEmpty()); | 
					
						
							|  |  |  |         const int lastIndex = ranges.size() - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |         // try an exact match, and ignore the first (default) access spec:
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         for (int i = lastIndex; i > 0; --i) { | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |             const AccessRange &range = ranges.at(i); | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |             if (range.xsSpec == xsSpec) { | 
					
						
							|  |  |  |                 beforeToken = range.end; | 
					
						
							|  |  |  |                 needsPrefix = false; | 
					
						
							|  |  |  |                 needsSuffix = (i != lastIndex); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         // try to find a fitting access spec to insert XXX:
 | 
					
						
							|  |  |  |         for (int i = lastIndex; i > 0; --i) { | 
					
						
							|  |  |  |             const AccessRange ¤t = ranges.at(i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (ordering(xsSpec) > ordering(current.xsSpec)) { | 
					
						
							|  |  |  |                 beforeToken = current.end; | 
					
						
							|  |  |  |                 needsPrefix = true; | 
					
						
							|  |  |  |                 needsSuffix = (i != lastIndex); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // otherwise:
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         beforeToken = ranges.first().end; | 
					
						
							|  |  |  |         needsPrefix = true; | 
					
						
							|  |  |  |         needsSuffix = (ranges.size() != 1); | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QList<AccessRange> collectAccessRanges(DeclarationListAST *decls, | 
					
						
							|  |  |  |                                            InsertionPointLocator::AccessSpec initialXs, | 
					
						
							|  |  |  |                                            int firstRangeStart, | 
					
						
							|  |  |  |                                            int lastRangeEnd) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QList<AccessRange> ranges; | 
					
						
							|  |  |  |         ranges.append(AccessRange(firstRangeStart, lastRangeEnd, initialXs)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (DeclarationListAST *iter = decls; iter; iter = iter->next) { | 
					
						
							|  |  |  |             DeclarationAST *decl = iter->value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (AccessDeclarationAST *xsDecl = decl->asAccessDeclaration()) { | 
					
						
							|  |  |  |                 const unsigned token = xsDecl->access_specifier_token; | 
					
						
							|  |  |  |                 int newXsSpec = initialXs; | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  |                 bool isSlot = xsDecl->slots_token | 
					
						
							|  |  |  |                         && tokenKind(xsDecl->slots_token) == T_Q_SLOTS; | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 switch (tokenKind(token)) { | 
					
						
							|  |  |  |                 case T_PUBLIC: | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  |                     newXsSpec = isSlot ? InsertionPointLocator::PublicSlot | 
					
						
							|  |  |  |                                        : InsertionPointLocator::Public; | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 case T_PROTECTED: | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  |                     newXsSpec = isSlot ? InsertionPointLocator::ProtectedSlot | 
					
						
							|  |  |  |                                        : InsertionPointLocator::Protected; | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 case T_PRIVATE: | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  |                     newXsSpec = isSlot ? InsertionPointLocator::PrivateSlot | 
					
						
							|  |  |  |                                        : InsertionPointLocator::Private; | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 case T_Q_SIGNALS: | 
					
						
							|  |  |  |                     newXsSpec = InsertionPointLocator::Signals; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 case T_Q_SLOTS: { | 
					
						
							|  |  |  |                     newXsSpec = ranges.last().xsSpec | InsertionPointLocator::SlotBit; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 default: | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (newXsSpec != ranges.last().xsSpec) { | 
					
						
							|  |  |  |                     ranges.last().end = token; | 
					
						
							|  |  |  |                     ranges.append(AccessRange(token, lastRangeEnd, (InsertionPointLocator::AccessSpec) newXsSpec)); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ranges.last().end = lastRangeEnd; | 
					
						
							|  |  |  |         return ranges; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     Document::Ptr _doc; | 
					
						
							|  |  |  |     const Class *_clazz; | 
					
						
							|  |  |  |     InsertionPointLocator::AccessSpec _xsSpec; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InsertionLocation _result; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // end of anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | InsertionLocation::InsertionLocation() | 
					
						
							|  |  |  |     : m_line(0) | 
					
						
							|  |  |  |     , m_column(0) | 
					
						
							|  |  |  | {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  | InsertionLocation::InsertionLocation(const QString &prefix, const QString &suffix, | 
					
						
							|  |  |  |                                      unsigned line, unsigned column) | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |     : m_prefix(prefix) | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |     , m_suffix(suffix) | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  |     , m_line(line) | 
					
						
							|  |  |  |     , m_column(column) | 
					
						
							|  |  |  | {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | InsertionPointLocator::InsertionPointLocator(const Snapshot &snapshot) | 
					
						
							|  |  |  |     : m_snapshot(snapshot) | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | InsertionLocation InsertionPointLocator::methodDeclarationInClass( | 
					
						
							|  |  |  |     const QString &fileName, | 
					
						
							|  |  |  |     const Class *clazz, | 
					
						
							|  |  |  |     AccessSpec xsSpec) const | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  |     const Document::Ptr doc = m_snapshot.document(fileName); | 
					
						
							|  |  |  |     if (doc) { | 
					
						
							|  |  |  |         FindInClass find(doc, clazz, xsSpec); | 
					
						
							|  |  |  |         return find(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return InsertionLocation(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-27 18:05:24 +02:00
										 |  |  | /// Currently, we return the end of fileName.cpp
 | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | QList<InsertionLocation> InsertionPointLocator::methodDefinition( | 
					
						
							| 
									
										
										
										
											2010-09-27 18:05:24 +02:00
										 |  |  |     const QString &/*fileName*/) const | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QList<InsertionLocation> result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return result; | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | } |