| 
									
										
										
										
											2012-10-02 09:12:39 +02:00
										 |  |  | /****************************************************************************
 | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2014-01-07 13:27:11 +01:00
										 |  |  | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). | 
					
						
							| 
									
										
										
										
											2012-10-02 09:12:39 +02:00
										 |  |  | ** Contact: http://www.qt-project.org/legal
 | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2012-10-02 09:12:39 +02:00
										 |  |  | ** This file is part of Qt Creator. | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | ** | 
					
						
							| 
									
										
										
										
											2012-10-02 09:12:39 +02:00
										 |  |  | ** Commercial License Usage | 
					
						
							|  |  |  | ** Licensees holding valid commercial Qt licenses may use this file in | 
					
						
							|  |  |  | ** accordance with the commercial license agreement provided with the | 
					
						
							|  |  |  | ** Software or, alternatively, in accordance with the terms contained in | 
					
						
							|  |  |  | ** a written agreement between you and Digia.  For licensing terms and | 
					
						
							|  |  |  | ** conditions see http://qt.digia.com/licensing.  For further information
 | 
					
						
							|  |  |  | ** use the contact form at http://qt.digia.com/contact-us.
 | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | ** | 
					
						
							|  |  |  | ** GNU Lesser General Public License Usage | 
					
						
							| 
									
										
										
										
											2012-10-02 09:12:39 +02: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.
 | 
					
						
							|  |  |  | ** | 
					
						
							|  |  |  | ** In addition, as a special exception, Digia gives you certain additional | 
					
						
							|  |  |  | ** rights.  These rights are described in the Digia Qt LGPL Exception | 
					
						
							| 
									
										
										
										
											2010-12-17 16:01:08 +01:00
										 |  |  | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | 
					
						
							|  |  |  | ** | 
					
						
							| 
									
										
										
										
											2012-10-02 09:12:39 +02:00
										 |  |  | ****************************************************************************/ | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | #include "cppquickfixes.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | #include "cppeditor.h"
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | #include "cppfunctiondecldeflink.h"
 | 
					
						
							| 
									
										
										
										
											2011-04-15 16:19:23 +02:00
										 |  |  | #include "cppquickfixassistant.h"
 | 
					
						
							| 
									
										
										
										
											2013-11-26 23:16:52 +02:00
										 |  |  | #include "cppvirtualfunctionassistprovider.h"
 | 
					
						
							| 
									
										
										
										
											2014-01-23 07:53:24 +02:00
										 |  |  | #include "cppinsertvirtualmethods.h"
 | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:15:50 +02:00
										 |  |  | #include <coreplugin/icore.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  | #include <cpptools/cppclassesfilter.h>
 | 
					
						
							| 
									
										
										
										
											2013-01-15 14:26:24 +01:00
										 |  |  | #include <cpptools/cppcodestylesettings.h>
 | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  | #include <cpptools/cpppointerdeclarationformatter.h>
 | 
					
						
							|  |  |  | #include <cpptools/cpptoolsconstants.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | #include <cpptools/cpptoolsreuse.h>
 | 
					
						
							| 
									
										
										
										
											2013-06-06 09:27:28 +02:00
										 |  |  | #include <cpptools/includeutils.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | #include <cpptools/insertionpointlocator.h>
 | 
					
						
							| 
									
										
										
										
											2012-01-20 14:43:21 +01:00
										 |  |  | #include <cpptools/symbolfinder.h>
 | 
					
						
							| 
									
										
										
										
											2013-03-27 18:54:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | #include <cplusplus/ASTPath.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | #include <cplusplus/CPlusPlusForwardDeclarations.h>
 | 
					
						
							| 
									
										
										
										
											2013-03-27 18:54:03 +01:00
										 |  |  | #include <cplusplus/CppRewriter.h>
 | 
					
						
							|  |  |  | #include <cplusplus/DependencyTable.h>
 | 
					
						
							|  |  |  | #include <cplusplus/TypeOfExpression.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | #include <extensionsystem/pluginmanager.h>
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | #include <utils/qtcassert.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-15 10:42:41 +01:00
										 |  |  | #include <QApplication>
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | #include <QDir>
 | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  | #include <QFileInfo>
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | #include <QInputDialog>
 | 
					
						
							|  |  |  | #include <QMessageBox>
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | #include <QSharedPointer>
 | 
					
						
							| 
									
										
										
										
											2012-02-15 10:42:41 +01:00
										 |  |  | #include <QTextCursor>
 | 
					
						
							| 
									
										
										
										
											2011-10-25 14:06:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-15 08:26:12 +01:00
										 |  |  | #include <cctype>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | using namespace CPlusPlus; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | using namespace CppEditor; | 
					
						
							|  |  |  | using namespace CppEditor::Internal; | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | using namespace CppTools; | 
					
						
							|  |  |  | using namespace TextEditor; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | void CppEditor::Internal::registerQuickFixes(ExtensionSystem::IPlugin *plugIn) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new AddIncludeForUndefinedIdentifier); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new AddIncludeForForwardDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new FlipLogicalOperands); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new InverseLogicalComparison); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new RewriteLogicalAnd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new ConvertToCamelCase); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new ConvertCStringToNSString); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new ConvertNumericLiteral); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new TranslateStringLiteral); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new WrapStringLiteral); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new MoveDeclarationOutOfIf); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new MoveDeclarationOutOfWhile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new SplitIfStatement); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new SplitSimpleDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new AddLocalDeclaration); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new AddBracesToIf); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new RearrangeParamDeclarationList); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new ReformatPointerDeclaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new CompleteSwitchCaseStatement); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new InsertQtPropertyMembers); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new ApplyDeclDefLinkChanges); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new ExtractFunction); | 
					
						
							| 
									
										
										
										
											2013-09-11 12:00:07 +02:00
										 |  |  |     plugIn->addAutoReleasedObject(new ExtractLiteralAsParameter); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     plugIn->addAutoReleasedObject(new GenerateGetterSetter); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new InsertDeclFromDef); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new InsertDefFromDecl); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new MoveFuncDefOutside); | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new MoveFuncDefToDecl); | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new AssignToLocalVariable); | 
					
						
							| 
									
										
										
										
											2013-04-29 23:15:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new InsertVirtualMethods); | 
					
						
							| 
									
										
										
										
											2013-05-23 20:59:02 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     plugIn->addAutoReleasedObject(new OptimizeForLoop); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | // In the following anonymous namespace all functions are collected, which could be of interest for
 | 
					
						
							|  |  |  | // different quick fixes.
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  | enum DefPos { | 
					
						
							|  |  |  |     DefPosInsideClass, | 
					
						
							|  |  |  |     DefPosOutsideClass, | 
					
						
							|  |  |  |     DefPosImplementationFile | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-15 11:50:44 +02:00
										 |  |  | InsertionLocation insertLocationForMethodDefinition(Symbol *symbol, const bool useSymbolFinder, | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |                                                     CppRefactoringChanges& refactoring, | 
					
						
							|  |  |  |                                                     const QString& fileName) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(symbol, return InsertionLocation()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Try to find optimal location
 | 
					
						
							|  |  |  |     const InsertionPointLocator locator(refactoring); | 
					
						
							| 
									
										
										
										
											2013-06-15 11:50:44 +02:00
										 |  |  |     const QList<InsertionLocation> list | 
					
						
							|  |  |  |             = locator.methodDefinition(symbol, useSymbolFinder, fileName); | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |     for (int i = 0; i < list.count(); ++i) { | 
					
						
							|  |  |  |         InsertionLocation location = list.at(i); | 
					
						
							| 
									
										
										
										
											2013-11-11 22:11:14 +02:00
										 |  |  |         if (location.isValid() && location.fileName() == fileName) | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |             return location; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-15 09:39:53 +02:00
										 |  |  |     // ...failed,
 | 
					
						
							|  |  |  |     // if class member try to get position right after class
 | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |     CppRefactoringFilePtr file = refactoring.file(fileName); | 
					
						
							| 
									
										
										
										
											2013-06-15 09:39:53 +02:00
										 |  |  |     unsigned line = 0, column = 0; | 
					
						
							|  |  |  |     if (Class *clazz = symbol->enclosingClass()) { | 
					
						
							|  |  |  |         if (symbol->fileName() == fileName.toUtf8()) { | 
					
						
							|  |  |  |             file->cppDocument()->translationUnit()->getPosition(clazz->endOffset(), &line, &column); | 
					
						
							|  |  |  |             if (line != 0) { | 
					
						
							|  |  |  |                 ++column; // Skipping the ";"
 | 
					
						
							|  |  |  |                 return InsertionLocation(fileName, QLatin1String("\n\n"), QLatin1String(""), | 
					
						
							|  |  |  |                                          line, column); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // fall through: position at end of file
 | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |     const QTextDocument *doc = file->document(); | 
					
						
							|  |  |  |     int pos = qMax(0, doc->characterCount() - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //TODO watch for matching namespace
 | 
					
						
							|  |  |  |     //TODO watch for moc-includes
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     file->lineAndColumn(pos, &line, &column); | 
					
						
							|  |  |  |     return InsertionLocation(fileName, QLatin1String("\n\n"), QLatin1String("\n"), line, column); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | inline bool isQtStringLiteral(const QByteArray &id) | 
					
						
							| 
									
										
										
										
											2011-09-30 10:45:11 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return id == "QLatin1String" || id == "QLatin1Literal" || id == "QStringLiteral"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | inline bool isQtStringTranslation(const QByteArray &id) | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     return id == "tr" || id == "trUtf8" || id == "translate" || id == "QT_TRANSLATE_NOOP"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | Class *isMemberFunction(const LookupContext &context, Function *function) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(function, return 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Scope *enclosingScope = function->enclosingScope(); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     while (!(enclosingScope->isNamespace() || enclosingScope->isClass())) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         enclosingScope = enclosingScope->enclosingScope(); | 
					
						
							|  |  |  |     QTC_ASSERT(enclosingScope != 0, return 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const Name *functionName = function->name(); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!functionName) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         return 0; // anonymous function names are not valid c++
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!functionName->isQualifiedNameId()) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         return 0; // trying to add a declaration for a global function
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const QualifiedNameId *q = functionName->asQualifiedNameId(); | 
					
						
							|  |  |  |     if (!q->base()) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ClassOrNamespace *binding = context.lookupType(q->base(), enclosingScope)) { | 
					
						
							|  |  |  |         foreach (Symbol *s, binding->symbols()) { | 
					
						
							|  |  |  |             if (Class *matchingClass = s->asClass()) | 
					
						
							|  |  |  |                 return matchingClass; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-12 13:40:17 +02:00
										 |  |  | Namespace *isNamespaceFunction(const LookupContext &context, Function *function) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(function, return 0); | 
					
						
							|  |  |  |     if (isMemberFunction(context, function)) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Scope *enclosingScope = function->enclosingScope(); | 
					
						
							|  |  |  |     while (!(enclosingScope->isNamespace() || enclosingScope->isClass())) | 
					
						
							|  |  |  |         enclosingScope = enclosingScope->enclosingScope(); | 
					
						
							|  |  |  |     QTC_ASSERT(enclosingScope != 0, return 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const Name *functionName = function->name(); | 
					
						
							|  |  |  |     if (!functionName) | 
					
						
							|  |  |  |         return 0; // anonymous function names are not valid c++
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // global namespace
 | 
					
						
							|  |  |  |     if (!functionName->isQualifiedNameId()) { | 
					
						
							|  |  |  |         foreach (Symbol *s, context.globalNamespace()->symbols()) { | 
					
						
							|  |  |  |             if (Namespace *matchingNamespace = s->asNamespace()) | 
					
						
							|  |  |  |                 return matchingNamespace; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const QualifiedNameId *q = functionName->asQualifiedNameId(); | 
					
						
							|  |  |  |     if (!q->base()) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ClassOrNamespace *binding = context.lookupType(q->base(), enclosingScope)) { | 
					
						
							|  |  |  |         foreach (Symbol *s, binding->symbols()) { | 
					
						
							|  |  |  |             if (Namespace *matchingNamespace = s->asNamespace()) | 
					
						
							|  |  |  |                 return matchingNamespace; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 09:27:28 +02:00
										 |  |  | // Given include is e.g. "afile.h" or <afile.h> (quotes/angle brackets included!).
 | 
					
						
							|  |  |  | void insertNewIncludeDirective(const QString &include, CppRefactoringFilePtr file) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // Find optimal position
 | 
					
						
							|  |  |  |     using namespace IncludeUtils; | 
					
						
							| 
									
										
										
										
											2013-07-25 11:21:31 +02:00
										 |  |  |     LineForNewIncludeDirective finder(file->document(), file->cppDocument()->resolvedIncludes(), | 
					
						
							| 
									
										
										
										
											2013-06-06 09:27:28 +02:00
										 |  |  |                                       LineForNewIncludeDirective::IgnoreMocIncludes, | 
					
						
							|  |  |  |                                       LineForNewIncludeDirective::AutoDetect); | 
					
						
							|  |  |  |     unsigned newLinesToPrepend = 0; | 
					
						
							|  |  |  |     unsigned newLinesToAppend = 0; | 
					
						
							|  |  |  |     const int insertLine = finder(include, &newLinesToPrepend, &newLinesToAppend); | 
					
						
							|  |  |  |     QTC_ASSERT(insertLine >= 1, return); | 
					
						
							|  |  |  |     const int insertPosition = file->position(insertLine, 1); | 
					
						
							|  |  |  |     QTC_ASSERT(insertPosition >= 0, return); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Construct text to insert
 | 
					
						
							|  |  |  |     const QString includeLine = QLatin1String("#include ") + include + QLatin1Char('\n'); | 
					
						
							|  |  |  |     QString prependedNewLines, appendedNewLines; | 
					
						
							|  |  |  |     while (newLinesToAppend--) | 
					
						
							|  |  |  |         appendedNewLines += QLatin1String("\n"); | 
					
						
							|  |  |  |     while (newLinesToPrepend--) | 
					
						
							|  |  |  |         prependedNewLines += QLatin1String("\n"); | 
					
						
							|  |  |  |     const QString textToInsert = prependedNewLines + includeLine + appendedNewLines; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Insert
 | 
					
						
							|  |  |  |     ChangeSet changes; | 
					
						
							|  |  |  |     changes.insert(insertPosition, textToInsert); | 
					
						
							|  |  |  |     file->setChangeSet(changes); | 
					
						
							|  |  |  |     file->apply(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  | bool nameIncludesOperatorName(const Name *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return name->isOperatorNameId() | 
					
						
							|  |  |  |         || (name->isQualifiedNameId() && name->asQualifiedNameId()->name()->isOperatorNameId()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class InverseLogicalComparisonOp: public CppQuickFixOperation | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     InverseLogicalComparisonOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                                BinaryExpressionAST *binary, Kind invertToken) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , binary(binary), nested(0), negation(0) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         Token tok; | 
					
						
							|  |  |  |         tok.f.kind = invertToken; | 
					
						
							|  |  |  |         replacement = QLatin1String(tok.spell()); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         // check for enclosing nested expression
 | 
					
						
							|  |  |  |         if (priority - 1 >= 0) | 
					
						
							|  |  |  |             nested = interface->path()[priority - 1]->asNestedExpression(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         // check for ! before parentheses
 | 
					
						
							|  |  |  |         if (nested && priority - 2 >= 0) { | 
					
						
							|  |  |  |             negation = interface->path()[priority - 2]->asUnaryExpression(); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             if (negation | 
					
						
							|  |  |  |                     && !interface->currentFile()->tokenAt(negation->unary_op_token).is(T_EXCLAIM)) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 negation = 0; | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     QString description() const | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ChangeSet changes; | 
					
						
							|  |  |  |         if (negation) { | 
					
						
							|  |  |  |             // can't remove parentheses since that might break precedence
 | 
					
						
							|  |  |  |             changes.remove(currentFile->range(negation->unary_op_token)); | 
					
						
							|  |  |  |         } else if (nested) { | 
					
						
							|  |  |  |             changes.insert(currentFile->startOf(nested), QLatin1String("!")); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             changes.insert(currentFile->startOf(binary), QLatin1String("!(")); | 
					
						
							|  |  |  |             changes.insert(currentFile->endOf(binary), QLatin1String(")")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         changes.replace(currentFile->range(binary->binary_op_token), replacement); | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | private: | 
					
						
							|  |  |  |     BinaryExpressionAST *binary; | 
					
						
							|  |  |  |     NestedExpressionAST *nested; | 
					
						
							|  |  |  |     UnaryExpressionAST *negation; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     QString replacement; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void InverseLogicalComparison::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                      QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     int index = path.size() - 1; | 
					
						
							|  |  |  |     BinaryExpressionAST *binary = path.at(index)->asBinaryExpression(); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!binary) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!interface->isCursorOn(binary->binary_op_token)) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Kind invertToken; | 
					
						
							|  |  |  |     switch (file->tokenAt(binary->binary_op_token).kind()) { | 
					
						
							|  |  |  |     case T_LESS_EQUAL: | 
					
						
							|  |  |  |         invertToken = T_GREATER; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_LESS: | 
					
						
							|  |  |  |         invertToken = T_GREATER_EQUAL; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_GREATER: | 
					
						
							|  |  |  |         invertToken = T_LESS_EQUAL; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_GREATER_EQUAL: | 
					
						
							|  |  |  |         invertToken = T_LESS; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_EQUAL_EQUAL: | 
					
						
							|  |  |  |         invertToken = T_EXCLAIM_EQUAL; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_EXCLAIM_EQUAL: | 
					
						
							|  |  |  |         invertToken = T_EQUAL_EQUAL; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     result.append(CppQuickFixOperation::Ptr( | 
					
						
							|  |  |  |         new InverseLogicalComparisonOp(interface, index, binary, invertToken))); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-01-07 16:55:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class FlipLogicalOperandsOp: public CppQuickFixOperation | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     FlipLogicalOperandsOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                           BinaryExpressionAST *binary, QString replacement) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , binary(binary) | 
					
						
							|  |  |  |         , replacement(replacement) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         setPriority(priority); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     QString description() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (replacement.isEmpty()) | 
					
						
							|  |  |  |             return QApplication::translate("CppTools::QuickFix", "Swap Operands"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         changes.flip(currentFile->range(binary->left_expression), | 
					
						
							|  |  |  |                      currentFile->range(binary->right_expression)); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |         if (!replacement.isEmpty()) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             changes.replace(currentFile->range(binary->binary_op_token), replacement); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     BinaryExpressionAST *binary; | 
					
						
							|  |  |  |     QString replacement; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void FlipLogicalOperands::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     int index = path.size() - 1; | 
					
						
							|  |  |  |     BinaryExpressionAST *binary = path.at(index)->asBinaryExpression(); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!binary) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!interface->isCursorOn(binary->binary_op_token)) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     Kind flipToken; | 
					
						
							|  |  |  |     switch (file->tokenAt(binary->binary_op_token).kind()) { | 
					
						
							|  |  |  |     case T_LESS_EQUAL: | 
					
						
							|  |  |  |         flipToken = T_GREATER_EQUAL; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_LESS: | 
					
						
							|  |  |  |         flipToken = T_GREATER; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_GREATER: | 
					
						
							|  |  |  |         flipToken = T_LESS; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_GREATER_EQUAL: | 
					
						
							|  |  |  |         flipToken = T_LESS_EQUAL; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case T_EQUAL_EQUAL: | 
					
						
							|  |  |  |     case T_EXCLAIM_EQUAL: | 
					
						
							|  |  |  |     case T_AMPER_AMPER: | 
					
						
							|  |  |  |     case T_PIPE_PIPE: | 
					
						
							|  |  |  |         flipToken = T_EOF_SYMBOL; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     QString replacement; | 
					
						
							|  |  |  |     if (flipToken != T_EOF_SYMBOL) { | 
					
						
							|  |  |  |         Token tok; | 
					
						
							|  |  |  |         tok.f.kind = flipToken; | 
					
						
							|  |  |  |         replacement = QLatin1String(tok.spell()); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |         new FlipLogicalOperandsOp(interface, index, binary, replacement))); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-01-07 16:55:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class RewriteLogicalAndOp: public CppQuickFixOperation | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     QSharedPointer<ASTPatternBuilder> mk; | 
					
						
							|  |  |  |     UnaryExpressionAST *left; | 
					
						
							|  |  |  |     UnaryExpressionAST *right; | 
					
						
							|  |  |  |     BinaryExpressionAST *pattern; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     RewriteLogicalAndOp(const CppQuickFixInterface &interface) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , mk(new ASTPatternBuilder) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         left = mk->UnaryExpression(); | 
					
						
							|  |  |  |         right = mk->UnaryExpression(); | 
					
						
							|  |  |  |         pattern = mk->BinaryExpression(left, right); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ChangeSet changes; | 
					
						
							|  |  |  |         changes.replace(currentFile->range(pattern->binary_op_token), QLatin1String("||")); | 
					
						
							|  |  |  |         changes.remove(currentFile->range(left->unary_op_token)); | 
					
						
							|  |  |  |         changes.remove(currentFile->range(right->unary_op_token)); | 
					
						
							|  |  |  |         const int start = currentFile->startOf(pattern); | 
					
						
							|  |  |  |         const int end = currentFile->endOf(pattern); | 
					
						
							|  |  |  |         changes.insert(start, QLatin1String("!(")); | 
					
						
							|  |  |  |         changes.insert(end, QLatin1String(")")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->appendIndentRange(currentFile->range(pattern)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void RewriteLogicalAnd::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     BinaryExpressionAST *expression = 0; | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     int index = path.size() - 1; | 
					
						
							|  |  |  |     for (; index != -1; --index) { | 
					
						
							|  |  |  |         expression = path.at(index)->asBinaryExpression(); | 
					
						
							|  |  |  |         if (expression) | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!expression) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!interface->isCursorOn(expression->binary_op_token)) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     QSharedPointer<RewriteLogicalAndOp> op(new RewriteLogicalAndOp(interface)); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (expression->match(op->pattern, &matcher) && | 
					
						
							|  |  |  |             file->tokenAt(op->pattern->binary_op_token).is(T_AMPER_AMPER) && | 
					
						
							|  |  |  |             file->tokenAt(op->left->unary_op_token).is(T_EXCLAIM) && | 
					
						
							|  |  |  |             file->tokenAt(op->right->unary_op_token).is(T_EXCLAIM)) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         op->setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                    "Rewrite Condition Using ||")); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         op->setPriority(index); | 
					
						
							|  |  |  |         result.append(op); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | bool SplitSimpleDeclaration::checkDeclaration(SimpleDeclarationAST *declaration) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!declaration->semicolon_token) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!declaration->decl_specifier_list) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2011-01-07 14:49:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     for (SpecifierListAST *it = declaration->decl_specifier_list; it; it = it->next) { | 
					
						
							|  |  |  |         SpecifierAST *specifier = it->value; | 
					
						
							| 
									
										
										
										
											2011-01-07 16:55:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         if (specifier->asEnumSpecifier() != 0) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         else if (specifier->asClassSpecifier() != 0) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!declaration->declarator_list) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     else if (!declaration->declarator_list->next) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class SplitSimpleDeclarationOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     SplitSimpleDeclarationOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                              SimpleDeclarationAST *decl) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , declaration(decl) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                "Split Declaration")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         SpecifierListAST *specifiers = declaration->decl_specifier_list; | 
					
						
							|  |  |  |         int declSpecifiersStart = currentFile->startOf(specifiers->firstToken()); | 
					
						
							|  |  |  |         int declSpecifiersEnd = currentFile->endOf(specifiers->lastToken() - 1); | 
					
						
							|  |  |  |         int insertPos = currentFile->endOf(declaration->semicolon_token); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         DeclaratorAST *prevDeclarator = declaration->declarator_list->value; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         for (DeclaratorListAST *it = declaration->declarator_list->next; it; it = it->next) { | 
					
						
							|  |  |  |             DeclaratorAST *declarator = it->value; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             changes.insert(insertPos, QLatin1String("\n")); | 
					
						
							|  |  |  |             changes.copy(declSpecifiersStart, declSpecifiersEnd, insertPos); | 
					
						
							|  |  |  |             changes.insert(insertPos, QLatin1String(" ")); | 
					
						
							|  |  |  |             changes.move(currentFile->range(declarator), insertPos); | 
					
						
							|  |  |  |             changes.insert(insertPos, QLatin1String(";")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             const int prevDeclEnd = currentFile->endOf(prevDeclarator); | 
					
						
							|  |  |  |             changes.remove(prevDeclEnd, currentFile->startOf(declarator)); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             prevDeclarator = declarator; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->appendIndentRange(currentFile->range(declaration)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     SimpleDeclarationAST *declaration; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void SplitSimpleDeclaration::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                    QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CoreDeclaratorAST *core_declarator = 0; | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  |     const int cursorPosition = file->cursor().selectionStart(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     for (int index = path.size() - 1; index != -1; --index) { | 
					
						
							|  |  |  |         AST *node = path.at(index); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-17 00:01:45 +03:00
										 |  |  |         if (CoreDeclaratorAST *coreDecl = node->asCoreDeclarator()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             core_declarator = coreDecl; | 
					
						
							| 
									
										
										
										
											2013-07-17 00:01:45 +03:00
										 |  |  |         } else if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             if (checkDeclaration(simpleDecl)) { | 
					
						
							|  |  |  |                 SimpleDeclarationAST *declaration = simpleDecl; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 const int startOfDeclSpecifier = file->startOf(declaration->decl_specifier_list->firstToken()); | 
					
						
							|  |  |  |                 const int endOfDeclSpecifier = file->endOf(declaration->decl_specifier_list->lastToken() - 1); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 if (cursorPosition >= startOfDeclSpecifier && cursorPosition <= endOfDeclSpecifier) { | 
					
						
							|  |  |  |                     // the AST node under cursor is a specifier.
 | 
					
						
							|  |  |  |                     result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                         new SplitSimpleDeclarationOp(interface, index, declaration))); | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 if (core_declarator && interface->isCursorOn(core_declarator)) { | 
					
						
							|  |  |  |                     // got a core-declarator under the text cursor.
 | 
					
						
							|  |  |  |                     result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                         new SplitSimpleDeclarationOp(interface, index, declaration))); | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class AddBracesToIfOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     AddBracesToIfOp(const CppQuickFixInterface &interface, int priority, StatementAST *statement) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , _statement(statement) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", "Add Curly Braces")); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const int start = currentFile->endOf(_statement->firstToken() - 1); | 
					
						
							|  |  |  |         changes.insert(start, QLatin1String(" {")); | 
					
						
							| 
									
										
										
										
											2011-01-07 14:49:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const int end = currentFile->endOf(_statement->lastToken() - 1); | 
					
						
							|  |  |  |         changes.insert(end, QLatin1String("\n}")); | 
					
						
							| 
									
										
										
										
											2011-01-07 16:55:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         currentFile->setChangeSet(changes); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         currentFile->appendIndentRange(ChangeSet::Range(start, end)); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     StatementAST *_statement; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void AddBracesToIf::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // show when we're on the 'if' of an if statement
 | 
					
						
							|  |  |  |     int index = path.size() - 1; | 
					
						
							|  |  |  |     IfStatementAST *ifStatement = path.at(index)->asIfStatement(); | 
					
						
							|  |  |  |     if (ifStatement && interface->isCursorOn(ifStatement->if_token) && ifStatement->statement | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |         && !ifStatement->statement->asCompoundStatement()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |             new AddBracesToIfOp(interface, index, ifStatement->statement))); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // or if we're on the statement contained in the if
 | 
					
						
							|  |  |  |     // ### This may not be such a good idea, consider nested ifs...
 | 
					
						
							|  |  |  |     for (; index != -1; --index) { | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         IfStatementAST *ifStatement = path.at(index)->asIfStatement(); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         if (ifStatement && ifStatement->statement | 
					
						
							|  |  |  |             && interface->isCursorOn(ifStatement->statement) | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             && !ifStatement->statement->asCompoundStatement()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                 new AddBracesToIfOp(interface, index, ifStatement->statement))); | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // ### This could very well be extended to the else branch
 | 
					
						
							|  |  |  |     // and other nodes entirely.
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class MoveDeclarationOutOfIfOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     MoveDeclarationOutOfIfOp(const CppQuickFixInterface &interface) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                "Move Declaration out of Condition")); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-27 15:53:03 +01:00
										 |  |  |         reset(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void reset() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         condition = mk.Condition(); | 
					
						
							|  |  |  |         pattern = mk.IfStatement(condition); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         changes.copy(currentFile->range(core), currentFile->startOf(condition)); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         int insertPos = currentFile->startOf(pattern); | 
					
						
							|  |  |  |         changes.move(currentFile->range(condition), insertPos); | 
					
						
							|  |  |  |         changes.insert(insertPos, QLatin1String(";\n")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->appendIndentRange(currentFile->range(pattern)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     ASTMatcher matcher; | 
					
						
							|  |  |  |     ASTPatternBuilder mk; | 
					
						
							|  |  |  |     ConditionAST *condition; | 
					
						
							|  |  |  |     IfStatementAST *pattern; | 
					
						
							|  |  |  |     CoreDeclaratorAST *core; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void MoveDeclarationOutOfIf::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                    QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     typedef QSharedPointer<MoveDeclarationOutOfIfOp> Ptr; | 
					
						
							|  |  |  |     Ptr op(new MoveDeclarationOutOfIfOp(interface)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int index = path.size() - 1; | 
					
						
							|  |  |  |     for (; index != -1; --index) { | 
					
						
							|  |  |  |         if (IfStatementAST *statement = path.at(index)->asIfStatement()) { | 
					
						
							|  |  |  |             if (statement->match(op->pattern, &op->matcher) && op->condition->declarator) { | 
					
						
							|  |  |  |                 DeclaratorAST *declarator = op->condition->declarator; | 
					
						
							|  |  |  |                 op->core = declarator->core_declarator; | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                 if (!op->core) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 if (interface->isCursorOn(op->core)) { | 
					
						
							|  |  |  |                     op->setPriority(index); | 
					
						
							|  |  |  |                     result.append(op); | 
					
						
							|  |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2013-11-27 15:53:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 op->reset(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class MoveDeclarationOutOfWhileOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     MoveDeclarationOutOfWhileOp(const CppQuickFixInterface &interface) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                "Move Declaration out of Condition")); | 
					
						
							| 
									
										
										
										
											2013-11-27 15:53:03 +01:00
										 |  |  |         reset(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-27 15:53:03 +01:00
										 |  |  |     void reset() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         condition = mk.Condition(); | 
					
						
							|  |  |  |         pattern = mk.WhileStatement(condition); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         changes.insert(currentFile->startOf(condition), QLatin1String("(")); | 
					
						
							|  |  |  |         changes.insert(currentFile->endOf(condition), QLatin1String(") != 0")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         int insertPos = currentFile->startOf(pattern); | 
					
						
							|  |  |  |         const int conditionStart = currentFile->startOf(condition); | 
					
						
							|  |  |  |         changes.move(conditionStart, currentFile->startOf(core), insertPos); | 
					
						
							|  |  |  |         changes.copy(currentFile->range(core), insertPos); | 
					
						
							|  |  |  |         changes.insert(insertPos, QLatin1String(";\n")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->appendIndentRange(currentFile->range(pattern)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     ASTMatcher matcher; | 
					
						
							|  |  |  |     ASTPatternBuilder mk; | 
					
						
							|  |  |  |     ConditionAST *condition; | 
					
						
							|  |  |  |     WhileStatementAST *pattern; | 
					
						
							|  |  |  |     CoreDeclaratorAST *core; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2011-01-07 16:55:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void MoveDeclarationOutOfWhile::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                       QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     QSharedPointer<MoveDeclarationOutOfWhileOp> op(new MoveDeclarationOutOfWhileOp(interface)); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     int index = path.size() - 1; | 
					
						
							|  |  |  |     for (; index != -1; --index) { | 
					
						
							|  |  |  |         if (WhileStatementAST *statement = path.at(index)->asWhileStatement()) { | 
					
						
							|  |  |  |             if (statement->match(op->pattern, &op->matcher) && op->condition->declarator) { | 
					
						
							|  |  |  |                 DeclaratorAST *declarator = op->condition->declarator; | 
					
						
							|  |  |  |                 op->core = declarator->core_declarator; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                 if (!op->core) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                 if (!declarator->equal_token) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                 if (!declarator->initializer) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 if (interface->isCursorOn(op->core)) { | 
					
						
							|  |  |  |                     op->setPriority(index); | 
					
						
							|  |  |  |                     result.append(op); | 
					
						
							|  |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2013-11-27 15:53:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 op->reset(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class SplitIfStatementOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     SplitIfStatementOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                        IfStatementAST *pattern, BinaryExpressionAST *condition) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , pattern(pattern) | 
					
						
							|  |  |  |         , condition(condition) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                "Split if Statement")); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const Token binaryToken = currentFile->tokenAt(condition->binary_op_token); | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         if (binaryToken.is(T_AMPER_AMPER)) | 
					
						
							|  |  |  |             splitAndCondition(currentFile); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             splitOrCondition(currentFile); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void splitAndCondition(CppRefactoringFilePtr currentFile) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         int startPos = currentFile->startOf(pattern); | 
					
						
							|  |  |  |         changes.insert(startPos, QLatin1String("if (")); | 
					
						
							|  |  |  |         changes.move(currentFile->range(condition->left_expression), startPos); | 
					
						
							|  |  |  |         changes.insert(startPos, QLatin1String(") {\n")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const int lExprEnd = currentFile->endOf(condition->left_expression); | 
					
						
							|  |  |  |         changes.remove(lExprEnd, currentFile->startOf(condition->right_expression)); | 
					
						
							|  |  |  |         changes.insert(currentFile->endOf(pattern), QLatin1String("\n}")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->appendIndentRange(currentFile->range(pattern)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void splitOrCondition(CppRefactoringFilePtr currentFile) const | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         StatementAST *ifTrueStatement = pattern->statement; | 
					
						
							|  |  |  |         CompoundStatementAST *compoundStatement = ifTrueStatement->asCompoundStatement(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         int insertPos = currentFile->endOf(ifTrueStatement); | 
					
						
							|  |  |  |         if (compoundStatement) | 
					
						
							|  |  |  |             changes.insert(insertPos, QLatin1String(" ")); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             changes.insert(insertPos, QLatin1String("\n")); | 
					
						
							|  |  |  |         changes.insert(insertPos, QLatin1String("else if (")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const int rExprStart = currentFile->startOf(condition->right_expression); | 
					
						
							|  |  |  |         changes.move(rExprStart, currentFile->startOf(pattern->rparen_token), insertPos); | 
					
						
							|  |  |  |         changes.insert(insertPos, QLatin1String(")")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const int rParenEnd = currentFile->endOf(pattern->rparen_token); | 
					
						
							|  |  |  |         changes.copy(rParenEnd, currentFile->endOf(pattern->statement), insertPos); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const int lExprEnd = currentFile->endOf(condition->left_expression); | 
					
						
							|  |  |  |         changes.remove(lExprEnd, currentFile->startOf(condition->right_expression)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->appendIndentRange(currentFile->range(pattern)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     IfStatementAST *pattern; | 
					
						
							|  |  |  |     BinaryExpressionAST *condition; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void SplitIfStatement::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     IfStatementAST *pattern = 0; | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     int index = path.size() - 1; | 
					
						
							|  |  |  |     for (; index != -1; --index) { | 
					
						
							|  |  |  |         AST *node = path.at(index); | 
					
						
							|  |  |  |         if (IfStatementAST *stmt = node->asIfStatement()) { | 
					
						
							|  |  |  |             pattern = stmt; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!pattern || !pattern->statement) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     unsigned splitKind = 0; | 
					
						
							|  |  |  |     for (++index; index < path.size(); ++index) { | 
					
						
							|  |  |  |         AST *node = path.at(index); | 
					
						
							|  |  |  |         BinaryExpressionAST *condition = node->asBinaryExpression(); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |         if (!condition) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         Token binaryToken = interface->currentFile()->tokenAt(condition->binary_op_token); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         // only accept a chain of ||s or &&s - no mixing
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |         if (!splitKind) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             splitKind = binaryToken.kind(); | 
					
						
							|  |  |  |             if (splitKind != T_AMPER_AMPER && splitKind != T_PIPE_PIPE) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             // we can't reliably split &&s in ifs with an else branch
 | 
					
						
							|  |  |  |             if (splitKind == T_AMPER_AMPER && pattern->else_statement) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |         } else if (splitKind != binaryToken.kind()) { | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         if (interface->isCursorOn(condition->binary_op_token)) { | 
					
						
							|  |  |  |             result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                 new SplitIfStatementOp(interface, index, pattern, condition))); | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-09-30 10:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | /* Analze a string/character literal like "x", QLatin1String("x") and return the literal
 | 
					
						
							|  |  |  |  * (StringLiteral or NumericLiteral for characters) and its type | 
					
						
							|  |  |  |  * and the enclosing function (QLatin1String, tr...) */ | 
					
						
							|  |  |  | ExpressionAST *WrapStringLiteral::analyze(const QList<AST *> &path, | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                                           const CppRefactoringFilePtr &file, Type *type, | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |                                           QByteArray *enclosingFunction /* = 0 */, | 
					
						
							|  |  |  |                                           CallAST **enclosingFunctionCall /* = 0 */) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     *type = TypeNone; | 
					
						
							|  |  |  |     if (enclosingFunction) | 
					
						
							|  |  |  |         enclosingFunction->clear(); | 
					
						
							|  |  |  |     if (enclosingFunctionCall) | 
					
						
							|  |  |  |         *enclosingFunctionCall = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (path.isEmpty()) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ExpressionAST *literal = path.last()->asExpression(); | 
					
						
							|  |  |  |     if (literal) { | 
					
						
							|  |  |  |         if (literal->asStringLiteral()) { | 
					
						
							|  |  |  |             // Check for Objective C string (@"bla")
 | 
					
						
							|  |  |  |             const QChar firstChar = file->charAt(file->startOf(literal)); | 
					
						
							|  |  |  |             *type = firstChar == QLatin1Char('@') ? TypeObjCString : TypeString; | 
					
						
							|  |  |  |         } else if (NumericLiteralAST *numericLiteral = literal->asNumericLiteral()) { | 
					
						
							|  |  |  |             // character ('c') constants are numeric.
 | 
					
						
							|  |  |  |             if (file->tokenAt(numericLiteral->literal_token).is(T_CHAR_LITERAL)) | 
					
						
							|  |  |  |                 *type = TypeChar; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |     if (*type != TypeNone && enclosingFunction && path.size() > 1) { | 
					
						
							|  |  |  |         if (CallAST *call = path.at(path.size() - 2)->asCall()) { | 
					
						
							|  |  |  |             if (call->base_expression) { | 
					
						
							|  |  |  |                 if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) { | 
					
						
							|  |  |  |                     if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) { | 
					
						
							|  |  |  |                         *enclosingFunction = file->tokenAt(functionName->identifier_token).identifier->chars(); | 
					
						
							|  |  |  |                         if (enclosingFunctionCall) | 
					
						
							|  |  |  |                             *enclosingFunctionCall = call; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     return literal; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | /// Operation performs the operations of type ActionFlags passed in as actions.
 | 
					
						
							|  |  |  | class WrapStringLiteralOp : public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     typedef WrapStringLiteral Factory; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     WrapStringLiteralOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                         unsigned actions, const QString &description, ExpressionAST *literal, | 
					
						
							|  |  |  |                         const QString &translationContext = QString()) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority), m_actions(actions), m_literal(literal), | 
					
						
							|  |  |  |           m_translationContext(translationContext) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(description); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ChangeSet changes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const int startPos = currentFile->startOf(m_literal); | 
					
						
							|  |  |  |         const int endPos = currentFile->endOf(m_literal); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // kill leading '@'. No need to adapt endPos, that is done by ChangeSet
 | 
					
						
							|  |  |  |         if (m_actions & Factory::RemoveObjectiveCAction) | 
					
						
							|  |  |  |             changes.remove(startPos, startPos + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Fix quotes
 | 
					
						
							|  |  |  |         if (m_actions & (Factory::SingleQuoteAction | Factory::DoubleQuoteAction)) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |             const QString newQuote((m_actions & Factory::SingleQuoteAction) | 
					
						
							|  |  |  |                                    ? QLatin1Char('\'') : QLatin1Char('"')); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             changes.replace(startPos, startPos + 1, newQuote); | 
					
						
							|  |  |  |             changes.replace(endPos - 1, endPos, newQuote); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Convert single character strings into character constants
 | 
					
						
							|  |  |  |         if (m_actions & Factory::ConvertEscapeSequencesToCharAction) { | 
					
						
							|  |  |  |             StringLiteralAST *stringLiteral = m_literal->asStringLiteral(); | 
					
						
							|  |  |  |             QTC_ASSERT(stringLiteral, return ;); | 
					
						
							|  |  |  |             const QByteArray oldContents(currentFile->tokenAt(stringLiteral->literal_token).identifier->chars()); | 
					
						
							|  |  |  |             const QByteArray newContents = Factory::stringToCharEscapeSequences(oldContents); | 
					
						
							|  |  |  |             QTC_ASSERT(!newContents.isEmpty(), return ;); | 
					
						
							|  |  |  |             if (oldContents != newContents) | 
					
						
							|  |  |  |                 changes.replace(startPos + 1, endPos -1, QString::fromLatin1(newContents)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Convert character constants into strings constants
 | 
					
						
							|  |  |  |         if (m_actions & Factory::ConvertEscapeSequencesToStringAction) { | 
					
						
							|  |  |  |             NumericLiteralAST *charLiteral = m_literal->asNumericLiteral(); // char 'c' constants are numerical.
 | 
					
						
							|  |  |  |             QTC_ASSERT(charLiteral, return ;); | 
					
						
							|  |  |  |             const QByteArray oldContents(currentFile->tokenAt(charLiteral->literal_token).identifier->chars()); | 
					
						
							|  |  |  |             const QByteArray newContents = Factory::charToStringEscapeSequences(oldContents); | 
					
						
							|  |  |  |             QTC_ASSERT(!newContents.isEmpty(), return ;); | 
					
						
							|  |  |  |             if (oldContents != newContents) | 
					
						
							|  |  |  |                 changes.replace(startPos + 1, endPos -1, QString::fromLatin1(newContents)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Enclose in literal or translation function, macro.
 | 
					
						
							|  |  |  |         if (m_actions & (Factory::EncloseActionMask | Factory::TranslationMask)) { | 
					
						
							|  |  |  |             changes.insert(endPos, QString(QLatin1Char(')'))); | 
					
						
							|  |  |  |             QString leading = Factory::replacement(m_actions); | 
					
						
							|  |  |  |             leading += QLatin1Char('('); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |             if (m_actions | 
					
						
							|  |  |  |                     & (Factory::TranslateQCoreApplicationAction | Factory::TranslateNoopAction)) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 leading += QLatin1Char('"'); | 
					
						
							|  |  |  |                 leading += m_translationContext; | 
					
						
							|  |  |  |                 leading += QLatin1String("\", "); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             changes.insert(startPos, leading); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     const unsigned m_actions; | 
					
						
							|  |  |  |     ExpressionAST *m_literal; | 
					
						
							|  |  |  |     const QString m_translationContext; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | void WrapStringLiteral::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     typedef CppQuickFixOperation::Ptr OperationPtr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Type type = TypeNone; | 
					
						
							|  |  |  |     QByteArray enclosingFunction; | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     ExpressionAST *literal = analyze(path, file, &type, &enclosingFunction); | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |     if (!literal || type == TypeNone) | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |     if ((type == TypeChar && enclosingFunction == "QLatin1Char") | 
					
						
							|  |  |  |         || isQtStringLiteral(enclosingFunction) | 
					
						
							|  |  |  |         || isQtStringTranslation(enclosingFunction)) | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-09-30 10:45:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |     const int priority = path.size() - 1; // very high priority
 | 
					
						
							|  |  |  |     if (type == TypeChar) { | 
					
						
							|  |  |  |         unsigned actions = EncloseInQLatin1CharAction; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         QString description = msgQtStringLiteralDescription(replacement(actions)); | 
					
						
							|  |  |  |         result << OperationPtr(new WrapStringLiteralOp(interface, priority, actions, | 
					
						
							|  |  |  |                                                              description, literal)); | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |         if (NumericLiteralAST *charLiteral = literal->asNumericLiteral()) { | 
					
						
							|  |  |  |             const QByteArray contents(file->tokenAt(charLiteral->literal_token).identifier->chars()); | 
					
						
							|  |  |  |             if (!charToStringEscapeSequences(contents).isEmpty()) { | 
					
						
							|  |  |  |                 actions = DoubleQuoteAction | ConvertEscapeSequencesToStringAction; | 
					
						
							|  |  |  |                 description = QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                               "Convert to String Literal"); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 result << OperationPtr(new WrapStringLiteralOp(interface, priority, actions, | 
					
						
							|  |  |  |                                                                      description, literal)); | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-09-30 10:45:11 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         const unsigned objectiveCActions = type == TypeObjCString ? | 
					
						
							|  |  |  |                                            unsigned(RemoveObjectiveCAction) : 0u; | 
					
						
							|  |  |  |         unsigned actions = 0; | 
					
						
							|  |  |  |         if (StringLiteralAST *stringLiteral = literal->asStringLiteral()) { | 
					
						
							|  |  |  |             const QByteArray contents(file->tokenAt(stringLiteral->literal_token).identifier->chars()); | 
					
						
							|  |  |  |             if (!stringToCharEscapeSequences(contents).isEmpty()) { | 
					
						
							|  |  |  |                 actions = EncloseInQLatin1CharAction | SingleQuoteAction | 
					
						
							|  |  |  |                           | ConvertEscapeSequencesToCharAction | objectiveCActions; | 
					
						
							|  |  |  |                 QString description = QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                       "Convert to Character Literal and Enclose in QLatin1Char(...)"); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                 result << OperationPtr(new WrapStringLiteralOp(interface, priority, actions, | 
					
						
							|  |  |  |                                                                description, literal)); | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |                 actions &= ~EncloseInQLatin1CharAction; | 
					
						
							|  |  |  |                 description = QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                               "Convert to Character Literal"); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                 result << OperationPtr(new WrapStringLiteralOp(interface, priority, actions, | 
					
						
							|  |  |  |                                                                description, literal)); | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         actions = EncloseInQLatin1StringAction | objectiveCActions; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         result << OperationPtr( | 
					
						
							|  |  |  |             new WrapStringLiteralOp(interface, priority, actions, | 
					
						
							|  |  |  |                 msgQtStringLiteralDescription(replacement(actions), 4), | 
					
						
							|  |  |  |                     literal)); | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |         actions = EncloseInQStringLiteralAction | objectiveCActions; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         result << OperationPtr( | 
					
						
							|  |  |  |             new WrapStringLiteralOp(interface, priority, actions, | 
					
						
							|  |  |  |                 msgQtStringLiteralDescription(replacement(actions), 5), literal)); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | QString WrapStringLiteral::replacement(unsigned actions) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (actions & EncloseInQLatin1CharAction) | 
					
						
							|  |  |  |         return QLatin1String("QLatin1Char"); | 
					
						
							|  |  |  |     if (actions & EncloseInQLatin1StringAction) | 
					
						
							|  |  |  |         return QLatin1String("QLatin1String"); | 
					
						
							|  |  |  |     if (actions & EncloseInQStringLiteralAction) | 
					
						
							|  |  |  |         return QLatin1String("QStringLiteral"); | 
					
						
							|  |  |  |     if (actions & TranslateTrAction) | 
					
						
							|  |  |  |         return QLatin1String("tr"); | 
					
						
							|  |  |  |     if (actions & TranslateQCoreApplicationAction) | 
					
						
							|  |  |  |         return QLatin1String("QCoreApplication::translate"); | 
					
						
							|  |  |  |     if (actions & TranslateNoopAction) | 
					
						
							|  |  |  |         return QLatin1String("QT_TRANSLATE_NOOP"); | 
					
						
							|  |  |  |     return QString(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | /* Convert single-character string literals into character literals with some
 | 
					
						
							|  |  |  |  * special cases "a" --> 'a', "'" --> '\'', "\n" --> '\n', "\"" --> '"'. */ | 
					
						
							|  |  |  | QByteArray WrapStringLiteral::stringToCharEscapeSequences(const QByteArray &content) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (content.size() == 1) | 
					
						
							|  |  |  |         return content.at(0) == '\'' ? QByteArray("\\'") : content; | 
					
						
							|  |  |  |     if (content.size() == 2 && content.at(0) == '\\') | 
					
						
							|  |  |  |         return content == "\\\"" ? QByteArray(1, '"') : content; | 
					
						
							|  |  |  |     return QByteArray(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | /* Convert character literal into a string literal with some special cases
 | 
					
						
							|  |  |  |  * 'a' -> "a", '\n' -> "\n", '\'' --> "'", '"' --> "\"". */ | 
					
						
							|  |  |  | QByteArray WrapStringLiteral::charToStringEscapeSequences(const QByteArray &content) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (content.size() == 1) | 
					
						
							|  |  |  |         return content.at(0) == '"' ? QByteArray("\\\"") : content; | 
					
						
							|  |  |  |     if (content.size() == 2) | 
					
						
							|  |  |  |         return content == "\\'" ? QByteArray("'") : content; | 
					
						
							|  |  |  |     return QByteArray(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | inline QString WrapStringLiteral::msgQtStringLiteralDescription(const QString &replacement, | 
					
						
							|  |  |  |                                                                        int qtVersion) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QApplication::translate("CppTools::QuickFix", "Enclose in %1(...) (Qt %2)") | 
					
						
							|  |  |  |            .arg(replacement).arg(qtVersion); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline QString WrapStringLiteral::msgQtStringLiteralDescription(const QString &replacement) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return QApplication::translate("CppTools::QuickFix", "Enclose in %1(...)").arg(replacement); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void TranslateStringLiteral::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                    QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // Initialize
 | 
					
						
							|  |  |  |     WrapStringLiteral::Type type = WrapStringLiteral::TypeNone; | 
					
						
							|  |  |  |     QByteArray enclosingFunction; | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  |     ExpressionAST *literal = WrapStringLiteral::analyze(path, file, &type, &enclosingFunction); | 
					
						
							|  |  |  |     if (!literal || type != WrapStringLiteral::TypeString | 
					
						
							|  |  |  |        || isQtStringLiteral(enclosingFunction) || isQtStringTranslation(enclosingFunction)) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     QString trContext; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-20 13:48:20 +01:00
										 |  |  |     QSharedPointer<Control> control = interface->context().bindings()->control(); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const Name *trName = control->identifier("tr"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-07 13:34:40 +02:00
										 |  |  |     // Check whether we are in a function:
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QString description = QApplication::translate("CppTools::QuickFix", "Mark as Translatable"); | 
					
						
							|  |  |  |     for (int i = path.size() - 1; i >= 0; --i) { | 
					
						
							|  |  |  |         if (FunctionDefinitionAST *definition = path.at(i)->asFunctionDefinition()) { | 
					
						
							|  |  |  |             Function *function = definition->symbol; | 
					
						
							|  |  |  |             ClassOrNamespace *b = interface->context().lookupType(function); | 
					
						
							|  |  |  |             if (b) { | 
					
						
							| 
									
										
										
										
											2013-10-07 13:34:40 +02:00
										 |  |  |                 // Do we have a tr function?
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 foreach (const LookupItem &r, b->find(trName)) { | 
					
						
							|  |  |  |                     Symbol *s = r.declaration(); | 
					
						
							|  |  |  |                     if (s->type()->isFunctionType()) { | 
					
						
							|  |  |  |                         // no context required for tr
 | 
					
						
							|  |  |  |                         result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                             new WrapStringLiteralOp(interface, path.size() - 1, | 
					
						
							|  |  |  |                                                           WrapStringLiteral::TranslateTrAction, | 
					
						
							|  |  |  |                                                           description, literal))); | 
					
						
							|  |  |  |                         return; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             // We need to do a QCA::translate, so we need a context.
 | 
					
						
							|  |  |  |             // Use fully qualified class name:
 | 
					
						
							|  |  |  |             Overview oo; | 
					
						
							|  |  |  |             foreach (const Name *n, LookupContext::path(function)) { | 
					
						
							|  |  |  |                 if (!trContext.isEmpty()) | 
					
						
							|  |  |  |                     trContext.append(QLatin1String("::")); | 
					
						
							|  |  |  |                 trContext.append(oo.prettyName(n)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             // ... or global if none available!
 | 
					
						
							|  |  |  |             if (trContext.isEmpty()) | 
					
						
							|  |  |  |                 trContext = QLatin1String("GLOBAL"); | 
					
						
							|  |  |  |             result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                 new WrapStringLiteralOp(interface, path.size() - 1, | 
					
						
							|  |  |  |                                               WrapStringLiteral::TranslateQCoreApplicationAction, | 
					
						
							|  |  |  |                                               description, literal, trContext))); | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // We need to use Q_TRANSLATE_NOOP
 | 
					
						
							|  |  |  |     result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |         new WrapStringLiteralOp(interface, path.size() - 1, | 
					
						
							|  |  |  |                                       WrapStringLiteral::TranslateNoopAction, | 
					
						
							|  |  |  |                                       description, literal, trContext))); | 
					
						
							| 
									
										
										
										
											2011-12-14 14:23:25 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class ConvertCStringToNSStringOp: public CppQuickFixOperation | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     ConvertCStringToNSStringOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                                StringLiteralAST *stringLiteral, CallAST *qlatin1Call) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , stringLiteral(stringLiteral) | 
					
						
							|  |  |  |         , qlatin1Call(qlatin1Call) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                "Convert to Objective-C String Literal")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							| 
									
										
										
										
											2010-08-13 12:49:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         if (qlatin1Call) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |             changes.replace(currentFile->startOf(qlatin1Call), currentFile->startOf(stringLiteral), | 
					
						
							|  |  |  |                             QLatin1String("@")); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             changes.remove(currentFile->endOf(stringLiteral), currentFile->endOf(qlatin1Call)); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             changes.insert(currentFile->startOf(stringLiteral), QLatin1String("@")); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     StringLiteralAST *stringLiteral; | 
					
						
							|  |  |  |     CallAST *qlatin1Call; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void ConvertCStringToNSString::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                      QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-10 12:42:41 +01:00
										 |  |  |     if (!interface->editor()->cppEditorDocument()->isObjCEnabled()) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     WrapStringLiteral::Type type = WrapStringLiteral::TypeNone; | 
					
						
							|  |  |  |     QByteArray enclosingFunction; | 
					
						
							|  |  |  |     CallAST *qlatin1Call; | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     ExpressionAST *literal = WrapStringLiteral::analyze(path, file, &type, &enclosingFunction, | 
					
						
							|  |  |  |                                                         &qlatin1Call); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (!literal || type != WrapStringLiteral::TypeString) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     if (!isQtStringLiteral(enclosingFunction)) | 
					
						
							|  |  |  |         qlatin1Call = 0; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |         new ConvertCStringToNSStringOp(interface, path.size() - 1, literal->asStringLiteral(), | 
					
						
							|  |  |  |             qlatin1Call))); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class ConvertNumericLiteralOp: public CppQuickFixOperation | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     ConvertNumericLiteralOp(const CppQuickFixInterface &interface, int start, int end, | 
					
						
							|  |  |  |                             const QString &replacement) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , start(start) | 
					
						
							|  |  |  |         , end(end) | 
					
						
							|  |  |  |         , replacement(replacement) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         ChangeSet changes; | 
					
						
							|  |  |  |         changes.replace(start, end, replacement); | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | private: | 
					
						
							|  |  |  |     int start, end; | 
					
						
							|  |  |  |     QString replacement; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void ConvertNumericLiteral::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (path.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     NumericLiteralAST *literal = path.last()->asNumericLiteral(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |     if (!literal) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     Token token = file->tokenAt(literal->asNumericLiteral()->literal_token); | 
					
						
							|  |  |  |     if (!token.is(T_NUMERIC_LITERAL)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     const NumericLiteral *numeric = token.number; | 
					
						
							|  |  |  |     if (numeric->isDouble() || numeric->isFloat()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // remove trailing L or U and stuff
 | 
					
						
							|  |  |  |     const char * const spell = numeric->chars(); | 
					
						
							|  |  |  |     int numberLength = numeric->size(); | 
					
						
							|  |  |  |     while (numberLength > 0 && !std::isxdigit(spell[numberLength - 1])) | 
					
						
							|  |  |  |         --numberLength; | 
					
						
							|  |  |  |     if (numberLength < 1) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // convert to number
 | 
					
						
							|  |  |  |     bool valid; | 
					
						
							|  |  |  |     ulong value = QString::fromUtf8(spell).left(numberLength).toULong(&valid, 0); | 
					
						
							|  |  |  |     if (!valid) // e.g. octal with digit > 7
 | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const int priority = path.size() - 1; // very high priority
 | 
					
						
							|  |  |  |     const int start = file->startOf(literal); | 
					
						
							|  |  |  |     const char * const str = numeric->chars(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!numeric->isHex()) { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |           Convert integer literal to hex representation. | 
					
						
							|  |  |  |           Replace | 
					
						
							|  |  |  |             32 | 
					
						
							|  |  |  |             040 | 
					
						
							|  |  |  |           With | 
					
						
							|  |  |  |             0x20 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         */ | 
					
						
							|  |  |  |         QString replacement; | 
					
						
							|  |  |  |         replacement.sprintf("0x%lX", value); | 
					
						
							|  |  |  |         QuickFixOperation::Ptr op( | 
					
						
							|  |  |  |             new ConvertNumericLiteralOp(interface, start, start + numberLength, replacement)); | 
					
						
							|  |  |  |         op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Hexadecimal")); | 
					
						
							|  |  |  |         op->setPriority(priority); | 
					
						
							|  |  |  |         result.append(op); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (value != 0) { | 
					
						
							|  |  |  |         if (!(numberLength > 1 && str[0] == '0' && str[1] != 'x' && str[1] != 'X')) { | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             /*
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |               Convert integer literal to octal representation. | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |               Replace | 
					
						
							|  |  |  |                 32 | 
					
						
							|  |  |  |                 0x20 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |               With | 
					
						
							|  |  |  |                 040 | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             */ | 
					
						
							|  |  |  |             QString replacement; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             replacement.sprintf("0%lo", value); | 
					
						
							|  |  |  |             QuickFixOperation::Ptr op( | 
					
						
							|  |  |  |                 new ConvertNumericLiteralOp(interface, start, start + numberLength, replacement)); | 
					
						
							|  |  |  |             op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Octal")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             op->setPriority(priority); | 
					
						
							|  |  |  |             result.append(op); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (value != 0 || numeric->isHex()) { | 
					
						
							|  |  |  |         if (!(numberLength > 1 && str[0] != '0')) { | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |               Convert integer literal to decimal representation. | 
					
						
							|  |  |  |               Replace | 
					
						
							|  |  |  |                 0x20 | 
					
						
							|  |  |  |                 040 | 
					
						
							|  |  |  |               With | 
					
						
							|  |  |  |                 32 | 
					
						
							|  |  |  |             */ | 
					
						
							|  |  |  |             QString replacement; | 
					
						
							|  |  |  |             replacement.sprintf("%lu", value); | 
					
						
							|  |  |  |             QuickFixOperation::Ptr op( | 
					
						
							|  |  |  |                 new ConvertNumericLiteralOp(interface, start, start + numberLength, replacement)); | 
					
						
							|  |  |  |             op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Decimal")); | 
					
						
							|  |  |  |             op->setPriority(priority); | 
					
						
							|  |  |  |             result.append(op); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class AddIncludeForForwardDeclarationOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     AddIncludeForForwardDeclarationOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                                       Symbol *fwdClass) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , fwdClass(fwdClass) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                "#include Header File")); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         QTC_ASSERT(fwdClass != 0, return); | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         SymbolFinder symbolFinder; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         if (Class *k = symbolFinder.findMatchingClassDeclaration(fwdClass, snapshot())) { | 
					
						
							|  |  |  |             const QString headerFile = QString::fromUtf8(k->fileName(), k->fileNameLength()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // collect the fwd headers
 | 
					
						
							|  |  |  |             Snapshot fwdHeaders; | 
					
						
							|  |  |  |             fwdHeaders.insert(snapshot().document(headerFile)); | 
					
						
							|  |  |  |             foreach (Document::Ptr doc, snapshot()) { | 
					
						
							|  |  |  |                 QFileInfo headerFileInfo(doc->fileName()); | 
					
						
							| 
									
										
										
										
											2013-07-25 11:21:31 +02:00
										 |  |  |                 if (doc->globalSymbolCount() == 0 && doc->resolvedIncludes().size() == 1) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                     fwdHeaders.insert(doc); | 
					
						
							|  |  |  |                 else if (headerFileInfo.suffix().isEmpty()) | 
					
						
							|  |  |  |                     fwdHeaders.insert(doc); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             DependencyTable dep; | 
					
						
							|  |  |  |             dep.build(fwdHeaders); | 
					
						
							|  |  |  |             QStringList candidates = dep.dependencyTable().value(headerFile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const QString className = QString::fromUtf8(k->identifier()->chars()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             QString best; | 
					
						
							|  |  |  |             foreach (const QString &c, candidates) { | 
					
						
							|  |  |  |                 QFileInfo headerFileInfo(c); | 
					
						
							|  |  |  |                 if (headerFileInfo.fileName() == className) { | 
					
						
							|  |  |  |                     best = c; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } else if (headerFileInfo.fileName().at(0).isUpper()) { | 
					
						
							|  |  |  |                     best = c; | 
					
						
							|  |  |  |                     // and continue
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                 } else if (!best.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                     if (c.count(QLatin1Char('/')) < best.count(QLatin1Char('/'))) | 
					
						
							|  |  |  |                         best = c; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             if (best.isEmpty()) | 
					
						
							|  |  |  |                 best = headerFile; | 
					
						
							| 
									
										
										
										
											2011-01-07 16:55:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 09:27:28 +02:00
										 |  |  |             const QString include = QString::fromLatin1("<%1>").arg(QFileInfo(best).fileName()); | 
					
						
							|  |  |  |             insertNewIncludeDirective(include, currentFile); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  |     static Symbol *checkName(const CppQuickFixInterface &interface, NameAST *ast) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2011-04-15 16:19:23 +02:00
										 |  |  |         if (ast && interface->isCursorOn(ast)) { | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             if (const Name *name = ast->name) { | 
					
						
							|  |  |  |                 unsigned line, column; | 
					
						
							| 
									
										
										
										
											2011-04-15 16:19:23 +02:00
										 |  |  |                 interface->semanticInfo().doc->translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 Symbol *fwdClass = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-15 16:19:23 +02:00
										 |  |  |                 foreach (const LookupItem &r, | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                          interface->context().lookup(name, interface->semanticInfo().doc->scopeAt(line, column))) { | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                     if (!r.declaration()) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |                         continue; | 
					
						
							|  |  |  |                     else if (ForwardClassDeclaration *fwd = r.declaration()->asForwardClassDeclaration()) | 
					
						
							|  |  |  |                         fwdClass = fwd; | 
					
						
							|  |  |  |                     else if (r.declaration()->isClass()) | 
					
						
							|  |  |  |                         return 0; // nothing to do.
 | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return fwdClass; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     Symbol *fwdClass; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void AddIncludeForForwardDeclaration::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                             QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     for (int index = path.size() - 1; index != -1; --index) { | 
					
						
							|  |  |  |         AST *ast = path.at(index); | 
					
						
							|  |  |  |         if (NamedTypeSpecifierAST *namedTy = ast->asNamedTypeSpecifier()) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |             if (Symbol *fwdClass = AddIncludeForForwardDeclarationOp::checkName(interface, | 
					
						
							|  |  |  |                                                                                 namedTy->name)) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                     new AddIncludeForForwardDeclarationOp(interface, index, fwdClass))); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (ElaboratedTypeSpecifierAST *eTy = ast->asElaboratedTypeSpecifier()) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |             if (Symbol *fwdClass = AddIncludeForForwardDeclarationOp::checkName(interface, | 
					
						
							|  |  |  |                                                                                 eTy->name)) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                     new AddIncludeForForwardDeclarationOp(interface, index, fwdClass))); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class AddLocalDeclarationOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     AddLocalDeclarationOp(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                           int priority, | 
					
						
							|  |  |  |                           const BinaryExpressionAST *binaryAST, | 
					
						
							|  |  |  |                           const SimpleNameAST *simpleNameAST) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , binaryAST(binaryAST) | 
					
						
							|  |  |  |         , simpleNameAST(simpleNameAST) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", "Add Local Declaration")); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TypeOfExpression typeOfExpression; | 
					
						
							|  |  |  |         typeOfExpression.init(assistInterface()->semanticInfo().doc, | 
					
						
							|  |  |  |                               snapshot(), assistInterface()->context().bindings()); | 
					
						
							|  |  |  |         Scope *scope = currentFile->scopeAt(binaryAST->firstToken()); | 
					
						
							|  |  |  |         const QList<LookupItem> result = | 
					
						
							|  |  |  |                 typeOfExpression(currentFile->textOf(binaryAST->right_expression).toUtf8(), | 
					
						
							|  |  |  |                                  scope, | 
					
						
							|  |  |  |                                  TypeOfExpression::Preprocess); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |         if (!result.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             SubstitutionEnvironment env; | 
					
						
							|  |  |  |             env.setContext(assistInterface()->context()); | 
					
						
							|  |  |  |             env.switchScope(result.first().scope()); | 
					
						
							|  |  |  |             ClassOrNamespace *con = typeOfExpression.context().lookupType(scope); | 
					
						
							|  |  |  |             if (!con) | 
					
						
							|  |  |  |                 con = typeOfExpression.context().globalNamespace(); | 
					
						
							|  |  |  |             UseMinimalNames q(con); | 
					
						
							|  |  |  |             env.enter(&q); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-20 13:48:20 +01:00
										 |  |  |             Control *control = assistInterface()->context().bindings()->control().data(); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             FullySpecifiedType tn = rewriteType(result.first().type(), &env, control); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							|  |  |  |             QString ty = oo.prettyType(tn, simpleNameAST->name); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             if (!ty.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                 ChangeSet changes; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 changes.replace(currentFile->startOf(binaryAST), | 
					
						
							|  |  |  |                                 currentFile->endOf(simpleNameAST), | 
					
						
							|  |  |  |                                 ty); | 
					
						
							| 
									
										
										
										
											2011-08-17 11:35:57 +02:00
										 |  |  |                 currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |                 currentFile->apply(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | private: | 
					
						
							|  |  |  |     const BinaryExpressionAST *binaryAST; | 
					
						
							|  |  |  |     const SimpleNameAST *simpleNameAST; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void AddLocalDeclaration::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int index = path.size() - 1; index != -1; --index) { | 
					
						
							|  |  |  |         if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |             if (binary->left_expression && binary->right_expression | 
					
						
							|  |  |  |                     && file->tokenAt(binary->binary_op_token).is(T_EQUAL)) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 IdExpressionAST *idExpr = binary->left_expression->asIdExpression(); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                 if (interface->isCursorOn(binary->left_expression) && idExpr | 
					
						
							|  |  |  |                         && idExpr->name->asSimpleName() != 0) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                     SimpleNameAST *nameAST = idExpr->name->asSimpleName(); | 
					
						
							|  |  |  |                     const QList<LookupItem> results = interface->context().lookup(nameAST->name, file->scopeAt(nameAST->firstToken())); | 
					
						
							|  |  |  |                     Declaration *decl = 0; | 
					
						
							|  |  |  |                     foreach (const LookupItem &r, results) { | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                         if (!r.declaration()) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                             continue; | 
					
						
							| 
									
										
										
										
											2013-07-17 00:01:45 +03:00
										 |  |  |                         if (Declaration *d = r.declaration()->asDeclaration()) { | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                             if (!d->type()->isFunctionType()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                                 decl = d; | 
					
						
							|  |  |  |                                 break; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |                     if (!decl) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                         result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                             new AddLocalDeclarationOp(interface, index, binary, nameAST))); | 
					
						
							|  |  |  |                         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class ConvertToCamelCaseOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     ConvertToCamelCaseOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                          const QString &newName) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , m_name(newName) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Camel Case")); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (int i = 1; i < m_name.length(); ++i) { | 
					
						
							|  |  |  |             QCharRef c = m_name[i]; | 
					
						
							|  |  |  |             if (c.isUpper()) { | 
					
						
							|  |  |  |                 c = c.toLower(); | 
					
						
							|  |  |  |             } else if (i < m_name.length() - 1 | 
					
						
							|  |  |  |                        && isConvertibleUnderscore(m_name, i)) { | 
					
						
							|  |  |  |                 m_name.remove(i, 1); | 
					
						
							|  |  |  |                 m_name[i] = m_name.at(i).toUpper(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         static_cast<CPPEditorWidget*>(assistInterface()->editor())->renameUsagesNow(m_name); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static bool isConvertibleUnderscore(const QString &name, int pos) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return name.at(pos) == QLatin1Char('_') && name.at(pos+1).isLetter() | 
					
						
							|  |  |  |                 && !(pos == 1 && name.at(0) == QLatin1Char('m')); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | private: | 
					
						
							|  |  |  |     QString m_name; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void ConvertToCamelCase::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (path.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     AST * const ast = path.last(); | 
					
						
							|  |  |  |     const Name *name = 0; | 
					
						
							|  |  |  |     if (const NameAST * const nameAst = ast->asName()) { | 
					
						
							|  |  |  |         if (nameAst->name && nameAst->name->asNameId()) | 
					
						
							|  |  |  |             name = nameAst->name; | 
					
						
							|  |  |  |     } else if (const NamespaceAST * const namespaceAst = ast->asNamespace()) { | 
					
						
							|  |  |  |         name = namespaceAst->symbol->name(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (!name) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     QString newName = QString::fromUtf8(name->identifier()->chars()); | 
					
						
							|  |  |  |     if (newName.length() < 3) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     for (int i = 1; i < newName.length() - 1; ++i) { | 
					
						
							|  |  |  |         if (ConvertToCamelCaseOp::isConvertibleUnderscore(newName, i)) { | 
					
						
							|  |  |  |             result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                 new ConvertToCamelCaseOp(interface, path.size() - 1, newName))); | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  |             return; | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 09:27:28 +02:00
										 |  |  | AddIncludeForUndefinedIdentifierOp::AddIncludeForUndefinedIdentifierOp( | 
					
						
							|  |  |  |         const CppQuickFixInterface &interface, int priority, const QString &include) | 
					
						
							|  |  |  |     : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |     , m_include(include) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-06 09:27:28 +02:00
										 |  |  |     setDescription(QApplication::translate("CppTools::QuickFix", "Add #include %1").arg(m_include)); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 09:27:28 +02:00
										 |  |  | void AddIncludeForUndefinedIdentifierOp::perform() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = refactoring.file(fileName()); | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-06 09:27:28 +02:00
										 |  |  |     insertNewIncludeDirective(m_include, file); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                              QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     CppClassesFilter *classesFilter = ExtensionSystem::PluginManager::getObject<CppClassesFilter>(); | 
					
						
							|  |  |  |     if (!classesFilter) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (path.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // find the largest enclosing Name
 | 
					
						
							|  |  |  |     const NameAST *enclosingName = 0; | 
					
						
							|  |  |  |     const SimpleNameAST *innermostName = 0; | 
					
						
							|  |  |  |     for (int i = path.size() - 1; i >= 0; --i) { | 
					
						
							|  |  |  |         if (NameAST *nameAst = path.at(i)->asName()) { | 
					
						
							|  |  |  |             enclosingName = nameAst; | 
					
						
							|  |  |  |             if (!innermostName) { | 
					
						
							|  |  |  |                 innermostName = nameAst->asSimpleName(); | 
					
						
							|  |  |  |                 if (!innermostName) | 
					
						
							|  |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!enclosingName || !enclosingName->name) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // find the enclosing scope
 | 
					
						
							|  |  |  |     unsigned line, column; | 
					
						
							|  |  |  |     const Document::Ptr &doc = interface->semanticInfo().doc; | 
					
						
							|  |  |  |     doc->translationUnit()->getTokenStartPosition(enclosingName->firstToken(), &line, &column); | 
					
						
							|  |  |  |     Scope *scope = doc->scopeAt(line, column); | 
					
						
							|  |  |  |     if (!scope) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // check if the name resolves to something
 | 
					
						
							|  |  |  |     QList<LookupItem> existingResults = interface->context().lookup(enclosingName->name, scope); | 
					
						
							|  |  |  |     if (!existingResults.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QString &className = Overview().prettyName(innermostName->name); | 
					
						
							|  |  |  |     if (className.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // find the include paths
 | 
					
						
							|  |  |  |     QStringList includePaths; | 
					
						
							|  |  |  |     CppModelManagerInterface *modelManager = CppModelManagerInterface::instance(); | 
					
						
							|  |  |  |     QList<CppModelManagerInterface::ProjectInfo> projectInfos = modelManager->projectInfos(); | 
					
						
							|  |  |  |     bool inProject = false; | 
					
						
							|  |  |  |     foreach (const CppModelManagerInterface::ProjectInfo &info, projectInfos) { | 
					
						
							| 
									
										
										
										
											2013-03-04 01:30:46 +04:00
										 |  |  |         foreach (ProjectPart::Ptr part, info.projectParts()) { | 
					
						
							|  |  |  |             foreach (const ProjectFile &file, part->files) { | 
					
						
							|  |  |  |                 if (file.path == doc->fileName()) { | 
					
						
							|  |  |  |                     inProject = true; | 
					
						
							|  |  |  |                     includePaths += part->includePaths; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (!inProject) { | 
					
						
							|  |  |  |         // better use all include paths than none
 | 
					
						
							| 
									
										
										
										
											2013-06-14 14:02:17 +02:00
										 |  |  |         includePaths = modelManager->includePaths(); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     // find a include file through the locator
 | 
					
						
							| 
									
										
										
										
											2014-01-13 16:17:34 +01:00
										 |  |  |     QFutureInterface<Core::LocatorFilterEntry> dummyInterface; | 
					
						
							|  |  |  |     QList<Core::LocatorFilterEntry> matches = classesFilter->matchesFor(dummyInterface, className); | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     bool classExists = false; | 
					
						
							| 
									
										
										
										
											2014-01-13 16:17:34 +01:00
										 |  |  |     foreach (const Core::LocatorFilterEntry &entry, matches) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const ModelItemInfo info = entry.internalData.value<ModelItemInfo>(); | 
					
						
							|  |  |  |         if (info.symbolName != className) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         classExists = true; | 
					
						
							|  |  |  |         const QString &fileName = info.fileName; | 
					
						
							|  |  |  |         const QFileInfo fileInfo(fileName); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // find the shortest way to include fileName given the includePaths
 | 
					
						
							|  |  |  |         QString shortestInclude; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (fileInfo.path() == QFileInfo(doc->fileName()).path()) { | 
					
						
							|  |  |  |             shortestInclude = QLatin1Char('"') + fileInfo.fileName() + QLatin1Char('"'); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             foreach (const QString &includePath, includePaths) { | 
					
						
							|  |  |  |                 if (!fileName.startsWith(includePath)) | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 QString relativePath = fileName.mid(includePath.size()); | 
					
						
							|  |  |  |                 if (!relativePath.isEmpty() && relativePath.at(0) == QLatin1Char('/')) | 
					
						
							|  |  |  |                     relativePath = relativePath.mid(1); | 
					
						
							|  |  |  |                 if (shortestInclude.isEmpty() || relativePath.size() + 2 < shortestInclude.size()) | 
					
						
							|  |  |  |                     shortestInclude = QLatin1Char('<') + relativePath + QLatin1Char('>'); | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         if (!shortestInclude.isEmpty()) { | 
					
						
							|  |  |  |             result += CppQuickFixOperation::Ptr( | 
					
						
							|  |  |  |                 new AddIncludeForUndefinedIdentifierOp(interface, 0, shortestInclude)); | 
					
						
							| 
									
										
										
										
											2011-11-25 12:05:58 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-14 14:02:17 +02:00
										 |  |  |     const bool isProbablyAQtClass = className.size() > 2 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             && className.at(0) == QLatin1Char('Q') | 
					
						
							| 
									
										
										
										
											2013-06-14 14:02:17 +02:00
										 |  |  |             && className.at(1).isUpper(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!isProbablyAQtClass) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // for QSomething, propose a <QSomething> include -- if such a class was in the locator
 | 
					
						
							|  |  |  |     if (classExists) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         const QString include = QLatin1Char('<') + className + QLatin1Char('>'); | 
					
						
							|  |  |  |         result += CppQuickFixOperation::Ptr( | 
					
						
							| 
									
										
										
										
											2013-06-14 14:02:17 +02:00
										 |  |  |                     new AddIncludeForUndefinedIdentifierOp(interface, 1, include)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // otherwise, check for a header file with the same name in the Qt include paths
 | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         foreach (const QString &includePath, includePaths) { | 
					
						
							|  |  |  |             if (!includePath.contains(QLatin1String("/Qt"))) // "QtCore", "QtGui" etc...
 | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const QString headerPathCandidate = includePath + QLatin1Char('/') + className; | 
					
						
							|  |  |  |             const QFileInfo fileInfo(headerPathCandidate); | 
					
						
							|  |  |  |             if (fileInfo.exists() && fileInfo.isFile()) { | 
					
						
							|  |  |  |                 const QString include = QLatin1Char('<') + className + QLatin1Char('>'); | 
					
						
							|  |  |  |                 result += CppQuickFixOperation::Ptr( | 
					
						
							|  |  |  |                             new AddIncludeForUndefinedIdentifierOp(interface, 1, include)); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class RearrangeParamDeclarationListOp: public CppQuickFixOperation | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     enum Target { TargetPrevious, TargetNext }; | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     RearrangeParamDeclarationListOp(const CppQuickFixInterface &interface, AST *currentParam, | 
					
						
							|  |  |  |                                     AST *targetParam, Target target) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , m_currentParam(currentParam) | 
					
						
							|  |  |  |         , m_targetParam(targetParam) | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         QString targetString; | 
					
						
							|  |  |  |         if (target == TargetPrevious) | 
					
						
							|  |  |  |             targetString = QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                    "Switch with Previous Parameter"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             targetString = QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                    "Switch with Next Parameter"); | 
					
						
							|  |  |  |         setDescription(targetString); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int targetEndPos = currentFile->endOf(m_targetParam); | 
					
						
							|  |  |  |         ChangeSet changes; | 
					
						
							|  |  |  |         changes.flip(currentFile->startOf(m_currentParam), currentFile->endOf(m_currentParam), | 
					
						
							|  |  |  |                      currentFile->startOf(m_targetParam), targetEndPos); | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->setOpenEditor(false, targetEndPos); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | private: | 
					
						
							|  |  |  |     AST *m_currentParam; | 
					
						
							|  |  |  |     AST *m_targetParam; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void RearrangeParamDeclarationList::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                           QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> path = interface->path(); | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     ParameterDeclarationAST *paramDecl = 0; | 
					
						
							|  |  |  |     int index = path.size() - 1; | 
					
						
							|  |  |  |     for (; index != -1; --index) { | 
					
						
							|  |  |  |         paramDecl = path.at(index)->asParameterDeclaration(); | 
					
						
							|  |  |  |         if (paramDecl) | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (index < 1) | 
					
						
							|  |  |  |         return; | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     ParameterDeclarationClauseAST *paramDeclClause = path.at(index-1)->asParameterDeclarationClause(); | 
					
						
							|  |  |  |     QTC_ASSERT(paramDeclClause && paramDeclClause->parameter_declaration_list, return); | 
					
						
							| 
									
										
										
										
											2012-10-10 23:27:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     ParameterDeclarationListAST *paramListNode = paramDeclClause->parameter_declaration_list; | 
					
						
							|  |  |  |     ParameterDeclarationListAST *prevParamListNode = 0; | 
					
						
							|  |  |  |     while (paramListNode) { | 
					
						
							|  |  |  |         if (paramDecl == paramListNode->value) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         prevParamListNode = paramListNode; | 
					
						
							|  |  |  |         paramListNode = paramListNode->next; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-02-04 14:41:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     if (!paramListNode) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (prevParamListNode) | 
					
						
							|  |  |  |         result.append(CppQuickFixOperation::Ptr( | 
					
						
							|  |  |  |             new RearrangeParamDeclarationListOp(interface, paramListNode->value, | 
					
						
							|  |  |  |                 prevParamListNode->value, RearrangeParamDeclarationListOp::TargetPrevious))); | 
					
						
							|  |  |  |     if (paramListNode->next) | 
					
						
							|  |  |  |         result.append(CppQuickFixOperation::Ptr( | 
					
						
							|  |  |  |             new RearrangeParamDeclarationListOp(interface, paramListNode->value, | 
					
						
							|  |  |  |                 paramListNode->next->value, RearrangeParamDeclarationListOp::TargetNext))); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-12-21 18:24:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | class ReformatPointerDeclarationOp: public CppQuickFixOperation | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     ReformatPointerDeclarationOp(const CppQuickFixInterface &interface, const ChangeSet change) | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , m_change(change) | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         QString description; | 
					
						
							|  |  |  |         if (m_change.operationList().size() == 1) { | 
					
						
							|  |  |  |             description = QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                 "Reformat to \"%1\"").arg(m_change.operationList().first().text); | 
					
						
							|  |  |  |         } else { // > 1
 | 
					
						
							|  |  |  |             description = QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                 "Reformat Pointers or References"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         setDescription(description); | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     void perform() | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  |         currentFile->setChangeSet(m_change); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     ChangeSet m_change; | 
					
						
							| 
									
										
										
										
											2013-01-17 17:23:43 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  | /// Filter the results of ASTPath.
 | 
					
						
							|  |  |  | /// The resulting list contains the supported AST types only once.
 | 
					
						
							|  |  |  | /// For this, the results of ASTPath are iterated in reverse order.
 | 
					
						
							|  |  |  | class ReformatPointerDeclarationASTPathResultsFilter | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     ReformatPointerDeclarationASTPathResultsFilter() | 
					
						
							|  |  |  |         : m_hasSimpleDeclaration(false) | 
					
						
							|  |  |  |         , m_hasFunctionDefinition(false) | 
					
						
							|  |  |  |         , m_hasParameterDeclaration(false) | 
					
						
							|  |  |  |         , m_hasIfStatement(false) | 
					
						
							|  |  |  |         , m_hasWhileStatement(false) | 
					
						
							|  |  |  |         , m_hasForStatement(false) | 
					
						
							|  |  |  |         , m_hasForeachStatement(false) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QList<AST*> filter(const QList<AST*> &astPathList) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QList<AST*> filtered; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (int i = astPathList.size() - 1; i >= 0; --i) { | 
					
						
							|  |  |  |             AST *ast = astPathList.at(i); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             if (!m_hasSimpleDeclaration && ast->asSimpleDeclaration()) { | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  |                 m_hasSimpleDeclaration = true; | 
					
						
							|  |  |  |                 filtered.append(ast); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             } else if (!m_hasFunctionDefinition && ast->asFunctionDefinition()) { | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  |                 m_hasFunctionDefinition = true; | 
					
						
							|  |  |  |                 filtered.append(ast); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             } else if (!m_hasParameterDeclaration && ast->asParameterDeclaration()) { | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  |                 m_hasParameterDeclaration = true; | 
					
						
							|  |  |  |                 filtered.append(ast); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             } else if (!m_hasIfStatement && ast->asIfStatement()) { | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  |                 m_hasIfStatement = true; | 
					
						
							|  |  |  |                 filtered.append(ast); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             } else if (!m_hasWhileStatement && ast->asWhileStatement()) { | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  |                 m_hasWhileStatement = true; | 
					
						
							|  |  |  |                 filtered.append(ast); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             } else if (!m_hasForStatement && ast->asForStatement()) { | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  |                 m_hasForStatement = true; | 
					
						
							|  |  |  |                 filtered.append(ast); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             } else if (!m_hasForeachStatement && ast->asForeachStatement()) { | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  |                 m_hasForeachStatement = true; | 
					
						
							|  |  |  |                 filtered.append(ast); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return filtered; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  | private: | 
					
						
							|  |  |  |     bool m_hasSimpleDeclaration; | 
					
						
							|  |  |  |     bool m_hasFunctionDefinition; | 
					
						
							|  |  |  |     bool m_hasParameterDeclaration; | 
					
						
							|  |  |  |     bool m_hasIfStatement; | 
					
						
							|  |  |  |     bool m_hasWhileStatement; | 
					
						
							|  |  |  |     bool m_hasForStatement; | 
					
						
							|  |  |  |     bool m_hasForeachStatement; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  | void ReformatPointerDeclaration::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                        QuickFixOperations &result) | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Overview overview = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							|  |  |  |     overview.showArgumentNames = true; | 
					
						
							|  |  |  |     overview.showReturnTypes = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const QTextCursor cursor = file->cursor(); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     ChangeSet change; | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |     PointerDeclarationFormatter formatter(file, overview, | 
					
						
							|  |  |  |         PointerDeclarationFormatter::RespectCursor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (cursor.hasSelection()) { | 
					
						
							| 
									
										
										
										
											2013-10-07 13:34:40 +02:00
										 |  |  |         // This will no work always as expected since this function is only called if
 | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |         // interface-path() is not empty. If the user selects the whole document via
 | 
					
						
							|  |  |  |         // ctrl-a and there is an empty line in the end, then the cursor is not on
 | 
					
						
							|  |  |  |         // any AST and therefore no quick fix will be triggered.
 | 
					
						
							|  |  |  |         change = formatter.format(file->cppDocument()->translationUnit()->ast()); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |         if (!change.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                 new ReformatPointerDeclarationOp(interface, change))); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2013-02-12 11:57:01 +01:00
										 |  |  |         const QList<AST *> suitableASTs | 
					
						
							|  |  |  |             = ReformatPointerDeclarationASTPathResultsFilter().filter(path); | 
					
						
							|  |  |  |         foreach (AST *ast, suitableASTs) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |             change = formatter.format(ast); | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             if (!change.isEmpty()) { | 
					
						
							| 
									
										
										
										
											2013-02-07 12:16:41 +01:00
										 |  |  |                 result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |                     new ReformatPointerDeclarationOp(interface, change))); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-07-26 13:06:33 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CaseStatementCollector : public ASTVisitor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     CaseStatementCollector(Document::Ptr document, const Snapshot &snapshot, | 
					
						
							|  |  |  |                            Scope *scope) | 
					
						
							|  |  |  |         : ASTVisitor(document->translationUnit()), | 
					
						
							|  |  |  |         document(document), | 
					
						
							|  |  |  |         scope(scope) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         typeOfExpression.init(document, snapshot); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QStringList operator ()(AST *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         values.clear(); | 
					
						
							|  |  |  |         foundCaseStatementLevel = false; | 
					
						
							|  |  |  |         accept(ast); | 
					
						
							|  |  |  |         return values; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool preVisit(AST *ast) { | 
					
						
							|  |  |  |         if (CaseStatementAST *cs = ast->asCaseStatement()) { | 
					
						
							|  |  |  |             foundCaseStatementLevel = true; | 
					
						
							|  |  |  |             if (ExpressionAST *expression = cs->expression->asIdExpression()) { | 
					
						
							|  |  |  |                 QList<LookupItem> candidates = typeOfExpression(expression, document, scope); | 
					
						
							|  |  |  |                 if (!candidates .isEmpty() && candidates.first().declaration()) { | 
					
						
							|  |  |  |                     Symbol *decl = candidates.first().declaration(); | 
					
						
							|  |  |  |                     values << prettyPrint.prettyName(LookupContext::fullyQualifiedName(decl)); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } else if (foundCaseStatementLevel) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Overview prettyPrint; | 
					
						
							|  |  |  |     bool foundCaseStatementLevel; | 
					
						
							|  |  |  |     QStringList values; | 
					
						
							|  |  |  |     TypeOfExpression typeOfExpression; | 
					
						
							|  |  |  |     Document::Ptr document; | 
					
						
							|  |  |  |     Scope *scope; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class CompleteSwitchCaseStatementOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     CompleteSwitchCaseStatementOp(const QSharedPointer<const CppQuickFixAssistInterface> &interface, | 
					
						
							|  |  |  |               int priority, CompoundStatementAST *compoundStatement, const QStringList &values) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , compoundStatement(compoundStatement) | 
					
						
							|  |  |  |         , values(values) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                "Complete Switch Statement")); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ChangeSet changes; | 
					
						
							|  |  |  |         int start = currentFile->endOf(compoundStatement->lbrace_token); | 
					
						
							|  |  |  |         changes.insert(start, QLatin1String("\ncase ") | 
					
						
							|  |  |  |                        + values.join(QLatin1String(":\nbreak;\ncase ")) | 
					
						
							|  |  |  |                        + QLatin1String(":\nbreak;")); | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->appendIndentRange(currentFile->range(compoundStatement)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CompoundStatementAST *compoundStatement; | 
					
						
							|  |  |  |     QStringList values; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Enum *findEnum(const QList<LookupItem> &results, const LookupContext &ctxt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     foreach (const LookupItem &result, results) { | 
					
						
							|  |  |  |         const FullySpecifiedType fst = result.type(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Type *type = result.declaration() ? result.declaration()->type().type() | 
					
						
							|  |  |  |                                           : fst.type(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!type) | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         if (Enum *e = type->asEnumType()) | 
					
						
							|  |  |  |             return e; | 
					
						
							|  |  |  |         if (const NamedType *namedType = type->asNamedType()) { | 
					
						
							| 
									
										
										
										
											2013-10-14 15:47:07 +02:00
										 |  |  |             if (ClassOrNamespace *con = ctxt.lookupType(namedType->name(), result.scope())) { | 
					
						
							|  |  |  |                 const QList<Enum *> enums = con->unscopedEnums(); | 
					
						
							|  |  |  |                 const Name *referenceName = namedType->name(); | 
					
						
							|  |  |  |                 foreach (Enum *e, enums) { | 
					
						
							|  |  |  |                     if (const Name *candidateName = e->name()) { | 
					
						
							| 
									
										
										
										
											2014-05-15 12:00:13 -04:00
										 |  |  |                         if (candidateName->match(referenceName)) | 
					
						
							| 
									
										
										
										
											2013-10-14 15:47:07 +02:00
										 |  |  |                             return e; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Enum *conditionEnum(const CppQuickFixInterface &interface, SwitchStatementAST *statement) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Block *block = statement->symbol; | 
					
						
							|  |  |  |     Scope *scope = interface->semanticInfo().doc->scopeAt(block->line(), block->column()); | 
					
						
							|  |  |  |     TypeOfExpression typeOfExpression; | 
					
						
							|  |  |  |     typeOfExpression.init(interface->semanticInfo().doc, interface->snapshot()); | 
					
						
							|  |  |  |     const QList<LookupItem> results = typeOfExpression(statement->condition, | 
					
						
							|  |  |  |                                                        interface->semanticInfo().doc, | 
					
						
							|  |  |  |                                                        scope); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return findEnum(results, typeOfExpression.context()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CompleteSwitchCaseStatement::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                         QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (path.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // look for switch statement
 | 
					
						
							|  |  |  |     for (int depth = path.size() - 1; depth >= 0; --depth) { | 
					
						
							|  |  |  |         AST *ast = path.at(depth); | 
					
						
							|  |  |  |         SwitchStatementAST *switchStatement = ast->asSwitchStatement(); | 
					
						
							|  |  |  |         if (switchStatement) { | 
					
						
							|  |  |  |             if (!interface->isCursorOn(switchStatement->switch_token) || !switchStatement->statement) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement(); | 
					
						
							|  |  |  |             if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;"
 | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             // look if the condition's type is an enum
 | 
					
						
							|  |  |  |             if (Enum *e = conditionEnum(interface, switchStatement)) { | 
					
						
							|  |  |  |                 // check the possible enum values
 | 
					
						
							|  |  |  |                 QStringList values; | 
					
						
							|  |  |  |                 Overview prettyPrint; | 
					
						
							|  |  |  |                 for (unsigned i = 0; i < e->memberCount(); ++i) { | 
					
						
							|  |  |  |                     if (Declaration *decl = e->memberAt(i)->asDeclaration()) | 
					
						
							|  |  |  |                         values << prettyPrint.prettyName(LookupContext::fullyQualifiedName(decl)); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 // Get the used values
 | 
					
						
							|  |  |  |                 Block *block = switchStatement->symbol; | 
					
						
							|  |  |  |                 CaseStatementCollector caseValues(interface->semanticInfo().doc, interface->snapshot(), | 
					
						
							|  |  |  |                                                   interface->semanticInfo().doc->scopeAt(block->line(), block->column())); | 
					
						
							|  |  |  |                 QStringList usedValues = caseValues(switchStatement); | 
					
						
							|  |  |  |                 // save the values that would be added
 | 
					
						
							|  |  |  |                 foreach (const QString &usedValue, usedValues) | 
					
						
							|  |  |  |                     values.removeAll(usedValue); | 
					
						
							|  |  |  |                 if (!values.isEmpty()) | 
					
						
							|  |  |  |                     result.append(CppQuickFixOperation::Ptr(new CompleteSwitchCaseStatementOp(interface, depth, compoundStatement, values))); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class InsertDeclOperation: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     InsertDeclOperation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, | 
					
						
							|  |  |  |                         const QString &targetFileName, const Class *targetSymbol, | 
					
						
							| 
									
										
										
										
											2013-06-03 14:57:13 +02:00
										 |  |  |                         InsertionPointLocator::AccessSpec xsSpec, const QString &decl, int priority) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         , m_targetFileName(targetFileName) | 
					
						
							|  |  |  |         , m_targetSymbol(targetSymbol) | 
					
						
							|  |  |  |         , m_xsSpec(xsSpec) | 
					
						
							|  |  |  |         , m_decl(decl) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QString type; | 
					
						
							|  |  |  |         switch (xsSpec) { | 
					
						
							|  |  |  |         case InsertionPointLocator::Public: type = QLatin1String("public"); break; | 
					
						
							|  |  |  |         case InsertionPointLocator::Protected: type = QLatin1String("protected"); break; | 
					
						
							|  |  |  |         case InsertionPointLocator::Private: type = QLatin1String("private"); break; | 
					
						
							|  |  |  |         case InsertionPointLocator::PublicSlot: type = QLatin1String("public slot"); break; | 
					
						
							|  |  |  |         case InsertionPointLocator::ProtectedSlot: type = QLatin1String("protected slot"); break; | 
					
						
							|  |  |  |         case InsertionPointLocator::PrivateSlot: type = QLatin1String("private slot"); break; | 
					
						
							|  |  |  |         default: break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         setDescription(QCoreApplication::translate("CppEditor::InsertDeclOperation", | 
					
						
							|  |  |  |                                                    "Add %1 Declaration").arg(type)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         InsertionPointLocator locator(refactoring); | 
					
						
							|  |  |  |         const InsertionLocation loc = locator.methodDeclarationInClass( | 
					
						
							|  |  |  |                     m_targetFileName, m_targetSymbol, m_xsSpec); | 
					
						
							|  |  |  |         QTC_ASSERT(loc.isValid(), return); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         CppRefactoringFilePtr targetFile = refactoring.file(m_targetFileName); | 
					
						
							|  |  |  |         int targetPosition1 = targetFile->position(loc.line(), loc.column()); | 
					
						
							|  |  |  |         int targetPosition2 = qMax(0, targetFile->position(loc.line(), 1) - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ChangeSet target; | 
					
						
							|  |  |  |         target.insert(targetPosition1, loc.prefix() + m_decl); | 
					
						
							|  |  |  |         targetFile->setChangeSet(target); | 
					
						
							|  |  |  |         targetFile->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1)); | 
					
						
							|  |  |  |         targetFile->setOpenEditor(true, targetPosition1); | 
					
						
							|  |  |  |         targetFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:15:50 +02:00
										 |  |  |     static QString generateDeclaration(const Function *function); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     QString m_targetFileName; | 
					
						
							|  |  |  |     const Class *m_targetSymbol; | 
					
						
							|  |  |  |     InsertionPointLocator::AccessSpec m_xsSpec; | 
					
						
							|  |  |  |     QString m_decl; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-10 19:37:25 +04:00
										 |  |  | class DeclOperationFactory | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     DeclOperationFactory(const CppQuickFixInterface &interface, const QString &fileName, | 
					
						
							|  |  |  |                          const Class *matchingClass, const QString &decl) | 
					
						
							|  |  |  |         : m_interface(interface) | 
					
						
							|  |  |  |         , m_fileName(fileName) | 
					
						
							|  |  |  |         , m_matchingClass(matchingClass) | 
					
						
							|  |  |  |         , m_decl(decl) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  |     TextEditor::QuickFixOperation::Ptr | 
					
						
							| 
									
										
										
										
											2013-06-03 14:57:13 +02:00
										 |  |  |     operator()(InsertionPointLocator::AccessSpec xsSpec, int priority) | 
					
						
							| 
									
										
										
										
											2013-04-10 19:37:25 +04:00
										 |  |  |     { | 
					
						
							|  |  |  |         return TextEditor::QuickFixOperation::Ptr( | 
					
						
							| 
									
										
										
										
											2013-06-03 14:57:13 +02:00
										 |  |  |             new InsertDeclOperation(m_interface, m_fileName, m_matchingClass, xsSpec, m_decl, | 
					
						
							|  |  |  |                                     priority)); | 
					
						
							| 
									
										
										
										
											2013-04-10 19:37:25 +04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     const CppQuickFixInterface &m_interface; | 
					
						
							|  |  |  |     const QString &m_fileName; | 
					
						
							|  |  |  |     const Class *m_matchingClass; | 
					
						
							|  |  |  |     const QString &m_decl; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void InsertDeclFromDef::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FunctionDefinitionAST *funDef = 0; | 
					
						
							|  |  |  |     int idx = 0; | 
					
						
							|  |  |  |     for (; idx < path.size(); ++idx) { | 
					
						
							|  |  |  |         AST *node = path.at(idx); | 
					
						
							|  |  |  |         if (idx > 1) { | 
					
						
							|  |  |  |             if (DeclaratorIdAST *declId = node->asDeclaratorId()) { | 
					
						
							|  |  |  |                 if (file->isCursorOn(declId)) { | 
					
						
							|  |  |  |                     if (FunctionDefinitionAST *candidate = path.at(idx - 2)->asFunctionDefinition()) { | 
					
						
							|  |  |  |                         if (funDef) | 
					
						
							|  |  |  |                             return; | 
					
						
							|  |  |  |                         funDef = candidate; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (node->asClassSpecifier()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!funDef || !funDef->symbol) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Function *fun = funDef->symbol; | 
					
						
							|  |  |  |     if (Class *matchingClass = isMemberFunction(interface->context(), fun)) { | 
					
						
							|  |  |  |         const QualifiedNameId *qName = fun->name()->asQualifiedNameId(); | 
					
						
							|  |  |  |         for (Symbol *s = matchingClass->find(qName->identifier()); s; s = s->next()) { | 
					
						
							|  |  |  |             if (!s->name() | 
					
						
							| 
									
										
										
										
											2014-05-15 12:00:13 -04:00
										 |  |  |                     || !qName->identifier()->match(s->identifier()) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                     || !s->type()->isFunctionType()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-15 12:00:13 -04:00
										 |  |  |             if (s->type().match(fun->type())) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                 // Declaration exists.
 | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         QString fileName = QString::fromUtf8(matchingClass->fileName(), | 
					
						
							|  |  |  |                                              matchingClass->fileNameLength()); | 
					
						
							|  |  |  |         const QString decl = InsertDeclOperation::generateDeclaration(fun); | 
					
						
							| 
									
										
										
										
											2013-04-10 19:37:25 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Add several possible insertion locations for declaration
 | 
					
						
							|  |  |  |         DeclOperationFactory operation(interface, fileName, matchingClass, decl); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-03 14:57:13 +02:00
										 |  |  |         result.append(operation(InsertionPointLocator::Public, 5)); | 
					
						
							|  |  |  |         result.append(operation(InsertionPointLocator::PublicSlot, 4)); | 
					
						
							|  |  |  |         result.append(operation(InsertionPointLocator::Protected, 3)); | 
					
						
							|  |  |  |         result.append(operation(InsertionPointLocator::ProtectedSlot, 2)); | 
					
						
							|  |  |  |         result.append(operation(InsertionPointLocator::Private, 1)); | 
					
						
							|  |  |  |         result.append(operation(InsertionPointLocator::PrivateSlot, 0)); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:15:50 +02:00
										 |  |  | QString InsertDeclOperation::generateDeclaration(const Function *function) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							|  |  |  |     oo.showFunctionSignatures = true; | 
					
						
							|  |  |  |     oo.showReturnTypes = true; | 
					
						
							|  |  |  |     oo.showArgumentNames = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString decl; | 
					
						
							|  |  |  |     decl += oo.prettyType(function->type(), function->unqualifiedName()); | 
					
						
							|  |  |  |     decl += QLatin1String(";\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return decl; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class InsertDefOperation: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |     // Make sure that either loc is valid or targetFileName is not empty.
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     InsertDefOperation(const QSharedPointer<const CppQuickFixAssistInterface> &interface, | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |                        Declaration *decl, DeclaratorAST *declAST, const InsertionLocation &loc, | 
					
						
							|  |  |  |                        const DefPos defpos, const QString &targetFileName = QString(), | 
					
						
							|  |  |  |                        bool freeFunction = false) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         : CppQuickFixOperation(interface, 0) | 
					
						
							|  |  |  |         , m_decl(decl) | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |         , m_declAST(declAST) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         , m_loc(loc) | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |         , m_defpos(defpos) | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |         , m_targetFileName(targetFileName) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |         if (m_defpos == DefPosImplementationFile) { | 
					
						
							|  |  |  |             const QString declFile = QString::fromUtf8(decl->fileName(), decl->fileNameLength()); | 
					
						
							|  |  |  |             const QDir dir = QFileInfo(declFile).dir(); | 
					
						
							| 
									
										
										
										
											2013-11-07 14:11:17 +01:00
										 |  |  |             setPriority(2); | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |             setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation", | 
					
						
							|  |  |  |                                                        "Add Definition in %1") | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                            .arg(dir.relativeFilePath(m_loc.isValid() ? m_loc.fileName() | 
					
						
							|  |  |  |                                                                      : m_targetFileName))); | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |         } else if (freeFunction) { | 
					
						
							|  |  |  |             setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation", | 
					
						
							|  |  |  |                                                        "Add Definition Here")); | 
					
						
							|  |  |  |         } else if (m_defpos == DefPosInsideClass) { | 
					
						
							|  |  |  |             setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation", | 
					
						
							|  |  |  |                                                        "Add Definition Inside Class")); | 
					
						
							|  |  |  |         } else if (m_defpos == DefPosOutsideClass) { | 
					
						
							| 
									
										
										
										
											2013-11-07 14:11:17 +01:00
										 |  |  |             setPriority(1); | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |             setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation", | 
					
						
							|  |  |  |                                                        "Add Definition Outside Class")); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |         if (!m_loc.isValid()) | 
					
						
							|  |  |  |             m_loc = insertLocationForMethodDefinition(m_decl, true, refactoring, m_targetFileName); | 
					
						
							|  |  |  |         QTC_ASSERT(m_loc.isValid(), return); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |         CppRefactoringFilePtr targetFile = refactoring.file(m_loc.fileName()); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							|  |  |  |         oo.showFunctionSignatures = true; | 
					
						
							|  |  |  |         oo.showReturnTypes = true; | 
					
						
							|  |  |  |         oo.showArgumentNames = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |         if (m_defpos == DefPosInsideClass) { | 
					
						
							|  |  |  |             const int targetPos = targetFile->position(m_loc.line(), m_loc.column()); | 
					
						
							|  |  |  |             ChangeSet target; | 
					
						
							| 
									
										
										
										
											2013-06-07 15:52:19 +02:00
										 |  |  |             target.replace(targetPos - 1, targetPos, QLatin1String("\n {\n\n}")); // replace ';'
 | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |             targetFile->setChangeSet(target); | 
					
						
							|  |  |  |             targetFile->appendIndentRange(ChangeSet::Range(targetPos, targetPos + 4)); | 
					
						
							|  |  |  |             targetFile->setOpenEditor(true, targetPos); | 
					
						
							|  |  |  |             targetFile->apply(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Move cursor inside definition
 | 
					
						
							|  |  |  |             QTextCursor c = targetFile->cursor(); | 
					
						
							|  |  |  |             c.setPosition(targetPos); | 
					
						
							|  |  |  |             c.movePosition(QTextCursor::Down); | 
					
						
							|  |  |  |             c.movePosition(QTextCursor::EndOfLine); | 
					
						
							|  |  |  |             assistInterface()->editor()->setTextCursor(c); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // make target lookup context
 | 
					
						
							|  |  |  |             Document::Ptr targetDoc = targetFile->cppDocument(); | 
					
						
							|  |  |  |             Scope *targetScope = targetDoc->scopeAt(m_loc.line(), m_loc.column()); | 
					
						
							|  |  |  |             LookupContext targetContext(targetDoc, assistInterface()->snapshot()); | 
					
						
							|  |  |  |             ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope); | 
					
						
							|  |  |  |             if (!targetCoN) | 
					
						
							|  |  |  |                 targetCoN = targetContext.globalNamespace(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // setup rewriting to get minimally qualified names
 | 
					
						
							|  |  |  |             SubstitutionEnvironment env; | 
					
						
							|  |  |  |             env.setContext(assistInterface()->context()); | 
					
						
							|  |  |  |             env.switchScope(m_decl->enclosingScope()); | 
					
						
							|  |  |  |             UseMinimalNames q(targetCoN); | 
					
						
							|  |  |  |             env.enter(&q); | 
					
						
							| 
									
										
										
										
											2013-05-15 10:21:47 +02:00
										 |  |  |             Control *control = assistInterface()->context().bindings()->control().data(); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |             // rewrite the function type
 | 
					
						
							|  |  |  |             const FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // rewrite the function name
 | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |             if (nameIncludesOperatorName(m_decl->name())) { | 
					
						
							|  |  |  |                 CppRefactoringFilePtr file = refactoring.file(fileName()); | 
					
						
							|  |  |  |                 const QString operatorNameText = file->textOf(m_declAST->core_declarator); | 
					
						
							|  |  |  |                 oo.includeWhiteSpaceInOperatorName = operatorNameText.contains(QLatin1Char(' ')); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |             const QString name = oo.prettyName(LookupContext::minimalName(m_decl, targetCoN, | 
					
						
							|  |  |  |                                                                           control)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const QString defText = oo.prettyType(tn, name) + QLatin1String("\n{\n\n}"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const int targetPos = targetFile->position(m_loc.line(), m_loc.column()); | 
					
						
							|  |  |  |             const int targetPos2 = qMax(0, targetFile->position(m_loc.line(), 1) - 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ChangeSet target; | 
					
						
							|  |  |  |             target.insert(targetPos,  m_loc.prefix() + defText + m_loc.suffix()); | 
					
						
							|  |  |  |             targetFile->setChangeSet(target); | 
					
						
							|  |  |  |             targetFile->appendIndentRange(ChangeSet::Range(targetPos2, targetPos)); | 
					
						
							|  |  |  |             targetFile->setOpenEditor(true, targetPos); | 
					
						
							|  |  |  |             targetFile->apply(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Move cursor inside definition
 | 
					
						
							|  |  |  |             QTextCursor c = targetFile->cursor(); | 
					
						
							|  |  |  |             c.setPosition(targetPos); | 
					
						
							|  |  |  |             c.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, | 
					
						
							|  |  |  |                            m_loc.prefix().count(QLatin1String("\n")) + 2); | 
					
						
							|  |  |  |             c.movePosition(QTextCursor::EndOfLine); | 
					
						
							|  |  |  |             if (m_defpos == DefPosImplementationFile) { | 
					
						
							| 
									
										
										
										
											2013-07-18 09:40:50 +02:00
										 |  |  |                 if (targetFile->editor()) | 
					
						
							|  |  |  |                     targetFile->editor()->setTextCursor(c); | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |             } else { | 
					
						
							|  |  |  |                 assistInterface()->editor()->setTextCursor(c); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     Declaration *m_decl; | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |     DeclaratorAST *m_declAST; | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |     InsertionLocation m_loc; | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |     const DefPos m_defpos; | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |     const QString m_targetFileName; | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void InsertDefFromDecl::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int idx = path.size() - 1; | 
					
						
							|  |  |  |     for (; idx >= 0; --idx) { | 
					
						
							|  |  |  |         AST *node = path.at(idx); | 
					
						
							|  |  |  |         if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) { | 
					
						
							| 
									
										
										
										
											2013-05-24 10:32:50 +02:00
										 |  |  |             if (idx > 0 && path.at(idx - 1)->asStatement()) | 
					
						
							|  |  |  |                 return; | 
					
						
							| 
									
										
										
										
											2013-07-24 11:52:01 +02:00
										 |  |  |             if (simpleDecl->symbols && !simpleDecl->symbols->next) { | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                 if (Symbol *symbol = simpleDecl->symbols->value) { | 
					
						
							|  |  |  |                     if (Declaration *decl = symbol->asDeclaration()) { | 
					
						
							|  |  |  |                         if (Function *func = decl->type()->asFunctionType()) { | 
					
						
							|  |  |  |                             if (func->isSignal()) | 
					
						
							|  |  |  |                                 return; | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-14 11:10:15 +02:00
										 |  |  |                             // Check if there is already a definition
 | 
					
						
							|  |  |  |                             CppTools::SymbolFinder symbolFinder; | 
					
						
							|  |  |  |                             if (symbolFinder.findMatchingDefinition(decl, interface->snapshot(), | 
					
						
							|  |  |  |                                                                     true)) { | 
					
						
							|  |  |  |                                 return; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |                             // Insert Position: Implementation File
 | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |                             DeclaratorAST *declAST = simpleDecl->declarator_list->value; | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                             InsertDefOperation *op = 0; | 
					
						
							|  |  |  |                             ProjectFile::Kind kind = ProjectFile::classify(interface->fileName()); | 
					
						
							|  |  |  |                             const bool isHeaderFile = ProjectFile::isHeader(kind); | 
					
						
							|  |  |  |                             if (isHeaderFile) { | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |                                 CppRefactoringChanges refactoring(interface->snapshot()); | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                                 InsertionPointLocator locator(refactoring); | 
					
						
							|  |  |  |                                 // find appropriate implementation file, but do not use this
 | 
					
						
							|  |  |  |                                 // location, because insertLocationForMethodDefinition() should
 | 
					
						
							|  |  |  |                                 // be used in perform() to get consistent insert positions.
 | 
					
						
							|  |  |  |                                 foreach (const InsertionLocation &location, | 
					
						
							|  |  |  |                                          locator.methodDefinition(decl, false, QString())) { | 
					
						
							| 
									
										
										
										
											2013-11-27 23:08:05 +01:00
										 |  |  |                                     if (!location.isValid()) | 
					
						
							|  |  |  |                                         continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                     const QString fileName = location.fileName(); | 
					
						
							|  |  |  |                                     if (ProjectFile::isHeader(ProjectFile::classify(fileName))) { | 
					
						
							|  |  |  |                                         const QString source | 
					
						
							|  |  |  |                                                 = CppTools::correspondingHeaderOrSource(fileName); | 
					
						
							|  |  |  |                                         if (!source.isEmpty()) { | 
					
						
							|  |  |  |                                             op = new InsertDefOperation(interface, decl, declAST, | 
					
						
							|  |  |  |                                                                         InsertionLocation(), | 
					
						
							|  |  |  |                                                                         DefPosImplementationFile, | 
					
						
							|  |  |  |                                                                         source); | 
					
						
							|  |  |  |                                         } | 
					
						
							|  |  |  |                                     } else { | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |                                         op = new InsertDefOperation(interface, decl, declAST, | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                                                                     InsertionLocation(), | 
					
						
							|  |  |  |                                                                     DefPosImplementationFile, | 
					
						
							| 
									
										
										
										
											2013-11-27 23:08:05 +01:00
										 |  |  |                                                                     fileName); | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                                     } | 
					
						
							| 
									
										
										
										
											2013-11-27 23:08:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                                     if (op) | 
					
						
							|  |  |  |                                         result.append(CppQuickFixOperation::Ptr(op)); | 
					
						
							|  |  |  |                                     break; | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |                                 } | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                             // Determine if we are dealing with a free function
 | 
					
						
							|  |  |  |                             const bool isFreeFunction = func->enclosingClass() == 0; | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                             // Insert Position: Outside Class
 | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                             if (!isFreeFunction) { | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |                                 op = new InsertDefOperation(interface, decl, declAST, | 
					
						
							|  |  |  |                                                             InsertionLocation(), DefPosOutsideClass, | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                                                             interface->fileName()); | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |                                 result.append(CppQuickFixOperation::Ptr(op)); | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |                             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                             // Insert Position: Inside Class
 | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                             // Determine insert location direct after the declaration.
 | 
					
						
							|  |  |  |                             unsigned line, column; | 
					
						
							|  |  |  |                             const CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |                             file->lineAndColumn(file->endOf(simpleDecl), &line, &column); | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  |                             const InsertionLocation loc | 
					
						
							|  |  |  |                                     = InsertionLocation(interface->fileName(), QString(), QString(), | 
					
						
							|  |  |  |                                                         line, column); | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |                             op = new InsertDefOperation(interface, decl, declAST, loc, | 
					
						
							|  |  |  |                                                         DefPosInsideClass, QString(), | 
					
						
							|  |  |  |                                                         isFreeFunction); | 
					
						
							| 
									
										
										
										
											2013-05-03 11:02:30 +02:00
										 |  |  |                             result.append(CppQuickFixOperation::Ptr(op)); | 
					
						
							| 
									
										
										
										
											2013-06-14 13:40:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                             return; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class GenerateGetterSetterOperation : public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     GenerateGetterSetterOperation(const QSharedPointer<const CppQuickFixAssistInterface> &interface) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , m_variableName(0) | 
					
						
							|  |  |  |         , m_declaratorId(0) | 
					
						
							|  |  |  |         , m_declarator(0) | 
					
						
							|  |  |  |         , m_variableDecl(0) | 
					
						
							|  |  |  |         , m_classSpecifier(0) | 
					
						
							|  |  |  |         , m_classDecl(0) | 
					
						
							|  |  |  |         , m_offerQuickFix(true) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-06-18 09:58:26 +02:00
										 |  |  |         setDescription(TextEditor::QuickFixFactory::tr("Create Getter and Setter Member Functions")); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |         // We expect something like
 | 
					
						
							|  |  |  |         // [0] TranslationUnitAST
 | 
					
						
							|  |  |  |         // [1] NamespaceAST
 | 
					
						
							|  |  |  |         // [2] LinkageBodyAST
 | 
					
						
							|  |  |  |         // [3] SimpleDeclarationAST
 | 
					
						
							|  |  |  |         // [4] ClassSpecifierAST
 | 
					
						
							|  |  |  |         // [5] SimpleDeclarationAST
 | 
					
						
							|  |  |  |         // [6] DeclaratorAST
 | 
					
						
							|  |  |  |         // [7] DeclaratorIdAST
 | 
					
						
							|  |  |  |         // [8] SimpleNameAST
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const int n = path.size(); | 
					
						
							|  |  |  |         if (n < 6) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         int i = 1; | 
					
						
							|  |  |  |         m_variableName = path.at(n - i++)->asSimpleName(); | 
					
						
							|  |  |  |         m_declaratorId = path.at(n - i++)->asDeclaratorId(); | 
					
						
							|  |  |  |         // DeclaratorAST might be preceded by PointerAST, e.g. for the case
 | 
					
						
							|  |  |  |         // "class C { char *@s; };", where '@' denotes the text cursor position.
 | 
					
						
							|  |  |  |         if (!(m_declarator = path.at(n - i++)->asDeclarator())) { | 
					
						
							|  |  |  |             --i; | 
					
						
							|  |  |  |             if (path.at(n - i++)->asPointer()) { | 
					
						
							|  |  |  |                 if (n < 7) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 m_declarator = path.at(n - i++)->asDeclarator(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         m_variableDecl = path.at(n - i++)->asSimpleDeclaration(); | 
					
						
							|  |  |  |         m_classSpecifier = path.at(n - i++)->asClassSpecifier(); | 
					
						
							|  |  |  |         m_classDecl = path.at(n - i++)->asSimpleDeclaration(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!isValid()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Do not get triggered on member functions and arrays
 | 
					
						
							|  |  |  |         if (m_declarator->postfix_declarator_list) { | 
					
						
							|  |  |  |             m_offerQuickFix = false; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Construct getter and setter names
 | 
					
						
							|  |  |  |         const Name *variableName = m_variableName->name; | 
					
						
							|  |  |  |         if (!variableName) { | 
					
						
							|  |  |  |             m_offerQuickFix = false; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const Identifier *variableId = variableName->identifier(); | 
					
						
							|  |  |  |         if (!variableId) { | 
					
						
							|  |  |  |             m_offerQuickFix = false; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-05-05 11:43:24 -04:00
										 |  |  |         m_variableString = QString::fromUtf8(variableId->chars(), variableId->size()); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         m_baseName = m_variableString; | 
					
						
							|  |  |  |         if (m_baseName.startsWith(QLatin1String("m_"))) | 
					
						
							|  |  |  |             m_baseName.remove(0, 2); | 
					
						
							|  |  |  |         else if (m_baseName.startsWith(QLatin1Char('_'))) | 
					
						
							|  |  |  |             m_baseName.remove(0, 1); | 
					
						
							|  |  |  |         else if (m_baseName.endsWith(QLatin1Char('_'))) | 
					
						
							|  |  |  |             m_baseName.chop(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         m_getterName = m_baseName != m_variableString | 
					
						
							|  |  |  |             ? QString::fromLatin1("%1").arg(m_baseName) | 
					
						
							|  |  |  |             : QString::fromLatin1("get%1%2") | 
					
						
							|  |  |  |                 .arg(m_baseName.left(1).toUpper()).arg(m_baseName.mid(1)); | 
					
						
							|  |  |  |         m_setterName = QString::fromLatin1("set%1%2") | 
					
						
							|  |  |  |             .arg(m_baseName.left(1).toUpper()).arg(m_baseName.mid(1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Check if the class has already a getter or setter.
 | 
					
						
							|  |  |  |         // This is only a simple check which should suffice not triggering the
 | 
					
						
							|  |  |  |         // same quick fix again. Limitations:
 | 
					
						
							|  |  |  |         //   1) It only checks in the current class, but not in base classes.
 | 
					
						
							|  |  |  |         //   2) It compares only names instead of types/signatures.
 | 
					
						
							|  |  |  |         if (Class *klass = m_classSpecifier->symbol) { | 
					
						
							|  |  |  |             for (unsigned i = 0; i < klass->memberCount(); ++i) { | 
					
						
							|  |  |  |                 Symbol *symbol = klass->memberAt(i); | 
					
						
							|  |  |  |                 if (const Name *symbolName = symbol->name()) { | 
					
						
							|  |  |  |                     if (const Identifier *id = symbolName->identifier()) { | 
					
						
							| 
									
										
										
										
											2014-05-05 11:43:24 -04:00
										 |  |  |                         const QString memberName = QString::fromUtf8(id->chars(), id->size()); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                         if (memberName == m_getterName || memberName == m_setterName) { | 
					
						
							|  |  |  |                             m_offerQuickFix = false; | 
					
						
							|  |  |  |                             return; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } // for
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool isValid() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return m_variableName | 
					
						
							|  |  |  |             && m_declaratorId | 
					
						
							|  |  |  |             && m_declarator | 
					
						
							|  |  |  |             && m_variableDecl | 
					
						
							|  |  |  |             && m_classSpecifier | 
					
						
							|  |  |  |             && m_classDecl | 
					
						
							|  |  |  |             && m_offerQuickFix; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const List<Symbol *> *symbols = m_variableDecl->symbols; | 
					
						
							|  |  |  |         QTC_ASSERT(symbols, return); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Find the right symbol in the simple declaration
 | 
					
						
							|  |  |  |         Symbol *symbol = 0; | 
					
						
							|  |  |  |         for (; symbols; symbols = symbols->next) { | 
					
						
							|  |  |  |             Symbol *s = symbols->value; | 
					
						
							|  |  |  |             if (const Name *name = s->name()) { | 
					
						
							|  |  |  |                 if (const Identifier *id = name->identifier()) { | 
					
						
							| 
									
										
										
										
											2014-05-05 11:43:24 -04:00
										 |  |  |                     const QString symbolName = QString::fromUtf8(id->chars(), id->size()); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |                     if (symbolName == m_variableString) { | 
					
						
							|  |  |  |                         symbol = s; | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QTC_ASSERT(symbol, return); | 
					
						
							|  |  |  |         FullySpecifiedType fullySpecifiedType = symbol->type(); | 
					
						
							|  |  |  |         Type *type = fullySpecifiedType.type(); | 
					
						
							|  |  |  |         QTC_ASSERT(type, return); | 
					
						
							|  |  |  |         Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							|  |  |  |         oo.showFunctionSignatures = true; | 
					
						
							|  |  |  |         oo.showReturnTypes = true; | 
					
						
							|  |  |  |         oo.showArgumentNames = true; | 
					
						
							|  |  |  |         const QString typeString = oo.prettyType(fullySpecifiedType); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const NameAST *classNameAST = m_classSpecifier->name; | 
					
						
							|  |  |  |         QTC_ASSERT(classNameAST, return); | 
					
						
							|  |  |  |         const Name *className = classNameAST->name; | 
					
						
							|  |  |  |         QTC_ASSERT(className, return); | 
					
						
							|  |  |  |         const Identifier *classId = className->identifier(); | 
					
						
							|  |  |  |         QTC_ASSERT(classId, return); | 
					
						
							| 
									
										
										
										
											2014-05-05 11:43:24 -04:00
										 |  |  |         QString classString = QString::fromUtf8(classId->chars(), classId->size()); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         bool wasHeader = true; | 
					
						
							|  |  |  |         QString declFileName = currentFile->fileName(); | 
					
						
							|  |  |  |         QString implFileName = correspondingHeaderOrSource(declFileName, &wasHeader); | 
					
						
							|  |  |  |         const bool sameFile = !wasHeader || !QFile::exists(implFileName); | 
					
						
							|  |  |  |         if (sameFile) | 
					
						
							|  |  |  |             implFileName = declFileName; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         InsertionPointLocator locator(refactoring); | 
					
						
							|  |  |  |         InsertionLocation declLocation = locator.methodDeclarationInClass | 
					
						
							|  |  |  |             (declFileName, m_classSpecifier->symbol->asClass(), InsertionPointLocator::Public); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const bool passByValue = type->isIntegerType() || type->isFloatType() | 
					
						
							|  |  |  |                 || type->isPointerType() || type->isEnumType(); | 
					
						
							|  |  |  |         const QString paramName = m_baseName != m_variableString | 
					
						
							|  |  |  |             ? m_baseName : QLatin1String("value"); | 
					
						
							|  |  |  |         QString paramString; | 
					
						
							|  |  |  |         if (passByValue) { | 
					
						
							|  |  |  |             paramString = oo.prettyType(fullySpecifiedType, paramName); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             FullySpecifiedType constParamType(fullySpecifiedType); | 
					
						
							|  |  |  |             constParamType.setConst(true); | 
					
						
							|  |  |  |             QScopedPointer<ReferenceType> referenceType(new ReferenceType(constParamType, false)); | 
					
						
							|  |  |  |             FullySpecifiedType referenceToConstParamType(referenceType.data()); | 
					
						
							|  |  |  |             paramString = oo.prettyType(referenceToConstParamType, paramName); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const bool isStatic = symbol->storage() == Symbol::Static; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Construct declaration strings
 | 
					
						
							|  |  |  |         QString declaration = declLocation.prefix(); | 
					
						
							|  |  |  |         QString getterTypeString = typeString; | 
					
						
							|  |  |  |         FullySpecifiedType getterType(fullySpecifiedType); | 
					
						
							|  |  |  |         if (fullySpecifiedType.isConst()) { | 
					
						
							|  |  |  |             getterType.setConst(false); | 
					
						
							|  |  |  |             getterTypeString = oo.prettyType(getterType); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const QString declarationGetterTypeAndNameString = oo.prettyType(getterType, m_getterName); | 
					
						
							|  |  |  |         const QString declarationGetter = QString::fromLatin1("%1%2()%3;\n") | 
					
						
							|  |  |  |                 .arg(isStatic ? QLatin1String("static ") : QString()) | 
					
						
							|  |  |  |             .arg(declarationGetterTypeAndNameString) | 
					
						
							|  |  |  |             .arg(isStatic ? QString() : QLatin1String(" const")); | 
					
						
							|  |  |  |         const QString declarationSetter = QString::fromLatin1("%1void %2(%3);\n") | 
					
						
							|  |  |  |             .arg(isStatic ? QLatin1String("static ") : QString()) | 
					
						
							|  |  |  |             .arg(m_setterName) | 
					
						
							|  |  |  |             .arg(paramString); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         declaration += declarationGetter; | 
					
						
							|  |  |  |         if (!fullySpecifiedType.isConst()) | 
					
						
							|  |  |  |             declaration += declarationSetter; | 
					
						
							|  |  |  |         declaration += declLocation.suffix(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Construct implementation strings
 | 
					
						
							|  |  |  |         const QString implementationGetterTypeAndNameString = oo.prettyType( | 
					
						
							|  |  |  |             getterType, QString::fromLatin1("%1::%2").arg(classString, m_getterName)); | 
					
						
							|  |  |  |         const QString implementationGetter = QString::fromLatin1( | 
					
						
							|  |  |  |                     "\n%1()%2\n" | 
					
						
							|  |  |  |                     "{\n" | 
					
						
							|  |  |  |                     "return %3;\n" | 
					
						
							|  |  |  |                     "}\n") | 
					
						
							|  |  |  |                 .arg(implementationGetterTypeAndNameString) | 
					
						
							|  |  |  |                 .arg(isStatic ? QString() : QLatin1String(" const")) | 
					
						
							|  |  |  |                 .arg(m_variableString); | 
					
						
							|  |  |  |         const QString implementationSetter = QString::fromLatin1( | 
					
						
							|  |  |  |                     "\nvoid %1::%2(%3)\n" | 
					
						
							|  |  |  |                     "{\n" | 
					
						
							|  |  |  |                     "%4 = %5;\n" | 
					
						
							|  |  |  |                     "}\n") | 
					
						
							|  |  |  |                 .arg(classString).arg(m_setterName) | 
					
						
							|  |  |  |                 .arg(paramString).arg(m_variableString) | 
					
						
							|  |  |  |                 .arg(paramName); | 
					
						
							|  |  |  |         QString implementation = implementationGetter; | 
					
						
							|  |  |  |         if (!fullySpecifiedType.isConst()) | 
					
						
							|  |  |  |             implementation += implementationSetter; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Create and apply changes
 | 
					
						
							|  |  |  |         ChangeSet currChanges; | 
					
						
							|  |  |  |         int declInsertPos = currentFile->position(qMax(1u, declLocation.line()), | 
					
						
							|  |  |  |                                                   declLocation.column()); | 
					
						
							|  |  |  |         currChanges.insert(declInsertPos, declaration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (sameFile) { | 
					
						
							| 
									
										
										
										
											2013-06-15 11:50:44 +02:00
										 |  |  |             InsertionLocation loc = insertLocationForMethodDefinition(symbol, false, refactoring, | 
					
						
							|  |  |  |                                                                       currentFile->fileName()); | 
					
						
							|  |  |  |             currChanges.insert(currentFile->position(loc.line(), loc.column()), implementation); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2013-06-15 11:50:44 +02:00
										 |  |  |             CppRefactoringChanges implRef(snapshot()); | 
					
						
							|  |  |  |             CppRefactoringFilePtr implFile = implRef.file(implFileName); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |             ChangeSet implChanges; | 
					
						
							| 
									
										
										
										
											2013-06-15 11:50:44 +02:00
										 |  |  |             InsertionLocation loc = insertLocationForMethodDefinition(symbol, false, | 
					
						
							|  |  |  |                                                                       implRef, implFileName); | 
					
						
							|  |  |  |             const int implInsertPos = implFile->position(loc.line(), loc.column()); | 
					
						
							|  |  |  |             implChanges.insert(implFile->position(loc.line(), loc.column()), implementation); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |             implFile->setChangeSet(implChanges); | 
					
						
							|  |  |  |             implFile->appendIndentRange( | 
					
						
							|  |  |  |                 ChangeSet::Range(implInsertPos, implInsertPos + implementation.size())); | 
					
						
							|  |  |  |             implFile->apply(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         currentFile->setChangeSet(currChanges); | 
					
						
							|  |  |  |         currentFile->appendIndentRange( | 
					
						
							|  |  |  |             ChangeSet::Range(declInsertPos, declInsertPos + declaration.size())); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SimpleNameAST *m_variableName; | 
					
						
							|  |  |  |     DeclaratorIdAST *m_declaratorId; | 
					
						
							|  |  |  |     DeclaratorAST *m_declarator; | 
					
						
							|  |  |  |     SimpleDeclarationAST *m_variableDecl; | 
					
						
							|  |  |  |     ClassSpecifierAST *m_classSpecifier; | 
					
						
							|  |  |  |     SimpleDeclarationAST *m_classDecl; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString m_baseName; | 
					
						
							|  |  |  |     QString m_getterName; | 
					
						
							|  |  |  |     QString m_setterName; | 
					
						
							|  |  |  |     QString m_variableString; | 
					
						
							|  |  |  |     bool m_offerQuickFix; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GenerateGetterSetter::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     GenerateGetterSetterOperation *op = new GenerateGetterSetterOperation(interface); | 
					
						
							|  |  |  |     if (op->isValid()) | 
					
						
							|  |  |  |         result.append(CppQuickFixOperation::Ptr(op)); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         delete op; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ExtractFunctionOperation : public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     ExtractFunctionOperation(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                     int extractionStart, | 
					
						
							|  |  |  |                     int extractionEnd, | 
					
						
							|  |  |  |                     FunctionDefinitionAST *refFuncDef, | 
					
						
							|  |  |  |                     Symbol *funcReturn, | 
					
						
							|  |  |  |                     QList<QPair<QString, QString> > relevantDecls) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , m_extractionStart(extractionStart) | 
					
						
							|  |  |  |         , m_extractionEnd(extractionEnd) | 
					
						
							|  |  |  |         , m_refFuncDef(refFuncDef) | 
					
						
							|  |  |  |         , m_funcReturn(funcReturn) | 
					
						
							|  |  |  |         , m_relevantDecls(relevantDecls) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QCoreApplication::translate("QuickFix::ExtractFunction", "Extract Function")); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QTC_ASSERT(!m_funcReturn || !m_relevantDecls.isEmpty(), return); | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const QString &funcName = getFunctionName(); | 
					
						
							|  |  |  |         if (funcName.isEmpty()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Function *refFunc = m_refFuncDef->symbol; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // We don't need to rewrite the type for declarations made inside the reference function,
 | 
					
						
							|  |  |  |         // since their scope will remain the same. Then we preserve the original spelling style.
 | 
					
						
							|  |  |  |         // However, we must do so for the return type in the definition.
 | 
					
						
							|  |  |  |         SubstitutionEnvironment env; | 
					
						
							|  |  |  |         env.setContext(assistInterface()->context()); | 
					
						
							|  |  |  |         env.switchScope(refFunc); | 
					
						
							|  |  |  |         ClassOrNamespace *targetCoN = | 
					
						
							|  |  |  |                 assistInterface()->context().lookupType(refFunc->enclosingScope()); | 
					
						
							|  |  |  |         if (!targetCoN) | 
					
						
							|  |  |  |             targetCoN = assistInterface()->context().globalNamespace(); | 
					
						
							|  |  |  |         UseMinimalNames subs(targetCoN); | 
					
						
							|  |  |  |         env.enter(&subs); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Overview printer = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							| 
									
										
										
										
											2013-05-15 10:21:47 +02:00
										 |  |  |         Control *control = assistInterface()->context().bindings()->control().data(); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         QString funcDef; | 
					
						
							|  |  |  |         QString funcDecl; // We generate a declaration only in the case of a member function.
 | 
					
						
							|  |  |  |         QString funcCall; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Class *matchingClass = isMemberFunction(assistInterface()->context(), refFunc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Write return type.
 | 
					
						
							|  |  |  |         if (!m_funcReturn) { | 
					
						
							|  |  |  |             funcDef.append(QLatin1String("void ")); | 
					
						
							|  |  |  |             if (matchingClass) | 
					
						
							|  |  |  |                 funcDecl.append(QLatin1String("void ")); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             const FullySpecifiedType &fullType = rewriteType(m_funcReturn->type(), &env, control); | 
					
						
							|  |  |  |             funcDef.append(printer.prettyType(fullType) + QLatin1Char(' ')); | 
					
						
							|  |  |  |             funcDecl.append(printer.prettyType(m_funcReturn->type()) + QLatin1Char(' ')); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Write class qualification, if any.
 | 
					
						
							|  |  |  |         if (matchingClass) { | 
					
						
							|  |  |  |             const Name *name = rewriteName(matchingClass->name(), &env, control); | 
					
						
							|  |  |  |             funcDef.append(printer.prettyName(name)); | 
					
						
							|  |  |  |             funcDef.append(QLatin1String("::")); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Write the extracted function itself and its call.
 | 
					
						
							|  |  |  |         funcDef.append(funcName); | 
					
						
							|  |  |  |         if (matchingClass) | 
					
						
							|  |  |  |             funcDecl.append(funcName); | 
					
						
							|  |  |  |         funcCall.append(funcName); | 
					
						
							|  |  |  |         funcDef.append(QLatin1Char('(')); | 
					
						
							|  |  |  |         if (matchingClass) | 
					
						
							|  |  |  |             funcDecl.append(QLatin1Char('(')); | 
					
						
							|  |  |  |         funcCall.append(QLatin1Char('(')); | 
					
						
							|  |  |  |         for (int i = m_funcReturn ? 1 : 0; i < m_relevantDecls.length(); ++i) { | 
					
						
							|  |  |  |             QPair<QString, QString> p = m_relevantDecls.at(i); | 
					
						
							|  |  |  |             funcCall.append(p.first); | 
					
						
							|  |  |  |             funcDef.append(p.second); | 
					
						
							|  |  |  |             if (matchingClass) | 
					
						
							|  |  |  |                 funcDecl.append(p.second); | 
					
						
							|  |  |  |             if (i < m_relevantDecls.length() - 1) { | 
					
						
							|  |  |  |                 funcCall.append(QLatin1String(", ")); | 
					
						
							|  |  |  |                 funcDef.append(QLatin1String(", ")); | 
					
						
							|  |  |  |                 if (matchingClass) | 
					
						
							|  |  |  |                     funcDecl.append(QLatin1String(", ")); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         funcDef.append(QLatin1Char(')')); | 
					
						
							|  |  |  |         if (matchingClass) | 
					
						
							|  |  |  |             funcDecl.append(QLatin1Char(')')); | 
					
						
							|  |  |  |         funcCall.append(QLatin1Char(')')); | 
					
						
							|  |  |  |         if (refFunc->isConst()) { | 
					
						
							|  |  |  |             funcDef.append(QLatin1String(" const")); | 
					
						
							|  |  |  |             funcDecl.append(QLatin1String(" const")); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         funcDef.append(QLatin1String("\n{\n")); | 
					
						
							|  |  |  |         if (matchingClass) | 
					
						
							|  |  |  |             funcDecl.append(QLatin1String(";\n")); | 
					
						
							|  |  |  |         if (m_funcReturn) { | 
					
						
							|  |  |  |             funcDef.append(QLatin1String("\nreturn ") | 
					
						
							| 
									
										
										
										
											2013-04-16 09:39:13 +02:00
										 |  |  |                         + m_relevantDecls.at(0).first | 
					
						
							|  |  |  |                         + QLatin1String(";")); | 
					
						
							|  |  |  |             funcCall.prepend(m_relevantDecls.at(0).second + QLatin1String(" = ")); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         funcDef.append(QLatin1String("\n}\n\n")); | 
					
						
							|  |  |  |         funcDef.replace(QChar::ParagraphSeparator, QLatin1String("\n")); | 
					
						
							|  |  |  |         funcCall.append(QLatin1Char(';')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Get starting indentation from original code.
 | 
					
						
							|  |  |  |         int indentedExtractionStart = m_extractionStart; | 
					
						
							|  |  |  |         QChar current = currentFile->document()->characterAt(indentedExtractionStart - 1); | 
					
						
							|  |  |  |         while (current == QLatin1Char(' ') || current == QLatin1Char('\t')) { | 
					
						
							|  |  |  |             --indentedExtractionStart; | 
					
						
							|  |  |  |             current = currentFile->document()->characterAt(indentedExtractionStart - 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         QString extract = currentFile->textOf(indentedExtractionStart, m_extractionEnd); | 
					
						
							|  |  |  |         extract.replace(QChar::ParagraphSeparator, QLatin1String("\n")); | 
					
						
							|  |  |  |         if (!extract.endsWith(QLatin1Char('\n')) && m_funcReturn) | 
					
						
							|  |  |  |             extract.append(QLatin1Char('\n')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Since we need an indent range and a nested reindent range (based on the original
 | 
					
						
							|  |  |  |         // formatting) it's simpler to have two different change sets.
 | 
					
						
							|  |  |  |         ChangeSet change; | 
					
						
							|  |  |  |         int position = currentFile->startOf(m_refFuncDef); | 
					
						
							|  |  |  |         change.insert(position, funcDef); | 
					
						
							|  |  |  |         change.replace(m_extractionStart, m_extractionEnd, funcCall); | 
					
						
							|  |  |  |         currentFile->setChangeSet(change); | 
					
						
							|  |  |  |         currentFile->appendIndentRange(ChangeSet::Range(position, position + 1)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         QTextCursor tc = currentFile->document()->find(QLatin1String("{"), position); | 
					
						
							|  |  |  |         QTC_ASSERT(tc.hasSelection(), return); | 
					
						
							|  |  |  |         position = tc.selectionEnd() + 1; | 
					
						
							|  |  |  |         change.clear(); | 
					
						
							|  |  |  |         change.insert(position, extract); | 
					
						
							|  |  |  |         currentFile->setChangeSet(change); | 
					
						
							|  |  |  |         currentFile->appendReindentRange(ChangeSet::Range(position, position + 1)); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Write declaration, if necessary.
 | 
					
						
							|  |  |  |         if (matchingClass) { | 
					
						
							|  |  |  |             InsertionPointLocator locator(refactoring); | 
					
						
							|  |  |  |             const QString fileName = QLatin1String(matchingClass->fileName()); | 
					
						
							|  |  |  |             const InsertionLocation &location = | 
					
						
							|  |  |  |                     locator.methodDeclarationInClass(fileName, matchingClass, | 
					
						
							|  |  |  |                                                      InsertionPointLocator::Public); | 
					
						
							|  |  |  |             CppRefactoringFilePtr declFile = refactoring.file(fileName); | 
					
						
							|  |  |  |             change.clear(); | 
					
						
							|  |  |  |             position = declFile->position(location.line(), location.column()); | 
					
						
							|  |  |  |             change.insert(position, funcDecl); | 
					
						
							|  |  |  |             declFile->setChangeSet(change); | 
					
						
							|  |  |  |             declFile->appendIndentRange(ChangeSet::Range(position, position + 1)); | 
					
						
							|  |  |  |             declFile->apply(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString getFunctionName() const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         bool ok; | 
					
						
							|  |  |  |         QString name = | 
					
						
							|  |  |  |                 QInputDialog::getText(0, | 
					
						
							|  |  |  |                                       QCoreApplication::translate("QuickFix::ExtractFunction", | 
					
						
							|  |  |  |                                                                   "Extract Function Refactoring"), | 
					
						
							|  |  |  |                                       QCoreApplication::translate("QuickFix::ExtractFunction", | 
					
						
							|  |  |  |                                                                   "Enter function name"), | 
					
						
							|  |  |  |                                       QLineEdit::Normal, | 
					
						
							|  |  |  |                                       QString(), | 
					
						
							|  |  |  |                                       &ok); | 
					
						
							|  |  |  |         name = name.trimmed(); | 
					
						
							|  |  |  |         if (!ok || name.isEmpty()) | 
					
						
							|  |  |  |             return QString(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!isValidIdentifier(name)) { | 
					
						
							|  |  |  |             QMessageBox::critical(0, | 
					
						
							|  |  |  |                                   QCoreApplication::translate("QuickFix::ExtractFunction", | 
					
						
							|  |  |  |                                                               "Extract Function Refactoring"), | 
					
						
							|  |  |  |                                   QCoreApplication::translate("QuickFix::ExtractFunction", | 
					
						
							|  |  |  |                                                               "Invalid function name")); | 
					
						
							|  |  |  |             return QString(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return name; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int m_extractionStart; | 
					
						
							|  |  |  |     int m_extractionEnd; | 
					
						
							|  |  |  |     FunctionDefinitionAST *m_refFuncDef; | 
					
						
							|  |  |  |     Symbol *m_funcReturn; | 
					
						
							|  |  |  |     QList<QPair<QString, QString> > m_relevantDecls; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QPair<QString, QString> assembleDeclarationData(const QString &specifiers, DeclaratorAST *decltr, | 
					
						
							|  |  |  |                                                 const CppRefactoringFilePtr &file, | 
					
						
							|  |  |  |                                                 const Overview &printer) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(decltr, return (QPair<QString, QString>())); | 
					
						
							|  |  |  |     if (decltr->core_declarator | 
					
						
							|  |  |  |             && decltr->core_declarator->asDeclaratorId() | 
					
						
							|  |  |  |             && decltr->core_declarator->asDeclaratorId()->name) { | 
					
						
							|  |  |  |         QString decltrText = file->textOf(file->startOf(decltr), | 
					
						
							|  |  |  |                                           file->endOf(decltr->core_declarator)); | 
					
						
							|  |  |  |         if (!decltrText.isEmpty()) { | 
					
						
							|  |  |  |             const QString &name = printer.prettyName( | 
					
						
							|  |  |  |                     decltr->core_declarator->asDeclaratorId()->name->name); | 
					
						
							|  |  |  |             QString completeDecl = specifiers; | 
					
						
							|  |  |  |             if (!decltrText.contains(QLatin1Char(' '))) | 
					
						
							|  |  |  |                 completeDecl.append(QLatin1Char(' ') + decltrText); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 completeDecl.append(decltrText); | 
					
						
							|  |  |  |             return qMakePair(name, completeDecl); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return QPair<QString, QString>(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FunctionExtractionAnalyser : public ASTVisitor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     FunctionExtractionAnalyser(TranslationUnit *unit, | 
					
						
							|  |  |  |                                const int selStart, | 
					
						
							|  |  |  |                                const int selEnd, | 
					
						
							|  |  |  |                                const CppRefactoringFilePtr &file, | 
					
						
							|  |  |  |                                const Overview &printer) | 
					
						
							|  |  |  |         : ASTVisitor(unit) | 
					
						
							|  |  |  |         , m_done(false) | 
					
						
							|  |  |  |         , m_failed(false) | 
					
						
							|  |  |  |         , m_selStart(selStart) | 
					
						
							|  |  |  |         , m_selEnd(selEnd) | 
					
						
							|  |  |  |         , m_extractionStart(0) | 
					
						
							|  |  |  |         , m_extractionEnd(0) | 
					
						
							|  |  |  |         , m_file(file) | 
					
						
							|  |  |  |         , m_printer(printer) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool operator()(FunctionDefinitionAST *refFunDef) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         accept(refFunDef); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!m_failed && m_extractionStart == m_extractionEnd) | 
					
						
							|  |  |  |             m_failed = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return !m_failed; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool preVisit(AST *) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (m_done) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void statement(StatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!stmt) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const int stmtStart = m_file->startOf(stmt); | 
					
						
							|  |  |  |         const int stmtEnd = m_file->endOf(stmt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (stmtStart >= m_selEnd | 
					
						
							|  |  |  |                 || (m_extractionStart && stmtEnd > m_selEnd)) { | 
					
						
							|  |  |  |             m_done = true; | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (stmtStart >= m_selStart && !m_extractionStart) | 
					
						
							|  |  |  |             m_extractionStart = stmtStart; | 
					
						
							|  |  |  |         if (stmtEnd > m_extractionEnd && m_extractionStart) | 
					
						
							|  |  |  |             m_extractionEnd = stmtEnd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         accept(stmt); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(CaseStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         statement(stmt->statement); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(CompoundStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (StatementListAST *it = stmt->statement_list; it; it = it->next) { | 
					
						
							|  |  |  |             statement(it->value); | 
					
						
							|  |  |  |             if (m_done) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(DoStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         statement(stmt->statement); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(ForeachStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         statement(stmt->statement); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(RangeBasedForStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         statement(stmt->statement); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(ForStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         statement(stmt->initializer); | 
					
						
							|  |  |  |         if (!m_done) | 
					
						
							|  |  |  |             statement(stmt->statement); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(IfStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         statement(stmt->statement); | 
					
						
							|  |  |  |         if (!m_done) | 
					
						
							|  |  |  |             statement(stmt->else_statement); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(TryBlockStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         statement(stmt->statement); | 
					
						
							|  |  |  |         for (CatchClauseListAST *it = stmt->catch_clause_list; it; it = it->next) { | 
					
						
							|  |  |  |             statement(it->value); | 
					
						
							|  |  |  |             if (m_done) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(WhileStatementAST *stmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         statement(stmt->statement); | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(DeclarationStatementAST *declStmt) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // We need to collect the declarations we see before the extraction or even inside it.
 | 
					
						
							|  |  |  |         // They might need to be used as either a parameter or return value. Actually, we could
 | 
					
						
							|  |  |  |         // still obtain their types from the local uses, but it's good to preserve the original
 | 
					
						
							|  |  |  |         // typing style.
 | 
					
						
							|  |  |  |         if (declStmt | 
					
						
							|  |  |  |                 && declStmt->declaration | 
					
						
							|  |  |  |                 && declStmt->declaration->asSimpleDeclaration()) { | 
					
						
							|  |  |  |             SimpleDeclarationAST *simpleDecl = declStmt->declaration->asSimpleDeclaration(); | 
					
						
							|  |  |  |             if (simpleDecl->decl_specifier_list | 
					
						
							|  |  |  |                     && simpleDecl->declarator_list) { | 
					
						
							|  |  |  |                 const QString &specifiers = | 
					
						
							|  |  |  |                         m_file->textOf(m_file->startOf(simpleDecl), | 
					
						
							|  |  |  |                                      m_file->endOf(simpleDecl->decl_specifier_list->lastValue())); | 
					
						
							|  |  |  |                 for (DeclaratorListAST *decltrList = simpleDecl->declarator_list; | 
					
						
							|  |  |  |                      decltrList; | 
					
						
							|  |  |  |                      decltrList = decltrList->next) { | 
					
						
							|  |  |  |                     const QPair<QString, QString> p = | 
					
						
							|  |  |  |                         assembleDeclarationData(specifiers, decltrList->value, m_file, m_printer); | 
					
						
							|  |  |  |                     if (!p.first.isEmpty()) | 
					
						
							|  |  |  |                         m_knownDecls.insert(p.first, p.second); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool visit(ReturnStatementAST *) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (m_extractionStart) { | 
					
						
							|  |  |  |             m_done = true; | 
					
						
							|  |  |  |             m_failed = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool m_done; | 
					
						
							|  |  |  |     bool m_failed; | 
					
						
							|  |  |  |     const int m_selStart; | 
					
						
							|  |  |  |     const int m_selEnd; | 
					
						
							|  |  |  |     int m_extractionStart; | 
					
						
							|  |  |  |     int m_extractionEnd; | 
					
						
							|  |  |  |     QHash<QString, QString> m_knownDecls; | 
					
						
							|  |  |  |     CppRefactoringFilePtr m_file; | 
					
						
							|  |  |  |     const Overview &m_printer; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ExtractFunction::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTextCursor cursor = file->cursor(); | 
					
						
							|  |  |  |     if (!cursor.hasSelection()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     FunctionDefinitionAST *refFuncDef = 0; // The "reference" function, which we will extract from.
 | 
					
						
							|  |  |  |     for (int i = path.size() - 1; i >= 0; --i) { | 
					
						
							|  |  |  |         refFuncDef = path.at(i)->asFunctionDefinition(); | 
					
						
							|  |  |  |         if (refFuncDef) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!refFuncDef | 
					
						
							|  |  |  |             || !refFuncDef->function_body | 
					
						
							|  |  |  |             || !refFuncDef->function_body->asCompoundStatement() | 
					
						
							|  |  |  |             || !refFuncDef->function_body->asCompoundStatement()->statement_list | 
					
						
							|  |  |  |             || !refFuncDef->symbol | 
					
						
							|  |  |  |             || !refFuncDef->symbol->name() | 
					
						
							|  |  |  |             || refFuncDef->symbol->enclosingScope()->isTemplate() /* TODO: Templates... */) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Adjust selection ends.
 | 
					
						
							|  |  |  |     int selStart = cursor.selectionStart(); | 
					
						
							|  |  |  |     int selEnd = cursor.selectionEnd(); | 
					
						
							|  |  |  |     if (selStart > selEnd) | 
					
						
							|  |  |  |         qSwap(selStart, selEnd); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Overview printer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Analyze the content to be extracted, which consists of determining the statements
 | 
					
						
							|  |  |  |     // which are complete and collecting the declarations seen.
 | 
					
						
							|  |  |  |     FunctionExtractionAnalyser analyser(interface->semanticInfo().doc->translationUnit(), | 
					
						
							|  |  |  |                                         selStart, selEnd, | 
					
						
							|  |  |  |                                         file, | 
					
						
							|  |  |  |                                         printer); | 
					
						
							|  |  |  |     if (!analyser(refFuncDef)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // We also need to collect the declarations of the parameters from the reference function.
 | 
					
						
							|  |  |  |     QSet<QString> refFuncParams; | 
					
						
							|  |  |  |     if (refFuncDef->declarator->postfix_declarator_list | 
					
						
							|  |  |  |             && refFuncDef->declarator->postfix_declarator_list->value | 
					
						
							|  |  |  |             && refFuncDef->declarator->postfix_declarator_list->value->asFunctionDeclarator()) { | 
					
						
							|  |  |  |         FunctionDeclaratorAST *funcDecltr = | 
					
						
							|  |  |  |             refFuncDef->declarator->postfix_declarator_list->value->asFunctionDeclarator(); | 
					
						
							|  |  |  |         if (funcDecltr->parameter_declaration_clause | 
					
						
							|  |  |  |                 && funcDecltr->parameter_declaration_clause->parameter_declaration_list) { | 
					
						
							|  |  |  |             for (ParameterDeclarationListAST *it = | 
					
						
							|  |  |  |                     funcDecltr->parameter_declaration_clause->parameter_declaration_list; | 
					
						
							|  |  |  |                  it; | 
					
						
							|  |  |  |                  it = it->next) { | 
					
						
							|  |  |  |                 ParameterDeclarationAST *paramDecl = it->value->asParameterDeclaration(); | 
					
						
							|  |  |  |                 if (paramDecl->declarator) { | 
					
						
							|  |  |  |                     const QString &specifiers = | 
					
						
							|  |  |  |                             file->textOf(file->startOf(paramDecl), | 
					
						
							|  |  |  |                                          file->endOf(paramDecl->type_specifier_list->lastValue())); | 
					
						
							|  |  |  |                     const QPair<QString, QString> &p = | 
					
						
							|  |  |  |                             assembleDeclarationData(specifiers, paramDecl->declarator, | 
					
						
							|  |  |  |                                                     file, printer); | 
					
						
							|  |  |  |                     if (!p.first.isEmpty()) { | 
					
						
							|  |  |  |                         analyser.m_knownDecls.insert(p.first, p.second); | 
					
						
							|  |  |  |                         refFuncParams.insert(p.first); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Identify what would be parameters for the new function and its return value, if any.
 | 
					
						
							|  |  |  |     Symbol *funcReturn = 0; | 
					
						
							|  |  |  |     QList<QPair<QString, QString> > relevantDecls; | 
					
						
							|  |  |  |     SemanticInfo::LocalUseIterator it(interface->semanticInfo().localUses); | 
					
						
							|  |  |  |     while (it.hasNext()) { | 
					
						
							|  |  |  |         it.next(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool usedBeforeExtraction = false; | 
					
						
							|  |  |  |         bool usedAfterExtraction = false; | 
					
						
							|  |  |  |         bool usedInsideExtraction = false; | 
					
						
							|  |  |  |         const QList<SemanticInfo::Use> &uses = it.value(); | 
					
						
							|  |  |  |         foreach (const SemanticInfo::Use &use, uses) { | 
					
						
							|  |  |  |             if (use.isInvalid()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const int position = file->position(use.line, use.column); | 
					
						
							|  |  |  |             if (position < analyser.m_extractionStart) | 
					
						
							|  |  |  |                 usedBeforeExtraction = true; | 
					
						
							|  |  |  |             else if (position >= analyser.m_extractionEnd) | 
					
						
							|  |  |  |                 usedAfterExtraction = true; | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 usedInsideExtraction = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const QString &name = printer.prettyName(it.key()->name()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((usedBeforeExtraction && usedInsideExtraction) | 
					
						
							|  |  |  |                 || (usedInsideExtraction && refFuncParams.contains(name))) { | 
					
						
							|  |  |  |             QTC_ASSERT(analyser.m_knownDecls.contains(name), return); | 
					
						
							|  |  |  |             relevantDecls.append(qMakePair(name, analyser.m_knownDecls.value(name))); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // We assume that the first use of a local corresponds to its declaration.
 | 
					
						
							|  |  |  |         if (usedInsideExtraction && usedAfterExtraction && !usedBeforeExtraction) { | 
					
						
							|  |  |  |             if (!funcReturn) { | 
					
						
							|  |  |  |                 QTC_ASSERT(analyser.m_knownDecls.contains(name), return); | 
					
						
							|  |  |  |                 // The return, if any, is stored as the first item in the list.
 | 
					
						
							|  |  |  |                 relevantDecls.prepend(qMakePair(name, analyser.m_knownDecls.value(name))); | 
					
						
							|  |  |  |                 funcReturn = it.key(); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 // Would require multiple returns. (Unless we do fancy things, as pointed below.)
 | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // The current implementation doesn't try to be too smart since it preserves the original form
 | 
					
						
							|  |  |  |     // of the declarations. This might be or not the desired effect. An improvement would be to
 | 
					
						
							|  |  |  |     // let the user somehow customize the function interface.
 | 
					
						
							|  |  |  |     result.append(CppQuickFixOperation::Ptr(new ExtractFunctionOperation(interface, | 
					
						
							|  |  |  |                                                      analyser.m_extractionStart, | 
					
						
							|  |  |  |                                                      analyser.m_extractionEnd, | 
					
						
							|  |  |  |                                                      refFuncDef, | 
					
						
							|  |  |  |                                                      funcReturn, | 
					
						
							|  |  |  |                                                      relevantDecls))); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-11 12:00:07 +02:00
										 |  |  | struct ReplaceLiteralsResult | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Token token; | 
					
						
							|  |  |  |     QString literalText; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | class ReplaceLiterals : private ASTVisitor | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     ReplaceLiterals(const CppRefactoringFilePtr &file, ChangeSet *changes, T *literal) | 
					
						
							|  |  |  |         : ASTVisitor(file->cppDocument()->translationUnit()), m_file(file), m_changes(changes), | 
					
						
							|  |  |  |           m_literal(literal) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         m_result.token = m_file->tokenAt(literal->firstToken()); | 
					
						
							|  |  |  |         m_literalTokenText = m_result.token.spell(); | 
					
						
							|  |  |  |         m_result.literalText = QLatin1String(m_literalTokenText); | 
					
						
							|  |  |  |         if (m_result.token.isCharLiteral()) { | 
					
						
							|  |  |  |             m_result.literalText.prepend(QLatin1Char('\'')); | 
					
						
							|  |  |  |             m_result.literalText.append(QLatin1Char('\'')); | 
					
						
							|  |  |  |             if (m_result.token.kind() == T_WIDE_CHAR_LITERAL) | 
					
						
							|  |  |  |                 m_result.literalText.prepend(QLatin1Char('L')); | 
					
						
							|  |  |  |             else if (m_result.token.kind() == T_UTF16_CHAR_LITERAL) | 
					
						
							|  |  |  |                 m_result.literalText.prepend(QLatin1Char('u')); | 
					
						
							|  |  |  |             else if (m_result.token.kind() == T_UTF32_CHAR_LITERAL) | 
					
						
							|  |  |  |                 m_result.literalText.prepend(QLatin1Char('U')); | 
					
						
							|  |  |  |         } else if (m_result.token.isStringLiteral()) { | 
					
						
							|  |  |  |             m_result.literalText.prepend(QLatin1Char('"')); | 
					
						
							|  |  |  |             m_result.literalText.append(QLatin1Char('"')); | 
					
						
							|  |  |  |             if (m_result.token.kind() == T_WIDE_STRING_LITERAL) | 
					
						
							|  |  |  |                 m_result.literalText.prepend(QLatin1Char('L')); | 
					
						
							|  |  |  |             else if (m_result.token.kind() == T_UTF16_STRING_LITERAL) | 
					
						
							|  |  |  |                 m_result.literalText.prepend(QLatin1Char('u')); | 
					
						
							|  |  |  |             else if (m_result.token.kind() == T_UTF32_STRING_LITERAL) | 
					
						
							|  |  |  |                 m_result.literalText.prepend(QLatin1Char('U')); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ReplaceLiteralsResult apply(AST *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         ast->accept(this); | 
					
						
							|  |  |  |         return m_result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     bool visit(T *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (ast != m_literal | 
					
						
							|  |  |  |                 && strcmp(m_file->tokenAt(ast->firstToken()).spell(), m_literalTokenText) != 0) { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         int start, end; | 
					
						
							|  |  |  |         m_file->startAndEndOf(ast->firstToken(), &start, &end); | 
					
						
							|  |  |  |         m_changes->replace(start, end, QLatin1String("newParameter")); | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const CppRefactoringFilePtr &m_file; | 
					
						
							|  |  |  |     ChangeSet *m_changes; | 
					
						
							|  |  |  |     T *m_literal; | 
					
						
							|  |  |  |     const char *m_literalTokenText; | 
					
						
							|  |  |  |     ReplaceLiteralsResult m_result; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ExtractLiteralAsParameterOp : public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     ExtractLiteralAsParameterOp(const CppQuickFixInterface &interface, int priority, | 
					
						
							|  |  |  |                                 ExpressionAST *literal, FunctionDefinitionAST *function) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority), | 
					
						
							|  |  |  |           m_literal(literal), | 
					
						
							|  |  |  |           m_functionDefinition(function) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", | 
					
						
							|  |  |  |                                                "Extract Constant as Function Parameter")); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     struct FoundDeclaration | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         FoundDeclaration() | 
					
						
							|  |  |  |             : ast(0) | 
					
						
							|  |  |  |         {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         FunctionDeclaratorAST *ast; | 
					
						
							|  |  |  |         CppRefactoringFilePtr file; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FoundDeclaration findDeclaration(const CppRefactoringChanges &refactoring, | 
					
						
							|  |  |  |                                      FunctionDefinitionAST *ast) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         FoundDeclaration result; | 
					
						
							|  |  |  |         Function *func = ast->symbol; | 
					
						
							|  |  |  |         QString declFileName; | 
					
						
							|  |  |  |         if (Class *matchingClass = isMemberFunction(assistInterface()->context(), func)) { | 
					
						
							|  |  |  |             // Dealing with member functions
 | 
					
						
							|  |  |  |             const QualifiedNameId *qName = func->name()->asQualifiedNameId(); | 
					
						
							|  |  |  |             for (Symbol *s = matchingClass->find(qName->identifier()); s; s = s->next()) { | 
					
						
							|  |  |  |                 if (!s->name() | 
					
						
							| 
									
										
										
										
											2014-05-15 12:00:13 -04:00
										 |  |  |                         || !qName->identifier()->match(s->identifier()) | 
					
						
							| 
									
										
										
										
											2013-09-11 12:00:07 +02:00
										 |  |  |                         || !s->type()->isFunctionType() | 
					
						
							| 
									
										
										
										
											2014-05-15 12:00:13 -04:00
										 |  |  |                         || !s->type().match(func->type()) | 
					
						
							| 
									
										
										
										
											2013-09-11 12:00:07 +02:00
										 |  |  |                         || s->isFunction()) { | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 declFileName = QString::fromUtf8(matchingClass->fileName(), | 
					
						
							|  |  |  |                                                  matchingClass->fileNameLength()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 result.file = refactoring.file(declFileName); | 
					
						
							|  |  |  |                 ASTPath astPath(result.file->cppDocument()); | 
					
						
							|  |  |  |                 const QList<AST *> path = astPath(s->line(), s->column()); | 
					
						
							|  |  |  |                 SimpleDeclarationAST *simpleDecl; | 
					
						
							|  |  |  |                 for (int idx = 0; idx < path.size(); ++idx) { | 
					
						
							|  |  |  |                     AST *node = path.at(idx); | 
					
						
							|  |  |  |                     simpleDecl = node->asSimpleDeclaration(); | 
					
						
							|  |  |  |                     if (simpleDecl) { | 
					
						
							|  |  |  |                         if (simpleDecl->symbols && !simpleDecl->symbols->next) { | 
					
						
							|  |  |  |                             result.ast = functionDeclarator(simpleDecl); | 
					
						
							|  |  |  |                             return result; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (simpleDecl) | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (Namespace *matchingNamespace | 
					
						
							|  |  |  |                    = isNamespaceFunction(assistInterface()->context(), func)) { | 
					
						
							|  |  |  |             // Dealing with free functions and inline member functions.
 | 
					
						
							|  |  |  |             bool isHeaderFile; | 
					
						
							|  |  |  |             declFileName = correspondingHeaderOrSource(fileName(), &isHeaderFile); | 
					
						
							|  |  |  |             if (!QFile::exists(declFileName)) | 
					
						
							|  |  |  |                 return FoundDeclaration(); | 
					
						
							|  |  |  |             result.file = refactoring.file(declFileName); | 
					
						
							|  |  |  |             if (!result.file) | 
					
						
							|  |  |  |                 return FoundDeclaration(); | 
					
						
							|  |  |  |             const LookupContext lc(result.file->cppDocument(), snapshot()); | 
					
						
							|  |  |  |             const QList<LookupItem> candidates = lc.lookup(func->name(), matchingNamespace); | 
					
						
							|  |  |  |             for (int i = 0; i < candidates.size(); ++i) { | 
					
						
							|  |  |  |                 if (Symbol *s = candidates.at(i).declaration()) { | 
					
						
							|  |  |  |                     if (s->asDeclaration()) { | 
					
						
							|  |  |  |                         ASTPath astPath(result.file->cppDocument()); | 
					
						
							|  |  |  |                         const QList<AST *> path = astPath(s->line(), s->column()); | 
					
						
							|  |  |  |                         for (int idx = 0; idx < path.size(); ++idx) { | 
					
						
							|  |  |  |                             AST *node = path.at(idx); | 
					
						
							|  |  |  |                             SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration(); | 
					
						
							|  |  |  |                             if (simpleDecl) { | 
					
						
							|  |  |  |                                 result.ast = functionDeclarator(simpleDecl); | 
					
						
							|  |  |  |                                 return result; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         FunctionDeclaratorAST *functionDeclaratorOfDefinition | 
					
						
							|  |  |  |                 = functionDeclarator(m_functionDefinition); | 
					
						
							|  |  |  |         const CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         const CppRefactoringFilePtr currentFile = refactoring.file(fileName()); | 
					
						
							|  |  |  |         deduceTypeNameOfLiteral(currentFile->cppDocument()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ChangeSet changes; | 
					
						
							|  |  |  |         if (NumericLiteralAST *concreteLiteral = m_literal->asNumericLiteral()) { | 
					
						
							|  |  |  |             m_literalInfo = ReplaceLiterals<NumericLiteralAST>(currentFile, &changes, | 
					
						
							|  |  |  |                                                                concreteLiteral) | 
					
						
							|  |  |  |                     .apply(m_functionDefinition->function_body); | 
					
						
							|  |  |  |         } else if (StringLiteralAST *concreteLiteral = m_literal->asStringLiteral()) { | 
					
						
							|  |  |  |             m_literalInfo = ReplaceLiterals<StringLiteralAST>(currentFile, &changes, | 
					
						
							|  |  |  |                                                               concreteLiteral) | 
					
						
							|  |  |  |                     .apply(m_functionDefinition->function_body); | 
					
						
							|  |  |  |         } else if (BoolLiteralAST *concreteLiteral = m_literal->asBoolLiteral()) { | 
					
						
							|  |  |  |             m_literalInfo = ReplaceLiterals<BoolLiteralAST>(currentFile, &changes, | 
					
						
							|  |  |  |                                                             concreteLiteral) | 
					
						
							|  |  |  |                     .apply(m_functionDefinition->function_body); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const FoundDeclaration functionDeclaration | 
					
						
							|  |  |  |                 = findDeclaration(refactoring, m_functionDefinition); | 
					
						
							|  |  |  |         appendFunctionParameter(functionDeclaratorOfDefinition, currentFile, &changes, | 
					
						
							|  |  |  |                 !functionDeclaration.ast); | 
					
						
							|  |  |  |         if (functionDeclaration.ast) { | 
					
						
							|  |  |  |             if (currentFile->fileName() != functionDeclaration.file->fileName()) { | 
					
						
							|  |  |  |                 ChangeSet declChanges; | 
					
						
							|  |  |  |                 appendFunctionParameter(functionDeclaration.ast, functionDeclaration.file, &declChanges, | 
					
						
							|  |  |  |                                         true); | 
					
						
							|  |  |  |                 functionDeclaration.file->setChangeSet(declChanges); | 
					
						
							|  |  |  |                 functionDeclaration.file->apply(); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 appendFunctionParameter(functionDeclaration.ast, currentFile, &changes, | 
					
						
							|  |  |  |                                         true); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         currentFile->setChangeSet(changes); | 
					
						
							|  |  |  |         currentFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     bool hasParameters(FunctionDeclaratorAST *ast) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return ast->parameter_declaration_clause | 
					
						
							|  |  |  |                 && ast->parameter_declaration_clause->parameter_declaration_list | 
					
						
							|  |  |  |                 && ast->parameter_declaration_clause->parameter_declaration_list->value; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void deduceTypeNameOfLiteral(const Document::Ptr &document) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         TypeOfExpression typeOfExpression; | 
					
						
							|  |  |  |         typeOfExpression.init(document, snapshot()); | 
					
						
							|  |  |  |         Overview overview; | 
					
						
							|  |  |  |         Scope *scope = m_functionDefinition->symbol->enclosingScope(); | 
					
						
							|  |  |  |         const QList<LookupItem> items = typeOfExpression(m_literal, document, scope); | 
					
						
							|  |  |  |         if (!items.isEmpty()) | 
					
						
							|  |  |  |             m_typeName = overview.prettyType(items.first().type()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QString parameterDeclarationTextToInsert(FunctionDeclaratorAST *ast) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QString str; | 
					
						
							|  |  |  |         if (hasParameters(ast)) | 
					
						
							|  |  |  |             str = QLatin1String(", "); | 
					
						
							|  |  |  |         str += m_typeName; | 
					
						
							|  |  |  |         if (!m_typeName.endsWith(QLatin1Char('*'))) | 
					
						
							|  |  |  |                 str += QLatin1Char(' '); | 
					
						
							|  |  |  |         str += QLatin1String("newParameter"); | 
					
						
							|  |  |  |         return str; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FunctionDeclaratorAST *functionDeclarator(SimpleDeclarationAST *ast) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (DeclaratorListAST *decls = ast->declarator_list; decls; decls = decls->next) { | 
					
						
							|  |  |  |             FunctionDeclaratorAST * const functionDeclaratorAST = functionDeclarator(decls->value); | 
					
						
							|  |  |  |             if (functionDeclaratorAST) | 
					
						
							|  |  |  |                 return functionDeclaratorAST; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FunctionDeclaratorAST *functionDeclarator(DeclaratorAST *ast) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (PostfixDeclaratorListAST *pds = ast->postfix_declarator_list; pds; pds = pds->next) { | 
					
						
							|  |  |  |             FunctionDeclaratorAST *funcdecl = pds->value->asFunctionDeclarator(); | 
					
						
							|  |  |  |             if (funcdecl) | 
					
						
							|  |  |  |                 return funcdecl; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FunctionDeclaratorAST *functionDeclarator(FunctionDefinitionAST *ast) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return functionDeclarator(ast->declarator); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void appendFunctionParameter(FunctionDeclaratorAST *ast, const CppRefactoringFileConstPtr &file, | 
					
						
							|  |  |  |                ChangeSet *changes, bool addDefaultValue) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!ast) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         if (m_declarationInsertionString.isEmpty()) | 
					
						
							|  |  |  |             m_declarationInsertionString = parameterDeclarationTextToInsert(ast); | 
					
						
							|  |  |  |         QString insertion = m_declarationInsertionString; | 
					
						
							|  |  |  |         if (addDefaultValue) | 
					
						
							|  |  |  |             insertion += QLatin1String(" = ") + m_literalInfo.literalText; | 
					
						
							|  |  |  |         changes->insert(file->startOf(ast->rparen_token), insertion); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ExpressionAST *m_literal; | 
					
						
							|  |  |  |     FunctionDefinitionAST *m_functionDefinition; | 
					
						
							|  |  |  |     QString m_typeName; | 
					
						
							|  |  |  |     QString m_declarationInsertionString; | 
					
						
							|  |  |  |     ReplaceLiteralsResult m_literalInfo; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ExtractLiteralAsParameter::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |         QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     if (path.count() < 2) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     AST * const lastAst = path.last(); | 
					
						
							|  |  |  |     ExpressionAST *literal; | 
					
						
							|  |  |  |     if (!((literal = lastAst->asNumericLiteral()) | 
					
						
							|  |  |  |           || (literal = lastAst->asStringLiteral()) | 
					
						
							|  |  |  |           || (literal = lastAst->asBoolLiteral()))) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FunctionDefinitionAST *function; | 
					
						
							|  |  |  |     int i = path.count() - 2; | 
					
						
							|  |  |  |     while (!(function = path.at(i)->asFunctionDefinition())) { | 
					
						
							|  |  |  |         // Ignore literals in lambda expressions for now.
 | 
					
						
							|  |  |  |         if (path.at(i)->asLambdaExpression()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         if (--i < 0) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     FunctionDeclaratorAST *functionDeclarator | 
					
						
							|  |  |  |             = function->declarator->postfix_declarator_list->value->asFunctionDeclarator(); | 
					
						
							|  |  |  |     if (functionDeclarator | 
					
						
							|  |  |  |             && functionDeclarator->parameter_declaration_clause | 
					
						
							|  |  |  |             && functionDeclarator->parameter_declaration_clause->dot_dot_dot_token) { | 
					
						
							|  |  |  |         // Do not handle functions with ellipsis parameter.
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int priority = path.size() - 1; | 
					
						
							|  |  |  |     QuickFixOperation::Ptr op( | 
					
						
							|  |  |  |                 new ExtractLiteralAsParameterOp(interface, priority, literal, function)); | 
					
						
							|  |  |  |     result.append(op); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  | class InsertQtPropertyMembersOp: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     enum GenerateFlag { | 
					
						
							|  |  |  |         GenerateGetter = 1 << 0, | 
					
						
							|  |  |  |         GenerateSetter = 1 << 1, | 
					
						
							|  |  |  |         GenerateSignal = 1 << 2, | 
					
						
							|  |  |  |         GenerateStorage = 1 << 3 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InsertQtPropertyMembersOp(const QSharedPointer<const CppQuickFixAssistInterface> &interface, | 
					
						
							|  |  |  |               int priority, QtPropertyDeclarationAST *declaration, Class *klass, int generateFlags, | 
					
						
							|  |  |  |               const QString &getterName, const QString &setterName, const QString &signalName, | 
					
						
							|  |  |  |               const QString &storageName) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface, priority) | 
					
						
							|  |  |  |         , m_declaration(declaration) | 
					
						
							|  |  |  |         , m_class(klass) | 
					
						
							|  |  |  |         , m_generateFlags(generateFlags) | 
					
						
							|  |  |  |         , m_getterName(getterName) | 
					
						
							|  |  |  |         , m_setterName(setterName) | 
					
						
							|  |  |  |         , m_signalName(signalName) | 
					
						
							|  |  |  |         , m_storageName(storageName) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-06-18 09:58:26 +02:00
										 |  |  |         setDescription(TextEditor::QuickFixFactory::tr("Generate Missing Q_PROPERTY Members...")); | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr file = refactoring.file(fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         InsertionPointLocator locator(refactoring); | 
					
						
							|  |  |  |         ChangeSet declarations; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const QString typeName = file->textOf(m_declaration->type_id); | 
					
						
							|  |  |  |         const QString propertyName = file->textOf(m_declaration->property_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // getter declaration
 | 
					
						
							|  |  |  |         if (m_generateFlags & GenerateGetter) { | 
					
						
							|  |  |  |             const QString getterDeclaration = typeName + QLatin1Char(' ') + m_getterName + | 
					
						
							|  |  |  |                     QLatin1String("() const\n{\nreturn ") + m_storageName + QLatin1String(";\n}\n"); | 
					
						
							|  |  |  |             InsertionLocation getterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Public); | 
					
						
							|  |  |  |             QTC_ASSERT(getterLoc.isValid(), return); | 
					
						
							|  |  |  |             insertAndIndent(file, &declarations, getterLoc, getterDeclaration); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // setter declaration
 | 
					
						
							|  |  |  |         if (m_generateFlags & GenerateSetter) { | 
					
						
							|  |  |  |             QString setterDeclaration; | 
					
						
							|  |  |  |             QTextStream setter(&setterDeclaration); | 
					
						
							|  |  |  |             setter << "void " << m_setterName << '(' << typeName << " arg)\n{\n"; | 
					
						
							|  |  |  |             if (m_signalName.isEmpty()) { | 
					
						
							|  |  |  |                 setter << m_storageName <<  " = arg;\n}\n"; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 setter << "if (" << m_storageName << " != arg) {\n" << m_storageName | 
					
						
							|  |  |  |                        << " = arg;\nemit " << m_signalName << "(arg);\n}\n}\n"; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             InsertionLocation setterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::PublicSlot); | 
					
						
							|  |  |  |             QTC_ASSERT(setterLoc.isValid(), return); | 
					
						
							|  |  |  |             insertAndIndent(file, &declarations, setterLoc, setterDeclaration); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // signal declaration
 | 
					
						
							|  |  |  |         if (m_generateFlags & GenerateSignal) { | 
					
						
							|  |  |  |             const QString declaration = QLatin1String("void ") + m_signalName + QLatin1Char('(') | 
					
						
							|  |  |  |                                         + typeName + QLatin1String(" arg);\n"); | 
					
						
							|  |  |  |             InsertionLocation loc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Signals); | 
					
						
							|  |  |  |             QTC_ASSERT(loc.isValid(), return); | 
					
						
							|  |  |  |             insertAndIndent(file, &declarations, loc, declaration); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // storage
 | 
					
						
							|  |  |  |         if (m_generateFlags & GenerateStorage) { | 
					
						
							|  |  |  |             const QString storageDeclaration = typeName  + QLatin1String(" m_") | 
					
						
							|  |  |  |                                                + propertyName + QLatin1String(";\n"); | 
					
						
							|  |  |  |             InsertionLocation storageLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Private); | 
					
						
							|  |  |  |             QTC_ASSERT(storageLoc.isValid(), return); | 
					
						
							|  |  |  |             insertAndIndent(file, &declarations, storageLoc, storageDeclaration); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         file->setChangeSet(declarations); | 
					
						
							|  |  |  |         file->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     void insertAndIndent(const RefactoringFilePtr &file, ChangeSet *changeSet, | 
					
						
							|  |  |  |                          const InsertionLocation &loc, const QString &text) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int targetPosition1 = file->position(loc.line(), loc.column()); | 
					
						
							|  |  |  |         int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1); | 
					
						
							|  |  |  |         changeSet->insert(targetPosition1, loc.prefix() + text + loc.suffix()); | 
					
						
							|  |  |  |         file->appendIndentRange(ChangeSet::Range(targetPosition2, targetPosition1)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QtPropertyDeclarationAST *m_declaration; | 
					
						
							|  |  |  |     Class *m_class; | 
					
						
							|  |  |  |     int m_generateFlags; | 
					
						
							|  |  |  |     QString m_getterName; | 
					
						
							|  |  |  |     QString m_setterName; | 
					
						
							|  |  |  |     QString m_signalName; | 
					
						
							|  |  |  |     QString m_storageName; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void InsertQtPropertyMembers::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |     QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (path.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     AST * const ast = path.last(); | 
					
						
							|  |  |  |     QtPropertyDeclarationAST *qtPropertyDeclaration = ast->asQtPropertyDeclaration(); | 
					
						
							|  |  |  |     if (!qtPropertyDeclaration) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ClassSpecifierAST *klass = 0; | 
					
						
							|  |  |  |     for (int i = path.size() - 2; i >= 0; --i) { | 
					
						
							|  |  |  |         klass = path.at(i)->asClassSpecifier(); | 
					
						
							|  |  |  |         if (klass) | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!klass) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  |     const QString propertyName = file->textOf(qtPropertyDeclaration->property_name); | 
					
						
							|  |  |  |     QString getterName; | 
					
						
							|  |  |  |     QString setterName; | 
					
						
							|  |  |  |     QString signalName; | 
					
						
							|  |  |  |     int generateFlags = 0; | 
					
						
							|  |  |  |     QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list; | 
					
						
							|  |  |  |     for (; it; it = it->next) { | 
					
						
							|  |  |  |         const char *tokenString = file->tokenAt(it->value->item_name_token).spell(); | 
					
						
							|  |  |  |         if (!qstrcmp(tokenString, "READ")) { | 
					
						
							|  |  |  |             getterName = file->textOf(it->value->expression); | 
					
						
							|  |  |  |             generateFlags |= InsertQtPropertyMembersOp::GenerateGetter; | 
					
						
							|  |  |  |         } else if (!qstrcmp(tokenString, "WRITE")) { | 
					
						
							|  |  |  |             setterName = file->textOf(it->value->expression); | 
					
						
							|  |  |  |             generateFlags |= InsertQtPropertyMembersOp::GenerateSetter; | 
					
						
							|  |  |  |         } else if (!qstrcmp(tokenString, "NOTIFY")) { | 
					
						
							|  |  |  |             signalName = file->textOf(it->value->expression); | 
					
						
							|  |  |  |             generateFlags |= InsertQtPropertyMembersOp::GenerateSignal; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const QString storageName = QLatin1String("m_") +  propertyName; | 
					
						
							|  |  |  |     generateFlags |= InsertQtPropertyMembersOp::GenerateStorage; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Class *c = klass->symbol; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Overview overview; | 
					
						
							|  |  |  |     for (unsigned i = 0; i < c->memberCount(); ++i) { | 
					
						
							|  |  |  |         Symbol *member = c->memberAt(i); | 
					
						
							|  |  |  |         FullySpecifiedType type = member->type(); | 
					
						
							|  |  |  |         if (member->asFunction() || (type.isValid() && type->asFunctionType())) { | 
					
						
							|  |  |  |             const QString name = overview.prettyName(member->name()); | 
					
						
							|  |  |  |             if (name == getterName) | 
					
						
							|  |  |  |                 generateFlags &= ~InsertQtPropertyMembersOp::GenerateGetter; | 
					
						
							|  |  |  |             else if (name == setterName) | 
					
						
							|  |  |  |                 generateFlags &= ~InsertQtPropertyMembersOp::GenerateSetter; | 
					
						
							|  |  |  |             else if (name == signalName) | 
					
						
							|  |  |  |                 generateFlags &= ~InsertQtPropertyMembersOp::GenerateSignal; | 
					
						
							|  |  |  |         } else if (member->asDeclaration()) { | 
					
						
							|  |  |  |             const QString name = overview.prettyName(member->name()); | 
					
						
							|  |  |  |             if (name == storageName) | 
					
						
							|  |  |  |                 generateFlags &= ~InsertQtPropertyMembersOp::GenerateStorage; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (getterName.isEmpty() && setterName.isEmpty() && signalName.isEmpty()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     result.append(QuickFixOperation::Ptr( | 
					
						
							|  |  |  |         new InsertQtPropertyMembersOp(interface, path.size() - 1, qtPropertyDeclaration, c, | 
					
						
							|  |  |  |             generateFlags, getterName, setterName, signalName, storageName))); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ApplyDeclDefLinkOperation : public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     explicit ApplyDeclDefLinkOperation(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |             const QSharedPointer<FunctionDeclDefLink> &link) | 
					
						
							| 
									
										
										
										
											2013-06-03 12:26:25 +02:00
										 |  |  |         : CppQuickFixOperation(interface, 100) | 
					
						
							| 
									
										
										
										
											2013-04-11 18:01:40 +02:00
										 |  |  |         , m_link(link) | 
					
						
							|  |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CPPEditorWidget *editor = assistInterface()->editor(); | 
					
						
							|  |  |  |         QSharedPointer<FunctionDeclDefLink> link = editor->declDefLink(); | 
					
						
							|  |  |  |         if (link == m_link) | 
					
						
							|  |  |  |             editor->applyDeclDefLinkChanges(/*don't jump*/false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							|  |  |  |     virtual void performChanges(const CppRefactoringFilePtr &, const CppRefactoringChanges &) | 
					
						
							|  |  |  |     { /* never called since perform is overridden */ } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     QSharedPointer<FunctionDeclDefLink> m_link; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ApplyDeclDefLinkChanges::match(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                     QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QSharedPointer<FunctionDeclDefLink> link = interface->editor()->declDefLink(); | 
					
						
							|  |  |  |     if (!link || !link->isMarkerVisible()) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QSharedPointer<ApplyDeclDefLinkOperation> op(new ApplyDeclDefLinkOperation(interface, link)); | 
					
						
							|  |  |  |     op->setDescription(FunctionDeclDefLink::tr("Apply Function Signature Changes")); | 
					
						
							|  |  |  |     result += op; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  | QString definitionSignature(const CppQuickFixAssistInterface *assist, | 
					
						
							|  |  |  |                             FunctionDefinitionAST *functionDefinitionAST, | 
					
						
							|  |  |  |                             CppRefactoringFilePtr &baseFile, | 
					
						
							|  |  |  |                             CppRefactoringFilePtr &targetFile, | 
					
						
							|  |  |  |                             Scope *scope) | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     QTC_ASSERT(assist, return QString()); | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |     QTC_ASSERT(functionDefinitionAST, return QString()); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |     QTC_ASSERT(scope, return QString()); | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |     Function *func = functionDefinitionAST->symbol; | 
					
						
							|  |  |  |     QTC_ASSERT(func, return QString()); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |     LookupContext cppContext(targetFile->cppDocument(), assist->snapshot()); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |     ClassOrNamespace *cppCoN = cppContext.lookupType(scope); | 
					
						
							|  |  |  |     if (!cppCoN) | 
					
						
							|  |  |  |         cppCoN = cppContext.globalNamespace(); | 
					
						
							|  |  |  |     SubstitutionEnvironment env; | 
					
						
							|  |  |  |     env.setContext(assist->context()); | 
					
						
							|  |  |  |     env.switchScope(func->enclosingScope()); | 
					
						
							|  |  |  |     UseMinimalNames q(cppCoN); | 
					
						
							|  |  |  |     env.enter(&q); | 
					
						
							| 
									
										
										
										
											2013-05-15 10:21:47 +02:00
										 |  |  |     Control *control = assist->context().bindings()->control().data(); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |     Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							|  |  |  |     oo.showFunctionSignatures = true; | 
					
						
							|  |  |  |     oo.showReturnTypes = true; | 
					
						
							|  |  |  |     oo.showArgumentNames = true; | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |     const Name *name = func->name(); | 
					
						
							|  |  |  |     if (nameIncludesOperatorName(name)) { | 
					
						
							|  |  |  |         CoreDeclaratorAST *coreDeclarator = functionDefinitionAST->declarator->core_declarator; | 
					
						
							|  |  |  |         const QString operatorNameText = baseFile->textOf(coreDeclarator); | 
					
						
							|  |  |  |         oo.includeWhiteSpaceInOperatorName = operatorNameText.contains(QLatin1Char(' ')); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const QString nameText = oo.prettyName(LookupContext::minimalName(func, cppCoN, control)); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |     const FullySpecifiedType tn = rewriteType(func->type(), &env, control); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |     return oo.prettyType(tn, nameText); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MoveFuncDefOutsideOp : public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     enum MoveType { | 
					
						
							|  |  |  |         MoveOutside, | 
					
						
							|  |  |  |         MoveToCppFile, | 
					
						
							|  |  |  |         MoveOutsideMemberToCppFile | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     MoveFuncDefOutsideOp(const QSharedPointer<const CppQuickFixAssistInterface> &interface, | 
					
						
							| 
									
										
										
										
											2014-05-19 23:32:19 +03:00
										 |  |  |                          MoveType type, FunctionDefinitionAST *funcDef, const QString &cppFileName) | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |         : CppQuickFixOperation(interface, 0) | 
					
						
							|  |  |  |         , m_funcDef(funcDef) | 
					
						
							|  |  |  |         , m_type(type) | 
					
						
							|  |  |  |         , m_cppFileName(cppFileName) | 
					
						
							|  |  |  |         , m_func(funcDef->symbol) | 
					
						
							|  |  |  |         , m_headerFileName(QString::fromUtf8(m_func->fileName(), m_func->fileNameLength())) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (m_type == MoveOutside) { | 
					
						
							|  |  |  |             setDescription(QCoreApplication::translate("CppEditor::QuickFix", | 
					
						
							| 
									
										
										
										
											2013-05-14 10:41:47 +02:00
										 |  |  |                                                        "Move Definition Outside Class")); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             const QDir dir = QFileInfo(m_headerFileName).dir(); | 
					
						
							|  |  |  |             setDescription(QCoreApplication::translate("CppEditor::QuickFix", | 
					
						
							|  |  |  |                                                        "Move Definition to %1") | 
					
						
							|  |  |  |                            .arg(dir.relativeFilePath(m_cppFileName))); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr fromFile = refactoring.file(m_headerFileName); | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |         CppRefactoringFilePtr toFile = (m_type == MoveOutside) ? fromFile | 
					
						
							|  |  |  |                                                                : refactoring.file(m_cppFileName); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Determine file, insert position and scope
 | 
					
						
							| 
									
										
										
										
											2013-06-15 11:50:44 +02:00
										 |  |  |         InsertionLocation l | 
					
						
							|  |  |  |                 = insertLocationForMethodDefinition(m_func, false, refactoring, toFile->fileName()); | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |         const QString prefix = l.prefix(); | 
					
						
							|  |  |  |         const QString suffix = l.suffix(); | 
					
						
							|  |  |  |         const int insertPos = toFile->position(l.line(), l.column()); | 
					
						
							|  |  |  |         Scope *scopeAtInsertPos = toFile->cppDocument()->scopeAt(l.line(), l.column()); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // construct definition
 | 
					
						
							| 
									
										
										
										
											2013-06-17 16:09:47 +02:00
										 |  |  |         const QString funcDec = definitionSignature(assistInterface(), m_funcDef, | 
					
						
							|  |  |  |                                                     fromFile, toFile, | 
					
						
							|  |  |  |                                                     scopeAtInsertPos); | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |         QString funcDef = prefix + funcDec; | 
					
						
							| 
									
										
										
										
											2013-05-24 12:18:34 +02:00
										 |  |  |         const int startPosition = fromFile->endOf(m_funcDef->declarator); | 
					
						
							|  |  |  |         const int endPosition = fromFile->endOf(m_funcDef->function_body); | 
					
						
							| 
									
										
										
										
											2013-06-04 17:37:24 +02:00
										 |  |  |         funcDef += fromFile->textOf(startPosition, endPosition); | 
					
						
							|  |  |  |         funcDef += suffix; | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // insert definition at new position
 | 
					
						
							|  |  |  |         ChangeSet cppChanges; | 
					
						
							|  |  |  |         cppChanges.insert(insertPos, funcDef); | 
					
						
							|  |  |  |         toFile->setChangeSet(cppChanges); | 
					
						
							|  |  |  |         toFile->appendIndentRange(ChangeSet::Range(insertPos, insertPos + funcDef.size())); | 
					
						
							|  |  |  |         toFile->setOpenEditor(true, insertPos); | 
					
						
							|  |  |  |         toFile->apply(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // remove definition from fromFile
 | 
					
						
							|  |  |  |         Utils::ChangeSet headerTarget; | 
					
						
							|  |  |  |         if (m_type == MoveOutsideMemberToCppFile) { | 
					
						
							|  |  |  |             headerTarget.remove(fromFile->range(m_funcDef)); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             QString textFuncDecl = fromFile->textOf(m_funcDef); | 
					
						
							| 
									
										
										
										
											2013-05-24 12:18:34 +02:00
										 |  |  |             textFuncDecl.truncate(startPosition - fromFile->startOf(m_funcDef)); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |             textFuncDecl = textFuncDecl.trimmed() + QLatin1String(";"); | 
					
						
							|  |  |  |             headerTarget.replace(fromFile->range(m_funcDef), textFuncDecl); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         fromFile->setChangeSet(headerTarget); | 
					
						
							|  |  |  |         fromFile->apply(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     FunctionDefinitionAST *m_funcDef; | 
					
						
							|  |  |  |     MoveType m_type; | 
					
						
							|  |  |  |     const QString m_cppFileName; | 
					
						
							|  |  |  |     Function *m_func; | 
					
						
							|  |  |  |     const QString m_headerFileName; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MoveFuncDefOutside::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     SimpleDeclarationAST *classAST = 0; | 
					
						
							|  |  |  |     FunctionDefinitionAST *funcAST = 0; | 
					
						
							|  |  |  |     bool moveOutsideMemberDefinition = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int pathSize = path.size(); | 
					
						
							|  |  |  |     for (int idx = 1; idx < pathSize; ++idx) { | 
					
						
							|  |  |  |         if ((funcAST = path.at(idx)->asFunctionDefinition())) { | 
					
						
							|  |  |  |             // check cursor position
 | 
					
						
							|  |  |  |             if (idx != pathSize - 1  // Do not allow "void a() @ {..."
 | 
					
						
							|  |  |  |                     && funcAST->function_body | 
					
						
							|  |  |  |                     && !interface->isCursorOn(funcAST->function_body)) { | 
					
						
							|  |  |  |                 if (path.at(idx - 1)->asTranslationUnit()) { // normal function
 | 
					
						
							|  |  |  |                     if (idx + 3 < pathSize && path.at(idx + 3)->asQualifiedName()) // Outside member
 | 
					
						
							|  |  |  |                         moveOutsideMemberDefinition = true;                        // definition
 | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (idx > 1) { | 
					
						
							|  |  |  |                     if ((classAST = path.at(idx - 2)->asSimpleDeclaration())) // member function
 | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     if (path.at(idx - 2)->asNamespace())  // normal function in namespace
 | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             funcAST = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!funcAST) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool isHeaderFile = false; | 
					
						
							|  |  |  |     const QString cppFileName = correspondingHeaderOrSource(interface->fileName(), &isHeaderFile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isHeaderFile && !cppFileName.isEmpty()) | 
					
						
							|  |  |  |         result.append(CppQuickFixOperation::Ptr( | 
					
						
							|  |  |  |                           new MoveFuncDefOutsideOp(interface, ((moveOutsideMemberDefinition) ? | 
					
						
							|  |  |  |                                                    MoveFuncDefOutsideOp::MoveOutsideMemberToCppFile | 
					
						
							|  |  |  |                                                    : MoveFuncDefOutsideOp::MoveToCppFile), | 
					
						
							| 
									
										
										
										
											2013-06-12 17:22:02 +02:00
										 |  |  |                                                    funcAST, cppFileName))); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (classAST) | 
					
						
							|  |  |  |         result.append(CppQuickFixOperation::Ptr( | 
					
						
							|  |  |  |                           new MoveFuncDefOutsideOp(interface, MoveFuncDefOutsideOp::MoveOutside, | 
					
						
							| 
									
										
										
										
											2013-06-12 17:22:02 +02:00
										 |  |  |                                                    funcAST, QLatin1String("")))); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MoveFuncDefToDeclOp : public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     MoveFuncDefToDeclOp(const QSharedPointer<const CppQuickFixAssistInterface> &interface, | 
					
						
							| 
									
										
										
										
											2014-05-19 23:32:19 +03:00
										 |  |  |                         const QString &fromFileName, const QString &toFileName, | 
					
						
							|  |  |  |                         FunctionDefinitionAST *funcDef, const QString &declText, | 
					
						
							|  |  |  |                         const ChangeSet::Range &toRange) | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |         : CppQuickFixOperation(interface, 0) | 
					
						
							|  |  |  |         , m_fromFileName(fromFileName) | 
					
						
							|  |  |  |         , m_toFileName(toFileName) | 
					
						
							|  |  |  |         , m_funcAST(funcDef) | 
					
						
							|  |  |  |         , m_declarationText(declText) | 
					
						
							|  |  |  |         , m_toRange(toRange) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (m_toFileName == m_fromFileName) { | 
					
						
							|  |  |  |             setDescription(QCoreApplication::translate("CppEditor::QuickFix", | 
					
						
							|  |  |  |                                                        "Move Definition to Class")); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             const QDir dir = QFileInfo(m_fromFileName).dir(); | 
					
						
							|  |  |  |             setDescription(QCoreApplication::translate("CppEditor::QuickFix", | 
					
						
							|  |  |  |                                                        "Move Definition to %1") | 
					
						
							|  |  |  |                            .arg(dir.relativeFilePath(m_toFileName))); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr fromFile = refactoring.file(m_fromFileName); | 
					
						
							|  |  |  |         CppRefactoringFilePtr toFile = refactoring.file(m_toFileName); | 
					
						
							|  |  |  |         ChangeSet::Range fromRange = fromFile->range(m_funcAST); | 
					
						
							| 
									
										
										
										
											2013-04-18 11:21:12 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-24 12:18:34 +02:00
										 |  |  |         const QString wholeFunctionText = m_declarationText | 
					
						
							|  |  |  |                 + fromFile->textOf(fromFile->endOf(m_funcAST->declarator), | 
					
						
							|  |  |  |                                    fromFile->endOf(m_funcAST->function_body)); | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Replace declaration with function and delete old definition
 | 
					
						
							|  |  |  |         Utils::ChangeSet toTarget; | 
					
						
							|  |  |  |         toTarget.replace(m_toRange, wholeFunctionText); | 
					
						
							|  |  |  |         if (m_toFileName == m_fromFileName) | 
					
						
							|  |  |  |             toTarget.remove(fromRange); | 
					
						
							|  |  |  |         toFile->setChangeSet(toTarget); | 
					
						
							|  |  |  |         toFile->appendIndentRange(m_toRange); | 
					
						
							|  |  |  |         toFile->setOpenEditor(true, m_toRange.start); | 
					
						
							|  |  |  |         toFile->apply(); | 
					
						
							|  |  |  |         if (m_toFileName != m_fromFileName) { | 
					
						
							|  |  |  |             Utils::ChangeSet fromTarget; | 
					
						
							|  |  |  |             fromTarget.remove(fromRange); | 
					
						
							|  |  |  |             fromFile->setChangeSet(fromTarget); | 
					
						
							|  |  |  |             fromFile->apply(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     const QString m_fromFileName; | 
					
						
							|  |  |  |     const QString m_toFileName; | 
					
						
							|  |  |  |     FunctionDefinitionAST *m_funcAST; | 
					
						
							|  |  |  |     const QString m_declarationText; | 
					
						
							|  |  |  |     const ChangeSet::Range m_toRange; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void MoveFuncDefToDecl::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     FunctionDefinitionAST *funcAST = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const int pathSize = path.size(); | 
					
						
							|  |  |  |     for (int idx = 1; idx < pathSize; ++idx) { | 
					
						
							|  |  |  |         if ((funcAST = path.at(idx)->asFunctionDefinition())) { | 
					
						
							|  |  |  |             if (path.at(idx - 1)->asClassSpecifier()) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // check cursor position
 | 
					
						
							|  |  |  |             if (idx != pathSize - 1  // Do not allow "void a() @ {..."
 | 
					
						
							|  |  |  |                     && funcAST->function_body | 
					
						
							|  |  |  |                     && !interface->isCursorOn(funcAST->function_body)) { | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             funcAST = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!funcAST || !funcAST->symbol) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Determine declaration (file, range, text);
 | 
					
						
							|  |  |  |     QString declFileName; | 
					
						
							|  |  |  |     ChangeSet::Range declRange; | 
					
						
							|  |  |  |     QString declText; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Function *func = funcAST->symbol; | 
					
						
							|  |  |  |     if (Class *matchingClass = isMemberFunction(interface->context(), func)) { | 
					
						
							|  |  |  |         // Dealing with member functions
 | 
					
						
							|  |  |  |         const QualifiedNameId *qName = func->name()->asQualifiedNameId(); | 
					
						
							|  |  |  |         for (Symbol *s = matchingClass->find(qName->identifier()); s; s = s->next()) { | 
					
						
							|  |  |  |             if (!s->name() | 
					
						
							| 
									
										
										
										
											2014-05-15 12:00:13 -04:00
										 |  |  |                     || !qName->identifier()->match(s->identifier()) | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |                     || !s->type()->isFunctionType() | 
					
						
							| 
									
										
										
										
											2014-05-15 12:00:13 -04:00
										 |  |  |                     || !s->type().match(func->type()) | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |                     || s->isFunction()) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             declFileName = QString::fromUtf8(matchingClass->fileName(), | 
					
						
							|  |  |  |                                              matchingClass->fileNameLength()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const CppRefactoringChanges refactoring(interface->snapshot()); | 
					
						
							|  |  |  |             const CppRefactoringFilePtr declFile = refactoring.file(declFileName); | 
					
						
							|  |  |  |             ASTPath astPath(declFile->cppDocument()); | 
					
						
							|  |  |  |             const QList<AST *> path = astPath(s->line(), s->column()); | 
					
						
							| 
									
										
										
										
											2013-10-05 21:15:43 +02:00
										 |  |  |             for (int idx = path.size() - 1; idx > 0; --idx) { | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |                 AST *node = path.at(idx); | 
					
						
							|  |  |  |                 if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) { | 
					
						
							|  |  |  |                     if (simpleDecl->symbols && !simpleDecl->symbols->next) { | 
					
						
							|  |  |  |                         declRange = declFile->range(simpleDecl); | 
					
						
							|  |  |  |                         declText = declFile->textOf(simpleDecl); | 
					
						
							|  |  |  |                         declText.remove(-1, 1); // remove ';' from declaration text
 | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!declText.isEmpty()) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2013-07-17 00:01:45 +03:00
										 |  |  |     } else if (Namespace *matchingNamespace = isNamespaceFunction(interface->context(), func)) { | 
					
						
							| 
									
										
										
										
											2013-04-15 14:23:33 +02:00
										 |  |  |         // Dealing with free functions
 | 
					
						
							|  |  |  |         bool isHeaderFile = false; | 
					
						
							|  |  |  |         declFileName = correspondingHeaderOrSource(interface->fileName(), &isHeaderFile); | 
					
						
							|  |  |  |         if (isHeaderFile) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const CppRefactoringChanges refactoring(interface->snapshot()); | 
					
						
							|  |  |  |         const CppRefactoringFilePtr declFile = refactoring.file(declFileName); | 
					
						
							|  |  |  |         const LookupContext lc(declFile->cppDocument(), interface->snapshot()); | 
					
						
							|  |  |  |         const QList<LookupItem> candidates = lc.lookup(func->name(), matchingNamespace); | 
					
						
							|  |  |  |         for (int i = 0; i < candidates.size(); ++i) { | 
					
						
							|  |  |  |             if (Symbol *s = candidates.at(i).declaration()) { | 
					
						
							|  |  |  |                 if (s->asDeclaration()) { | 
					
						
							|  |  |  |                     ASTPath astPath(declFile->cppDocument()); | 
					
						
							|  |  |  |                     const QList<AST *> path = astPath(s->line(), s->column()); | 
					
						
							|  |  |  |                     for (int idx = 0; idx < path.size(); ++idx) { | 
					
						
							|  |  |  |                         AST *node = path.at(idx); | 
					
						
							|  |  |  |                         if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) { | 
					
						
							|  |  |  |                             declRange = declFile->range(simpleDecl); | 
					
						
							|  |  |  |                             declText = declFile->textOf(simpleDecl); | 
					
						
							|  |  |  |                             declText.remove(-1, 1); // remove ';' from declaration text
 | 
					
						
							|  |  |  |                             break; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!declText.isEmpty()) | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!declFileName.isEmpty() && !declText.isEmpty()) | 
					
						
							|  |  |  |         result.append(QuickFixOperation::Ptr(new MoveFuncDefToDeclOp(interface, | 
					
						
							|  |  |  |                                                                      interface->fileName(), | 
					
						
							|  |  |  |                                                                      declFileName, | 
					
						
							|  |  |  |                                                                      funcAST, declText, | 
					
						
							|  |  |  |                                                                      declRange))); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class AssignToLocalVariableOperation : public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     explicit AssignToLocalVariableOperation(const CppQuickFixInterface &interface, | 
					
						
							|  |  |  |                                             const int insertPos, const AST *ast, const Name *name) | 
					
						
							|  |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , m_insertPos(insertPos) | 
					
						
							|  |  |  |         , m_ast(ast) | 
					
						
							|  |  |  |         , m_name(name) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", "Assign to Local Variable")); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CppRefactoringChanges refactoring(snapshot()); | 
					
						
							|  |  |  |         CppRefactoringFilePtr file = refactoring.file(assistInterface()->fileName()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Determine return type and new variable name
 | 
					
						
							|  |  |  |         TypeOfExpression typeOfExpression; | 
					
						
							|  |  |  |         typeOfExpression.init(assistInterface()->semanticInfo().doc, snapshot(), | 
					
						
							|  |  |  |                               assistInterface()->context().bindings()); | 
					
						
							| 
									
										
										
										
											2013-06-12 17:40:11 +02:00
										 |  |  |         typeOfExpression.setExpandTemplates(true); | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |         Scope *scope = file->scopeAt(m_ast->firstToken()); | 
					
						
							|  |  |  |         const QList<LookupItem> result = typeOfExpression(file->textOf(m_ast).toUtf8(), | 
					
						
							|  |  |  |                                                           scope, TypeOfExpression::Preprocess); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!result.isEmpty()) { | 
					
						
							|  |  |  |             SubstitutionEnvironment env; | 
					
						
							|  |  |  |             env.setContext(assistInterface()->context()); | 
					
						
							|  |  |  |             env.switchScope(result.first().scope()); | 
					
						
							|  |  |  |             ClassOrNamespace *con = typeOfExpression.context().lookupType(scope); | 
					
						
							|  |  |  |             if (!con) | 
					
						
							|  |  |  |                 con = typeOfExpression.context().globalNamespace(); | 
					
						
							|  |  |  |             UseMinimalNames q(con); | 
					
						
							|  |  |  |             env.enter(&q); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-15 10:21:47 +02:00
										 |  |  |             Control *control = assistInterface()->context().bindings()->control().data(); | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |             FullySpecifiedType type = rewriteType(result.first().type(), &env, control); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							|  |  |  |             QString originalName = oo.prettyName(m_name); | 
					
						
							|  |  |  |             QString newName = originalName; | 
					
						
							|  |  |  |             if (newName.startsWith(QLatin1String("get"), Qt::CaseInsensitive) | 
					
						
							|  |  |  |                     && newName.length() > 3 | 
					
						
							|  |  |  |                     && newName.at(3).isUpper()) { | 
					
						
							|  |  |  |                 newName.remove(0, 3); | 
					
						
							|  |  |  |                 newName.replace(0, 1, newName.at(0).toLower()); | 
					
						
							|  |  |  |             } else if (newName.startsWith(QLatin1String("to"), Qt::CaseInsensitive) | 
					
						
							|  |  |  |                        && newName.length() > 2 | 
					
						
							|  |  |  |                        && newName.at(2).isUpper()) { | 
					
						
							|  |  |  |                 newName.remove(0, 2); | 
					
						
							|  |  |  |                 newName.replace(0, 1, newName.at(0).toLower()); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 newName.replace(0, 1, newName.at(0).toUpper()); | 
					
						
							|  |  |  |                 newName.prepend(QLatin1String("local")); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const int nameLength = originalName.length(); | 
					
						
							|  |  |  |             QString tempType = oo.prettyType(type, m_name); | 
					
						
							|  |  |  |             const QString insertString = tempType.replace( | 
					
						
							|  |  |  |                         tempType.length() - nameLength, nameLength, newName + QLatin1String(" = ")); | 
					
						
							|  |  |  |             if (!tempType.isEmpty()) { | 
					
						
							|  |  |  |                 ChangeSet changes; | 
					
						
							|  |  |  |                 changes.insert(m_insertPos, insertString); | 
					
						
							|  |  |  |                 file->setChangeSet(changes); | 
					
						
							|  |  |  |                 file->apply(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // move cursor to new variable name
 | 
					
						
							|  |  |  |                 QTextCursor c = file->cursor(); | 
					
						
							|  |  |  |                 c.setPosition(m_insertPos + insertString.length() - newName.length() - 3); | 
					
						
							|  |  |  |                 c.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); | 
					
						
							|  |  |  |                 assistInterface()->editor()->setTextCursor(c); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     const int m_insertPos; | 
					
						
							|  |  |  |     const AST *m_ast; | 
					
						
							|  |  |  |     const Name *m_name; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AssignToLocalVariable::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> &path = interface->path(); | 
					
						
							|  |  |  |     AST *outerAST = 0; | 
					
						
							|  |  |  |     SimpleNameAST *nameAST = 0; | 
					
						
							|  |  |  |     SimpleNameAST *visibleNameAST = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (int i = path.size() - 3; i >= 0; --i) { | 
					
						
							|  |  |  |         if (CallAST *callAST = path.at(i)->asCall()) { | 
					
						
							|  |  |  |             if (!interface->isCursorOn(callAST)) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             if (i - 2 >= 0) { | 
					
						
							|  |  |  |                 const int idx = i - 2; | 
					
						
							|  |  |  |                 if (path.at(idx)->asSimpleDeclaration()) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 if (path.at(idx)->asExpressionStatement()) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 if (path.at(idx)->asMemInitializer()) | 
					
						
							|  |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2013-06-11 21:20:06 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             for (int a = i - 1; a > 0; --a) { | 
					
						
							|  |  |  |                 if (path.at(a)->asBinaryExpression()) | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2013-06-11 21:20:06 +02:00
										 |  |  |                 if (path.at(a)->asReturnStatement()) | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2013-06-11 21:20:06 +02:00
										 |  |  |                 if (path.at(a)->asCall()) | 
					
						
							| 
									
										
										
										
											2013-06-10 17:27:09 +02:00
										 |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (MemberAccessAST *member = path.at(i + 1)->asMemberAccess()) { // member
 | 
					
						
							|  |  |  |                 if (member->base_expression) { | 
					
						
							|  |  |  |                     if (IdExpressionAST *idex = member->base_expression->asIdExpression()) { | 
					
						
							|  |  |  |                         nameAST = idex->name->asSimpleName(); | 
					
						
							|  |  |  |                         visibleNameAST = member->member_name->asSimpleName(); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else if (QualifiedNameAST *qname = path.at(i + 2)->asQualifiedName()) { // static or
 | 
					
						
							|  |  |  |                 nameAST = qname->unqualified_name->asSimpleName();                    // func in ns
 | 
					
						
							|  |  |  |                 visibleNameAST = nameAST; | 
					
						
							|  |  |  |             } else { // normal
 | 
					
						
							|  |  |  |                 nameAST = path.at(i + 2)->asSimpleName(); | 
					
						
							|  |  |  |                 visibleNameAST = nameAST; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (nameAST && visibleNameAST) { | 
					
						
							|  |  |  |                 outerAST = callAST; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } else if (NewExpressionAST *newexp = path.at(i)->asNewExpression()) { | 
					
						
							|  |  |  |             if (!interface->isCursorOn(newexp)) | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             if (i - 2 >= 0) { | 
					
						
							|  |  |  |                 const int idx = i - 2; | 
					
						
							|  |  |  |                 if (path.at(idx)->asSimpleDeclaration()) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 if (path.at(idx)->asExpressionStatement()) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |                 if (path.at(idx)->asMemInitializer()) | 
					
						
							|  |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2013-06-11 21:20:06 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             for (int a = i - 1; a > 0; --a) { | 
					
						
							|  |  |  |                 if (path.at(a)->asReturnStatement()) | 
					
						
							| 
									
										
										
										
											2013-06-10 17:27:09 +02:00
										 |  |  |                     return; | 
					
						
							| 
									
										
										
										
											2013-06-11 21:20:06 +02:00
										 |  |  |                 if (path.at(a)->asCall()) | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |                     return; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-06-11 21:20:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |             if (NamedTypeSpecifierAST *ts = path.at(i + 2)->asNamedTypeSpecifier()) { | 
					
						
							|  |  |  |                 nameAST = ts->name->asSimpleName(); | 
					
						
							|  |  |  |                 visibleNameAST = nameAST; | 
					
						
							|  |  |  |                 outerAST = newexp; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (outerAST && nameAST && visibleNameAST) { | 
					
						
							|  |  |  |         const CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  |         QList<LookupItem> items; | 
					
						
							|  |  |  |         TypeOfExpression typeOfExpression; | 
					
						
							|  |  |  |         typeOfExpression.init(interface->semanticInfo().doc, interface->snapshot(), | 
					
						
							|  |  |  |                               interface->context().bindings()); | 
					
						
							| 
									
										
										
										
											2013-06-12 17:40:11 +02:00
										 |  |  |         typeOfExpression.setExpandTemplates(true); | 
					
						
							| 
									
										
										
										
											2013-05-17 17:30:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // If items are empty, AssignToLocalVariableOperation will fail.
 | 
					
						
							|  |  |  |         items = typeOfExpression(file->textOf(outerAST).toUtf8(), | 
					
						
							|  |  |  |                                  file->scopeAt(outerAST->firstToken()), | 
					
						
							|  |  |  |                                  TypeOfExpression::Preprocess); | 
					
						
							|  |  |  |         if (items.isEmpty()) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |         if (CallAST *callAST = outerAST->asCall()) { | 
					
						
							| 
									
										
										
										
											2013-05-17 17:30:18 +02:00
										 |  |  |             items = typeOfExpression(file->textOf(callAST->base_expression).toUtf8(), | 
					
						
							|  |  |  |                                      file->scopeAt(callAST->base_expression->firstToken()), | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |                                      TypeOfExpression::Preprocess); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2013-05-17 17:30:18 +02:00
										 |  |  |             items = typeOfExpression(file->textOf(nameAST).toUtf8(), | 
					
						
							|  |  |  |                                      file->scopeAt(nameAST->firstToken()), | 
					
						
							| 
									
										
										
										
											2013-04-17 21:53:20 +02:00
										 |  |  |                                      TypeOfExpression::Preprocess); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach (const LookupItem &item, items) { | 
					
						
							|  |  |  |             if (!item.declaration()) | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (Function *func = item.declaration()->asFunction()) { | 
					
						
							|  |  |  |                 if (func->isSignal() || func->returnType()->isVoidType()) | 
					
						
							|  |  |  |                     return; | 
					
						
							|  |  |  |             } else if (Declaration *dec = item.declaration()->asDeclaration()) { | 
					
						
							|  |  |  |                 if (Function *func = dec->type()->asFunctionType()) { | 
					
						
							|  |  |  |                     if (func->isSignal() || func->returnType()->isVoidType()) | 
					
						
							|  |  |  |                       return; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const Name *name = visibleNameAST->name; | 
					
						
							|  |  |  |             const int insertPos = interface->currentFile()->startOf(outerAST); | 
					
						
							|  |  |  |             result.append(CppQuickFixOperation::Ptr( | 
					
						
							|  |  |  |                               new AssignToLocalVariableOperation(interface, insertPos, outerAST, | 
					
						
							|  |  |  |                                                                  name))); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-29 23:15:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-23 20:59:02 +02:00
										 |  |  | class OptimizeForLoopOperation: public CppQuickFixOperation | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  |     OptimizeForLoopOperation(const CppQuickFixInterface &interface, const ForStatementAST *forAst, | 
					
						
							|  |  |  |                              const bool optimizePostcrement, const ExpressionAST *expression, | 
					
						
							| 
									
										
										
										
											2014-05-19 23:32:19 +03:00
										 |  |  |                              const FullySpecifiedType &type) | 
					
						
							| 
									
										
										
										
											2013-05-23 20:59:02 +02:00
										 |  |  |         : CppQuickFixOperation(interface) | 
					
						
							|  |  |  |         , m_forAst(forAst) | 
					
						
							|  |  |  |         , m_optimizePostcrement(optimizePostcrement) | 
					
						
							|  |  |  |         , m_expression(expression) | 
					
						
							|  |  |  |         , m_type(type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         setDescription(QApplication::translate("CppTools::QuickFix", "Optimize for-Loop")); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void perform() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QTC_ASSERT(m_forAst, return); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const QString filename = assistInterface()->currentFile()->fileName(); | 
					
						
							|  |  |  |         const CppRefactoringChanges refactoring(assistInterface()->snapshot()); | 
					
						
							|  |  |  |         const CppRefactoringFilePtr file = refactoring.file(filename); | 
					
						
							|  |  |  |         ChangeSet change; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Optimize post (in|de)crement operator to pre (in|de)crement operator
 | 
					
						
							|  |  |  |         if (m_optimizePostcrement && m_forAst->expression) { | 
					
						
							|  |  |  |             PostIncrDecrAST *incrdecr = m_forAst->expression->asPostIncrDecr(); | 
					
						
							|  |  |  |             if (incrdecr && incrdecr->base_expression && incrdecr->incr_decr_token) { | 
					
						
							|  |  |  |                 change.flip(file->range(incrdecr->base_expression), | 
					
						
							|  |  |  |                             file->range(incrdecr->incr_decr_token)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Optimize Condition
 | 
					
						
							|  |  |  |         int renamePos = -1; | 
					
						
							|  |  |  |         if (m_expression) { | 
					
						
							|  |  |  |             QString varName = QLatin1String("total"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (file->textOf(m_forAst->initializer).length() == 1) { | 
					
						
							|  |  |  |                 Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); | 
					
						
							|  |  |  |                 const QString typeAndName = oo.prettyType(m_type, varName); | 
					
						
							|  |  |  |                 renamePos = file->endOf(m_forAst->initializer) - 1 + typeAndName.length(); | 
					
						
							|  |  |  |                 change.insert(file->endOf(m_forAst->initializer) - 1, // "-1" because of ";"
 | 
					
						
							|  |  |  |                               typeAndName + QLatin1String(" = ") + file->textOf(m_expression)); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 // Check if varName is already used
 | 
					
						
							|  |  |  |                 if (DeclarationStatementAST *ds = m_forAst->initializer->asDeclarationStatement()) { | 
					
						
							|  |  |  |                     if (DeclarationAST *decl = ds->declaration) { | 
					
						
							|  |  |  |                         if (SimpleDeclarationAST *sdecl = decl->asSimpleDeclaration()) { | 
					
						
							|  |  |  |                             for (;;) { | 
					
						
							|  |  |  |                                 bool match = false; | 
					
						
							|  |  |  |                                 for (DeclaratorListAST *it = sdecl->declarator_list; it; | 
					
						
							|  |  |  |                                      it = it->next) { | 
					
						
							|  |  |  |                                     if (file->textOf(it->value->core_declarator) == varName) { | 
					
						
							|  |  |  |                                         varName += QLatin1Char('X'); | 
					
						
							|  |  |  |                                         match = true; | 
					
						
							|  |  |  |                                         break; | 
					
						
							|  |  |  |                                     } | 
					
						
							|  |  |  |                                 } | 
					
						
							|  |  |  |                                 if (!match) | 
					
						
							|  |  |  |                                     break; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 renamePos = file->endOf(m_forAst->initializer) + 1 + varName.length(); | 
					
						
							|  |  |  |                 change.insert(file->endOf(m_forAst->initializer) - 1, // "-1" because of ";"
 | 
					
						
							|  |  |  |                               QLatin1String(", ") + varName + QLatin1String(" = ") | 
					
						
							|  |  |  |                               + file->textOf(m_expression)); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ChangeSet::Range exprRange(file->startOf(m_expression), file->endOf(m_expression)); | 
					
						
							|  |  |  |             change.replace(exprRange, varName); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         file->setChangeSet(change); | 
					
						
							|  |  |  |         file->apply(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Select variable name and trigger symbol rename
 | 
					
						
							|  |  |  |         if (renamePos != -1) { | 
					
						
							|  |  |  |             QTextCursor c = file->cursor(); | 
					
						
							|  |  |  |             c.setPosition(renamePos); | 
					
						
							|  |  |  |             assistInterface()->editor()->setTextCursor(c); | 
					
						
							|  |  |  |             assistInterface()->editor()->renameSymbolUnderCursor(); | 
					
						
							|  |  |  |             c.select(QTextCursor::WordUnderCursor); | 
					
						
							|  |  |  |             assistInterface()->editor()->setTextCursor(c); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     const ForStatementAST *m_forAst; | 
					
						
							|  |  |  |     const bool m_optimizePostcrement; | 
					
						
							|  |  |  |     const ExpressionAST *m_expression; | 
					
						
							|  |  |  |     const FullySpecifiedType m_type; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OptimizeForLoop::match(const CppQuickFixInterface &interface, QuickFixOperations &result) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const QList<AST *> path = interface->path(); | 
					
						
							|  |  |  |     ForStatementAST *forAst = 0; | 
					
						
							|  |  |  |     if (!path.isEmpty()) | 
					
						
							|  |  |  |         forAst = path.last()->asForStatement(); | 
					
						
							|  |  |  |     if (!forAst || !interface->isCursorOn(forAst)) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Check for optimizing a postcrement
 | 
					
						
							|  |  |  |     const CppRefactoringFilePtr file = interface->currentFile(); | 
					
						
							|  |  |  |     bool optimizePostcrement = false; | 
					
						
							|  |  |  |     if (forAst->expression) { | 
					
						
							|  |  |  |         if (PostIncrDecrAST *incrdecr = forAst->expression->asPostIncrDecr()) { | 
					
						
							|  |  |  |             const Token t = file->tokenAt(incrdecr->incr_decr_token); | 
					
						
							|  |  |  |             if (t.is(T_PLUS_PLUS) || t.is(T_MINUS_MINUS)) | 
					
						
							|  |  |  |                 optimizePostcrement = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Check for optimizing condition
 | 
					
						
							|  |  |  |     bool optimizeCondition = false; | 
					
						
							|  |  |  |     FullySpecifiedType conditionType; | 
					
						
							|  |  |  |     ExpressionAST *conditionExpression = 0; | 
					
						
							|  |  |  |     if (forAst->initializer && forAst->condition) { | 
					
						
							|  |  |  |         if (BinaryExpressionAST *binary = forAst->condition->asBinaryExpression()) { | 
					
						
							|  |  |  |             // Get the expression against which we should evaluate
 | 
					
						
							|  |  |  |             IdExpressionAST *conditionId = binary->left_expression->asIdExpression(); | 
					
						
							|  |  |  |             if (conditionId) { | 
					
						
							|  |  |  |                 conditionExpression = binary->right_expression; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 conditionId = binary->right_expression->asIdExpression(); | 
					
						
							|  |  |  |                 conditionExpression = binary->left_expression; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (conditionId && conditionExpression | 
					
						
							|  |  |  |                     && !(conditionExpression->asNumericLiteral() | 
					
						
							|  |  |  |                          || conditionExpression->asStringLiteral() | 
					
						
							|  |  |  |                          || conditionExpression->asIdExpression() | 
					
						
							|  |  |  |                          || conditionExpression->asUnaryExpression())) { | 
					
						
							|  |  |  |                 // Determine type of for initializer
 | 
					
						
							|  |  |  |                 FullySpecifiedType initializerType; | 
					
						
							|  |  |  |                 if (DeclarationStatementAST *stmt = forAst->initializer->asDeclarationStatement()) { | 
					
						
							|  |  |  |                     if (stmt->declaration) { | 
					
						
							|  |  |  |                         if (SimpleDeclarationAST *decl = stmt->declaration->asSimpleDeclaration()) { | 
					
						
							|  |  |  |                             if (decl->symbols) { | 
					
						
							|  |  |  |                                 if (Symbol *symbol = decl->symbols->value) | 
					
						
							|  |  |  |                                     initializerType = symbol->type(); | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 // Determine type of for condition
 | 
					
						
							|  |  |  |                 TypeOfExpression typeOfExpression; | 
					
						
							|  |  |  |                 typeOfExpression.init(interface->semanticInfo().doc, interface->snapshot(), | 
					
						
							|  |  |  |                                       interface->context().bindings()); | 
					
						
							|  |  |  |                 typeOfExpression.setExpandTemplates(true); | 
					
						
							|  |  |  |                 Scope *scope = file->scopeAt(conditionId->firstToken()); | 
					
						
							|  |  |  |                 const QList<LookupItem> conditionItems = typeOfExpression( | 
					
						
							|  |  |  |                             conditionId, interface->semanticInfo().doc, scope); | 
					
						
							|  |  |  |                 if (!conditionItems.isEmpty()) | 
					
						
							|  |  |  |                     conditionType = conditionItems.first().type(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (conditionType.isValid() | 
					
						
							|  |  |  |                         && (file->textOf(forAst->initializer) == QLatin1String(";") | 
					
						
							|  |  |  |                             || initializerType == conditionType)) { | 
					
						
							|  |  |  |                     optimizeCondition = true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (optimizePostcrement || optimizeCondition) { | 
					
						
							|  |  |  |         OptimizeForLoopOperation *op | 
					
						
							|  |  |  |                 = new OptimizeForLoopOperation(interface, forAst, optimizePostcrement, | 
					
						
							|  |  |  |                                                (optimizeCondition) ? conditionExpression : 0, | 
					
						
							|  |  |  |                                                conditionType); | 
					
						
							|  |  |  |         result.append(QuickFixOperation::Ptr(op)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |