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

View File

@@ -4999,6 +4999,34 @@ void QuickfixTest::testInsertDefFromDeclTemplateFunction()
QuickFixOperationTest(singleDocument(original, expected), &factory); 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() void QuickfixTest::testInsertDefFromDeclFunctionWithSignedUnsignedArgument()
{ {
QByteArray original; QByteArray original;
@@ -5398,6 +5426,115 @@ SpaceBeforeParens: Always
prefs->setCodeStyleSettings(settings); 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 // Function for one of InsertDeclDef section cases
void insertToSectionDeclFromDef(const QByteArray &section, int sectionIndex) void insertToSectionDeclFromDef(const QByteArray &section, int sectionIndex)
{ {

View File

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

View File

@@ -2782,10 +2782,27 @@ public:
} }
const QString name = oo.prettyName(LookupContext::minimalName(decl, targetCoN, const QString name = oo.prettyName(LookupContext::minimalName(decl, targetCoN,
control)); control));
const QString defText = inlinePrefix(
targetFilePath, [defPos] { return defPos == DefPosOutsideClass; }) const QString inlinePref = inlinePrefix(targetFilePath, [defPos] {
+ oo.prettyType(tn, name) return defPos == DefPosOutsideClass;
+ QLatin1String("\n{\n\n}"); });
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 targetPos = targetFile->position(loc.line(), loc.column());
const int targetPos2 = qMax(0, targetFile->position(loc.line(), 1) - 1); 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; const bool isFreeFunction = func->enclosingClass() == nullptr;
// Insert Position: Outside Class // Insert Position: Outside Class
if (!isFreeFunction) { if (!isFreeFunction || m_defPosOutsideClass) {
result << new InsertDefOperation(interface, decl, declAST, result << new InsertDefOperation(interface, decl, declAST,
InsertionLocation(), InsertionLocation(),
DefPosOutsideClass, DefPosOutsideClass,

View File

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