aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorLorenz Haas <lykurg@gmail.com>2013-04-11 18:01:40 +0200
committerNikolai Kosjar <nikolai.kosjar@digia.com>2013-04-15 13:32:42 +0200
commit61ddf16689e7499ac26aede6bf50a33ba03a6d69 (patch)
tree5946f64ee61ad181c1db5733dd70a32069bfe3c6 /src/plugins
parent38531a781ef0aef317c201da26ecfb49b2ae6366 (diff)
CppEditor: Rearrange quick fix files
Moved content of cppinsertdecldef.(cpp|h) cppcompleteswitch.(cpp|h) cppinsertqtpropertymembers.(cpp|h) and ApplyDeclDefLinkChanges to cppquickfixes.(cpp|h). Made msgQtStringLiteralDescription private member function of WrapStringLiteral, added anonymous namespace, "extracted" useful functions to the top of cppquickfixes.cpp. Change-Id: I4f82a005a62be3c29d4b96902667bd3a2b9397cc Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/cppeditor/cppcompleteswitch.cpp210
-rw-r--r--src/plugins/cppeditor/cppcompleteswitch.h50
-rw-r--r--src/plugins/cppeditor/cppeditor.pro6
-rw-r--r--src/plugins/cppeditor/cppeditor.qbs6
-rw-r--r--src/plugins/cppeditor/cppfunctiondecldeflink.cpp36
-rw-r--r--src/plugins/cppeditor/cppfunctiondecldeflink.h6
-rw-r--r--src/plugins/cppeditor/cppinsertdecldef.cpp1131
-rw-r--r--src/plugins/cppeditor/cppinsertdecldef.h65
-rw-r--r--src/plugins/cppeditor/cppinsertqtpropertymembers.cpp205
-rw-r--r--src/plugins/cppeditor/cppinsertqtpropertymembers.h102
-rw-r--r--src/plugins/cppeditor/cppquickfix_test.cpp1
-rw-r--r--src/plugins/cppeditor/cppquickfixes.cpp1646
-rw-r--r--src/plugins/cppeditor/cppquickfixes.h67
13 files changed, 1665 insertions, 1866 deletions
diff --git a/src/plugins/cppeditor/cppcompleteswitch.cpp b/src/plugins/cppeditor/cppcompleteswitch.cpp
deleted file mode 100644
index 29fd4a1a2ae..00000000000
--- a/src/plugins/cppeditor/cppcompleteswitch.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of Qt Creator.
-**
-** 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.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#include "cppcompleteswitch.h"
-
-#include "cppquickfixassistant.h"
-
-#include <cpptools/cpprefactoringchanges.h>
-
-#include <cplusplus/Overview.h>
-#include <cplusplus/TypeOfExpression.h>
-
-#include <QApplication>
-
-using namespace CPlusPlus;
-using namespace CppEditor;
-using namespace CppEditor::Internal;
-using namespace CppTools;
-using namespace TextEditor;
-using namespace Utils;
-
-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 Operation: public CppQuickFixOperation
-{
-public:
- Operation(const QSharedPointer<const CppEditor::Internal::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;
-};
-
-} // end of anonymous namespace
-
-static 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()) {
- const QList<LookupItem> candidates =
- ctxt.lookup(namedType->name(), result.scope());
- return findEnum(candidates, ctxt);
- }
- }
-
- return 0;
-}
-
-static 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());
-}
-
-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 Operation(interface, depth, compoundStatement, values)));
- return;
- }
-
- return;
- }
- }
-}
diff --git a/src/plugins/cppeditor/cppcompleteswitch.h b/src/plugins/cppeditor/cppcompleteswitch.h
deleted file mode 100644
index 9fca8a0d164..00000000000
--- a/src/plugins/cppeditor/cppcompleteswitch.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of Qt Creator.
-**
-** 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.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef CPPCOMPLETESWITCH_H
-#define CPPCOMPLETESWITCH_H
-
-#include "cppquickfix.h"
-
-namespace CppEditor {
-namespace Internal {
-
-/*!
- Adds missing case statements for "switch (enumVariable)"
- */
-class CompleteSwitchCaseStatement: public CppQuickFixFactory
-{
-public:
- void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
-};
-
-} // namespace Internal
-} // namespace CppEditor
-
-#endif // CPPCOMPLETESWITCH_H
diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro
index 5e8d82d2783..6287ab1fa77 100644
--- a/src/plugins/cppeditor/cppeditor.pro
+++ b/src/plugins/cppeditor/cppeditor.pro
@@ -10,13 +10,10 @@ HEADERS += cppplugin.h \
cppeditor_global.h \
cppclasswizard.h \
cppoutline.h \
- cppinsertdecldef.h \
cpptypehierarchy.h \
cppelementevaluator.h \
cppautocompleter.h \
- cppcompleteswitch.h \
cppsnippetprovider.h \
- cppinsertqtpropertymembers.h \
cppquickfixassistant.h \
cppquickfix.h \
cppquickfixes.h \
@@ -30,13 +27,10 @@ SOURCES += cppplugin.cpp \
cppclasswizard.cpp \
cppquickfixes.cpp \
cppoutline.cpp \
- cppinsertdecldef.cpp \
cpptypehierarchy.cpp \
cppelementevaluator.cpp \
cppautocompleter.cpp \
- cppcompleteswitch.cpp \
cppsnippetprovider.cpp \
- cppinsertqtpropertymembers.cpp \
cppquickfixassistant.cpp \
cppquickfix.cpp \
cppfunctiondecldeflink.cpp
diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs
index 5e12d69d607..8aab82e7465 100644
--- a/src/plugins/cppeditor/cppeditor.qbs
+++ b/src/plugins/cppeditor/cppeditor.qbs
@@ -23,8 +23,6 @@ QtcPlugin {
"cppautocompleter.h",
"cppclasswizard.cpp",
"cppclasswizard.h",
- "cppcompleteswitch.cpp",
- "cppcompleteswitch.h",
"cppeditor.cpp",
"cppeditor.h",
"cppeditor.qrc",
@@ -41,10 +39,6 @@ QtcPlugin {
"cpphighlighter.h",
"cpphoverhandler.cpp",
"cpphoverhandler.h",
- "cppinsertdecldef.cpp",
- "cppinsertdecldef.h",
- "cppinsertqtpropertymembers.cpp",
- "cppinsertqtpropertymembers.h",
"cppoutline.cpp",
"cppoutline.h",
"cppplugin.cpp",
diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp
index 41c575c6001..8546f438b0e 100644
--- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp
+++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp
@@ -981,39 +981,3 @@ Utils::ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targ
return changes;
}
-
-class ApplyDeclDefLinkOperation : public CppQuickFixOperation
-{
-public:
- explicit ApplyDeclDefLinkOperation(const CppQuickFixInterface &interface,
- const QSharedPointer<FunctionDeclDefLink> &link)
- : CppQuickFixOperation(interface, 10)
- , 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 CppTools::CppRefactoringFilePtr &, const CppTools::CppRefactoringChanges &)
- { /* never called since perform is overridden */ }
-
-private:
- QSharedPointer<FunctionDeclDefLink> m_link;
-};
-
-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;
-}
diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.h b/src/plugins/cppeditor/cppfunctiondecldeflink.h
index 1d23260f475..f15b51c9a31 100644
--- a/src/plugins/cppeditor/cppfunctiondecldeflink.h
+++ b/src/plugins/cppeditor/cppfunctiondecldeflink.h
@@ -120,12 +120,6 @@ private:
friend class FunctionDeclDefLinkFinder;
};
-class ApplyDeclDefLinkChanges: public CppQuickFixFactory
-{
-public:
- void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
-};
-
} // namespace Internal
} // namespace CppEditor
diff --git a/src/plugins/cppeditor/cppinsertdecldef.cpp b/src/plugins/cppeditor/cppinsertdecldef.cpp
deleted file mode 100644
index cd63871dd96..00000000000
--- a/src/plugins/cppeditor/cppinsertdecldef.cpp
+++ /dev/null
@@ -1,1131 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of Qt Creator.
-**
-** 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.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#include "cppinsertdecldef.h"
-#include "cppquickfixassistant.h"
-
-#include <cpptools/cppcodestylesettings.h>
-#include <cpptools/cpptoolsreuse.h>
-#include <cpptools/insertionpointlocator.h>
-
-#include <cplusplus/CppRewriter.h>
-
-#include <utils/qtcassert.h>
-
-#include <QCoreApplication>
-#include <QDir>
-#include <QHash>
-#include <QStringBuilder>
-#include <QTextDocument>
-#include <QInputDialog>
-#include <QMessageBox>
-
-using namespace CPlusPlus;
-using namespace CppEditor;
-using namespace CppEditor::Internal;
-using namespace CppTools;
-using namespace TextEditor;
-using namespace Utils;
-
-namespace {
-
-class InsertDeclOperation: public CppQuickFixOperation
-{
-public:
- InsertDeclOperation(const QSharedPointer<const CppEditor::Internal::CppQuickFixAssistInterface> &interface,
- const QString &targetFileName, const Class *targetSymbol,
- InsertionPointLocator::AccessSpec xsSpec,
- const QString &decl)
- : CppQuickFixOperation(interface, 0)
- , 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);
-
- Utils::ChangeSet target;
- target.insert(targetPosition1, loc.prefix() + m_decl);
- targetFile->setChangeSet(target);
- targetFile->appendIndentRange(Utils::ChangeSet::Range(targetPosition2, targetPosition1));
- targetFile->setOpenEditor(true, targetPosition1);
- targetFile->apply();
- }
-
- static QString generateDeclaration(Function *function);
-
-private:
- QString m_targetFileName;
- const Class *m_targetSymbol;
- InsertionPointLocator::AccessSpec m_xsSpec;
- QString m_decl;
-};
-
-Class *isMemberFunction(const LookupContext &context, Function *function)
-{
- QTC_ASSERT(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++
-
- if (! functionName->isQualifiedNameId())
- 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;
-}
-
-} // 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()
- || !qName->identifier()->isEqualTo(s->identifier())
- || !s->type()->isFunctionType())
- continue;
-
- if (s->type().isEqualTo(fun->type())) {
- // Declaration exists.
- return;
- }
- }
- QString fileName = QString::fromUtf8(matchingClass->fileName(),
- matchingClass->fileNameLength());
- const QString decl = InsertDeclOperation::generateDeclaration(fun);
- result.append(TextEditor::QuickFixOperation::Ptr(new InsertDeclOperation(interface, fileName, matchingClass,
- InsertionPointLocator::Public, decl)));
- }
-}
-
-QString InsertDeclOperation::generateDeclaration(Function *function)
-{
- 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:
- InsertDefOperation(const QSharedPointer<const CppEditor::Internal::CppQuickFixAssistInterface> &interface,
- Declaration *decl, const InsertionLocation &loc)
- : CppQuickFixOperation(interface, 0)
- , m_decl(decl)
- , m_loc(loc)
- {
- const QString declFile = QString::fromUtf8(decl->fileName(), decl->fileNameLength());
- const QDir dir = QFileInfo(declFile).dir();
- setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
- "Add Definition in %1")
- .arg(dir.relativeFilePath(m_loc.fileName())));
- }
-
- void perform()
- {
- QTC_ASSERT(m_loc.isValid(), return);
- CppRefactoringChanges refactoring(snapshot());
- CppRefactoringFilePtr targetFile = refactoring.file(m_loc.fileName());
-
- Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
- oo.showFunctionSignatures = true;
- oo.showReturnTypes = true;
- oo.showArgumentNames = true;
-
- // 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);
- Control *control = assistInterface()->context().control().data();
-
- // rewrite the function type
- FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
-
- // rewrite the function name
- QString name = oo.prettyName(LookupContext::minimalName(m_decl, targetCoN, control));
-
- QString defText = oo.prettyType(tn, name) + QLatin1String("\n{\n}");
-
- int targetPos = targetFile->position(m_loc.line(), m_loc.column());
- int targetPos2 = qMax(0, targetFile->position(m_loc.line(), 1) - 1);
-
- Utils::ChangeSet target;
- target.insert(targetPos, m_loc.prefix() + defText + m_loc.suffix());
- targetFile->setChangeSet(target);
- targetFile->appendIndentRange(Utils::ChangeSet::Range(targetPos2, targetPos));
- targetFile->setOpenEditor(true, targetPos);
- targetFile->apply();
- }
-
-private:
- Declaration *m_decl;
- InsertionLocation m_loc;
-};
-
-} // 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()) {
- if (simpleDecl->symbols && ! simpleDecl->symbols->next) {
- if (Symbol *symbol = simpleDecl->symbols->value) {
- if (Declaration *decl = symbol->asDeclaration()) {
- if (Function *func = decl->type()->asFunctionType()) {
- if (func->isSignal())
- return;
- CppRefactoringChanges refactoring(interface->snapshot());
- InsertionPointLocator locator(refactoring);
- foreach (const InsertionLocation &loc, locator.methodDefinition(decl)) {
- if (loc.isValid())
- result.append(CppQuickFixOperation::Ptr(new InsertDefOperation(interface, decl, loc)));
- }
- 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)
- {
- setDescription(TextEditor::QuickFixFactory::tr("Create Getter and Setter Member Functions"));
-
- 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;
- }
- m_variableString = QString::fromLatin1(variableId->chars(), variableId->size());
-
- 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()) {
- const QString memberName = QString::fromLatin1(id->chars(), id->size());
- 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()) {
- const QString symbolName = QString::fromLatin1(id->chars(), id->size());
- 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);
- QString classString = QString::fromLatin1(classId->chars(), classId->size());
-
- bool wasHeader = true;
- QString declFileName = currentFile->fileName();
- QString implFileName = CppTools::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) {
- const int pos = currentFile->endOf(m_classDecl) + 1;
- unsigned line, column;
- currentFile->lineAndColumn(pos, &line, &column);
- const int insertPos = currentFile->position(line + 1, 1) - 1;
- currChanges.insert(insertPos < 0 ? pos : insertPos, implementation);
- } else {
- CppRefactoringChanges implRefactoring(snapshot());
- CppRefactoringFilePtr implFile = implRefactoring.file(implFileName);
- ChangeSet implChanges;
- const int implInsertPos = implFile->document()->characterCount() - 1;
- implChanges.insert(implInsertPos, implementation);
- 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;
-};
-
-} // 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();
- Control *control = assistInterface()->context().control().data();
- 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 ")
- % m_relevantDecls.at(0).first
- % QLatin1String(";"));
- funcCall.prepend(m_relevantDecls.at(0).second % QLatin1String(" = "));
- }
- 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.
- Utils::ChangeSet change;
- int position = currentFile->startOf(m_refFuncDef);
- change.insert(position, funcDef);
- change.replace(m_extractionStart, m_extractionEnd, funcCall);
- currentFile->setChangeSet(change);
- currentFile->appendIndentRange(Utils::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(Utils::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);
- CppTools::CppRefactoringFilePtr declFile = refactoring.file(fileName);
- change.clear();
- position = declFile->position(location.line(), location.column());
- change.insert(position, funcDecl);
- declFile->setChangeSet(change);
- declFile->appendIndentRange(Utils::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;
-
- // Analyse 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)));
-}
diff --git a/src/plugins/cppeditor/cppinsertdecldef.h b/src/plugins/cppeditor/cppinsertdecldef.h
deleted file mode 100644
index 3a0110eae67..00000000000
--- a/src/plugins/cppeditor/cppinsertdecldef.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of Qt Creator.
-**
-** 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.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef CPPINSERTDECLDEF_H
-#define CPPINSERTDECLDEF_H
-
-#include "cppquickfix.h"
-
-namespace CppEditor {
-namespace Internal {
-
-class InsertDeclFromDef: public CppQuickFixFactory
-{
-public:
- void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
-};
-
-class InsertDefFromDecl: public CppQuickFixFactory
-{
-public:
- void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
-};
-
-class ExtractFunction : public CppQuickFixFactory
-{
-public:
- void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
-};
-
-class GenerateGetterSetter : public CppQuickFixFactory
-{
-public:
- void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
-};
-
-} // namespace Internal
-} // namespace CppEditor
-
-#endif // CPPINSERTDECLDEF_H
diff --git a/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp b/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp
deleted file mode 100644
index a4f1e47e466..00000000000
--- a/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of Qt Creator.
-**
-** 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.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#include "cppinsertqtpropertymembers.h"
-
-#include "cppquickfixassistant.h"
-
-#include <cpptools/insertionpointlocator.h>
-
-#include <cplusplus/Overview.h>
-
-#include <utils/qtcassert.h>
-
-#include <QTextStream>
-
-using namespace CPlusPlus;
-using namespace CppTools;
-using namespace TextEditor;
-using namespace Utils;
-using namespace CppEditor;
-using namespace CppEditor::Internal;
-
-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;
- for (QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list;
- 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 |= GenerateGetter;
- } else if (!qstrcmp(tokenString, "WRITE")) {
- setterName = file->textOf(it->value->expression);
- generateFlags |= GenerateSetter;
- } else if (!qstrcmp(tokenString, "NOTIFY")) {
- signalName = file->textOf(it->value->expression);
- generateFlags |= GenerateSignal;
- }
- }
- const QString storageName = QLatin1String("m_") + propertyName;
- generateFlags |= 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 &= ~GenerateGetter;
- else if (name == setterName)
- generateFlags &= ~GenerateSetter;
- else if (name == signalName)
- generateFlags &= ~GenerateSignal;
- } else if (member->asDeclaration()) {
- const QString name = overview.prettyName(member->name());
- if (name == storageName)
- generateFlags &= ~GenerateStorage;
- }
- }
-
- if (getterName.isEmpty() && setterName.isEmpty() && signalName.isEmpty())
- return;
-
- result.append(QuickFixOperation::Ptr(
- new Operation(interface, path.size() - 1, qtPropertyDeclaration, c,
- generateFlags, getterName, setterName, signalName, storageName)));
-}
-
-InsertQtPropertyMembers::Operation::Operation(
- const CppQuickFixInterface &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)
-{
- QString desc = InsertQtPropertyMembers::tr("Generate Missing Q_PROPERTY Members...");
- setDescription(desc);
-}
-
-void InsertQtPropertyMembers::Operation::perform()
-{
- CppRefactoringChanges refactoring(snapshot());
- CppRefactoringFilePtr file = refactoring.file(fileName());
-
- InsertionPointLocator locator(refactoring);
- Utils::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();
-}
-
-void InsertQtPropertyMembers::Operation::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(Utils::ChangeSet::Range(targetPosition2, targetPosition1));
-}
diff --git a/src/plugins/cppeditor/cppinsertqtpropertymembers.h b/src/plugins/cppeditor/cppinsertqtpropertymembers.h
deleted file mode 100644
index 90cb2712394..00000000000
--- a/src/plugins/cppeditor/cppinsertqtpropertymembers.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of Qt Creator.
-**
-** 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.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-****************************************************************************/
-
-#ifndef CPPINSERTQTPROPERTYMEMBERS_H
-#define CPPINSERTQTPROPERTYMEMBERS_H
-
-#include "cppquickfix.h"
-
-#include <QString>
-
-namespace CPlusPlus {
-class QtPropertyDeclarationAST;
-class Class;
-}
-
-namespace TextEditor {
-class RefactoringFile;
-typedef QSharedPointer<RefactoringFile> RefactoringFilePtr;
-}
-
-namespace Utils {
-class ChangeSet;
-}
-
-namespace CppTools {
-class InsertionLocation;
-}
-
-namespace CppEditor {
-namespace Internal {
-
-class InsertQtPropertyMembers : public CppQuickFixFactory
-{
- Q_OBJECT
-
-public:
- void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
-
-private:
- enum GenerateFlag {
- GenerateGetter = 1 << 0,
- GenerateSetter = 1 << 1,
- GenerateSignal = 1 << 2,
- GenerateStorage = 1 << 3
- };
-
- class Operation: public CppQuickFixOperation
- {
- public:
- Operation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
- int priority,
- CPlusPlus::QtPropertyDeclarationAST *declaration, CPlusPlus::Class *klass,
- int generateFlags,
- const QString &getterName, const QString &setterName, const QString &signalName,
- const QString &storageName);
-
- void perform();
-
- private:
- void insertAndIndent(const TextEditor::RefactoringFilePtr &file, Utils::ChangeSet *changeSet,
- const CppTools::InsertionLocation &loc, const QString &text);
-
- CPlusPlus::QtPropertyDeclarationAST *m_declaration;
- CPlusPlus::Class *m_class;
- int m_generateFlags;
- QString m_getterName;
- QString m_setterName;
- QString m_signalName;
- QString m_storageName;
- };
-};
-
-} // namespace Internal
-} // namespace CppEditor
-
-#endif // CPPINSERTQTPROPERTYMEMBERS_H
diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp
index 3cf0f80c3d2..41374c5336d 100644
--- a/src/plugins/cppeditor/cppquickfix_test.cpp
+++ b/src/plugins/cppeditor/cppquickfix_test.cpp
@@ -28,7 +28,6 @@
****************************************************************************/
#include "cppeditor.h"
-#include "cppinsertdecldef.h"
#include "cppplugin.h"
#include "cppquickfixassistant.h"
#include "cppquickfixes.h"
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index 2274fa6c0f5..867795115ca 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -29,35 +29,44 @@
#include "cppquickfixes.h"
-#include "cppcompleteswitch.h"
#include "cppeditor.h"
-#include "cppinsertdecldef.h"
-#include "cppinsertqtpropertymembers.h"
+#include "cppfunctiondecldeflink.h"
#include "cppquickfixassistant.h"
#include <cpptools/cppclassesfilter.h>
#include <cpptools/cppcodestylesettings.h>
#include <cpptools/cpppointerdeclarationformatter.h>
#include <cpptools/cpptoolsconstants.h>
+#include <cpptools/cpptoolsreuse.h>
+#include <cpptools/insertionpointlocator.h>
#include <cpptools/symbolfinder.h>
+#include <cplusplus/CPlusPlusForwardDeclarations.h>
#include <cplusplus/CppRewriter.h>
#include <cplusplus/DependencyTable.h>
#include <cplusplus/TypeOfExpression.h>
#include <extensionsystem/pluginmanager.h>
+
#include <utils/qtcassert.h>
#include <QApplication>
+#include <QDir>
#include <QFileInfo>
+#include <QInputDialog>
+#include <QMessageBox>
#include <QSharedPointer>
#include <QTextBlock>
#include <QTextCursor>
#include <cctype>
+using namespace CPlusPlus;
using namespace CppEditor;
using namespace CppEditor::Internal;
+using namespace CppTools;
+using namespace TextEditor;
+using namespace Utils;
void CppEditor::Internal::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
{
@@ -96,16 +105,54 @@ void CppEditor::Internal::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
plugIn->addAutoReleasedObject(new InsertDefFromDecl);
}
-static inline bool isQtStringLiteral(const QByteArray &id)
+// In the following anonymous namespace all functions are collected, which could be of interest for
+// different quick fixes.
+namespace {
+
+inline bool isQtStringLiteral(const QByteArray &id)
{
return id == "QLatin1String" || id == "QLatin1Literal" || id == "QStringLiteral";
}
-static inline bool isQtStringTranslation(const QByteArray &id)
+inline bool isQtStringTranslation(const QByteArray &id)
{
return id == "tr" || id == "trUtf8" || id == "translate" || id == "QT_TRANSLATE_NOOP";
}
+Class *isMemberFunction(const LookupContext &context, Function *function)
+{
+ QTC_ASSERT(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++
+
+ if (! functionName->isQualifiedNameId())
+ 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;
+}
+
+} // anonymous namespace
+
+namespace {
+
class InverseLogicalComparisonOp: public CppQuickFixOperation
{
public:
@@ -163,6 +210,8 @@ private:
QString replacement;
};
+} // anonymous namespace
+
void InverseLogicalComparison::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -204,6 +253,8 @@ void InverseLogicalComparison::match(const CppQuickFixInterface &interface,
new InverseLogicalComparisonOp(interface, index, binary, invertToken)));
}
+namespace {
+
class FlipLogicalOperandsOp: public CppQuickFixOperation
{
public:
@@ -230,7 +281,8 @@ public:
CppRefactoringFilePtr currentFile = refactoring.file(fileName());
ChangeSet changes;
- changes.flip(currentFile->range(binary->left_expression), currentFile->range(binary->right_expression));
+ changes.flip(currentFile->range(binary->left_expression),
+ currentFile->range(binary->right_expression));
if (! replacement.isEmpty())
changes.replace(currentFile->range(binary->binary_op_token), replacement);
@@ -243,6 +295,8 @@ private:
QString replacement;
};
+} // anonymous namespace
+
void FlipLogicalOperands::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
const QList<AST *> &path = interface->path();
@@ -290,6 +344,8 @@ void FlipLogicalOperands::match(const CppQuickFixInterface &interface, QuickFixO
new FlipLogicalOperandsOp(interface, index, binary, replacement)));
}
+namespace {
+
class RewriteLogicalAndOp: public CppQuickFixOperation
{
public:
@@ -327,6 +383,8 @@ public:
}
};
+} // anonymous namespace
+
void RewriteLogicalAnd::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
BinaryExpressionAST *expression = 0;
@@ -352,7 +410,8 @@ void RewriteLogicalAnd::match(const CppQuickFixInterface &interface, QuickFixOpe
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)) {
- op->setDescription(QApplication::translate("CppTools::QuickFix", "Rewrite Condition Using ||"));
+ op->setDescription(QApplication::translate("CppTools::QuickFix",
+ "Rewrite Condition Using ||"));
op->setPriority(index);
result.append(op);
}
@@ -385,6 +444,8 @@ bool SplitSimpleDeclaration::checkDeclaration(SimpleDeclarationAST *declaration)
return true;
}
+namespace {
+
class SplitSimpleDeclarationOp: public CppQuickFixOperation
{
public:
@@ -435,6 +496,8 @@ private:
SimpleDeclarationAST *declaration;
};
+} // anonymous namespace
+
void SplitSimpleDeclaration::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -476,6 +539,8 @@ void SplitSimpleDeclaration::match(const CppQuickFixInterface &interface,
}
}
+namespace {
+
class AddBracesToIfOp: public CppQuickFixOperation
{
public:
@@ -483,8 +548,7 @@ public:
: CppQuickFixOperation(interface, priority)
, _statement(statement)
{
- setDescription(QApplication::translate("CppTools::QuickFix",
- "Add Curly Braces"));
+ setDescription(QApplication::translate("CppTools::QuickFix", "Add Curly Braces"));
}
void perform()
@@ -501,7 +565,7 @@ public:
changes.insert(end, QLatin1String("\n}"));
currentFile->setChangeSet(changes);
- currentFile->appendIndentRange(Utils::ChangeSet::Range(start, end));
+ currentFile->appendIndentRange(ChangeSet::Range(start, end));
currentFile->apply();
}
@@ -509,6 +573,8 @@ private:
StatementAST *_statement;
};
+} // anonymous namespace
+
void AddBracesToIf::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
const QList<AST *> &path = interface->path();
@@ -540,6 +606,8 @@ void AddBracesToIf::match(const CppQuickFixInterface &interface, QuickFixOperati
// and other nodes entirely.
}
+namespace {
+
class MoveDeclarationOutOfIfOp: public CppQuickFixOperation
{
public:
@@ -579,6 +647,8 @@ public:
CoreDeclaratorAST *core;
};
+} // anonymous namespace
+
void MoveDeclarationOutOfIf::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -605,6 +675,8 @@ void MoveDeclarationOutOfIf::match(const CppQuickFixInterface &interface,
}
}
+namespace {
+
class MoveDeclarationOutOfWhileOp: public CppQuickFixOperation
{
public:
@@ -647,6 +719,8 @@ public:
CoreDeclaratorAST *core;
};
+} // anonymous namespace
+
void MoveDeclarationOutOfWhile::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -679,6 +753,8 @@ void MoveDeclarationOutOfWhile::match(const CppQuickFixInterface &interface,
}
}
+namespace {
+
class SplitIfStatementOp: public CppQuickFixOperation
{
public:
@@ -757,6 +833,8 @@ private:
BinaryExpressionAST *condition;
};
+} // anonymous namespace
+
void SplitIfStatement::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
IfStatementAST *pattern = 0;
@@ -803,23 +881,11 @@ void SplitIfStatement::match(const CppQuickFixInterface &interface, QuickFixOper
}
}
-static inline QString msgQtStringLiteralDescription(const QString &replacement, int qtVersion)
-{
- return QApplication::translate("CppTools::QuickFix", "Enclose in %1(...) (Qt %2)")
- .arg(replacement).arg(qtVersion);
-}
-
-static inline QString msgQtStringLiteralDescription(const QString &replacement)
-{
- return QApplication::translate("CppTools::QuickFix", "Enclose in %1(...)").arg(replacement);
-}
-
/* 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,
- const CppRefactoringFilePtr &file,
- Type *type,
+ const CppRefactoringFilePtr &file, Type *type,
QByteArray *enclosingFunction /* = 0 */,
CallAST **enclosingFunctionCall /* = 0 */)
{
@@ -861,6 +927,8 @@ ExpressionAST *WrapStringLiteral::analyze(const QList<AST *> &path,
return literal;
}
+namespace {
+
/// Operation performs the operations of type ActionFlags passed in as actions.
class WrapStringLiteralOp : public CppQuickFixOperation
{
@@ -892,7 +960,8 @@ public:
// Fix quotes
if (m_actions & (Factory::SingleQuoteAction | Factory::DoubleQuoteAction)) {
- const QString newQuote((m_actions & Factory::SingleQuoteAction) ? QLatin1Char('\'') : QLatin1Char('"'));
+ const QString newQuote((m_actions & Factory::SingleQuoteAction)
+ ? QLatin1Char('\'') : QLatin1Char('"'));
changes.replace(startPos, startPos + 1, newQuote);
changes.replace(endPos - 1, endPos, newQuote);
}
@@ -924,7 +993,8 @@ public:
changes.insert(endPos, QString(QLatin1Char(')')));
QString leading = Factory::replacement(m_actions);
leading += QLatin1Char('(');
- if (m_actions & (Factory::TranslateQCoreApplicationAction | Factory::TranslateNoopAction)) {
+ if (m_actions
+ & (Factory::TranslateQCoreApplicationAction | Factory::TranslateNoopAction)) {
leading += QLatin1Char('"');
leading += m_translationContext;
leading += QLatin1String("\", ");
@@ -942,6 +1012,8 @@ private:
const QString m_translationContext;
};
+} // anonymous namespace
+
void WrapStringLiteral::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
typedef CppQuickFixOperation::Ptr OperationPtr;
@@ -985,13 +1057,13 @@ void WrapStringLiteral::match(const CppQuickFixInterface &interface, QuickFixOpe
| ConvertEscapeSequencesToCharAction | objectiveCActions;
QString description = QApplication::translate("CppTools::QuickFix",
"Convert to Character Literal and Enclose in QLatin1Char(...)");
- result << OperationPtr(new WrapStringLiteralOp(interface, priority,
- actions, description, literal));
+ result << OperationPtr(new WrapStringLiteralOp(interface, priority, actions,
+ description, literal));
actions &= ~EncloseInQLatin1CharAction;
description = QApplication::translate("CppTools::QuickFix",
"Convert to Character Literal");
- result << OperationPtr(new WrapStringLiteralOp(interface, priority,
- actions, description, literal));
+ result << OperationPtr(new WrapStringLiteralOp(interface, priority, actions,
+ description, literal));
}
}
actions = EncloseInQLatin1StringAction | objectiveCActions;
@@ -1045,6 +1117,18 @@ QByteArray WrapStringLiteral::charToStringEscapeSequences(const QByteArray &cont
return QByteArray();
}
+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);
+}
+
void TranslateStringLiteral::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -1109,6 +1193,8 @@ void TranslateStringLiteral::match(const CppQuickFixInterface &interface,
description, literal, trContext)));
}
+namespace {
+
class ConvertCStringToNSStringOp: public CppQuickFixOperation
{
public:
@@ -1130,7 +1216,8 @@ public:
ChangeSet changes;
if (qlatin1Call) {
- changes.replace(currentFile->startOf(qlatin1Call), currentFile->startOf(stringLiteral), QLatin1String("@"));
+ changes.replace(currentFile->startOf(qlatin1Call), currentFile->startOf(stringLiteral),
+ QLatin1String("@"));
changes.remove(currentFile->endOf(stringLiteral), currentFile->endOf(qlatin1Call));
} else {
changes.insert(currentFile->startOf(stringLiteral), QLatin1String("@"));
@@ -1145,6 +1232,8 @@ private:
CallAST *qlatin1Call;
};
+} // anonymous namespace
+
void ConvertCStringToNSString::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -1157,7 +1246,8 @@ void ConvertCStringToNSString::match(const CppQuickFixInterface &interface,
QByteArray enclosingFunction;
CallAST *qlatin1Call;
const QList<AST *> &path = interface->path();
- ExpressionAST *literal = WrapStringLiteral::analyze(path, file, &type, &enclosingFunction, &qlatin1Call);
+ ExpressionAST *literal = WrapStringLiteral::analyze(path, file, &type, &enclosingFunction,
+ &qlatin1Call);
if (!literal || type != WrapStringLiteral::TypeString)
return;
if (!isQtStringLiteral(enclosingFunction))
@@ -1168,6 +1258,8 @@ void ConvertCStringToNSString::match(const CppQuickFixInterface &interface,
qlatin1Call)));
}
+namespace {
+
class ConvertNumericLiteralOp: public CppQuickFixOperation
{
public:
@@ -1195,6 +1287,8 @@ private:
QString replacement;
};
+} // anonymous namespace
+
void ConvertNumericLiteral::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
const QList<AST *> &path = interface->path();
@@ -1293,6 +1387,8 @@ void ConvertNumericLiteral::match(const CppQuickFixInterface &interface, QuickFi
}
}
+namespace {
+
class AddIncludeForForwardDeclarationOp: public CppQuickFixOperation
{
public:
@@ -1311,7 +1407,7 @@ public:
CppRefactoringChanges refactoring(snapshot());
CppRefactoringFilePtr currentFile = refactoring.file(fileName());
- CppTools::SymbolFinder symbolFinder;
+ SymbolFinder symbolFinder;
if (Class *k = symbolFinder.findMatchingClassDeclaration(fwdClass, snapshot())) {
const QString headerFile = QString::fromUtf8(k->fileName(), k->fileNameLength());
@@ -1354,7 +1450,8 @@ public:
unsigned currentLine = currentFile->cursor().blockNumber() + 1;
unsigned bestLine = 0;
- foreach (const Document::Include &incl, assistInterface()->semanticInfo().doc->includes()) {
+ foreach (const Document::Include &incl,
+ assistInterface()->semanticInfo().doc->includes()) {
if (incl.line() < currentLine)
bestLine = incl.line();
}
@@ -1362,7 +1459,7 @@ public:
if (bestLine)
pos = currentFile->document()->findBlockByNumber(bestLine).position();
- Utils::ChangeSet changes;
+ ChangeSet changes;
changes.insert(pos, QLatin1String("#include <")
+ QFileInfo(best).fileName() + QLatin1String(">\n"));
currentFile->setChangeSet(changes);
@@ -1380,8 +1477,7 @@ public:
Symbol *fwdClass = 0;
foreach (const LookupItem &r,
- interface->context().lookup(name,
- interface->semanticInfo().doc->scopeAt(line, column))) {
+ interface->context().lookup(name, interface->semanticInfo().doc->scopeAt(line, column))) {
if (! r.declaration())
continue;
else if (ForwardClassDeclaration *fwd = r.declaration()->asForwardClassDeclaration())
@@ -1401,6 +1497,8 @@ private:
Symbol *fwdClass;
};
+} // anonymous namespace
+
void AddIncludeForForwardDeclaration::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -1409,13 +1507,15 @@ void AddIncludeForForwardDeclaration::match(const CppQuickFixInterface &interfac
for (int index = path.size() - 1; index != -1; --index) {
AST *ast = path.at(index);
if (NamedTypeSpecifierAST *namedTy = ast->asNamedTypeSpecifier()) {
- if (Symbol *fwdClass = AddIncludeForForwardDeclarationOp::checkName(interface, namedTy->name)) {
+ if (Symbol *fwdClass = AddIncludeForForwardDeclarationOp::checkName(interface,
+ namedTy->name)) {
result.append(QuickFixOperation::Ptr(
new AddIncludeForForwardDeclarationOp(interface, index, fwdClass)));
return;
}
} else if (ElaboratedTypeSpecifierAST *eTy = ast->asElaboratedTypeSpecifier()) {
- if (Symbol *fwdClass = AddIncludeForForwardDeclarationOp::checkName(interface, eTy->name)) {
+ if (Symbol *fwdClass = AddIncludeForForwardDeclarationOp::checkName(interface,
+ eTy->name)) {
result.append(QuickFixOperation::Ptr(
new AddIncludeForForwardDeclarationOp(interface, index, fwdClass)));
return;
@@ -1424,6 +1524,8 @@ void AddIncludeForForwardDeclaration::match(const CppQuickFixInterface &interfac
}
}
+namespace {
+
class AddLocalDeclarationOp: public CppQuickFixOperation
{
public:
@@ -1468,7 +1570,7 @@ public:
Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
QString ty = oo.prettyType(tn, simpleNameAST->name);
if (! ty.isEmpty()) {
- Utils::ChangeSet changes;
+ ChangeSet changes;
changes.replace(currentFile->startOf(binaryAST),
currentFile->endOf(simpleNameAST),
ty);
@@ -1483,6 +1585,8 @@ private:
const SimpleNameAST *simpleNameAST;
};
+} // anonymous namespace
+
void AddLocalDeclaration::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
const QList<AST *> &path = interface->path();
@@ -1490,9 +1594,11 @@ void AddLocalDeclaration::match(const CppQuickFixInterface &interface, QuickFixO
for (int index = path.size() - 1; index != -1; --index) {
if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) {
- if (binary->left_expression && binary->right_expression && file->tokenAt(binary->binary_op_token).is(T_EQUAL)) {
+ if (binary->left_expression && binary->right_expression
+ && file->tokenAt(binary->binary_op_token).is(T_EQUAL)) {
IdExpressionAST *idExpr = binary->left_expression->asIdExpression();
- if (interface->isCursorOn(binary->left_expression) && idExpr && idExpr->name->asSimpleName() != 0) {
+ if (interface->isCursorOn(binary->left_expression) && idExpr
+ && idExpr->name->asSimpleName() != 0) {
SimpleNameAST *nameAST = idExpr->name->asSimpleName();
const QList<LookupItem> results = interface->context().lookup(nameAST->name, file->scopeAt(nameAST->firstToken()));
Declaration *decl = 0;
@@ -1518,6 +1624,8 @@ void AddLocalDeclaration::match(const CppQuickFixInterface &interface, QuickFixO
}
}
+namespace {
+
class ConvertToCamelCaseOp: public CppQuickFixOperation
{
public:
@@ -1526,8 +1634,7 @@ public:
: CppQuickFixOperation(interface, priority)
, m_name(newName)
{
- setDescription(QApplication::translate("CppTools::QuickFix",
- "Convert to Camel Case"));
+ setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Camel Case"));
}
void perform()
@@ -1545,7 +1652,7 @@ public:
m_name[i] = m_name.at(i).toUpper();
}
}
- static_cast<CppEditor::Internal::CPPEditorWidget*>(assistInterface()->editor())->renameUsagesNow(m_name);
+ static_cast<CPPEditorWidget*>(assistInterface()->editor())->renameUsagesNow(m_name);
}
static bool isConvertibleUnderscore(const QString &name, int pos)
@@ -1558,6 +1665,8 @@ private:
QString m_name;
};
+} // anonymous namespace
+
void ConvertToCamelCase::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
const QList<AST *> &path = interface->path();
@@ -1589,6 +1698,8 @@ void ConvertToCamelCase::match(const CppQuickFixInterface &interface, QuickFixOp
}
}
+namespace {
+
class AddIncludeForUndefinedIdentifierOp: public CppQuickFixOperation
{
public:
@@ -1669,6 +1780,8 @@ private:
QString m_include;
};
+} // anonymous namespace
+
void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -1785,6 +1898,8 @@ void AddIncludeForUndefinedIdentifier::match(const CppQuickFixInterface &interfa
}
}
+namespace {
+
class RearrangeParamDeclarationListOp: public CppQuickFixOperation
{
public:
@@ -1825,6 +1940,8 @@ private:
AST *m_targetParam;
};
+} // anonymous namespace
+
void RearrangeParamDeclarationList::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -1866,11 +1983,12 @@ void RearrangeParamDeclarationList::match(const CppQuickFixInterface &interface,
paramListNode->next->value, RearrangeParamDeclarationListOp::TargetNext)));
}
+namespace {
+
class ReformatPointerDeclarationOp: public CppQuickFixOperation
{
public:
- ReformatPointerDeclarationOp(const CppQuickFixInterface &interface,
- const Utils::ChangeSet change)
+ ReformatPointerDeclarationOp(const CppQuickFixInterface &interface, const ChangeSet change)
: CppQuickFixOperation(interface)
, m_change(change)
{
@@ -1894,7 +2012,7 @@ public:
}
private:
- Utils::ChangeSet m_change;
+ ChangeSet m_change;
};
/// Filter the results of ASTPath.
@@ -1945,6 +2063,7 @@ public:
return filtered;
}
+
private:
bool m_hasSimpleDeclaration;
bool m_hasFunctionDefinition;
@@ -1955,6 +2074,8 @@ private:
bool m_hasForeachStatement;
};
+} // anonymous namespace
+
void ReformatPointerDeclaration::match(const CppQuickFixInterface &interface,
QuickFixOperations &result)
{
@@ -1966,7 +2087,7 @@ void ReformatPointerDeclaration::match(const CppQuickFixInterface &interface,
overview.showReturnTypes = true;
const QTextCursor cursor = file->cursor();
- Utils::ChangeSet change;
+ ChangeSet change;
PointerDeclarationFormatter formatter(file, overview,
PointerDeclarationFormatter::RespectCursor);
@@ -1993,3 +2114,1432 @@ void ReformatPointerDeclaration::match(const CppQuickFixInterface &interface,
}
}
}
+
+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()) {
+ const QList<LookupItem> candidates =
+ ctxt.lookup(namedType->name(), result.scope());
+ return findEnum(candidates, ctxt);
+ }
+ }
+
+ 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,
+ InsertionPointLocator::AccessSpec xsSpec, const QString &decl)
+ : CppQuickFixOperation(interface, 0)
+ , 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();
+ }
+
+ static QString generateDeclaration(Function *function);
+
+private:
+ QString m_targetFileName;
+ const Class *m_targetSymbol;
+ InsertionPointLocator::AccessSpec m_xsSpec;
+ QString m_decl;
+};
+
+} // 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()
+ || !qName->identifier()->isEqualTo(s->identifier())
+ || !s->type()->isFunctionType())
+ continue;
+
+ if (s->type().isEqualTo(fun->type())) {
+ // Declaration exists.
+ return;
+ }
+ }
+ QString fileName = QString::fromUtf8(matchingClass->fileName(),
+ matchingClass->fileNameLength());
+ const QString decl = InsertDeclOperation::generateDeclaration(fun);
+ result.append(QuickFixOperation::Ptr(new InsertDeclOperation(interface, fileName, matchingClass,
+ InsertionPointLocator::Public, decl)));
+ }
+}
+
+QString InsertDeclOperation::generateDeclaration(Function *function)
+{
+ 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:
+ InsertDefOperation(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
+ Declaration *decl, const InsertionLocation &loc)
+ : CppQuickFixOperation(interface, 0)
+ , m_decl(decl)
+ , m_loc(loc)
+ {
+ const QString declFile = QString::fromUtf8(decl->fileName(), decl->fileNameLength());
+ const QDir dir = QFileInfo(declFile).dir();
+ setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
+ "Add Definition in %1")
+ .arg(dir.relativeFilePath(m_loc.fileName())));
+ }
+
+ void perform()
+ {
+ QTC_ASSERT(m_loc.isValid(), return);
+ CppRefactoringChanges refactoring(snapshot());
+ CppRefactoringFilePtr targetFile = refactoring.file(m_loc.fileName());
+
+ Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
+ oo.showFunctionSignatures = true;
+ oo.showReturnTypes = true;
+ oo.showArgumentNames = true;
+
+ // 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);
+ Control *control = assistInterface()->context().control().data();
+
+ // rewrite the function type
+ FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
+
+ // rewrite the function name
+ QString name = oo.prettyName(LookupContext::minimalName(m_decl, targetCoN, control));
+
+ QString defText = oo.prettyType(tn, name) + QLatin1String("\n{\n}");
+
+ int targetPos = targetFile->position(m_loc.line(), m_loc.column());
+ 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();
+ }
+
+private:
+ Declaration *m_decl;
+ InsertionLocation m_loc;
+};
+
+} // 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()) {
+ if (simpleDecl->symbols && ! simpleDecl->symbols->next) {
+ if (Symbol *symbol = simpleDecl->symbols->value) {
+ if (Declaration *decl = symbol->asDeclaration()) {
+ if (Function *func = decl->type()->asFunctionType()) {
+ if (func->isSignal())
+ return;
+ CppRefactoringChanges refactoring(interface->snapshot());
+ InsertionPointLocator locator(refactoring);
+ foreach (const InsertionLocation &loc, locator.methodDefinition(decl)) {
+ if (loc.isValid())
+ result.append(CppQuickFixOperation::Ptr(new InsertDefOperation(interface, decl, loc)));
+ }
+ 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)
+ {
+ setDescription(QuickFixFactory::tr("Create Getter and Setter Member Functions"));
+
+ 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;
+ }
+ m_variableString = QString::fromLatin1(variableId->chars(), variableId->size());
+
+ 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()) {
+ const QString memberName = QString::fromLatin1(id->chars(), id->size());
+ 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()) {
+ const QString symbolName = QString::fromLatin1(id->chars(), id->size());
+ 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);
+ QString classString = QString::fromLatin1(classId->chars(), classId->size());
+
+ 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) {
+ const int pos = currentFile->endOf(m_classDecl) + 1;
+ unsigned line, column;
+ currentFile->lineAndColumn(pos, &line, &column);
+ const int insertPos = currentFile->position(line + 1, 1) - 1;
+ currChanges.insert(insertPos < 0 ? pos : insertPos, implementation);
+ } else {
+ CppRefactoringChanges implRefactoring(snapshot());
+ CppRefactoringFilePtr implFile = implRefactoring.file(implFileName);
+ ChangeSet implChanges;
+ const int implInsertPos = implFile->document()->characterCount() - 1;
+ implChanges.insert(implInsertPos, implementation);
+ 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();
+ Control *control = assistInterface()->context().control().data();
+ 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 ")
+ % m_relevantDecls.at(0).first
+ % QLatin1String(";"));
+ funcCall.prepend(m_relevantDecls.at(0).second % QLatin1String(" = "));
+ }
+ 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 {
+
+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)
+ {
+ QString desc = InsertQtPropertyMembers::tr("Generate Missing Q_PROPERTY Members...");
+ setDescription(desc);
+ }
+
+ 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)
+ : CppQuickFixOperation(interface, 10)
+ , 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;
+}
diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h
index 66950f98ac3..61e2dbe9faa 100644
--- a/src/plugins/cppeditor/cppquickfixes.h
+++ b/src/plugins/cppeditor/cppquickfixes.h
@@ -230,6 +230,10 @@ public:
Type *type,
QByteArray *enclosingFunction = 0,
CallAST **enclosingFunctionCall = 0);
+
+private:
+ static QString msgQtStringLiteralDescription(const QString &replacement, int qtVersion);
+ static QString msgQtStringLiteralDescription(const QString &replacement);
};
/*!
@@ -387,6 +391,69 @@ public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
+/*!
+ Adds missing case statements for "switch (enumVariable)"
+ */
+class CompleteSwitchCaseStatement: public CppQuickFixFactory
+{
+public:
+ void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
+};
+
+/*!
+ Adds a declarations to a definition
+ */
+class InsertDeclFromDef: public CppQuickFixFactory
+{
+public:
+ void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
+};
+
+/*!
+ Adds a definition for a declaration.
+ */
+class InsertDefFromDecl: public CppQuickFixFactory
+{
+public:
+ void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
+};
+
+/*!
+ Extracts the selected code and puts it to a function
+ */
+class ExtractFunction : public CppQuickFixFactory
+{
+public:
+ void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
+};
+
+/*!
+ Adds getter and setter functions for a member variable
+ */
+class GenerateGetterSetter : public CppQuickFixFactory
+{
+public:
+ void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
+};
+
+/*!
+ Adds missing members for a Q_PROPERTY
+ */
+class InsertQtPropertyMembers : public CppQuickFixFactory
+{
+public:
+ void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
+};
+
+/*!
+ Applies function signature changes
+ */
+class ApplyDeclDefLinkChanges: public CppQuickFixFactory
+{
+public:
+ void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
+};
+
} // namespace Internal
} // namespace CppEditor