Commit 61ddf166 authored by Lorenz Haas's avatar Lorenz Haas Committed by Nikolai Kosjar

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: default avatarNikolai Kosjar <nikolai.kosjar@digia.com>
parent 38531a78
/****************************************************************************
**
** 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;
}
}
}
/****************************************************************************
**
** 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
......@@ -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
......
......@@ -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",
......
......@@ -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;
}
......@@ -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
......
This diff is collapsed.
/****************************************************************************
**
** 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
/****************************************************************************
**
** 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));
}
/****************************************************************************
**
** 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