forked from qt-creator/qt-creator
CppEditor: Fix "move function definition"
... for member functions with exception specification and/or reference qualifiers. The FunctionDeclaratorAST::cv_qualifier_list member can contain both the proper qualifiers "const" and "volatile" as well as the pseudo-qualifiers "override" and "final". The problem is that the former appear before exception specification and reference qualifiers, whereas the latter come afterwards. Therefore, when calculating the declarator's first and last tokens, we can't just mechanically check the different declarator members in order. Instead, we need to compare the token values to see which comes first. Task-number: QTCREATORBUG-27132 Change-Id: I924f9afe49453fa51b4a2fe010d1cc00c9defad1 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
45
src/libs/3rdparty/cplusplus/AST.cpp
vendored
45
src/libs/3rdparty/cplusplus/AST.cpp
vendored
@@ -1393,7 +1393,6 @@ int ForeachStatementAST::lastToken() const
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \generated */
|
|
||||||
int FunctionDeclaratorAST::firstToken() const
|
int FunctionDeclaratorAST::firstToken() const
|
||||||
{
|
{
|
||||||
if (lparen_token)
|
if (lparen_token)
|
||||||
@@ -1403,40 +1402,50 @@ int FunctionDeclaratorAST::firstToken() const
|
|||||||
return candidate;
|
return candidate;
|
||||||
if (rparen_token)
|
if (rparen_token)
|
||||||
return rparen_token;
|
return rparen_token;
|
||||||
if (cv_qualifier_list)
|
const int firstQualListToken = cv_qualifier_list ? cv_qualifier_list->firstToken() : 0;
|
||||||
if (int candidate = cv_qualifier_list->firstToken())
|
const auto isBeforeFirstQualListToken = [firstQualListToken](int token) {
|
||||||
return candidate;
|
return token && (!firstQualListToken || token < firstQualListToken);
|
||||||
if (ref_qualifier_token)
|
};
|
||||||
|
if (isBeforeFirstQualListToken(ref_qualifier_token))
|
||||||
return ref_qualifier_token;
|
return ref_qualifier_token;
|
||||||
if (exception_specification)
|
if (exception_specification) {
|
||||||
if (int candidate = exception_specification->firstToken())
|
const int candidate = exception_specification->firstToken();
|
||||||
|
if (isBeforeFirstQualListToken(candidate))
|
||||||
return candidate;
|
return candidate;
|
||||||
if (trailing_return_type)
|
}
|
||||||
if (int candidate = trailing_return_type->firstToken())
|
if (trailing_return_type) {
|
||||||
|
const int candidate = trailing_return_type->firstToken();
|
||||||
|
if (isBeforeFirstQualListToken(candidate))
|
||||||
return candidate;
|
return candidate;
|
||||||
|
}
|
||||||
|
if (firstQualListToken)
|
||||||
|
return firstQualListToken;
|
||||||
if (as_cpp_initializer)
|
if (as_cpp_initializer)
|
||||||
if (int candidate = as_cpp_initializer->firstToken())
|
if (int candidate = as_cpp_initializer->firstToken())
|
||||||
return candidate;
|
return candidate;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \generated */
|
|
||||||
int FunctionDeclaratorAST::lastToken() const
|
int FunctionDeclaratorAST::lastToken() const
|
||||||
{
|
{
|
||||||
if (as_cpp_initializer)
|
if (as_cpp_initializer)
|
||||||
if (int candidate = as_cpp_initializer->lastToken())
|
if (int candidate = as_cpp_initializer->lastToken())
|
||||||
return candidate;
|
return candidate;
|
||||||
if (trailing_return_type)
|
const int lastQualListToken = cv_qualifier_list ? cv_qualifier_list->lastToken() : 0;
|
||||||
if (int candidate = trailing_return_type->lastToken())
|
const auto tokenOrLastQualListToken = [lastQualListToken](int token) {
|
||||||
|
return std::max(token ? token + 1 : 0, lastQualListToken);
|
||||||
|
};
|
||||||
|
const auto tokenFromAstOrLastQualListToken = [lastQualListToken](const AST *ast) {
|
||||||
|
return std::max(ast ? ast->lastToken() : 0, lastQualListToken);
|
||||||
|
};
|
||||||
|
if (int candidate = tokenFromAstOrLastQualListToken(trailing_return_type))
|
||||||
return candidate;
|
return candidate;
|
||||||
if (exception_specification)
|
if (int candidate = tokenFromAstOrLastQualListToken(exception_specification))
|
||||||
if (int candidate = exception_specification->lastToken())
|
|
||||||
return candidate;
|
return candidate;
|
||||||
if (ref_qualifier_token)
|
if (int candidate = tokenOrLastQualListToken(ref_qualifier_token))
|
||||||
return ref_qualifier_token + 1;
|
|
||||||
if (cv_qualifier_list)
|
|
||||||
if (int candidate = cv_qualifier_list->lastToken())
|
|
||||||
return candidate;
|
return candidate;
|
||||||
|
if (lastQualListToken)
|
||||||
|
return lastQualListToken;
|
||||||
if (rparen_token)
|
if (rparen_token)
|
||||||
return rparen_token + 1;
|
return rparen_token + 1;
|
||||||
if (parameter_declaration_clause)
|
if (parameter_declaration_clause)
|
||||||
|
@@ -6110,6 +6110,41 @@ void QuickfixTest::testMoveFuncDefOutsideMemberFuncToCppWithInlinePartOfName()
|
|||||||
QuickFixOperationTest(testDocuments, &factory);
|
QuickFixOperationTest(testDocuments, &factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QuickfixTest::testMoveFuncDefOutsideMixedQualifiers()
|
||||||
|
{
|
||||||
|
QList<TestDocumentPtr> testDocuments;
|
||||||
|
QByteArray original;
|
||||||
|
QByteArray expected;
|
||||||
|
|
||||||
|
// Header File
|
||||||
|
original = R"(
|
||||||
|
struct Base {
|
||||||
|
virtual auto func() const && noexcept -> void = 0;
|
||||||
|
};
|
||||||
|
struct Derived : public Base {
|
||||||
|
auto @func() const && noexcept -> void override {}
|
||||||
|
};)";
|
||||||
|
expected = R"(
|
||||||
|
struct Base {
|
||||||
|
virtual auto func() const && noexcept -> void = 0;
|
||||||
|
};
|
||||||
|
struct Derived : public Base {
|
||||||
|
auto func() const && noexcept -> void override;
|
||||||
|
};)";
|
||||||
|
testDocuments << CppTestDocument::create("file.h", original, expected);
|
||||||
|
|
||||||
|
// Source File
|
||||||
|
original = "#include \"file.h\"\n";
|
||||||
|
expected = R"DELIM(#include "file.h"
|
||||||
|
|
||||||
|
void Derived::func() const &&noexcept {}
|
||||||
|
)DELIM";
|
||||||
|
testDocuments << CppTestDocument::create("file.cpp", original, expected);
|
||||||
|
|
||||||
|
MoveFuncDefOutside factory;
|
||||||
|
QuickFixOperationTest(testDocuments, &factory);
|
||||||
|
}
|
||||||
|
|
||||||
void QuickfixTest::testMoveFuncDefOutsideMemberFuncToCppInsideNS()
|
void QuickfixTest::testMoveFuncDefOutsideMemberFuncToCppInsideNS()
|
||||||
{
|
{
|
||||||
QList<TestDocumentPtr> testDocuments;
|
QList<TestDocumentPtr> testDocuments;
|
||||||
|
@@ -192,6 +192,7 @@ private slots:
|
|||||||
void testMoveFuncDefOutsideUnnamedTemplate();
|
void testMoveFuncDefOutsideUnnamedTemplate();
|
||||||
void testMoveFuncDefOutsideMemberFuncToCppStatic();
|
void testMoveFuncDefOutsideMemberFuncToCppStatic();
|
||||||
void testMoveFuncDefOutsideMemberFuncToCppWithInlinePartOfName();
|
void testMoveFuncDefOutsideMemberFuncToCppWithInlinePartOfName();
|
||||||
|
void testMoveFuncDefOutsideMixedQualifiers();
|
||||||
|
|
||||||
void testMoveAllFuncDefOutsideMemberFuncToCpp();
|
void testMoveAllFuncDefOutsideMemberFuncToCpp();
|
||||||
void testMoveAllFuncDefOutsideMemberFuncOutside();
|
void testMoveAllFuncDefOutsideMemberFuncOutside();
|
||||||
|
Reference in New Issue
Block a user