forked from qt-creator/qt-creator
CppEditor: Move "move function definition" quickfixes to dedicated files
Change-Id: I4e963bd7fef1f1c9f0b69dde56298a52c74e01e4 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -108,6 +108,7 @@ add_qtc_plugin(CppEditor
|
|||||||
quickfixes/cppquickfixsettingswidget.cpp quickfixes/cppquickfixsettingswidget.h
|
quickfixes/cppquickfixsettingswidget.cpp quickfixes/cppquickfixsettingswidget.h
|
||||||
quickfixes/convertqt4connect.cpp quickfixes/convertqt4connect.h
|
quickfixes/convertqt4connect.cpp quickfixes/convertqt4connect.h
|
||||||
quickfixes/moveclasstoownfile.cpp quickfixes/moveclasstoownfile.h
|
quickfixes/moveclasstoownfile.cpp quickfixes/moveclasstoownfile.h
|
||||||
|
quickfixes/movefunctiondefinition.cpp quickfixes/movefunctiondefinition.h
|
||||||
quickfixes/removeusingnamespace.cpp quickfixes/removeusingnamespace.h
|
quickfixes/removeusingnamespace.cpp quickfixes/removeusingnamespace.h
|
||||||
resourcepreviewhoverhandler.cpp resourcepreviewhoverhandler.h
|
resourcepreviewhoverhandler.cpp resourcepreviewhoverhandler.h
|
||||||
searchsymbols.cpp searchsymbols.h
|
searchsymbols.cpp searchsymbols.h
|
||||||
|
@@ -245,6 +245,8 @@ QtcPlugin {
|
|||||||
"cppquickfixsettingswidget.h",
|
"cppquickfixsettingswidget.h",
|
||||||
"moveclasstoownfile.cpp",
|
"moveclasstoownfile.cpp",
|
||||||
"moveclasstoownfile.h",
|
"moveclasstoownfile.h",
|
||||||
|
"movefunctiondefinition.cpp",
|
||||||
|
"movefunctiondefinition.h",
|
||||||
"removeusingnamespace.cpp",
|
"removeusingnamespace.cpp",
|
||||||
"removeusingnamespace.h",
|
"removeusingnamespace.h",
|
||||||
]
|
]
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -152,40 +152,6 @@ private slots:
|
|||||||
void testAddForwardDeclForUndefinedIdentifier_data();
|
void testAddForwardDeclForUndefinedIdentifier_data();
|
||||||
void testAddForwardDeclForUndefinedIdentifier();
|
void testAddForwardDeclForUndefinedIdentifier();
|
||||||
|
|
||||||
void testMoveFuncDefOutsideMemberFuncToCpp();
|
|
||||||
void testMoveFuncDefOutsideMemberFuncToCppInsideNS();
|
|
||||||
void testMoveFuncDefOutsideMemberFuncOutside1();
|
|
||||||
void testMoveFuncDefOutsideMemberFuncOutside2();
|
|
||||||
void testMoveFuncDefOutsideMemberFuncToCppNS();
|
|
||||||
void testMoveFuncDefOutsideMemberFuncToCppNSUsing();
|
|
||||||
void testMoveFuncDefOutsideMemberFuncOutsideWithNs();
|
|
||||||
void testMoveFuncDefOutsideFreeFuncToCpp();
|
|
||||||
void testMoveFuncDefOutsideFreeFuncToCppNS();
|
|
||||||
void testMoveFuncDefOutsideCtorWithInitialization1();
|
|
||||||
void testMoveFuncDefOutsideCtorWithInitialization2();
|
|
||||||
void testMoveFuncDefOutsideAfterClass();
|
|
||||||
void testMoveFuncDefOutsideRespectWsInOperatorNames1();
|
|
||||||
void testMoveFuncDefOutsideRespectWsInOperatorNames2();
|
|
||||||
void testMoveFuncDefOutsideMacroUses();
|
|
||||||
void testMoveFuncDefOutsideTemplate();
|
|
||||||
void testMoveFuncDefOutsideMemberFunctionTemplate();
|
|
||||||
void testMoveFuncDefOutsideTemplateSpecializedClass();
|
|
||||||
void testMoveFuncDefOutsideUnnamedTemplate();
|
|
||||||
void testMoveFuncDefOutsideMemberFuncToCppStatic();
|
|
||||||
void testMoveFuncDefOutsideMemberFuncToCppWithInlinePartOfName();
|
|
||||||
void testMoveFuncDefOutsideMixedQualifiers();
|
|
||||||
|
|
||||||
void testMoveAllFuncDefOutsideMemberFuncToCpp();
|
|
||||||
void testMoveAllFuncDefOutsideMemberFuncOutside();
|
|
||||||
void testMoveAllFuncDefOutsideDoNotTriggerOnBaseClass();
|
|
||||||
void testMoveAllFuncDefOutsideClassWithBaseClass();
|
|
||||||
void testMoveAllFuncDefOutsideIgnoreMacroCode();
|
|
||||||
|
|
||||||
void testMoveFuncDefToDecl_data();
|
|
||||||
void testMoveFuncDefToDecl();
|
|
||||||
|
|
||||||
void testMoveFuncDefToDeclMacroUses();
|
|
||||||
|
|
||||||
void testAssignToLocalVariableTemplates();
|
void testAssignToLocalVariableTemplates();
|
||||||
|
|
||||||
void testExtractFunction_data();
|
void testExtractFunction_data();
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include "cppquickfixprojectsettings.h"
|
#include "cppquickfixprojectsettings.h"
|
||||||
#include "convertqt4connect.h"
|
#include "convertqt4connect.h"
|
||||||
#include "moveclasstoownfile.h"
|
#include "moveclasstoownfile.h"
|
||||||
|
#include "movefunctiondefinition.h"
|
||||||
#include "removeusingnamespace.h"
|
#include "removeusingnamespace.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
@@ -126,15 +127,6 @@ const QList<CppQuickFixFactory *> &CppQuickFixFactory::cppQuickFixFactories()
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
QString inlinePrefix(const FilePath &targetFile, const std::function<bool()> &extraCondition = {})
|
|
||||||
{
|
|
||||||
if (ProjectFile::isHeader(ProjectFile::classify(targetFile.path()))
|
|
||||||
&& (!extraCondition || extraCondition())) {
|
|
||||||
return "inline ";
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the following anonymous namespace all functions are collected, which could be of interest for
|
// In the following anonymous namespace all functions are collected, which could be of interest for
|
||||||
// different quick fixes.
|
// different quick fixes.
|
||||||
namespace {
|
namespace {
|
||||||
@@ -157,84 +149,6 @@ inline bool isQtStringTranslation(const QByteArray &id)
|
|||||||
return id == "tr" || id == "trUtf8" || id == "translate" || id == "QT_TRANSLATE_NOOP";
|
return id == "tr" || id == "trUtf8" || id == "translate" || id == "QT_TRANSLATE_NOOP";
|
||||||
}
|
}
|
||||||
|
|
||||||
Class *isMemberFunction(const LookupContext &context, Function *function)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(function, return nullptr);
|
|
||||||
|
|
||||||
Scope *enclosingScope = function->enclosingScope();
|
|
||||||
while (!(enclosingScope->asNamespace() || enclosingScope->asClass()))
|
|
||||||
enclosingScope = enclosingScope->enclosingScope();
|
|
||||||
QTC_ASSERT(enclosingScope != nullptr, return nullptr);
|
|
||||||
|
|
||||||
const Name *functionName = function->name();
|
|
||||||
if (!functionName)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (!functionName->asQualifiedNameId())
|
|
||||||
return nullptr; // trying to add a declaration for a global function
|
|
||||||
|
|
||||||
const QualifiedNameId *q = functionName->asQualifiedNameId();
|
|
||||||
if (!q->base())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (ClassOrNamespace *binding = context.lookupType(q->base(), enclosingScope)) {
|
|
||||||
const QList<Symbol *> symbols = binding->symbols();
|
|
||||||
for (Symbol *s : symbols) {
|
|
||||||
if (Class *matchingClass = s->asClass())
|
|
||||||
return matchingClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Namespace *isNamespaceFunction(const LookupContext &context, Function *function)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(function, return nullptr);
|
|
||||||
if (isMemberFunction(context, function))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
Scope *enclosingScope = function->enclosingScope();
|
|
||||||
while (!(enclosingScope->asNamespace() || enclosingScope->asClass()))
|
|
||||||
enclosingScope = enclosingScope->enclosingScope();
|
|
||||||
QTC_ASSERT(enclosingScope != nullptr, return nullptr);
|
|
||||||
|
|
||||||
const Name *functionName = function->name();
|
|
||||||
if (!functionName)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// global namespace
|
|
||||||
if (!functionName->asQualifiedNameId()) {
|
|
||||||
const QList<Symbol *> symbols = context.globalNamespace()->symbols();
|
|
||||||
for (Symbol *s : symbols) {
|
|
||||||
if (Namespace *matchingNamespace = s->asNamespace())
|
|
||||||
return matchingNamespace;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QualifiedNameId *q = functionName->asQualifiedNameId();
|
|
||||||
if (!q->base())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (ClassOrNamespace *binding = context.lookupType(q->base(), enclosingScope)) {
|
|
||||||
const QList<Symbol *> symbols = binding->symbols();
|
|
||||||
for (Symbol *s : symbols) {
|
|
||||||
if (Namespace *matchingNamespace = s->asNamespace())
|
|
||||||
return matchingNamespace;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nameIncludesOperatorName(const Name *name)
|
|
||||||
{
|
|
||||||
return name->asOperatorNameId()
|
|
||||||
|| (name->asQualifiedNameId() && name->asQualifiedNameId()->name()->asOperatorNameId());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString nameString(const NameAST *name)
|
QString nameString(const NameAST *name)
|
||||||
{
|
{
|
||||||
return CppCodeStyleSettings::currentProjectCodeStyleOverview().prettyName(name->name);
|
return CppCodeStyleSettings::currentProjectCodeStyleOverview().prettyName(name->name);
|
||||||
@@ -4895,561 +4809,6 @@ void ApplyDeclDefLinkChanges::doMatch(const CppQuickFixInterface &interface,
|
|||||||
result << op;
|
result << op;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
QString definitionSignature(const CppQuickFixInterface *assist,
|
|
||||||
FunctionDefinitionAST *functionDefinitionAST,
|
|
||||||
CppRefactoringFilePtr &baseFile,
|
|
||||||
CppRefactoringFilePtr &targetFile,
|
|
||||||
Scope *scope)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(assist, return QString());
|
|
||||||
QTC_ASSERT(functionDefinitionAST, return QString());
|
|
||||||
QTC_ASSERT(scope, return QString());
|
|
||||||
Function *func = functionDefinitionAST->symbol;
|
|
||||||
QTC_ASSERT(func, return QString());
|
|
||||||
|
|
||||||
LookupContext cppContext(targetFile->cppDocument(), assist->snapshot());
|
|
||||||
ClassOrNamespace *cppCoN = cppContext.lookupType(scope);
|
|
||||||
if (!cppCoN)
|
|
||||||
cppCoN = cppContext.globalNamespace();
|
|
||||||
SubstitutionEnvironment env;
|
|
||||||
env.setContext(assist->context());
|
|
||||||
env.switchScope(func->enclosingScope());
|
|
||||||
UseMinimalNames q(cppCoN);
|
|
||||||
env.enter(&q);
|
|
||||||
Control *control = assist->context().bindings()->control().get();
|
|
||||||
Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
|
|
||||||
oo.showFunctionSignatures = true;
|
|
||||||
oo.showReturnTypes = true;
|
|
||||||
oo.showArgumentNames = true;
|
|
||||||
oo.showEnclosingTemplate = true;
|
|
||||||
oo.showTemplateParameters = true;
|
|
||||||
oo.trailingReturnType = functionDefinitionAST->declarator
|
|
||||||
&& functionDefinitionAST->declarator->postfix_declarator_list
|
|
||||||
&& functionDefinitionAST->declarator->postfix_declarator_list->value
|
|
||||||
&& functionDefinitionAST->declarator->postfix_declarator_list
|
|
||||||
->value->asFunctionDeclarator()
|
|
||||||
&& functionDefinitionAST->declarator->postfix_declarator_list
|
|
||||||
->value->asFunctionDeclarator()->trailing_return_type;
|
|
||||||
const Name *name = func->name();
|
|
||||||
if (name && nameIncludesOperatorName(name)) {
|
|
||||||
CoreDeclaratorAST *coreDeclarator = functionDefinitionAST->declarator->core_declarator;
|
|
||||||
const QString operatorNameText = baseFile->textOf(coreDeclarator);
|
|
||||||
oo.includeWhiteSpaceInOperatorName = operatorNameText.contains(QLatin1Char(' '));
|
|
||||||
}
|
|
||||||
const QString nameText = oo.prettyName(LookupContext::minimalName(func, cppCoN, control));
|
|
||||||
oo.showTemplateParameters = false;
|
|
||||||
const FullySpecifiedType tn = rewriteType(func->type(), &env, control);
|
|
||||||
|
|
||||||
return oo.prettyType(tn, nameText);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MoveFuncDefRefactoringHelper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum MoveType {
|
|
||||||
MoveOutside,
|
|
||||||
MoveToCppFile,
|
|
||||||
MoveOutsideMemberToCppFile
|
|
||||||
};
|
|
||||||
|
|
||||||
MoveFuncDefRefactoringHelper(CppQuickFixOperation *operation, MoveType type,
|
|
||||||
const FilePath &fromFile, const FilePath &toFile)
|
|
||||||
: m_operation(operation), m_type(type), m_changes(m_operation->snapshot())
|
|
||||||
{
|
|
||||||
m_fromFile = m_changes.cppFile(fromFile);
|
|
||||||
m_toFile = (m_type == MoveOutside) ? m_fromFile : m_changes.cppFile(toFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void performMove(FunctionDefinitionAST *funcAST)
|
|
||||||
{
|
|
||||||
// Determine file, insert position and scope
|
|
||||||
InsertionLocation l = insertLocationForMethodDefinition(
|
|
||||||
funcAST->symbol, false, NamespaceHandling::Ignore,
|
|
||||||
m_changes, m_toFile->filePath());
|
|
||||||
const QString prefix = l.prefix();
|
|
||||||
const QString suffix = l.suffix();
|
|
||||||
const int insertPos = m_toFile->position(l.line(), l.column());
|
|
||||||
Scope *scopeAtInsertPos = m_toFile->cppDocument()->scopeAt(l.line(), l.column());
|
|
||||||
|
|
||||||
// construct definition
|
|
||||||
const QString funcDec = inlinePrefix(m_toFile->filePath(), [this] { return m_type == MoveOutside; })
|
|
||||||
+ definitionSignature(m_operation, funcAST, m_fromFile, m_toFile,
|
|
||||||
scopeAtInsertPos);
|
|
||||||
QString funcDef = prefix + funcDec;
|
|
||||||
const int startPosition = m_fromFile->endOf(funcAST->declarator);
|
|
||||||
const int endPosition = m_fromFile->endOf(funcAST);
|
|
||||||
funcDef += m_fromFile->textOf(startPosition, endPosition);
|
|
||||||
funcDef += suffix;
|
|
||||||
|
|
||||||
// insert definition at new position
|
|
||||||
m_toFileChangeSet.insert(insertPos, funcDef);
|
|
||||||
m_toFile->setOpenEditor(true, insertPos);
|
|
||||||
|
|
||||||
// remove definition from fromFile
|
|
||||||
if (m_type == MoveOutsideMemberToCppFile) {
|
|
||||||
m_fromFileChangeSet.remove(m_fromFile->range(funcAST));
|
|
||||||
} else {
|
|
||||||
QString textFuncDecl = m_fromFile->textOf(funcAST);
|
|
||||||
textFuncDecl.truncate(startPosition - m_fromFile->startOf(funcAST));
|
|
||||||
if (textFuncDecl.left(7) == QLatin1String("inline "))
|
|
||||||
textFuncDecl = textFuncDecl.mid(7);
|
|
||||||
else
|
|
||||||
textFuncDecl.replace(" inline ", QLatin1String(" "));
|
|
||||||
textFuncDecl = textFuncDecl.trimmed() + QLatin1Char(';');
|
|
||||||
m_fromFileChangeSet.replace(m_fromFile->range(funcAST), textFuncDecl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void applyChanges()
|
|
||||||
{
|
|
||||||
if (!m_toFileChangeSet.isEmpty()) {
|
|
||||||
m_toFile->setChangeSet(m_toFileChangeSet);
|
|
||||||
m_toFile->apply();
|
|
||||||
}
|
|
||||||
if (!m_fromFileChangeSet.isEmpty()) {
|
|
||||||
m_fromFile->setChangeSet(m_fromFileChangeSet);
|
|
||||||
m_fromFile->apply();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CppQuickFixOperation *m_operation;
|
|
||||||
MoveType m_type;
|
|
||||||
CppRefactoringChanges m_changes;
|
|
||||||
CppRefactoringFilePtr m_fromFile;
|
|
||||||
CppRefactoringFilePtr m_toFile;
|
|
||||||
ChangeSet m_fromFileChangeSet;
|
|
||||||
ChangeSet m_toFileChangeSet;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MoveFuncDefOutsideOp : public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MoveFuncDefOutsideOp(const CppQuickFixInterface &interface,
|
|
||||||
MoveFuncDefRefactoringHelper::MoveType type,
|
|
||||||
FunctionDefinitionAST *funcDef, const FilePath &cppFilePath)
|
|
||||||
: CppQuickFixOperation(interface, 0)
|
|
||||||
, m_funcDef(funcDef)
|
|
||||||
, m_type(type)
|
|
||||||
, m_cppFilePath(cppFilePath)
|
|
||||||
, m_headerFilePath(funcDef->symbol->filePath())
|
|
||||||
{
|
|
||||||
if (m_type == MoveFuncDefRefactoringHelper::MoveOutside) {
|
|
||||||
setDescription(Tr::tr("Move Definition Outside Class"));
|
|
||||||
} else {
|
|
||||||
const FilePath resolved = m_cppFilePath.relativePathFrom(m_headerFilePath.parentDir());
|
|
||||||
setDescription(Tr::tr("Move Definition to %1").arg(resolved.displayName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
MoveFuncDefRefactoringHelper helper(this, m_type, m_headerFilePath, m_cppFilePath);
|
|
||||||
helper.performMove(m_funcDef);
|
|
||||||
helper.applyChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
FunctionDefinitionAST *m_funcDef;
|
|
||||||
MoveFuncDefRefactoringHelper::MoveType m_type;
|
|
||||||
const FilePath m_cppFilePath;
|
|
||||||
const FilePath m_headerFilePath;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void MoveFuncDefOutside::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
const QList<AST *> &path = interface.path();
|
|
||||||
SimpleDeclarationAST *classAST = nullptr;
|
|
||||||
FunctionDefinitionAST *funcAST = nullptr;
|
|
||||||
bool moveOutsideMemberDefinition = false;
|
|
||||||
|
|
||||||
const int pathSize = path.size();
|
|
||||||
for (int idx = 1; idx < pathSize; ++idx) {
|
|
||||||
if ((funcAST = path.at(idx)->asFunctionDefinition())) {
|
|
||||||
// check cursor position
|
|
||||||
if (idx != pathSize - 1 // Do not allow "void a() @ {..."
|
|
||||||
&& funcAST->function_body
|
|
||||||
&& !interface.isCursorOn(funcAST->function_body)) {
|
|
||||||
if (path.at(idx - 1)->asTranslationUnit()) { // normal function
|
|
||||||
if (idx + 3 < pathSize && path.at(idx + 3)->asQualifiedName()) // Outside member
|
|
||||||
moveOutsideMemberDefinition = true; // definition
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx > 1) {
|
|
||||||
if ((classAST = path.at(idx - 2)->asSimpleDeclaration())) // member function
|
|
||||||
break;
|
|
||||||
if (path.at(idx - 2)->asNamespace()) // normal function in namespace
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (idx > 2 && path.at(idx - 1)->asTemplateDeclaration()) {
|
|
||||||
if ((classAST = path.at(idx - 3)->asSimpleDeclaration())) // member template
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
funcAST = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!funcAST || !funcAST->symbol)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool isHeaderFile = false;
|
|
||||||
const FilePath cppFileName = correspondingHeaderOrSource(interface.filePath(), &isHeaderFile);
|
|
||||||
|
|
||||||
if (isHeaderFile && !cppFileName.isEmpty()) {
|
|
||||||
const MoveFuncDefRefactoringHelper::MoveType type = moveOutsideMemberDefinition
|
|
||||||
? MoveFuncDefRefactoringHelper::MoveOutsideMemberToCppFile
|
|
||||||
: MoveFuncDefRefactoringHelper::MoveToCppFile;
|
|
||||||
result << new MoveFuncDefOutsideOp(interface, type, funcAST, cppFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (classAST)
|
|
||||||
result << new MoveFuncDefOutsideOp(interface, MoveFuncDefRefactoringHelper::MoveOutside,
|
|
||||||
funcAST, FilePath());
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class MoveAllFuncDefOutsideOp : public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MoveAllFuncDefOutsideOp(const CppQuickFixInterface &interface,
|
|
||||||
MoveFuncDefRefactoringHelper::MoveType type,
|
|
||||||
ClassSpecifierAST *classDef, const FilePath &cppFileName)
|
|
||||||
: CppQuickFixOperation(interface, 0)
|
|
||||||
, m_type(type)
|
|
||||||
, m_classDef(classDef)
|
|
||||||
, m_cppFilePath(cppFileName)
|
|
||||||
, m_headerFilePath(classDef->symbol->filePath())
|
|
||||||
{
|
|
||||||
if (m_type == MoveFuncDefRefactoringHelper::MoveOutside) {
|
|
||||||
setDescription(Tr::tr("Definitions Outside Class"));
|
|
||||||
} else {
|
|
||||||
const FilePath resolved = m_cppFilePath.relativePathFrom(m_headerFilePath.parentDir());
|
|
||||||
setDescription(Tr::tr("Move All Function Definitions to %1")
|
|
||||||
.arg(resolved.displayName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
MoveFuncDefRefactoringHelper helper(this, m_type, m_headerFilePath, m_cppFilePath);
|
|
||||||
for (DeclarationListAST *it = m_classDef->member_specifier_list; it; it = it->next) {
|
|
||||||
if (FunctionDefinitionAST *funcAST = it->value->asFunctionDefinition()) {
|
|
||||||
if (funcAST->symbol && !funcAST->symbol->isGenerated())
|
|
||||||
helper.performMove(funcAST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
helper.applyChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
MoveFuncDefRefactoringHelper::MoveType m_type;
|
|
||||||
ClassSpecifierAST *m_classDef;
|
|
||||||
const FilePath m_cppFilePath;
|
|
||||||
const FilePath m_headerFilePath;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void MoveAllFuncDefOutside::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
ClassSpecifierAST * const classAST = astForClassOperations(interface);
|
|
||||||
if (!classAST)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Determine if the class has at least one function definition
|
|
||||||
bool classContainsFunctions = false;
|
|
||||||
for (DeclarationListAST *it = classAST->member_specifier_list; it; it = it->next) {
|
|
||||||
if (FunctionDefinitionAST *funcAST = it->value->asFunctionDefinition()) {
|
|
||||||
if (funcAST->symbol && !funcAST->symbol->isGenerated()) {
|
|
||||||
classContainsFunctions = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!classContainsFunctions)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool isHeaderFile = false;
|
|
||||||
const FilePath cppFileName = correspondingHeaderOrSource(interface.filePath(), &isHeaderFile);
|
|
||||||
if (isHeaderFile && !cppFileName.isEmpty()) {
|
|
||||||
result << new MoveAllFuncDefOutsideOp(interface,
|
|
||||||
MoveFuncDefRefactoringHelper::MoveToCppFile,
|
|
||||||
classAST, cppFileName);
|
|
||||||
}
|
|
||||||
result << new MoveAllFuncDefOutsideOp(interface, MoveFuncDefRefactoringHelper::MoveOutside,
|
|
||||||
classAST, FilePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class MoveFuncDefToDeclOp : public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Type { Push, Pull };
|
|
||||||
MoveFuncDefToDeclOp(const CppQuickFixInterface &interface,
|
|
||||||
const FilePath &fromFilePath, const FilePath &toFilePath,
|
|
||||||
FunctionDefinitionAST *funcAst, Function *func, const QString &declText,
|
|
||||||
const ChangeSet::Range &fromRange,
|
|
||||||
const ChangeSet::Range &toRange,
|
|
||||||
Type type)
|
|
||||||
: CppQuickFixOperation(interface, 0)
|
|
||||||
, m_fromFilePath(fromFilePath)
|
|
||||||
, m_toFilePath(toFilePath)
|
|
||||||
, m_funcAST(funcAst)
|
|
||||||
, m_func(func)
|
|
||||||
, m_declarationText(declText)
|
|
||||||
, m_fromRange(fromRange)
|
|
||||||
, m_toRange(toRange)
|
|
||||||
{
|
|
||||||
if (type == Type::Pull) {
|
|
||||||
setDescription(Tr::tr("Move Definition Here"));
|
|
||||||
} else if (m_toFilePath == m_fromFilePath) {
|
|
||||||
setDescription(Tr::tr("Move Definition to Class"));
|
|
||||||
} else {
|
|
||||||
const FilePath resolved = m_toFilePath.relativePathFrom(m_fromFilePath.parentDir());
|
|
||||||
setDescription(Tr::tr("Move Definition to %1").arg(resolved.displayName()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
|
||||||
CppRefactoringFilePtr fromFile = refactoring.cppFile(m_fromFilePath);
|
|
||||||
CppRefactoringFilePtr toFile = refactoring.cppFile(m_toFilePath);
|
|
||||||
|
|
||||||
ensureFuncDefAstAndRange(*fromFile);
|
|
||||||
if (!m_funcAST)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const QString wholeFunctionText = m_declarationText
|
|
||||||
+ fromFile->textOf(fromFile->endOf(m_funcAST->declarator),
|
|
||||||
fromFile->endOf(m_funcAST->function_body));
|
|
||||||
|
|
||||||
// Replace declaration with function and delete old definition
|
|
||||||
ChangeSet toTarget;
|
|
||||||
toTarget.replace(m_toRange, wholeFunctionText);
|
|
||||||
if (m_toFilePath == m_fromFilePath)
|
|
||||||
toTarget.remove(m_fromRange);
|
|
||||||
toFile->setChangeSet(toTarget);
|
|
||||||
toFile->setOpenEditor(true, m_toRange.start);
|
|
||||||
toFile->apply();
|
|
||||||
if (m_toFilePath != m_fromFilePath) {
|
|
||||||
ChangeSet fromTarget;
|
|
||||||
fromTarget.remove(m_fromRange);
|
|
||||||
fromFile->setChangeSet(fromTarget);
|
|
||||||
fromFile->apply();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ensureFuncDefAstAndRange(CppRefactoringFile &defFile)
|
|
||||||
{
|
|
||||||
if (m_funcAST) {
|
|
||||||
QTC_CHECK(m_fromRange.end > m_fromRange.start);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QTC_ASSERT(m_func, return);
|
|
||||||
const QList<AST *> astPath = ASTPath(defFile.cppDocument())(m_func->line(),
|
|
||||||
m_func->column());
|
|
||||||
if (astPath.isEmpty())
|
|
||||||
return;
|
|
||||||
for (auto it = std::rbegin(astPath); it != std::rend(astPath); ++it) {
|
|
||||||
m_funcAST = (*it)->asFunctionDefinition();
|
|
||||||
if (!m_funcAST)
|
|
||||||
continue;
|
|
||||||
AST *astForRange = m_funcAST;
|
|
||||||
const auto prev = std::next(it);
|
|
||||||
if (prev != std::rend(astPath)) {
|
|
||||||
if (const auto templAst = (*prev)->asTemplateDeclaration())
|
|
||||||
astForRange = templAst;
|
|
||||||
}
|
|
||||||
m_fromRange = defFile.range(astForRange);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const FilePath m_fromFilePath;
|
|
||||||
const FilePath m_toFilePath;
|
|
||||||
FunctionDefinitionAST *m_funcAST;
|
|
||||||
Function *m_func;
|
|
||||||
const QString m_declarationText;
|
|
||||||
ChangeSet::Range m_fromRange;
|
|
||||||
const ChangeSet::Range m_toRange;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void MoveFuncDefToDeclPush::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
const QList<AST *> &path = interface.path();
|
|
||||||
AST *completeDefAST = nullptr;
|
|
||||||
FunctionDefinitionAST *funcAST = nullptr;
|
|
||||||
|
|
||||||
const int pathSize = path.size();
|
|
||||||
for (int idx = 1; idx < pathSize; ++idx) {
|
|
||||||
if ((funcAST = path.at(idx)->asFunctionDefinition())) {
|
|
||||||
AST *enclosingAST = path.at(idx - 1);
|
|
||||||
if (enclosingAST->asClassSpecifier())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// check cursor position
|
|
||||||
if (idx != pathSize - 1 // Do not allow "void a() @ {..."
|
|
||||||
&& funcAST->function_body
|
|
||||||
&& !interface.isCursorOn(funcAST->function_body)) {
|
|
||||||
completeDefAST = enclosingAST->asTemplateDeclaration() ? enclosingAST : funcAST;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
funcAST = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!funcAST || !funcAST->symbol)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const CppRefactoringChanges refactoring(interface.snapshot());
|
|
||||||
const CppRefactoringFilePtr defFile = refactoring.cppFile(interface.filePath());
|
|
||||||
const ChangeSet::Range defRange = defFile->range(completeDefAST);
|
|
||||||
|
|
||||||
// Determine declaration (file, range, text);
|
|
||||||
ChangeSet::Range declRange;
|
|
||||||
QString declText;
|
|
||||||
FilePath declFilePath;
|
|
||||||
|
|
||||||
Function *func = funcAST->symbol;
|
|
||||||
if (Class *matchingClass = isMemberFunction(interface.context(), func)) {
|
|
||||||
// Dealing with member functions
|
|
||||||
const QualifiedNameId *qName = func->name()->asQualifiedNameId();
|
|
||||||
for (Symbol *symbol = matchingClass->find(qName->identifier());
|
|
||||||
symbol; symbol = symbol->next()) {
|
|
||||||
Symbol *s = symbol;
|
|
||||||
if (func->enclosingScope()->asTemplate()) {
|
|
||||||
if (const Template *templ = s->type()->asTemplateType()) {
|
|
||||||
if (Symbol *decl = templ->declaration()) {
|
|
||||||
if (decl->type()->asFunctionType())
|
|
||||||
s = decl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!s->name()
|
|
||||||
|| !qName->identifier()->match(s->identifier())
|
|
||||||
|| !s->type()->asFunctionType()
|
|
||||||
|| !s->type().match(func->type())
|
|
||||||
|| s->asFunction()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
declFilePath = matchingClass->filePath();
|
|
||||||
const CppRefactoringFilePtr declFile = refactoring.cppFile(declFilePath);
|
|
||||||
ASTPath astPath(declFile->cppDocument());
|
|
||||||
const QList<AST *> path = astPath(s->line(), s->column());
|
|
||||||
for (int idx = path.size() - 1; idx > 0; --idx) {
|
|
||||||
AST *node = path.at(idx);
|
|
||||||
if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) {
|
|
||||||
if (simpleDecl->symbols && !simpleDecl->symbols->next) {
|
|
||||||
declRange = declFile->range(simpleDecl);
|
|
||||||
declText = declFile->textOf(simpleDecl);
|
|
||||||
declText.remove(-1, 1); // remove ';' from declaration text
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!declText.isEmpty())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (Namespace *matchingNamespace = isNamespaceFunction(interface.context(), func)) {
|
|
||||||
// Dealing with free functions
|
|
||||||
bool isHeaderFile = false;
|
|
||||||
declFilePath = correspondingHeaderOrSource(interface.filePath(), &isHeaderFile);
|
|
||||||
if (isHeaderFile)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const CppRefactoringFilePtr declFile = refactoring.cppFile(declFilePath);
|
|
||||||
const LookupContext lc(declFile->cppDocument(), interface.snapshot());
|
|
||||||
const QList<LookupItem> candidates = lc.lookup(func->name(), matchingNamespace);
|
|
||||||
for (const LookupItem &candidate : candidates) {
|
|
||||||
if (Symbol *s = candidate.declaration()) {
|
|
||||||
if (s->asDeclaration()) {
|
|
||||||
ASTPath astPath(declFile->cppDocument());
|
|
||||||
const QList<AST *> path = astPath(s->line(), s->column());
|
|
||||||
for (AST *node : path) {
|
|
||||||
if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) {
|
|
||||||
declRange = declFile->range(simpleDecl);
|
|
||||||
declText = declFile->textOf(simpleDecl);
|
|
||||||
declText.remove(-1, 1); // remove ';' from declaration text
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!declText.isEmpty()) {
|
|
||||||
declText.prepend(inlinePrefix(declFilePath));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!declFilePath.isEmpty() && !declText.isEmpty())
|
|
||||||
result << new MoveFuncDefToDeclOp(interface,
|
|
||||||
interface.filePath(),
|
|
||||||
declFilePath,
|
|
||||||
funcAST, func, declText,
|
|
||||||
defRange, declRange, MoveFuncDefToDeclOp::Push);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveFuncDefToDeclPull::doMatch(const CppQuickFixInterface &interface,
|
|
||||||
QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
const QList<AST *> &path = interface.path();
|
|
||||||
for (auto it = std::rbegin(path); it != std::rend(path); ++it) {
|
|
||||||
SimpleDeclarationAST * const simpleDecl = (*it)->asSimpleDeclaration();
|
|
||||||
if (!simpleDecl)
|
|
||||||
continue;
|
|
||||||
const auto prev = std::next(it);
|
|
||||||
if (prev != std::rend(path) && (*prev)->asStatement())
|
|
||||||
return;
|
|
||||||
if (!simpleDecl->symbols || !simpleDecl->symbols->value || simpleDecl->symbols->next)
|
|
||||||
return;
|
|
||||||
Declaration * const decl = simpleDecl->symbols->value->asDeclaration();
|
|
||||||
if (!decl)
|
|
||||||
return;
|
|
||||||
Function * const funcDecl = decl->type()->asFunctionType();
|
|
||||||
if (!funcDecl)
|
|
||||||
return;
|
|
||||||
if (funcDecl->isSignal() || funcDecl->isPureVirtual() || funcDecl->isFriend())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Is there a definition?
|
|
||||||
SymbolFinder symbolFinder;
|
|
||||||
Function * const funcDef = symbolFinder.findMatchingDefinition(decl, interface.snapshot(),
|
|
||||||
true);
|
|
||||||
if (!funcDef)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QString declText = interface.currentFile()->textOf(simpleDecl);
|
|
||||||
declText.chop(1); // semicolon
|
|
||||||
declText.prepend(inlinePrefix(interface.filePath(), [funcDecl] {
|
|
||||||
return !funcDecl->enclosingScope()->asClass();
|
|
||||||
}));
|
|
||||||
result << new MoveFuncDefToDeclOp(interface, funcDef->filePath(), decl->filePath(), nullptr,
|
|
||||||
funcDef, declText, {},
|
|
||||||
interface.currentFile()->range(simpleDecl),
|
|
||||||
MoveFuncDefToDeclOp::Pull);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class AssignToLocalVariableOperation : public CppQuickFixOperation
|
class AssignToLocalVariableOperation : public CppQuickFixOperation
|
||||||
@@ -6639,11 +5998,6 @@ void createCppQuickFixes()
|
|||||||
new AddDeclarationForUndeclaredIdentifier;
|
new AddDeclarationForUndeclaredIdentifier;
|
||||||
new InsertDefsFromDecls;
|
new InsertDefsFromDecls;
|
||||||
|
|
||||||
new MoveFuncDefOutside;
|
|
||||||
new MoveAllFuncDefOutside;
|
|
||||||
new MoveFuncDefToDeclPush;
|
|
||||||
new MoveFuncDefToDeclPull;
|
|
||||||
|
|
||||||
new AssignToLocalVariable;
|
new AssignToLocalVariable;
|
||||||
|
|
||||||
registerInsertVirtualMethodsQuickfix();
|
registerInsertVirtualMethodsQuickfix();
|
||||||
@@ -6651,6 +6005,7 @@ void createCppQuickFixes()
|
|||||||
registerRemoveUsingNamespaceQuickfix();
|
registerRemoveUsingNamespaceQuickfix();
|
||||||
registerCodeGenerationQuickfixes();
|
registerCodeGenerationQuickfixes();
|
||||||
registerConvertQt4ConnectQuickfix();
|
registerConvertQt4ConnectQuickfix();
|
||||||
|
registerMoveFunctionDefinitionQuickfixes();
|
||||||
|
|
||||||
new OptimizeForLoop;
|
new OptimizeForLoop;
|
||||||
|
|
||||||
|
@@ -462,43 +462,6 @@ public:
|
|||||||
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
Moves the definition of a member function outside the class or moves the definition of a member
|
|
||||||
function or a normal function to the implementation file.
|
|
||||||
*/
|
|
||||||
class MoveFuncDefOutside: public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Moves all member function definitions outside the class or to the implementation file.
|
|
||||||
*/
|
|
||||||
class MoveAllFuncDefOutside: public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Moves the definition of a function to its declaration, with the cursor on the definition.
|
|
||||||
*/
|
|
||||||
class MoveFuncDefToDeclPush : public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Moves the definition of a function to its declaration, with the cursor on the declaration.
|
|
||||||
*/
|
|
||||||
class MoveFuncDefToDeclPull : public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Assigns the return value of a function call or a new expression to a local variable
|
Assigns the return value of a function call or a new expression to a local variable
|
||||||
*/
|
*/
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "cppquickfixhelpers.h"
|
#include "cppquickfixhelpers.h"
|
||||||
|
|
||||||
|
#include "../cppprojectfile.h"
|
||||||
#include "../includeutils.h"
|
#include "../includeutils.h"
|
||||||
#include "cppquickfixassistant.h"
|
#include "cppquickfixassistant.h"
|
||||||
|
|
||||||
@@ -65,4 +66,91 @@ ClassSpecifierAST *astForClassOperations(const CppQuickFixInterface &interface)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nameIncludesOperatorName(const Name *name)
|
||||||
|
{
|
||||||
|
return name->asOperatorNameId()
|
||||||
|
|| (name->asQualifiedNameId() && name->asQualifiedNameId()->name()->asOperatorNameId());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString inlinePrefix(const FilePath &targetFile, const std::function<bool()> &extraCondition)
|
||||||
|
{
|
||||||
|
if (ProjectFile::isHeader(ProjectFile::classify(targetFile.path()))
|
||||||
|
&& (!extraCondition || extraCondition())) {
|
||||||
|
return "inline ";
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Class *isMemberFunction(const CPlusPlus::LookupContext &context, CPlusPlus::Function *function)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(function, return nullptr);
|
||||||
|
|
||||||
|
Scope *enclosingScope = function->enclosingScope();
|
||||||
|
while (!(enclosingScope->asNamespace() || enclosingScope->asClass()))
|
||||||
|
enclosingScope = enclosingScope->enclosingScope();
|
||||||
|
QTC_ASSERT(enclosingScope != nullptr, return nullptr);
|
||||||
|
|
||||||
|
const Name *functionName = function->name();
|
||||||
|
if (!functionName)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!functionName->asQualifiedNameId())
|
||||||
|
return nullptr; // trying to add a declaration for a global function
|
||||||
|
|
||||||
|
const QualifiedNameId *q = functionName->asQualifiedNameId();
|
||||||
|
if (!q->base())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (ClassOrNamespace *binding = context.lookupType(q->base(), enclosingScope)) {
|
||||||
|
const QList<Symbol *> symbols = binding->symbols();
|
||||||
|
for (Symbol *s : symbols) {
|
||||||
|
if (Class *matchingClass = s->asClass())
|
||||||
|
return matchingClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPlusPlus::Namespace *isNamespaceFunction(
|
||||||
|
const CPlusPlus::LookupContext &context, CPlusPlus::Function *function)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(function, return nullptr);
|
||||||
|
if (isMemberFunction(context, function))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
Scope *enclosingScope = function->enclosingScope();
|
||||||
|
while (!(enclosingScope->asNamespace() || enclosingScope->asClass()))
|
||||||
|
enclosingScope = enclosingScope->enclosingScope();
|
||||||
|
QTC_ASSERT(enclosingScope != nullptr, return nullptr);
|
||||||
|
|
||||||
|
const Name *functionName = function->name();
|
||||||
|
if (!functionName)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// global namespace
|
||||||
|
if (!functionName->asQualifiedNameId()) {
|
||||||
|
const QList<Symbol *> symbols = context.globalNamespace()->symbols();
|
||||||
|
for (Symbol *s : symbols) {
|
||||||
|
if (Namespace *matchingNamespace = s->asNamespace())
|
||||||
|
return matchingNamespace;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QualifiedNameId *q = functionName->asQualifiedNameId();
|
||||||
|
if (!q->base())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (ClassOrNamespace *binding = context.lookupType(q->base(), enclosingScope)) {
|
||||||
|
const QList<Symbol *> symbols = binding->symbols();
|
||||||
|
for (Symbol *s : symbols) {
|
||||||
|
if (Namespace *matchingNamespace = s->asNamespace())
|
||||||
|
return matchingNamespace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace CppEditor::Internal
|
} // namespace CppEditor::Internal
|
||||||
|
@@ -25,4 +25,15 @@ void insertNewIncludeDirective(
|
|||||||
// correspond to an AST of its own, i.e. on "empty space".
|
// correspond to an AST of its own, i.e. on "empty space".
|
||||||
CPlusPlus::ClassSpecifierAST *astForClassOperations(const CppQuickFixInterface &interface);
|
CPlusPlus::ClassSpecifierAST *astForClassOperations(const CppQuickFixInterface &interface);
|
||||||
|
|
||||||
|
bool nameIncludesOperatorName(const CPlusPlus::Name *name);
|
||||||
|
|
||||||
|
QString inlinePrefix(const Utils::FilePath &targetFile,
|
||||||
|
const std::function<bool()> &extraCondition = {});
|
||||||
|
|
||||||
|
CPlusPlus::Class *isMemberFunction(
|
||||||
|
const CPlusPlus::LookupContext &context, CPlusPlus::Function *function);
|
||||||
|
|
||||||
|
CPlusPlus::Namespace *isNamespaceFunction(
|
||||||
|
const CPlusPlus::LookupContext &context, CPlusPlus::Function *function);
|
||||||
|
|
||||||
} // namespace CppEditor::Internal
|
} // namespace CppEditor::Internal
|
||||||
|
1904
src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp
Normal file
1904
src/plugins/cppeditor/quickfixes/movefunctiondefinition.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace CppEditor::Internal {
|
||||||
|
void registerMoveFunctionDefinitionQuickfixes();
|
||||||
|
} // namespace CppEditor::Internal
|
Reference in New Issue
Block a user