Commit 3ebc3284 authored by Erik Verbruggen's avatar Erik Verbruggen

C++: added quickfix to insert a method definition.

Reviewed-by: Christian Kamm
parent 44d87bf8
......@@ -48,8 +48,7 @@ HEADERS += \
$$PWD/pp-cctype.h \
$$PWD/pp-engine.h \
$$PWD/pp-macro-expander.h \
$$PWD/pp-scanner.h \
$$PWD/InsertionPointLocator.h
$$PWD/pp-scanner.h
SOURCES += \
$$PWD/SimpleLexer.cpp \
......@@ -73,7 +72,6 @@ SOURCES += \
$$PWD/Macro.cpp \
$$PWD/pp-engine.cpp \
$$PWD/pp-macro-expander.cpp \
$$PWD/pp-scanner.cpp \
$$PWD/InsertionPointLocator.cpp
$$PWD/pp-scanner.cpp
RESOURCES += $$PWD/cplusplus.qrc
......@@ -15,7 +15,6 @@ HEADERS += cppplugin.h \
cppeditor_global.h \
cppclasswizard.h \
cppquickfix.h \
cpprefactoringchanges.h \
cppchecksymbols.h \
cppsemanticinfo.h \
cppoutline.h \
......@@ -31,7 +30,6 @@ SOURCES += cppplugin.cpp \
cppclasswizard.cpp \
cppquickfix.cpp \
cppquickfixes.cpp \
cpprefactoringchanges.cpp \
cppchecksymbols.cpp \
cppsemanticinfo.cpp \
cppoutline.cpp \
......
......@@ -36,9 +36,10 @@
#include <Symbols.h>
#include <TranslationUnit.h>
#include <cplusplus/ASTPath.h>
#include <cplusplus/InsertionPointLocator.h>
#include <cplusplus/CppRewriter.h>
#include <cplusplus/LookupContext.h>
#include <cplusplus/Overview.h>
#include <cpptools/InsertionPointLocator.h>
#include <QtCore/QCoreApplication>
......@@ -47,8 +48,6 @@ using namespace CppEditor;
using namespace CppEditor::Internal;
using namespace CppTools;
using CppEditor::CppRefactoringChanges;
namespace {
class InsertDeclOperation: public CppQuickFixOperation
......@@ -81,9 +80,7 @@ public:
void performChanges(CppRefactoringFile *, CppRefactoringChanges *refactoring)
{
Snapshot snapshot = state().snapshot();
snapshot.insert(refactoring->file(m_targetFileName).cppDocument());
InsertionPointLocator locator(snapshot);
InsertionPointLocator locator(refactoring);
const InsertionLocation loc = locator.methodDeclarationInClass(
m_targetFileName, m_targetSymbol, m_xsSpec);
Q_ASSERT(loc.isValid());
......@@ -211,170 +208,97 @@ QString DeclFromDef::generateDeclaration(const CppQuickFixState &,
namespace {
static inline bool hasFunctionType(DeclarationAST *decl)
class InsertDefOperation: public CppQuickFixOperation
{
if (decl->asFunctionDefinition())
return true;
public:
InsertDefOperation(const CppQuickFixState &state, int priority,
Declaration *decl, const InsertionLocation &loc)
: CppQuickFixOperation(state, priority)
, m_decl(decl)
, m_loc(loc)
{
setDescription(QCoreApplication::tr("Add definition in %1",
"CppEditor::DefFromDecl")
.arg(m_loc.fileName()));
}
if (SimpleDeclarationAST *ast = decl->asSimpleDeclaration())
if (ast->symbols && ast->symbols->value && !ast->symbols->next)
if (Declaration *decl = ast->symbols->value->asDeclaration())
if (FullySpecifiedType ty = decl->type())
return ty->asFunctionType();
void performChanges(CppRefactoringFile *,
CppRefactoringChanges *refactoring)
{
Q_ASSERT(m_loc.isValid());
return false;
}
CppRefactoringFile targetFile = refactoring->file(m_loc.fileName());
static QPair<DeclarationAST *, DeclarationAST *> findSurroundingDeclarations(
DeclarationListAST *members,
DeclarationAST *decl)
{
bool found = false;
DeclarationAST *last = 0, *next = 0, *prev = 0;
DeclarationListAST *iter = members;
for (; iter; iter = iter->next) {
DeclarationAST *value = iter->value;
if (value == decl) {
prev = last;
found = true;
} else if (hasFunctionType(value)) {
if (found) {
next = value;
break;
} else {
last = value;
}
}
Overview oo;
oo.setShowFunctionSignatures(true);
oo.setShowReturnTypes(true);
oo.setShowArgumentNames(true);
//--
SubstitutionEnvironment env;
env.setContext(state().context());
env.switchScope(m_decl->enclosingScope());
UseQualifiedNames q;
env.enter(&q);
Control *control = state().context().control().data();
FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
QString name = oo(LookupContext::fullyQualifiedName(m_decl));
//--
QString defText = oo.prettyType(tn, name) + "\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.change(target);
targetFile.indent(Utils::ChangeSet::Range(targetPos2, targetPos));
const int prefixLineCount = m_loc.prefix().count(QLatin1Char('\n'));
refactoring->activateEditor(m_loc.fileName(),
m_loc.line() + prefixLineCount,
0);
}
return qMakePair(prev, next);
}
private:
Declaration *m_decl;
InsertionLocation m_loc;
};
} // anonymous namespace
QList<CppQuickFixOperation::Ptr> DefFromDecl::match(const CppQuickFixState &state)
{
#if 0
qDebug() << Q_FUNC_INFO;
const QList<AST *> &path = state.path();
const CppRefactoringFile &file = state.currentFile();
DeclaratorAST *declAST = 0;
ClassSpecifierAST *classSpec = 0;
int idx = path.size() - 1;
for (; idx >= 0; --idx) {
AST *node = path.at(idx);
if (ClassSpecifierAST *clazz = node->asClassSpecifier()) {
classSpec = clazz;
continue;
}
if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) {
if (simpleDecl->symbols && ! simpleDecl->symbols->next) {
if (Symbol *symbol = simpleDecl->symbols->value) {
if (Declaration *decl = symbol->asDeclaration()) {
if (decl->type()->isFunctionType() && decl->enclosingScope() && decl->enclosingScope()->isClass()) {
DeclaratorAST *declarator = simpleDecl->declarator_list->value;
if (file.isCursorOn(declarator->core_declarator)) {
CppRefactoringChanges refactoring(state.snapshot());
InsertionPointLocator locator(&refactoring);
QList<CppQuickFixOperation::Ptr> results;
foreach (const InsertionLocation &loc, locator.methodDefinition(decl))
results.append(CppQuickFixOperation::Ptr(new InsertDefOperation(state, idx, decl, loc)));
return results;
}
}
}
}
}
if (idx <= 1) continue;
DeclaratorIdAST *declId = node->asDeclaratorId();
if (!declId) continue;
if (!file.isCursorOn(declId)) continue;
DeclaratorAST *candidate = path.at(idx - 1)->asDeclarator();
if (!candidate) continue;
if (!candidate->postfix_declarator_list) continue;
if (!candidate->postfix_declarator_list->value) continue;
if (candidate->postfix_declarator_list->next) continue;
FunctionDeclaratorAST *funDecl = candidate->postfix_declarator_list->value->asFunctionDeclarator();
if (!funDecl) continue;
if (funDecl->symbol->asFunctionType())
declAST = candidate;
break;
}
}
if (!declAST || !classSpec || !classSpec->symbol)
return noResult();
if (!declAST->symbols || !declAST->symbols->value || declAST->symbols->next)
return noResult();
Declaration *decl = declAST->symbols->value->asDeclaration();
if (!decl)
return noResult();
Function *funTy = decl->type()->asFunctionType();
if (!funTy)
return noResult();
qDebug() << "-> Found funTy.";
QPair<DeclarationAST *, DeclarationAST *> surroundingNodes =
findSurroundingDeclarations(classSpec->member_specifier_list, declAST);
qDebug() << "->("<<surroundingNodes.first<<","<<surroundingNodes.second<<")";
if (surroundingNodes.first)
if (SimpleDeclarationAST *sd = surroundingNodes.first->asSimpleDeclaration())
qDebug()<<"-->prev@"<<sd->symbols->value->line()<<sd->symbols->value->column();
if (surroundingNodes.second)
if (SimpleDeclarationAST *sd=surroundingNodes.second->asSimpleDeclaration())
qDebug()<<"-->next@"<<sd->symbols->value->line()<<sd->symbols->value->column();
#endif
// if (ClassOrNamespace *targetBinding = state.context().lookupParent(method)) {
// foreach (Symbol *s, targetBinding->symbols()) {
// if (Class *clazz = s->asClass()) {
// QList<CppQuickFixOperation::Ptr> results;
// const QLatin1String fn(clazz->fileName());
// const QString decl = generateDeclaration(state,
// method,
// targetBinding);
// results.append(
// singleResult(
// new InsertDeclOperation(state, idx, fn, clazz,
// InsertionPointLocator::Public,
// decl)));
// results.append(
// singleResult(
// new InsertDeclOperation(state, idx, fn, clazz,
// InsertionPointLocator::Protected,
// decl)));
// results.append(
// singleResult(
// new InsertDeclOperation(state, idx, fn, clazz,
// InsertionPointLocator::Private,
// decl)));
// results.append(
// singleResult(
// new InsertDeclOperation(state, idx, fn, clazz,
// InsertionPointLocator::PublicSlot,
// decl)));
// results.append(
// singleResult(
// new InsertDeclOperation(state, idx, fn, clazz,
// InsertionPointLocator::ProtectedSlot,
// decl)));
// results.append(
// singleResult(
// new InsertDeclOperation(state, idx, fn, clazz,
// InsertionPointLocator::PrivateSlot,
// decl)));
// return results;
// } //! \todo support insertion into namespaces
// }
// }
Q_UNUSED(findSurroundingDeclarations)
Q_UNUSED(state)
return noResult();
}
QString DefFromDecl::generateDefinition(const CppQuickFixState &,
Function *method,
ClassOrNamespace *targetBinding)
{
Q_UNUSED(targetBinding);
Overview oo;
oo.setShowFunctionSignatures(true);
oo.setShowReturnTypes(true);
oo.setShowArgumentNames(true);
QString decl;
decl += oo(method->type(), method->unqualifiedName());
decl += QLatin1String(";\n");
return decl;
}
......@@ -56,11 +56,6 @@ class DefFromDecl: public CppQuickFixFactory
{
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
protected:
static QString generateDefinition(const CppQuickFixState &state,
CPlusPlus::Function *method,
CPlusPlus::ClassOrNamespace *targetBinding);
};
} // namespace Internal
......
......@@ -43,7 +43,7 @@
#include <cplusplus/CppRewriter.h>
#include <cppeditor/cppeditor.h>
#include <cppeditor/cpprefactoringchanges.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <extensionsystem/pluginmanager.h>
......@@ -52,6 +52,7 @@
using namespace CppEditor;
using namespace CppEditor::Internal;
using namespace CppTools;
using namespace TextEditor;
using namespace CPlusPlus;
using namespace Utils;
......
......@@ -30,11 +30,12 @@
#ifndef CPPQUICKFIX_H
#define CPPQUICKFIX_H
#include "cpprefactoringchanges.h"
#include "cppeditor_global.h"
#include "cppsemanticinfo.h"
#include <ASTfwd.h>
#include <cplusplus/CppDocument.h>
#include <cpptools/cpprefactoringchanges.h>
#include <texteditor/icompletioncollector.h>
#include <texteditor/quickfix.h>
#include <utils/changeset.h>
......@@ -69,7 +70,7 @@ public:
CppEditor::Internal::SemanticInfo semanticInfo() const;
const CPlusPlus::LookupContext &context() const;
const CppRefactoringFile currentFile() const;
const CppTools::CppRefactoringFile currentFile() const;
bool isCursorOn(unsigned tokenIndex) const
{ return currentFile().isCursorOn(tokenIndex); }
......@@ -94,7 +95,8 @@ public:
virtual void perform();
protected:
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *refactoring) = 0;
virtual void performChanges(CppTools::CppRefactoringFile *currentFile,
CppTools::CppRefactoringChanges *refactoring) = 0;
QString fileName() const;
......
......@@ -58,6 +58,7 @@
using namespace CppEditor;
using namespace CppEditor::Internal;
using namespace CppTools;
using namespace TextEditor;
using namespace CPlusPlus;
using namespace Utils;
......
......@@ -37,8 +37,8 @@
#include <QtGui/QTextBlock>
using namespace CppEditor;
using namespace CPlusPlus;
using namespace CppTools;
using namespace Utils;
CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot)
......
......@@ -35,15 +35,15 @@
#include <cplusplus/LookupContext.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <cppeditor/cppeditor_global.h>
#include <cpptools/cpptools_global.h>
#include <texteditor/refactoringchanges.h>
namespace CppEditor {
namespace CppTools {
class CppRefactoringChanges;
class CPPEDITOR_EXPORT CppRefactoringFile: public TextEditor::RefactoringFile
class CPPTOOLS_EXPORT CppRefactoringFile: public TextEditor::RefactoringFile
{
public:
CppRefactoringFile();
......@@ -79,7 +79,7 @@ private:
mutable CPlusPlus::Document::Ptr m_cppDocument;
};
class CPPEDITOR_EXPORT CppRefactoringChanges: public TextEditor::RefactoringChanges
class CPPTOOLS_EXPORT CppRefactoringChanges: public TextEditor::RefactoringChanges
{
public:
CppRefactoringChanges(const CPlusPlus::Snapshot &snapshot);
......@@ -99,6 +99,6 @@ private:
CppTools::CppModelManagerInterface::WorkingCopy m_workingCopy;
};
} // namespace CppEditor
} // namespace CppTools
#endif // CPPREFACTORINGCHANGES_H
......@@ -25,7 +25,9 @@ HEADERS += completionsettingspage.h \
cppfilesettingspage.h \
cppfindreferences.h \
cppcodeformatter.h \
symbolsfindfilter.h
symbolsfindfilter.h \
insertionpointlocator.h \
cpprefactoringchanges.h
SOURCES += completionsettingspage.cpp \
cppclassesfilter.cpp \
......@@ -42,7 +44,9 @@ SOURCES += completionsettingspage.cpp \
abstracteditorsupport.cpp \
cppfindreferences.cpp \
cppcodeformatter.cpp \
symbolsfindfilter.cpp
symbolsfindfilter.cpp \
insertionpointlocator.cpp \
cpprefactoringchanges.cpp
FORMS += completionsettingspage.ui \
cppfilesettingspage.ui
......
......@@ -27,6 +27,8 @@
**
**************************************************************************/
#include "CppToolsPlugin.h"
#include "cpprefactoringchanges.h"
#include "InsertionPointLocator.h"
#include <AST.h>
......@@ -34,6 +36,7 @@
#include <TranslationUnit.h>
using namespace CPlusPlus;
using namespace CppTools;
namespace {
......@@ -150,7 +153,8 @@ protected:
if (needsSuffix)
suffix = QLatin1Char('\n');
_result = InsertionLocation(prefix, suffix, line, column);
_result = InsertionLocation(_doc->fileName(), prefix, suffix,
line, column);
return false;
}
......@@ -264,16 +268,19 @@ InsertionLocation::InsertionLocation()
, m_column(0)
{}
InsertionLocation::InsertionLocation(const QString &prefix, const QString &suffix,
InsertionLocation::InsertionLocation(const QString &fileName,
const QString &prefix,
const QString &suffix,
unsigned line, unsigned column)
: m_prefix(prefix)
: m_fileName(fileName)
, m_prefix(prefix)
, m_suffix(suffix)
, m_line(line)
, m_column(column)
{}
InsertionPointLocator::InsertionPointLocator(const Snapshot &snapshot)
: m_snapshot(snapshot)
InsertionPointLocator::InsertionPointLocator(CppRefactoringChanges *refactoringChanges)
: m_refactoringChanges(refactoringChanges)
{
}
......@@ -282,7 +289,7 @@ InsertionLocation InsertionPointLocator::methodDeclarationInClass(
const Class *clazz,
AccessSpec xsSpec) const
{
const Document::Ptr doc = m_snapshot.document(fileName);
const Document::Ptr doc = m_refactoringChanges->file(fileName).cppDocument();
if (doc) {
FindInClass find(doc, clazz, xsSpec);
return find();
......@@ -293,11 +300,30 @@ InsertionLocation InsertionPointLocator::methodDeclarationInClass(
/// Currently, we return the end of fileName.cpp
QList<InsertionLocation> InsertionPointLocator::methodDefinition(
const QString &/*fileName*/) const
Declaration *declaration) const
{
QList<InsertionLocation> result;
if (!declaration)
return result;
Internal::CppToolsPlugin *cpptools = Internal::CppToolsPlugin::instance();
const QString declFileName = QLatin1String(declaration->fileName());
QString target = cpptools->correspondingHeaderOrSource(declFileName);
Document::Ptr doc = m_refactoringChanges->file(target).cppDocument();
if (doc.isNull())
return result;
TranslationUnit *xUnit = doc->translationUnit();
unsigned tokenCount = xUnit->tokenCount();
if (tokenCount < 2) // no tokens available
return result;
unsigned line = 0, column = 0;
xUnit->getTokenEndPosition(xUnit->tokenCount() - 2, &line, &column);
const QLatin1String prefix("\n\n");
result.append(InsertionLocation(target, prefix, QString(), line, column));
return result;
}
......@@ -30,19 +30,27 @@
#ifndef INSERTIONPOINTLOCATOR_H
#define INSERTIONPOINTLOCATOR_H
#include "cpptools_global.h"
#include <ASTfwd.h>
#include <CPlusPlusForwardDeclarations.h>
#include <Symbols.h>
#include "CppDocument.h"
#include <cplusplus/CppDocument.h>
namespace CppTools {
namespace CPlusPlus {
class CppRefactoringChanges;
class CPLUSPLUS_EXPORT InsertionLocation
class CPPTOOLS_EXPORT InsertionLocation
{
public:
InsertionLocation();
InsertionLocation(const QString &prefix, const QString &suffix, unsigned line, unsigned column);
InsertionLocation(const QString &fileName, const QString &prefix,
const QString &suffix, unsigned line, unsigned column);
QString fileName() const
{ return m_fileName; }
/// \returns The prefix to insert before any other text.
QString prefix() const
......@@ -61,16 +69,17 @@ public:
{ return m_column; }
bool isValid() const
{ return m_line > 0 && m_column > 0; }
{ return !m_fileName.isEmpty() && m_line > 0 && m_column > 0; }
private:
QString m_fileName;
QString m_prefix;
QString m_suffix;
unsigned m_line;
unsigned m_column;
};
class CPLUSPLUS_EXPORT InsertionPointLocator
class CPPTOOLS_EXPORT InsertionPointLocator
{
public:
enum AccessSpec {
......@@ -89,18 +98,18 @@ public:
};
public:
InsertionPointLocator(const Snapshot &snapshot);
InsertionPointLocator(CppRefactoringChanges *refactoringChanges);
InsertionLocation methodDeclarationInClass(const QString &fileName,
const Class *clazz,
const CPlusPlus::Class *clazz,
AccessSpec xsSpec) const;
QList<InsertionLocation> methodDefinition(const QString &fileName) const;
QList<InsertionLocation> methodDefinition(CPlusPlus::Declaration *declaration) const;
private:
Snapshot m_snapshot;
CppRefactoringChanges *m_refactoringChanges;
};
} // namespace CPlusPlus
} // namespace CppTools
#endif // INSERTIONPOINTLOCATOR_H
......@@ -37,8 +37,9 @@
#include <widgethost.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cpptools/cpptoolsconstants.h>
#include <cplusplus/InsertionPointLocator.h>
#include <cpptools/insertionpointlocator.h>
#include <cplusplus/Symbols.h>
#include <cplusplus/Overview.h>
#include <cplusplus/CoreTypes.h>
......@@ -282,9 +283,10 @@ static void addDeclaration(const Snapshot &snapshot,
declaration += functionName;
declaration += QLatin1String(";\n");
InsertionPointLocator find(snapshot);
const InsertionLocation loc = find.methodDeclarationInClass(
fileName, cl, InsertionPointLocator::PrivateSlot);
CppTools::CppRefactoringChanges refactoring(snapshot);
CppTools::InsertionPointLocator find(&refactoring);
const CppTools::InsertionLocation loc = find.methodDeclarationInClass(
fileName, cl, CppTools::InsertionPointLocator::PrivateSlot);