QuickFix: Fix add definition for templated function

- Fix add definition for templated function in templated
class
- Fix "inline" placement for templated function

Fixes: QTCREATORBUG-29408
Change-Id: I15f7793c9ae1e49d8338c1120135ddd1afbca4ca
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Artem Sokolovskii
2023-11-08 16:51:15 +01:00
parent ec99782105
commit 9c4ba3ff21
5 changed files with 215 additions and 48 deletions

View File

@@ -364,9 +364,14 @@ void TypePrettyPrinter::visit(Function *type)
bool showTemplateParameters = _overview->showTemplateParameters;
QStringList nameParts = _name.split("::");
int i = nameParts.length() - 1;
for (Scope *s = type->enclosingScope(); s && i >= 0; s = s->enclosingScope()) {
Scope *s = type->enclosingScope();
if (s && s->asTemplate())
s = s->enclosingScope();
for (; s && i >= 0; s = s->enclosingScope()) {
if (s->asClass())
showTemplateParameters = true;
if (Template *templ = s->asTemplate(); templ && showTemplateParameters) {
QString &n = nameParts[i];
const int paramCount = templ->templateParameterCount();
@@ -375,8 +380,7 @@ void TypePrettyPrinter::visit(Function *type)
for (int index = 0; index < paramCount; ++index) {
if (index)
n += QLatin1String(", ");
QString arg = _overview->prettyName(
templ->templateParameterAt(index)->name());
QString arg = _overview->prettyName(templ->templateParameterAt(index)->name());
if (arg.isEmpty()) {
arg += 'T';
arg += QString::number(index + 1);
@@ -385,10 +389,10 @@ void TypePrettyPrinter::visit(Function *type)
}
n += '>';
}
}
if (s->identifier())
} else if (s->identifier()) {
--i;
}
}
_name = nameParts.join("::");
if (_needsParens) {
@@ -429,7 +433,8 @@ void TypePrettyPrinter::visit(Function *type)
}
if (_overview->showEnclosingTemplate) {
if (Template *templ = type->enclosingTemplate()) {
for (Scope *s = type->enclosingScope(); s && i >= 0; s = s->enclosingScope()) {
if (Template *templ = s->asTemplate()) {
QString templateScope = "template<";
const int paramCount = templ->templateParameterCount();
for (int i = 0; i < paramCount; ++i) {
@@ -437,8 +442,8 @@ void TypePrettyPrinter::visit(Function *type)
if (i > 0)
templateScope.append(", ");
if (TypenameArgument *typenameArg = param->asTypenameArgument()) {
templateScope.append(QLatin1String(typenameArg->isClassDeclarator()
? "class " : "typename "));
templateScope.append(QLatin1String(
typenameArg->isClassDeclarator() ? "class " : "typename "));
QString name = _overview->prettyName(typenameArg->name());
if (name.isEmpty())
name.append('T').append(QString::number(i + 1));
@@ -453,6 +458,7 @@ void TypePrettyPrinter::visit(Function *type)
_text.prepend(templateScope + ">\n");
}
}
}
if (_overview->showFunctionSignatures) {
_text += QLatin1Char('(');

View File

@@ -4999,6 +4999,34 @@ void QuickfixTest::testInsertDefFromDeclTemplateFunction()
QuickFixOperationTest(singleDocument(original, expected), &factory);
}
void QuickfixTest::testInsertDefFromDeclTemplateClassAndTemplateFunction()
{
QByteArray original =
"template<class T>"
"class Foo\n"
"{\n"
" template<class U>\n"
" void fun@c();\n"
"};\n";
QByteArray expected =
"template<class T>"
"class Foo\n"
"{\n"
" template<class U>\n"
" void fun@c();\n"
"};\n"
"\n"
"template<class T>\n"
"template<class U>\n"
"void Foo<T>::func()\n"
"{\n"
"\n"
"}\n";
InsertDefFromDecl factory;
QuickFixOperationTest(singleDocument(original, expected), &factory);
}
void QuickfixTest::testInsertDefFromDeclFunctionWithSignedUnsignedArgument()
{
QByteArray original;
@@ -5398,6 +5426,115 @@ SpaceBeforeParens: Always
prefs->setCodeStyleSettings(settings);
}
QList<TestDocumentPtr> singleHeader(const QByteArray &original, const QByteArray &expected)
{
return {CppTestDocument::create("file.h", original, expected)};
}
void QuickfixTest::testInsertDefOutsideFromDeclTemplateClassAndTemplateFunction()
{
QByteArray original =
"template<class T>"
"class Foo\n"
"{\n"
" template<class U>\n"
" void fun@c();\n"
"};\n";
QByteArray expected =
"template<class T>"
"class Foo\n"
"{\n"
" template<class U>\n"
" void fun@c();\n"
"};\n"
"\n"
"template<class T>\n"
"template<class U>\n"
"inline void Foo<T>::func()\n"
"{\n"
"\n"
"}\n";
InsertDefFromDecl factory;
factory.m_defPosOutsideClass = true;
QuickFixOperationTest(singleHeader(original, expected), &factory);
}
void QuickfixTest::testInsertDefOutsideFromDeclTemplateClass()
{
QByteArray original =
"template<class T>"
"class Foo\n"
"{\n"
" void fun@c();\n"
"};\n";
QByteArray expected =
"template<class T>"
"class Foo\n"
"{\n"
" void fun@c();\n"
"};\n"
"\n"
"template<class T>\n"
"inline void Foo<T>::func()\n"
"{\n"
"\n"
"}\n";
InsertDefFromDecl factory;
factory.m_defPosOutsideClass = true;
QuickFixOperationTest(singleHeader(original, expected), &factory);
}
void QuickfixTest::testInsertDefOutsideFromDeclTemplateFunction()
{
QByteArray original =
"class Foo\n"
"{\n"
" template<class U>\n"
" void fun@c();\n"
"};\n";
QByteArray expected =
"class Foo\n"
"{\n"
" template<class U>\n"
" void fun@c();\n"
"};\n"
"\n"
"template<class U>\n"
"inline void Foo::func()\n"
"{\n"
"\n"
"}\n";
InsertDefFromDecl factory;
factory.m_defPosOutsideClass = true;
QuickFixOperationTest(singleHeader(original, expected), &factory);
}
void QuickfixTest::testInsertDefOutsideFromDeclFunction()
{
QByteArray original =
"class Foo\n"
"{\n"
" void fun@c();\n"
"};\n";
QByteArray expected =
"class Foo\n"
"{\n"
" void fun@c();\n"
"};\n"
"\n"
"inline void Foo::func()\n"
"{\n"
"\n"
"}\n";
InsertDefFromDecl factory;
factory.m_defPosOutsideClass = true;
QuickFixOperationTest(singleHeader(original, expected), &factory);
}
// Function for one of InsertDeclDef section cases
void insertToSectionDeclFromDef(const QByteArray &section, int sectionIndex)
{

View File

@@ -136,6 +136,7 @@ private slots:
void testInsertDefFromDeclTemplateClass();
void testInsertDefFromDeclTemplateClassWithValueParam();
void testInsertDefFromDeclTemplateFunction();
void testInsertDefFromDeclTemplateClassAndTemplateFunction();
void testInsertDefFromDeclFunctionWithSignedUnsignedArgument();
void testInsertDefFromDeclNotTriggeredForFriendFunc();
void testInsertDefFromDeclMinimalFunctionParameterType();
@@ -144,6 +145,11 @@ private slots:
void testInsertDefsFromDecls();
void testInsertAndFormatDefsFromDecls();
void testInsertDefOutsideFromDeclTemplateClassAndTemplateFunction();
void testInsertDefOutsideFromDeclTemplateClass();
void testInsertDefOutsideFromDeclTemplateFunction();
void testInsertDefOutsideFromDeclFunction();
void testInsertDeclFromDef();
void testInsertDeclFromDefTemplateFuncTypename();
void testInsertDeclFromDefTemplateFuncInt();

View File

@@ -2782,10 +2782,27 @@ public:
}
const QString name = oo.prettyName(LookupContext::minimalName(decl, targetCoN,
control));
const QString defText = inlinePrefix(
targetFilePath, [defPos] { return defPos == DefPosOutsideClass; })
+ oo.prettyType(tn, name)
+ QLatin1String("\n{\n\n}");
const QString inlinePref = inlinePrefix(targetFilePath, [defPos] {
return defPos == DefPosOutsideClass;
});
const QString prettyType = oo.prettyType(tn, name);
QString input = prettyType;
int index = 0;
while (input.startsWith("template")) {
QRegularExpression templateRegex("template\\s*<[^>]*>");
QRegularExpressionMatch match = templateRegex.match(input);
if (match.hasMatch()) {
index += match.captured().size() + 1;
input = input.mid(match.captured().size() + 1);
}
}
QString defText = prettyType;
defText.insert(index, inlinePref);
defText += QLatin1String("\n{\n\n}");
const int targetPos = targetFile->position(loc.line(), loc.column());
const int targetPos2 = qMax(0, targetFile->position(loc.line(), 1) - 1);
@@ -2901,7 +2918,7 @@ void InsertDefFromDecl::match(const CppQuickFixInterface &interface, QuickFixOpe
const bool isFreeFunction = func->enclosingClass() == nullptr;
// Insert Position: Outside Class
if (!isFreeFunction) {
if (!isFreeFunction || m_defPosOutsideClass) {
result << new InsertDefOperation(interface, decl, declAST,
InsertionLocation(),
DefPosOutsideClass,

View File

@@ -357,6 +357,7 @@ class InsertDefFromDecl: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
bool m_defPosOutsideClass = false;
};
class AddDeclarationForUndeclaredIdentifier : public CppQuickFixFactory