CppEditor: Move InsertVirtualMethods to its own file

It contains many components, doesn't make sense to have it with all
other quickfixes.

Change-Id: Idede14c90ba9b612ae9e9048f5795d674811acfe
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Orgad Shaneh
2014-01-23 07:53:24 +02:00
committed by Orgad Shaneh
parent f84074b81d
commit b728045588
9 changed files with 1734 additions and 1660 deletions

View File

@@ -29,7 +29,8 @@ HEADERS += \
cppsnippetprovider.h \ cppsnippetprovider.h \
cpptypehierarchy.h \ cpptypehierarchy.h \
cppvirtualfunctionassistprovider.h \ cppvirtualfunctionassistprovider.h \
cppvirtualfunctionproposalitem.h cppvirtualfunctionproposalitem.h \
cppinsertvirtualmethods.h
SOURCES += \ SOURCES += \
cppautocompleter.cpp \ cppautocompleter.cpp \
@@ -56,7 +57,8 @@ SOURCES += \
cppsnippetprovider.cpp \ cppsnippetprovider.cpp \
cpptypehierarchy.cpp \ cpptypehierarchy.cpp \
cppvirtualfunctionassistprovider.cpp \ cppvirtualfunctionassistprovider.cpp \
cppvirtualfunctionproposalitem.cpp cppvirtualfunctionproposalitem.cpp \
cppinsertvirtualmethods.cpp
FORMS += \ FORMS += \
cpppreprocessordialog.ui \ cpppreprocessordialog.ui \
@@ -68,13 +70,12 @@ RESOURCES += \
equals(TEST, 1) { equals(TEST, 1) {
HEADERS += \ HEADERS += \
cppeditortestcase.h \ cppeditortestcase.h \
cppquickfix_test_utils.h cppquickfix_test.h
SOURCES += \ SOURCES += \
cppdoxygen_test.cpp \ cppdoxygen_test.cpp \
cppeditortestcase.cpp \ cppeditortestcase.cpp \
cppincludehierarchy_test.cpp \ cppincludehierarchy_test.cpp \
cppquickfix_test.cpp \ cppquickfix_test.cpp \
cppquickfix_test_utils.cpp \
fileandtokenactions_test.cpp \ fileandtokenactions_test.cpp \
followsymbol_switchmethoddecldef_test.cpp followsymbol_switchmethoddecldef_test.cpp
DEFINES += SRCDIR=\\\"$$PWD\\\" DEFINES += SRCDIR=\\\"$$PWD\\\"

File diff suppressed because it is too large Load Diff

View File

@@ -27,22 +27,32 @@
** **
****************************************************************************/ ****************************************************************************/
#ifndef INSERTVIRTUALMETHODS_H
#define INSERTVIRTUALMETHODS_H
#ifndef CPPQUICKFIX_TEST_UTILS_H #include "cppquickfix.h"
#define CPPQUICKFIX_TEST_UTILS_H
#include "cppquickfixes.h" namespace CppEditor {
namespace Internal {
/// Fake dialog of InsertVirtualMethodsDialog that does not pop up anything. class InsertVirtualMethodsDialog;
class InsertVirtualMethodsDialogTest : public CppEditor::Internal::InsertVirtualMethodsDialog
class InsertVirtualMethods : public CppQuickFixFactory
{ {
Q_OBJECT
public: public:
InsertVirtualMethodsDialogTest(ImplementationMode mode, bool insertVirtualKeyword, InsertVirtualMethods(InsertVirtualMethodsDialog *dialog = 0);
QWidget *parent = 0); ~InsertVirtualMethods();
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
#ifdef WITH_TESTS
static InsertVirtualMethods *createTestFactory();
#endif
bool gather(); private:
ImplementationMode implementationMode() const; InsertVirtualMethodsDialog *m_dialog;
bool insertKeywordVirtual() const;
}; };
#endif // CPPQUICKFIX_TEST_UTILS_H } // namespace Internal
} // namespace CppEditor
#endif // INSERTVIRTUALMETHODS_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,101 @@
/****************************************************************************
**
** Copyright (C) 2014 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 "cppeditortestcase.h"
#include <QByteArray>
#include <QList>
#include <QSharedPointer>
#include <QStringList>
typedef QByteArray _;
namespace CppTools { class CppCodeStylePreferences; }
namespace TextEditor { class QuickFixOperation; }
namespace CppEditor {
namespace Internal {
namespace Tests {
/**
* Represents a test document before and after applying the quick fix.
*
* A TestDocument's source may contain an '@' character to denote
* the cursor position. This marker is removed before the Editor reads
* the document.
*/
class QuickFixTestDocument : public TestDocument
{
public:
typedef QSharedPointer<QuickFixTestDocument> Ptr;
QuickFixTestDocument(const QByteArray &fileName, const QByteArray &source,
const QByteArray &expectedSource);
static Ptr create(const QByteArray &fileName, const QByteArray &source,
const QByteArray &expectedSource);
public:
QByteArray m_expectedSource;
};
/**
* Encapsulates the whole process of setting up an editor, getting the
* quick-fix, applying it, and checking the result.
*/
class QuickFixTestCase : public TestCase
{
public:
QuickFixTestCase(const QList<QuickFixTestDocument::Ptr> theTestFiles,
CppQuickFixFactory *factory,
const QStringList &includePaths = QStringList(),
int resultIndex = 0);
~QuickFixTestCase();
private:
QSharedPointer<TextEditor::QuickFixOperation> getFix(CppQuickFixFactory *factory,
CPPEditorWidget *editorWidget,
int resultIndex = 0);
private:
QList<QuickFixTestDocument::Ptr> m_testFiles;
CppTools::CppCodeStylePreferences *m_cppCodeStylePreferences;
QByteArray m_cppCodeStylePreferencesOriginalDelegateId;
QStringList m_includePathsToRestore;
bool m_restoreIncludePaths;
};
QList<QuickFixTestDocument::Ptr> singleDocument(const QByteArray &original,
const QByteArray &expected);
} // namespace Tests
} // namespace Internal
} // namespace CppEditor

View File

@@ -1,58 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2014 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 "cppquickfix_test_utils.h"
#include "cppquickfixes.h"
using namespace CppEditor::Internal;
InsertVirtualMethodsDialogTest::InsertVirtualMethodsDialogTest(ImplementationMode mode,
bool insertVirtualKeyword,
QWidget *parent)
: InsertVirtualMethodsDialog(parent)
{
setImplementationsMode(mode);
setInsertKeywordVirtual(insertVirtualKeyword);
}
InsertVirtualMethodsDialog::ImplementationMode InsertVirtualMethodsDialogTest::implementationMode() const
{
return m_implementationMode;
}
bool InsertVirtualMethodsDialogTest::insertKeywordVirtual() const
{
return m_insertKeywordVirtual;
}
bool InsertVirtualMethodsDialogTest::gather()
{
return true;
}

View File

@@ -33,6 +33,7 @@
#include "cppfunctiondecldeflink.h" #include "cppfunctiondecldeflink.h"
#include "cppquickfixassistant.h" #include "cppquickfixassistant.h"
#include "cppvirtualfunctionassistprovider.h" #include "cppvirtualfunctionassistprovider.h"
#include "cppinsertvirtualmethods.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -41,7 +42,6 @@
#include <cpptools/cpppointerdeclarationformatter.h> #include <cpptools/cpppointerdeclarationformatter.h>
#include <cpptools/cpptoolsconstants.h> #include <cpptools/cpptoolsconstants.h>
#include <cpptools/cpptoolsreuse.h> #include <cpptools/cpptoolsreuse.h>
#include <cpptools/functionutils.h>
#include <cpptools/includeutils.h> #include <cpptools/includeutils.h>
#include <cpptools/insertionpointlocator.h> #include <cpptools/insertionpointlocator.h>
#include <cpptools/symbolfinder.h> #include <cpptools/symbolfinder.h>
@@ -54,33 +54,15 @@
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <texteditor/fontsettings.h>
#include <texteditor/texteditorsettings.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QApplication> #include <QApplication>
#include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QInputDialog> #include <QInputDialog>
#include <QItemDelegate>
#include <QLabel>
#include <QMessageBox> #include <QMessageBox>
#include <QPointer>
#include <QPushButton>
#include <QQueue>
#include <QSharedPointer> #include <QSharedPointer>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QTextBlock>
#include <QTextCursor> #include <QTextCursor>
#include <QTreeView>
#include <QVBoxLayout>
#include <cctype> #include <cctype>
@@ -89,7 +71,6 @@ using namespace CppEditor;
using namespace CppEditor::Internal; using namespace CppEditor::Internal;
using namespace CppTools; using namespace CppTools;
using namespace TextEditor; using namespace TextEditor;
using namespace Utils;
void CppEditor::Internal::registerQuickFixes(ExtensionSystem::IPlugin *plugIn) void CppEditor::Internal::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
{ {
@@ -4679,728 +4660,6 @@ void AssignToLocalVariable::match(const CppQuickFixInterface &interface, QuickFi
namespace { namespace {
class InsertVirtualMethodsOp : public CppQuickFixOperation
{
public:
InsertVirtualMethodsOp(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
InsertVirtualMethodsDialog *factory)
: CppQuickFixOperation(interface, 0)
, m_factory(factory)
, m_classAST(0)
, m_valid(false)
, m_cppFileName(QString::null)
, m_insertPosDecl(0)
, m_insertPosOutside(0)
, m_functionCount(0)
{
setDescription(QCoreApplication::translate(
"CppEditor::QuickFix", "Insert Virtual Functions of Base Classes"));
const QList<AST *> &path = interface->path();
const int pathSize = path.size();
if (pathSize < 2)
return;
// Determine if cursor is on a class or a base class
if (SimpleNameAST *nameAST = path.at(pathSize - 1)->asSimpleName()) {
if (!interface->isCursorOn(nameAST))
return;
if (!(m_classAST = path.at(pathSize - 2)->asClassSpecifier())) { // normal class
int index = pathSize - 2;
const BaseSpecifierAST *baseAST = path.at(index)->asBaseSpecifier();// simple bclass
if (!baseAST) {
if (index > 0 && path.at(index)->asQualifiedName()) // namespaced base class
baseAST = path.at(--index)->asBaseSpecifier();
}
--index;
if (baseAST && index >= 0)
m_classAST = path.at(index)->asClassSpecifier();
}
}
if (!m_classAST || !m_classAST->base_clause_list)
return;
// Determine insert positions
const int endOfClassAST = interface->currentFile()->endOf(m_classAST);
m_insertPosDecl = endOfClassAST - 1; // Skip last "}"
m_insertPosOutside = endOfClassAST + 1; // Step over ";"
// Determine base classes
QList<const Class *> baseClasses;
QQueue<ClassOrNamespace *> baseClassQueue;
QSet<ClassOrNamespace *> visitedBaseClasses;
if (ClassOrNamespace *clazz = interface->context().lookupType(m_classAST->symbol))
baseClassQueue.enqueue(clazz);
while (!baseClassQueue.isEmpty()) {
ClassOrNamespace *clazz = baseClassQueue.dequeue();
visitedBaseClasses.insert(clazz);
const QList<ClassOrNamespace *> bases = clazz->usings();
foreach (ClassOrNamespace *baseClass, bases) {
foreach (Symbol *symbol, baseClass->symbols()) {
Class *base = symbol->asClass();
if (base
&& (clazz = interface->context().lookupType(symbol))
&& !visitedBaseClasses.contains(clazz)
&& !baseClasses.contains(base)) {
baseClasses.prepend(base);
baseClassQueue.enqueue(clazz);
}
}
}
}
// Determine virtual functions
m_factory->classFunctionModel->clear();
Overview printer = CppCodeStyleSettings::currentProjectCodeStyleOverview();
printer.showFunctionSignatures = true;
const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::fontSettings();
const Format formatReimpFunc = fs.formatFor(C_DISABLED_CODE);
QHash<const Function *, QStandardItem *> virtualFunctions;
foreach (const Class *clazz, baseClasses) {
QStandardItem *itemBase = new QStandardItem(printer.prettyName(clazz->name()));
itemBase->setData(false, InsertVirtualMethodsDialog::Reimplemented);
itemBase->setData(qVariantFromValue((void *) clazz),
InsertVirtualMethodsDialog::ClassOrFunction);
for (Scope::iterator it = clazz->firstMember(); it != clazz->lastMember(); ++it) {
if (const Function *func = (*it)->type()->asFunctionType()) {
// Filter virtual destructors
if (func->name()->asDestructorNameId())
continue;
const Function *firstVirtual = 0;
const bool isVirtual = FunctionUtils::isVirtualFunction(
func, interface->context(), &firstVirtual);
if (!isVirtual)
continue;
// Filter OQbject's
// - virtual const QMetaObject *metaObject() const;
// - virtual void *qt_metacast(const char *);
// - virtual int qt_metacall(QMetaObject::Call, int, void **);
if (printer.prettyName(firstVirtual->enclosingClass()->name())
== QLatin1String("QObject")) {
const QString funcName = printer.prettyName(func->name());
if (funcName == QLatin1String("metaObject")
|| funcName == QLatin1String("qt_metacast")
|| funcName == QLatin1String("qt_metacall")) {
continue;
}
}
// Do not implement existing functions inside target class
bool funcExistsInClass = false;
const Name *funcName = func->name();
for (Symbol *symbol = m_classAST->symbol->find(funcName->identifier());
symbol; symbol = symbol->next()) {
if (!symbol->name()
|| !funcName->identifier()->isEqualTo(symbol->identifier())) {
continue;
}
if (symbol->type().isEqualTo(func->type())) {
funcExistsInClass = true;
break;
}
}
// Construct function item
const bool isReimplemented = (func != firstVirtual);
const bool isPureVirtual = func->isPureVirtual();
QString itemName = printer.prettyType(func->type(), func->name());
if (isPureVirtual)
itemName += QLatin1String(" = 0");
const QString itemReturnTypeString = printer.prettyType(func->returnType());
itemName += QLatin1String(" : ") + itemReturnTypeString;
if (isReimplemented)
itemName += QLatin1String(" (redeclared)");
QStandardItem *funcItem = new QStandardItem(itemName);
funcItem->setCheckable(true);
if (isReimplemented) {
factory->setHasReimplementedFunctions(true);
funcItem->setEnabled(false);
funcItem->setCheckState(Qt::Unchecked);
if (QStandardItem *first = virtualFunctions[firstVirtual]) {
if (!first->data(InsertVirtualMethodsDialog::Reimplemented).toBool()) {
first->setCheckState(isPureVirtual ? Qt::Checked : Qt::Unchecked);
factory->updateCheckBoxes(first);
}
}
} else {
if (!funcExistsInClass) {
funcItem->setCheckState(isPureVirtual ? Qt::Checked : Qt::Unchecked);
} else {
funcItem->setEnabled(false);
funcItem->setCheckState(Qt::Checked);
funcItem->setData(formatReimpFunc.foreground(), Qt::ForegroundRole);
factory->setHasReimplementedFunctions(true);
if (formatReimpFunc.background().isValid())
funcItem->setData(formatReimpFunc.background(), Qt::BackgroundRole);
}
}
funcItem->setData(qVariantFromValue((void *) func),
InsertVirtualMethodsDialog::ClassOrFunction);
funcItem->setData(isPureVirtual, InsertVirtualMethodsDialog::PureVirtual);
funcItem->setData(acessSpec(*it), InsertVirtualMethodsDialog::AccessSpec);
funcItem->setData(funcExistsInClass || isReimplemented,
InsertVirtualMethodsDialog::Reimplemented);
itemBase->appendRow(funcItem);
virtualFunctions[func] = funcItem;
// update internal counters
if (!funcExistsInClass)
++m_functionCount;
}
}
if (itemBase->hasChildren()) {
itemBase->setData(false, InsertVirtualMethodsDialog::Reimplemented);
bool enabledFound = false;
Qt::CheckState state = Qt::Unchecked;
for (int i = 0; i < itemBase->rowCount(); ++i) {
QStandardItem *childItem = itemBase->child(i, 0);
if (!childItem->isEnabled())
continue;
if (!enabledFound) {
state = childItem->checkState();
enabledFound = true;
}
if (childItem->isCheckable()) {
if (!itemBase->isCheckable()) {
itemBase->setCheckable(true);
itemBase->setTristate(true);
itemBase->setCheckState(state);
}
if (state != childItem->checkState()) {
itemBase->setCheckState(Qt::PartiallyChecked);
break;
}
}
}
if (!enabledFound) {
itemBase->setCheckable(true);
itemBase->setEnabled(false);
}
m_factory->classFunctionModel->invisibleRootItem()->appendRow(itemBase);
}
}
if (!m_factory->classFunctionModel->invisibleRootItem()->hasChildren()
|| m_functionCount == 0) {
return;
}
bool isHeaderFile = false;
m_cppFileName = correspondingHeaderOrSource(interface->fileName(), &isHeaderFile);
m_factory->setHasImplementationFile(isHeaderFile && !m_cppFileName.isEmpty());
m_valid = true;
}
bool isValid() const
{
return m_valid;
}
InsertionPointLocator::AccessSpec acessSpec(const Symbol *symbol)
{
const Function *func = symbol->type()->asFunctionType();
if (!func)
return InsertionPointLocator::Invalid;
if (func->isSignal())
return InsertionPointLocator::Signals;
InsertionPointLocator::AccessSpec spec = InsertionPointLocator::Invalid;
if (symbol->isPrivate())
spec = InsertionPointLocator::Private;
else if (symbol->isProtected())
spec = InsertionPointLocator::Protected;
else if (symbol->isPublic())
spec = InsertionPointLocator::Public;
else
return InsertionPointLocator::Invalid;
if (func->isSlot()) {
switch (spec) {
case InsertionPointLocator::Private:
return InsertionPointLocator::PrivateSlot;
case InsertionPointLocator::Protected:
return InsertionPointLocator::ProtectedSlot;
case InsertionPointLocator::Public:
return InsertionPointLocator::PublicSlot;
default:
return spec;
}
}
return spec;
}
void perform()
{
if (!m_factory->gather())
return;
Core::ICore::settings()->setValue(
QLatin1String("QuickFix/InsertVirtualMethods/insertKeywordVirtual"),
m_factory->insertKeywordVirtual());
Core::ICore::settings()->setValue(
QLatin1String("QuickFix/InsertVirtualMethods/implementationMode"),
m_factory->implementationMode());
Core::ICore::settings()->setValue(
QLatin1String("QuickFix/InsertVirtualMethods/hideReimplementedFunctions"),
m_factory->hideReimplementedFunctions());
// Insert declarations (and definition if Inside-/OutsideClass)
Overview printer = CppCodeStyleSettings::currentProjectCodeStyleOverview();
printer.showFunctionSignatures = true;
printer.showReturnTypes = true;
printer.showArgumentNames = true;
ChangeSet headerChangeSet;
const CppRefactoringChanges refactoring(assistInterface()->snapshot());
const QString filename = assistInterface()->currentFile()->fileName();
const CppRefactoringFilePtr headerFile = refactoring.file(filename);
const LookupContext targetContext(headerFile->cppDocument(), assistInterface()->snapshot());
const Class *targetClass = m_classAST->symbol;
ClassOrNamespace *targetCoN = targetContext.lookupType(targetClass->enclosingScope());
if (!targetCoN)
targetCoN = targetContext.globalNamespace();
UseMinimalNames useMinimalNames(targetCoN);
Control *control = assistInterface()->context().bindings()->control().data();
for (int i = 0; i < m_factory->classFunctionModel->rowCount(); ++i) {
const QStandardItem *parent =
m_factory->classFunctionModel->invisibleRootItem()->child(i, 0);
if (!parent->isCheckable() || parent->checkState() == Qt::Unchecked)
continue;
const Class *clazz = (const Class *)
parent->data(InsertVirtualMethodsDialog::ClassOrFunction).value<void *>();
// Add comment
const QString comment = QLatin1String("\n// ") + printer.prettyName(clazz->name()) +
QLatin1String(" interface\n");
headerChangeSet.insert(m_insertPosDecl, comment);
// Insert Declarations (+ definitions)
QString lastAccessSpecString;
for (int j = 0; j < parent->rowCount(); ++j) {
const QStandardItem *item = parent->child(j, 0);
if (!item->isEnabled() || !item->isCheckable() || item->checkState() == Qt::Unchecked)
continue;
const Function *func = (const Function *)
item->data(InsertVirtualMethodsDialog::ClassOrFunction).value<void *>();
// Construct declaration
// setup rewriting to get minimally qualified names
SubstitutionEnvironment env;
env.setContext(assistInterface()->context());
env.switchScope(clazz->enclosingScope());
env.enter(&useMinimalNames);
QString declaration;
const FullySpecifiedType tn = rewriteType(func->type(), &env, control);
declaration += printer.prettyType(tn, func->unqualifiedName());
if (m_factory->insertKeywordVirtual())
declaration = QLatin1String("virtual ") + declaration;
if (m_factory->implementationMode() & InsertVirtualMethodsDialog::ModeInsideClass)
declaration += QLatin1String("\n{\n}\n");
else
declaration += QLatin1String(";\n");
const InsertionPointLocator::AccessSpec spec =
static_cast<InsertionPointLocator::AccessSpec>(
item->data(InsertVirtualMethodsDialog::AccessSpec).toInt());
const QString accessSpecString = InsertionPointLocator::accessSpecToString(spec);
if (accessSpecString != lastAccessSpecString) {
declaration = accessSpecString + declaration;
if (!lastAccessSpecString.isEmpty()) // separate if not direct after the comment
declaration = QLatin1String("\n") + declaration;
lastAccessSpecString = accessSpecString;
}
headerChangeSet.insert(m_insertPosDecl, declaration);
// Insert definition outside class
if (m_factory->implementationMode() & InsertVirtualMethodsDialog::ModeOutsideClass) {
const QString name = printer.prettyName(targetClass->name()) +
QLatin1String("::") + printer.prettyName(func->name());
const QString defText = printer.prettyType(tn, name) + QLatin1String("\n{\n}");
headerChangeSet.insert(m_insertPosOutside, QLatin1String("\n\n") + defText);
}
}
}
// Write header file
headerFile->setChangeSet(headerChangeSet);
headerFile->appendIndentRange(ChangeSet::Range(m_insertPosDecl, m_insertPosDecl + 1));
headerFile->setOpenEditor(true, m_insertPosDecl);
headerFile->apply();
// Insert in implementation file
if (m_factory->implementationMode() & InsertVirtualMethodsDialog::ModeImplementationFile) {
const Symbol *symbol = headerFile->cppDocument()->lastVisibleSymbolAt(
targetClass->line(), targetClass->column());
if (!symbol)
return;
const Class *clazz = symbol->asClass();
if (!clazz)
return;
CppRefactoringFilePtr implementationFile = refactoring.file(m_cppFileName);
ChangeSet implementationChangeSet;
const int insertPos = qMax(0, implementationFile->document()->characterCount() - 1);
// make target lookup context
Document::Ptr implementationDoc = implementationFile->cppDocument();
unsigned line, column;
implementationDoc->translationUnit()->getPosition(insertPos, &line, &column);
Scope *targetScope = implementationDoc->scopeAt(line, column);
const LookupContext targetContext(implementationDoc, assistInterface()->snapshot());
ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope);
if (!targetCoN)
targetCoN = targetContext.globalNamespace();
// Loop through inserted declarations
for (unsigned i = targetClass->memberCount(); i < clazz->memberCount(); ++i) {
Declaration *decl = clazz->memberAt(i)->asDeclaration();
if (!decl)
continue;
// setup rewriting to get minimally qualified names
SubstitutionEnvironment env;
env.setContext(assistInterface()->context());
env.switchScope(decl->enclosingScope());
UseMinimalNames q(targetCoN);
env.enter(&q);
Control *control = assistInterface()->context().bindings()->control().data();
// rewrite the function type and name + create definition
const FullySpecifiedType type = rewriteType(decl->type(), &env, control);
const QString name = printer.prettyName(
LookupContext::minimalName(decl, targetCoN, control));
const QString defText = printer.prettyType(type, name) + QLatin1String("\n{\n}");
implementationChangeSet.insert(insertPos, QLatin1String("\n\n") + defText);
}
implementationFile->setChangeSet(implementationChangeSet);
implementationFile->appendIndentRange(ChangeSet::Range(insertPos, insertPos + 1));
implementationFile->apply();
}
}
private:
InsertVirtualMethodsDialog *m_factory;
const ClassSpecifierAST *m_classAST;
bool m_valid;
QString m_cppFileName;
int m_insertPosDecl;
int m_insertPosOutside;
unsigned m_functionCount;
};
class InsertVirtualMethodsFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
InsertVirtualMethodsFilterModel(QObject *parent = 0)
: QSortFilterProxyModel(parent)
, m_hideReimplemented(false)
{}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
// Handle base class
if (!sourceParent.isValid()) {
// check if any child is valid
if (!sourceModel()->hasChildren(index))
return false;
if (!m_hideReimplemented)
return true;
for (int i = 0; i < sourceModel()->rowCount(index); ++i) {
const QModelIndex child = sourceModel()->index(i, 0, index);
if (!child.data(InsertVirtualMethodsDialog::Reimplemented).toBool())
return true;
}
return false;
}
if (m_hideReimplemented)
return !index.data(InsertVirtualMethodsDialog::Reimplemented).toBool();
return true;
}
bool hideReimplemented() const
{
return m_hideReimplemented;
}
void setHideReimplementedFunctions(bool show)
{
m_hideReimplemented = show;
invalidateFilter();
}
private:
bool m_hideReimplemented;
};
} // anonymous namespace
InsertVirtualMethodsDialog::InsertVirtualMethodsDialog(QWidget *parent)
: QDialog(parent)
, m_view(0)
, m_hideReimplementedFunctions(0)
, m_insertMode(0)
, m_virtualKeyword(0)
, m_buttons(0)
, m_hasImplementationFile(false)
, m_hasReimplementedFunctions(false)
, m_implementationMode(ModeOnlyDeclarations)
, m_insertKeywordVirtual(false)
, classFunctionModel(new QStandardItemModel(this))
, classFunctionFilterModel(new InsertVirtualMethodsFilterModel(this))
{
classFunctionFilterModel->setSourceModel(classFunctionModel);
}
void InsertVirtualMethodsDialog::initGui()
{
if (m_view)
return;
setWindowTitle(tr("Insert Virtual Functions"));
QVBoxLayout *globalVerticalLayout = new QVBoxLayout;
// View
QGroupBox *groupBoxView = new QGroupBox(tr("&Functions to insert:"), this);
QVBoxLayout *groupBoxViewLayout = new QVBoxLayout(groupBoxView);
m_view = new QTreeView(this);
m_view->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_view->setHeaderHidden(true);
groupBoxViewLayout->addWidget(m_view);
m_hideReimplementedFunctions =
new QCheckBox(tr("&Hide reimplemented functions"), this);
groupBoxViewLayout->addWidget(m_hideReimplementedFunctions);
// Insertion options
QGroupBox *groupBoxImplementation = new QGroupBox(tr("&Insertion options:"), this);
QVBoxLayout *groupBoxImplementationLayout = new QVBoxLayout(groupBoxImplementation);
m_insertMode = new QComboBox(this);
m_insertMode->addItem(tr("Insert only declarations"), ModeOnlyDeclarations);
m_insertMode->addItem(tr("Insert definitions inside class"), ModeInsideClass);
m_insertMode->addItem(tr("Insert definitions outside class"), ModeOutsideClass);
m_insertMode->addItem(tr("Insert definitions in implementation file"), ModeImplementationFile);
m_virtualKeyword = new QCheckBox(tr("&Add keyword 'virtual' to function declaration"), this);
groupBoxImplementationLayout->addWidget(m_insertMode);
groupBoxImplementationLayout->addWidget(m_virtualKeyword);
groupBoxImplementationLayout->addStretch(99);
// Bottom button box
m_buttons = new QDialogButtonBox(this);
m_buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(m_buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_buttons, SIGNAL(rejected()), this, SLOT(reject()));
globalVerticalLayout->addWidget(groupBoxView, 9);
globalVerticalLayout->addWidget(groupBoxImplementation, 0);
globalVerticalLayout->addWidget(m_buttons, 0);
setLayout(globalVerticalLayout);
connect(classFunctionModel, SIGNAL(itemChanged(QStandardItem*)),
this, SLOT(updateCheckBoxes(QStandardItem*)));
connect(m_hideReimplementedFunctions, SIGNAL(toggled(bool)),
this, SLOT(setHideReimplementedFunctions(bool)));
}
void InsertVirtualMethodsDialog::initData()
{
m_insertKeywordVirtual = Core::ICore::settings()->value(
QLatin1String("QuickFix/InsertVirtualMethods/insertKeywordVirtual"),
false).toBool();
m_implementationMode = static_cast<InsertVirtualMethodsDialog::ImplementationMode>(
Core::ICore::settings()->value(
QLatin1String("QuickFix/InsertVirtualMethods/implementationMode"), 1).toInt());
m_hideReimplementedFunctions->setChecked(
Core::ICore::settings()->value(
QLatin1String("QuickFix/InsertVirtualMethods/hideReimplementedFunctions"),
false).toBool());
m_view->setModel(classFunctionFilterModel);
m_expansionStateNormal.clear();
m_expansionStateReimp.clear();
m_hideReimplementedFunctions->setEnabled(m_hasReimplementedFunctions);
m_virtualKeyword->setChecked(m_insertKeywordVirtual);
m_insertMode->setCurrentIndex(m_insertMode->findData(m_implementationMode));
setHideReimplementedFunctions(m_hideReimplementedFunctions->isChecked());
if (m_hasImplementationFile) {
if (m_insertMode->count() == 3) {
m_insertMode->addItem(tr("Insert definitions in implementation file"),
ModeImplementationFile);
}
} else {
if (m_insertMode->count() == 4)
m_insertMode->removeItem(3);
}
}
bool InsertVirtualMethodsDialog::gather()
{
initGui();
initData();
// Expand the dialog a little bit
adjustSize();
resize(size() * 1.5);
QPointer<InsertVirtualMethodsDialog> that(this);
const int ret = exec();
if (!that)
return false;
m_implementationMode = implementationMode();
m_insertKeywordVirtual = insertKeywordVirtual();
return (ret == QDialog::Accepted);
}
InsertVirtualMethodsDialog::ImplementationMode
InsertVirtualMethodsDialog::implementationMode() const
{
return static_cast<InsertVirtualMethodsDialog::ImplementationMode>(
m_insertMode->itemData(m_insertMode->currentIndex()).toInt());
}
void InsertVirtualMethodsDialog::setImplementationsMode(InsertVirtualMethodsDialog::ImplementationMode mode)
{
m_implementationMode = mode;
}
bool InsertVirtualMethodsDialog::insertKeywordVirtual() const
{
return m_virtualKeyword->isChecked();
}
void InsertVirtualMethodsDialog::setInsertKeywordVirtual(bool insert)
{
m_insertKeywordVirtual = insert;
}
void InsertVirtualMethodsDialog::setHasImplementationFile(bool file)
{
m_hasImplementationFile = file;
}
void InsertVirtualMethodsDialog::setHasReimplementedFunctions(bool functions)
{
m_hasReimplementedFunctions = functions;
}
bool InsertVirtualMethodsDialog::hideReimplementedFunctions() const
{
// Safty check necessary because of testing class
return (m_hideReimplementedFunctions && m_hideReimplementedFunctions->isChecked());
}
void InsertVirtualMethodsDialog::updateCheckBoxes(QStandardItem *item)
{
if (item->hasChildren()) {
const Qt::CheckState state = item->checkState();
if (!item->isCheckable() || state == Qt::PartiallyChecked)
return;
for (int i = 0; i < item->rowCount(); ++i) {
QStandardItem *childItem = item->child(i, 0);
if (childItem->isCheckable() && childItem->isEnabled())
childItem->setCheckState(state);
}
} else {
QStandardItem *parent = item->parent();
if (!parent->isCheckable())
return;
const Qt::CheckState state = item->checkState();
for (int i = 0; i < parent->rowCount(); ++i) {
QStandardItem *childItem = parent->child(i, 0);
if (childItem->isEnabled() && state != childItem->checkState()) {
parent->setCheckState(Qt::PartiallyChecked);
return;
}
}
parent->setCheckState(state);
}
}
void InsertVirtualMethodsDialog::setHideReimplementedFunctions(bool hide)
{
InsertVirtualMethodsFilterModel *model =
qobject_cast<InsertVirtualMethodsFilterModel *>(classFunctionFilterModel);
if (m_expansionStateNormal.isEmpty() && m_expansionStateReimp.isEmpty()) {
model->setHideReimplementedFunctions(hide);
m_view->expandAll();
saveExpansionState();
return;
}
if (model->hideReimplemented() == hide)
return;
saveExpansionState();
model->setHideReimplementedFunctions(hide);
restoreExpansionState();
}
void InsertVirtualMethodsDialog::saveExpansionState()
{
InsertVirtualMethodsFilterModel *model =
qobject_cast<InsertVirtualMethodsFilterModel *>(classFunctionFilterModel);
QList<bool> &state = model->hideReimplemented() ? m_expansionStateReimp
: m_expansionStateNormal;
state.clear();
for (int i = 0; i < model->rowCount(); ++i)
state << m_view->isExpanded(model->index(i, 0));
}
void InsertVirtualMethodsDialog::restoreExpansionState()
{
InsertVirtualMethodsFilterModel *model =
qobject_cast<InsertVirtualMethodsFilterModel *>(classFunctionFilterModel);
const QList<bool> &state = model->hideReimplemented() ? m_expansionStateReimp
: m_expansionStateNormal;
const int stateCount = state.count();
for (int i = 0; i < model->rowCount(); ++i) {
if (i < stateCount && !state.at(i)) {
m_view->collapse(model->index(i, 0));
continue;
}
m_view->expand(model->index(i, 0));
}
}
InsertVirtualMethods::InsertVirtualMethods(InsertVirtualMethodsDialog *dialog)
: m_dialog(dialog)
{}
InsertVirtualMethods::~InsertVirtualMethods()
{
if (m_dialog)
m_dialog->deleteLater();
}
void InsertVirtualMethods::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
InsertVirtualMethodsOp *op = new InsertVirtualMethodsOp(interface, m_dialog);
if (op->isValid())
result.append(QuickFixOperation::Ptr(op));
else
delete op;
}
namespace {
class OptimizeForLoopOperation: public CppQuickFixOperation class OptimizeForLoopOperation: public CppQuickFixOperation
{ {
public: public:
@@ -5581,5 +4840,3 @@ void OptimizeForLoop::match(const CppQuickFixInterface &interface, QuickFixOpera
result.append(QuickFixOperation::Ptr(op)); result.append(QuickFixOperation::Ptr(op));
} }
} }
#include "cppquickfixes.moc"

View File

@@ -40,14 +40,6 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QByteArray; class QByteArray;
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
class QStandardItem;
class QSortFilterProxyModel;
class QStandardItemModel;
class QString;
class QTreeView;
template <class> class QList; template <class> class QList;
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -522,81 +514,6 @@ public:
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result); void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
}; };
/*!
Insert (pure) virtual functions of a base class.
Exposed for tests.
*/
class InsertVirtualMethodsDialog : public QDialog
{
Q_OBJECT
public:
enum CustomItemRoles {
ClassOrFunction = Qt::UserRole + 1,
Reimplemented = Qt::UserRole + 2,
PureVirtual = Qt::UserRole + 3,
AccessSpec = Qt::UserRole + 4
};
enum ImplementationMode {
ModeOnlyDeclarations = 0x00000001,
ModeInsideClass = 0x00000002,
ModeOutsideClass = 0x00000004,
ModeImplementationFile = 0x00000008
};
InsertVirtualMethodsDialog(QWidget *parent = 0);
void initGui();
void initData();
virtual ImplementationMode implementationMode() const;
void setImplementationsMode(ImplementationMode mode);
virtual bool insertKeywordVirtual() const;
void setInsertKeywordVirtual(bool insert);
void setHasImplementationFile(bool file);
void setHasReimplementedFunctions(bool functions);
bool hideReimplementedFunctions() const;
virtual bool gather();
public slots:
void updateCheckBoxes(QStandardItem *item);
private slots:
void setHideReimplementedFunctions(bool hide);
private:
QTreeView *m_view;
QCheckBox *m_hideReimplementedFunctions;
QComboBox *m_insertMode;
QCheckBox *m_virtualKeyword;
QDialogButtonBox *m_buttons;
QList<bool> m_expansionStateNormal;
QList<bool> m_expansionStateReimp;
bool m_hasImplementationFile;
bool m_hasReimplementedFunctions;
void saveExpansionState();
void restoreExpansionState();
protected:
ImplementationMode m_implementationMode;
bool m_insertKeywordVirtual;
public:
QStandardItemModel *classFunctionModel;
QSortFilterProxyModel *classFunctionFilterModel;
};
class InsertVirtualMethods: public CppQuickFixFactory
{
Q_OBJECT
public:
InsertVirtualMethods(InsertVirtualMethodsDialog *dialog = new InsertVirtualMethodsDialog);
~InsertVirtualMethods();
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
private:
InsertVirtualMethodsDialog *m_dialog;
};
/*! /*!
Optimizes a for loop to avoid permanent condition check and forces to use preincrement Optimizes a for loop to avoid permanent condition check and forces to use preincrement
or predecrement operators in the expression of the for loop. or predecrement operators in the expression of the for loop.

View File

@@ -31,9 +31,9 @@
#include "cppeditorplugin.h" #include "cppeditorplugin.h"
#include "cppeditortestcase.h" #include "cppeditortestcase.h"
#include "cppquickfix.h" #include "cppquickfix.h"
#include "cppquickfix_test_utils.h"
#include "cppquickfixassistant.h" #include "cppquickfixassistant.h"
#include "cppquickfixes.h" #include "cppquickfixes.h"
#include "cppinsertvirtualmethods.h"
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <cpptools/cppmodelmanagerinterface.h> #include <cpptools/cppmodelmanagerinterface.h>
@@ -474,10 +474,7 @@ void RunAllQuickFixesTokenAction::run(CPPEditorWidget *editorWidget)
// Where possible, use a guiless version of the factory. // Where possible, use a guiless version of the factory.
if (qobject_cast<InsertVirtualMethods *>(quickFixFactory)) { if (qobject_cast<InsertVirtualMethods *>(quickFixFactory)) {
QScopedPointer<CppQuickFixFactory> factoryProducingGuiLessOperations; QScopedPointer<CppQuickFixFactory> factoryProducingGuiLessOperations;
factoryProducingGuiLessOperations.reset( factoryProducingGuiLessOperations.reset(InsertVirtualMethods::createTestFactory());
new InsertVirtualMethods(
new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOutsideClass, true)));
factoryProducingGuiLessOperations->match(qfi, operations); factoryProducingGuiLessOperations->match(qfi, operations);
} else { } else {
quickFixFactory->match(qfi, operations); quickFixFactory->match(qfi, operations);