forked from qt-creator/qt-creator
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:
@@ -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('(');
|
||||||
|
@@ -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 §ion, int sectionIndex)
|
void insertToSectionDeclFromDef(const QByteArray §ion, int sectionIndex)
|
||||||
{
|
{
|
||||||
|
@@ -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();
|
||||||
|
@@ -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,
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user