| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | /**************************************************************************
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** This file is part of Qt Creator | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-01-11 16:28:15 +01:00
										 |  |  | ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-11-02 15:59:12 +01:00
										 |  |  | ** Contact: Nokia Corporation (qt-info@nokia.com) | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | ** | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** GNU Lesser General Public License Usage | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-04-13 08:42:33 +02:00
										 |  |  | ** 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.
 | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-12-17 16:01:08 +01:00
										 |  |  | ** In addition, as a special exception, Nokia gives you certain additional | 
					
						
							| 
									
										
										
										
											2011-04-13 08:42:33 +02:00
										 |  |  | ** rights. These rights are described in the Nokia Qt LGPL Exception | 
					
						
							| 
									
										
										
										
											2010-12-17 16:01:08 +01:00
										 |  |  | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2011-04-13 08:42:33 +02:00
										 |  |  | ** Other Usage | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** Alternatively, this file may be used in accordance with the terms and | 
					
						
							|  |  |  | ** conditions contained in a signed written agreement between you and Nokia. | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2010-12-17 16:01:08 +01:00
										 |  |  | ** If you have questions regarding the use of this file, please contact | 
					
						
							| 
									
										
										
										
											2011-11-02 15:59:12 +01:00
										 |  |  | ** Nokia at qt-info@nokia.com. | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | ** | 
					
						
							|  |  |  | **************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-30 14:00:43 +02:00
										 |  |  | #include "cpptoolsplugin.h"
 | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  | #include "cpprefactoringchanges.h"
 | 
					
						
							| 
									
										
										
										
											2010-09-30 14:00:43 +02:00
										 |  |  | #include "insertionpointlocator.h"
 | 
					
						
							| 
									
										
										
										
											2012-01-20 14:43:21 +01:00
										 |  |  | #include "symbolfinder.h"
 | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <AST.h>
 | 
					
						
							|  |  |  | #include <ASTVisitor.h>
 | 
					
						
							|  |  |  | #include <TranslationUnit.h>
 | 
					
						
							| 
									
										
										
										
											2011-07-28 22:11:38 +02:00
										 |  |  | #include <Literals.h>
 | 
					
						
							| 
									
										
										
										
											2011-08-18 15:04:13 +02:00
										 |  |  | #include <Symbols.h>
 | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-06 14:01:59 +02:00
										 |  |  | #include <coreplugin/icore.h>
 | 
					
						
							|  |  |  | #include <coreplugin/mimedatabase.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-23 17:44:49 +01:00
										 |  |  | #include <utils/qtcassert.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | using namespace CPlusPlus; | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  | using namespace CppTools; | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  |         _result = InsertionLocation(_doc->fileName(), 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
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2012-01-23 17:44:49 +01:00
										 |  |  |         QTC_ASSERT(!ranges.isEmpty(), return); | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |         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-09-30 12:09:38 +02:00
										 |  |  | InsertionLocation::InsertionLocation(const QString &fileName, | 
					
						
							|  |  |  |                                      const QString &prefix, | 
					
						
							|  |  |  |                                      const QString &suffix, | 
					
						
							| 
									
										
										
										
											2010-07-28 12:09:50 +02:00
										 |  |  |                                      unsigned line, unsigned column) | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  |     : m_fileName(fileName) | 
					
						
							|  |  |  |     , 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) | 
					
						
							|  |  |  | {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-17 11:35:57 +02:00
										 |  |  | InsertionPointLocator::InsertionPointLocator(const CppRefactoringChanges &refactoringChanges) | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  |     : m_refactoringChanges(refactoringChanges) | 
					
						
							| 
									
										
										
										
											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
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-08-17 11:35:57 +02:00
										 |  |  |     const Document::Ptr doc = m_refactoringChanges.file(fileName)->cppDocument(); | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  |     if (doc) { | 
					
						
							|  |  |  |         FindInClass find(doc, clazz, xsSpec); | 
					
						
							|  |  |  |         return find(); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         return InsertionLocation(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-06 14:01:59 +02:00
										 |  |  | static bool isSourceFile(const QString &fileName) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const Core::MimeDatabase *mimeDb = Core::ICore::instance()->mimeDatabase(); | 
					
						
							|  |  |  |     Core::MimeType cSourceTy = mimeDb->findByType(QLatin1String("text/x-csrc")); | 
					
						
							|  |  |  |     Core::MimeType cppSourceTy = mimeDb->findByType(QLatin1String("text/x-c++src")); | 
					
						
							|  |  |  |     Core::MimeType mSourceTy = mimeDb->findByType(QLatin1String("text/x-objcsrc")); | 
					
						
							|  |  |  |     QStringList suffixes = cSourceTy.suffixes(); | 
					
						
							|  |  |  |     suffixes += cppSourceTy.suffixes(); | 
					
						
							|  |  |  |     suffixes += mSourceTy.suffixes(); | 
					
						
							|  |  |  |     QFileInfo fileInfo(fileName); | 
					
						
							|  |  |  |     return suffixes.contains(fileInfo.suffix()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-28 22:11:38 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | template <class Key, class Value> | 
					
						
							|  |  |  | class HighestValue | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Key _key; | 
					
						
							|  |  |  |     Value _value; | 
					
						
							|  |  |  |     bool _set; | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     HighestValue() | 
					
						
							|  |  |  |         : _set(false) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     HighestValue(const Key &initialKey, const Value &initialValue) | 
					
						
							|  |  |  |         : _key(initialKey) | 
					
						
							|  |  |  |         , _value(initialValue) | 
					
						
							|  |  |  |         , _set(true) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void maybeSet(const Key &key, const Value &value) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!_set || key > _key) { | 
					
						
							|  |  |  |             _value = value; | 
					
						
							|  |  |  |             _key = key; | 
					
						
							|  |  |  |             _set = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const Value &get() const | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2012-01-23 17:44:49 +01:00
										 |  |  |         QTC_ASSERT(_set, return Value()); | 
					
						
							| 
									
										
										
										
											2011-07-28 22:11:38 +02:00
										 |  |  |         return _value; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FindMethodDefinitionInsertPoint : protected ASTVisitor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QList<const Identifier *> _namespaceNames; | 
					
						
							|  |  |  |     int _currentDepth; | 
					
						
							|  |  |  |     HighestValue<int, int> _bestToken; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     FindMethodDefinitionInsertPoint(TranslationUnit *translationUnit) | 
					
						
							|  |  |  |         : ASTVisitor(translationUnit) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void operator()(Declaration *decl, unsigned *line, unsigned *column) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         *line = *column = 0; | 
					
						
							|  |  |  |         if (translationUnit()->ast()->lastToken() < 2) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QList<const Name *> names = LookupContext::fullyQualifiedName(decl); | 
					
						
							|  |  |  |         foreach (const Name *name, names) { | 
					
						
							|  |  |  |             const Identifier *id = name->asNameId(); | 
					
						
							|  |  |  |             if (!id) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             _namespaceNames += id; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         _currentDepth = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // default to end of file
 | 
					
						
							|  |  |  |         _bestToken.maybeSet(-1, translationUnit()->ast()->lastToken() - 1); | 
					
						
							|  |  |  |         accept(translationUnit()->ast()); | 
					
						
							|  |  |  |         translationUnit()->getTokenEndPosition(_bestToken.get(), line, column); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							|  |  |  |     bool preVisit(AST *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return ast->asNamespace() || ast->asTranslationUnit() || ast->asLinkageBody(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(NamespaceAST *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (_currentDepth >= _namespaceNames.size()) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // ignore anonymous namespaces
 | 
					
						
							|  |  |  |         if (!ast->identifier_token) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const Identifier *name = translationUnit()->identifier(ast->identifier_token); | 
					
						
							|  |  |  |         if (!name->equalTo(_namespaceNames.at(_currentDepth))) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // found a good namespace
 | 
					
						
							|  |  |  |         _bestToken.maybeSet(_currentDepth, ast->lastToken() - 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ++_currentDepth; | 
					
						
							|  |  |  |         accept(ast->linkage_body); | 
					
						
							|  |  |  |         --_currentDepth; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2011-08-29 09:53:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class FindFunctionDefinition : protected ASTVisitor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FunctionDefinitionAST *_result; | 
					
						
							|  |  |  |     unsigned _line, _column; | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     FindFunctionDefinition(TranslationUnit *translationUnit) | 
					
						
							|  |  |  |         : ASTVisitor(translationUnit) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FunctionDefinitionAST *operator()(unsigned line, unsigned column) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         _result = 0; | 
					
						
							|  |  |  |         _line = line; | 
					
						
							|  |  |  |         _column = column; | 
					
						
							|  |  |  |         accept(translationUnit()->ast()); | 
					
						
							|  |  |  |         return _result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							|  |  |  |     bool preVisit(AST *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (_result) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         unsigned line, column; | 
					
						
							|  |  |  |         translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column); | 
					
						
							|  |  |  |         if (line > _line || (line == _line && column > _column)) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         translationUnit()->getTokenEndPosition(ast->lastToken() - 1, &line, &column); | 
					
						
							|  |  |  |         if (line < _line || (line == _line && column < _column)) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(FunctionDefinitionAST *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         _result = ast; | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-28 22:11:38 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-29 09:53:52 +02:00
										 |  |  | static Declaration *isNonVirtualFunctionDeclaration(Symbol *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!s) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     Declaration *declaration = s->asDeclaration(); | 
					
						
							|  |  |  |     if (!declaration) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     Function *type = s->type()->asFunctionType(); | 
					
						
							|  |  |  |     if (!type || type->isPureVirtual()) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     return declaration; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static InsertionLocation nextToSurroundingDefinitions(Declaration *declaration, const CppRefactoringChanges &changes) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InsertionLocation noResult; | 
					
						
							|  |  |  |     Class *klass = declaration->enclosingClass(); | 
					
						
							|  |  |  |     if (!klass) | 
					
						
							|  |  |  |         return noResult; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // find the index of declaration
 | 
					
						
							|  |  |  |     int declIndex = -1; | 
					
						
							|  |  |  |     for (unsigned i = 0; i < klass->memberCount(); ++i) { | 
					
						
							|  |  |  |         Symbol *s = klass->memberAt(i); | 
					
						
							|  |  |  |         if (s == declaration) { | 
					
						
							|  |  |  |             declIndex = i; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (declIndex == -1) | 
					
						
							|  |  |  |         return noResult; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // scan preceding declarations for a function declaration
 | 
					
						
							|  |  |  |     QString prefix, suffix; | 
					
						
							|  |  |  |     Declaration *surroundingFunctionDecl = 0; | 
					
						
							|  |  |  |     for (int i = declIndex - 1; i >= 0; --i) { | 
					
						
							|  |  |  |         Symbol *s = klass->memberAt(i); | 
					
						
							|  |  |  |         surroundingFunctionDecl = isNonVirtualFunctionDeclaration(s); | 
					
						
							|  |  |  |         if (surroundingFunctionDecl) { | 
					
						
							|  |  |  |             prefix = QLatin1String("\n\n"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!surroundingFunctionDecl) { | 
					
						
							|  |  |  |         // try to find one below
 | 
					
						
							|  |  |  |         for (unsigned i = declIndex + 1; i < klass->memberCount(); ++i) { | 
					
						
							|  |  |  |             Symbol *s = klass->memberAt(i); | 
					
						
							|  |  |  |             surroundingFunctionDecl = isNonVirtualFunctionDeclaration(s); | 
					
						
							|  |  |  |             if (surroundingFunctionDecl) { | 
					
						
							|  |  |  |                 suffix = QLatin1String("\n\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!surroundingFunctionDecl) | 
					
						
							|  |  |  |             return noResult; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // find the declaration's definition
 | 
					
						
							| 
									
										
										
										
											2012-01-23 16:08:01 +01:00
										 |  |  |     CppTools::SymbolFinder symbolFinder; | 
					
						
							| 
									
										
										
										
											2012-01-20 14:43:21 +01:00
										 |  |  |     Symbol *definition = symbolFinder.findMatchingDefinition(surroundingFunctionDecl, | 
					
						
							|  |  |  |                                                              changes.snapshot()); | 
					
						
							| 
									
										
										
										
											2011-08-29 09:53:52 +02:00
										 |  |  |     if (!definition) | 
					
						
							|  |  |  |         return noResult; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unsigned line, column; | 
					
						
							|  |  |  |     if (suffix.isEmpty()) { | 
					
						
							|  |  |  |         Function *definitionFunction = definition->asFunction(); | 
					
						
							|  |  |  |         if (!definitionFunction) | 
					
						
							|  |  |  |             return noResult; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Document::Ptr targetDoc = changes.snapshot().document(definition->fileName()); | 
					
						
							|  |  |  |         if (!targetDoc) | 
					
						
							|  |  |  |             return noResult; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         targetDoc->translationUnit()->getPosition(definitionFunction->endOffset(), &line, &column); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         // we don't have an offset to the start of the function definition, so we need to manually find it...
 | 
					
						
							|  |  |  |         CppRefactoringFilePtr targetFile = changes.file(definition->fileName()); | 
					
						
							|  |  |  |         if (!targetFile->isValid()) | 
					
						
							|  |  |  |             return noResult; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         FindFunctionDefinition finder(targetFile->cppDocument()->translationUnit()); | 
					
						
							|  |  |  |         FunctionDefinitionAST *functionDefinition = finder(definition->line(), definition->column()); | 
					
						
							|  |  |  |         if (!functionDefinition) | 
					
						
							|  |  |  |             return noResult; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         targetFile->cppDocument()->translationUnit()->getTokenStartPosition(functionDefinition->firstToken(), &line, &column); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return InsertionLocation(definition->fileName(), prefix, suffix, line, column); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | QList<InsertionLocation> InsertionPointLocator::methodDefinition( | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  |     Declaration *declaration) const | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QList<InsertionLocation> result; | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  |     if (!declaration) | 
					
						
							|  |  |  |         return result; | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-23 16:08:01 +01:00
										 |  |  |     CppTools::SymbolFinder symbolFinder; | 
					
						
							| 
									
										
										
										
											2012-01-20 14:43:21 +01:00
										 |  |  |     if (Symbol *s = symbolFinder.findMatchingDefinition(declaration, | 
					
						
							|  |  |  |                                                         m_refactoringChanges.snapshot(), | 
					
						
							|  |  |  |                                                         true)) { | 
					
						
							| 
									
										
										
										
											2011-08-29 09:53:52 +02:00
										 |  |  |         if (Function *f = s->asFunction()) { | 
					
						
							|  |  |  |             if (f->isConst() == declaration->type().isConst() | 
					
						
							|  |  |  |                     && f->isVolatile() == declaration->type().isVolatile()) | 
					
						
							|  |  |  |                 return result; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const InsertionLocation location = nextToSurroundingDefinitions(declaration, m_refactoringChanges); | 
					
						
							|  |  |  |     if (location.isValid()) { | 
					
						
							|  |  |  |         result += location; | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-06 14:01:59 +02:00
										 |  |  |     const QString declFileName = QString::fromUtf8(declaration->fileName(), | 
					
						
							|  |  |  |                                                    declaration->fileNameLength()); | 
					
						
							|  |  |  |     QString target = declFileName; | 
					
						
							|  |  |  |     if (!isSourceFile(declFileName)) { | 
					
						
							| 
									
										
										
										
											2011-07-06 17:34:45 +02:00
										 |  |  |         QString candidate = Internal::CppToolsPlugin::correspondingHeaderOrSource(declFileName); | 
					
						
							| 
									
										
										
										
											2010-10-07 15:22:32 +02:00
										 |  |  |         if (!candidate.isEmpty()) | 
					
						
							|  |  |  |             target = candidate; | 
					
						
							| 
									
										
										
										
											2010-10-06 14:01:59 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-17 11:35:57 +02:00
										 |  |  |     Document::Ptr doc = m_refactoringChanges.file(target)->cppDocument(); | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  |     if (doc.isNull()) | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unsigned line = 0, column = 0; | 
					
						
							| 
									
										
										
										
											2011-07-28 22:11:38 +02:00
										 |  |  |     FindMethodDefinitionInsertPoint finder(doc->translationUnit()); | 
					
						
							|  |  |  |     finder(declaration, &line, &column); | 
					
						
							| 
									
										
										
										
											2010-09-30 12:09:38 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const QLatin1String prefix("\n\n"); | 
					
						
							|  |  |  |     result.append(InsertionLocation(target, prefix, QString(), line, column)); | 
					
						
							| 
									
										
										
										
											2010-09-27 18:01:04 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return result; | 
					
						
							| 
									
										
										
										
											2010-07-27 15:29:16 +02:00
										 |  |  | } |