Commit fcba0ad8 authored by Friedrich W. H. Kossebau's avatar Friedrich W. H. Kossebau
Browse files

Avoid duplicates in virtual overrides code completion proposals

Summary:
Currently methods which have multiple overrides in the inheritance
chain are also displayed as often. Filtering out these duplicates
based on the signature improves the situation as a first step.

Test Plan:
E.g. QWidget subclasses have lots of methods repeated, with this
patch no longer.
Extended unit test failed before, no longer fails with patch.

Reviewers: #kdevelop, mwolff

Reviewed By: #kdevelop, mwolff

Subscribers: mwolff, kdevelop-devel

Differential Revision: https://phabricator.kde.org/D6417
parent ea3ad93d
......@@ -74,7 +74,7 @@ QStringList templateParams(CXCursor cursor)
FuncOverrideInfo processCXXMethod(CXCursor cursor, OverrideInfo* info)
{
QStringList params;
FuncParameterList params;
int numArgs = clang_Cursor_getNumArguments(cursor);
for (int i = 0; i < numArgs; i++) {
......@@ -84,7 +84,10 @@ FuncOverrideInfo processCXXMethod(CXCursor cursor, OverrideInfo* info)
if (info->templateTypeMap.contains(type)) {
type = info->templateTypeMap.value(type);
}
params << type + QLatin1Char(' ') + id;
FuncParameterInfo param;
param.type = type;
param.id = id;
params << param;
}
FuncOverrideInfo fp;
......@@ -142,7 +145,15 @@ CXChildVisitResult baseClassVisitor(CXCursor cursor, CXCursor parent, CXClientDa
return CXChildVisit_Continue;
case CXCursor_CXXMethod:
if (clang_CXXMethod_isVirtual(cursor)) {
info->functions->append(processCXXMethod(cursor, info));
auto methodInfo = processCXXMethod(cursor, info);
const int methodIndex = info->functions->indexOf(methodInfo);
if (methodIndex == -1) {
info->functions->append(methodInfo);
} else {
// update to subclass override
auto& listedMethodInfo = (*info->functions)[methodIndex];
listedMethodInfo.isPureVirtual = methodInfo.isPureVirtual;
}
}
return CXChildVisit_Continue;
default:
......@@ -164,10 +175,9 @@ CXChildVisitResult findBaseVisitor(CXCursor cursor, CXCursor parent, CXClientDat
OverrideInfo overrideInfo {info, {}, {}};
auto methodInfo = processCXXMethod(cursor, &overrideInfo);
if (info->contains(methodInfo)) {
// This method is already implemented, remove it from the list of methods that can be overridden.
info->remove(info->indexOf(methodInfo), 1);
}
// If this method is already implemented, remove it from the list of methods that can be overridden.
// If not implemented, this is a noop
info->removeOne(methodInfo);
}
return CXChildVisit_Continue;
......
......@@ -28,13 +28,24 @@
#include <language/duchain/duchainpointer.h>
struct FuncParameterInfo
{
QString type;
QString id;
/// Returns true if types are equal, id is ignored
bool operator==(const FuncParameterInfo& rhs) const { return type == rhs.type; }
};
Q_DECLARE_TYPEINFO(FuncParameterInfo, Q_MOVABLE_TYPE);
using FuncParameterList = QVector<FuncParameterInfo>;
struct FuncOverrideInfo
{
QString returnType;
QString name;
QStringList params;
FuncParameterList params;
bool isPureVirtual;
bool isConst;
/// Returns true if equal, isPureVirtual & parameter ids are ignored
bool operator==(const FuncOverrideInfo& rhs) const;
};
......
......@@ -1174,9 +1174,12 @@ void ClangCodeCompletionContext::addOverwritableItems()
}
QList<CompletionTreeItemPointer> overrides;
for (int i = 0; i < overrideList.count(); i++) {
FuncOverrideInfo info = overrideList.at(i);
QString nameAndParams = info.name + QLatin1Char('(') + info.params.join(QLatin1String(", ")) + QLatin1Char(')');
for (const auto& info : overrideList) {
QStringList params;
for (const auto& param : info.params) {
params << param.type + QLatin1Char(' ') + param.id;
}
QString nameAndParams = info.name + QLatin1Char('(') + params.join(QStringLiteral(", ")) + QLatin1Char(')');
if(info.isConst)
nameAndParams = nameAndParams + QLatin1String(" const");
if(info.isPureVirtual)
......
......@@ -560,11 +560,23 @@ void TestCodeCompletion::testVirtualOverride_data()
"class Bar : Baz \n{int overridden(int i) overridden;\n}"
<< CompletionItems{{4, 1}, {"foo(int i)"}};
QTest::newRow("repeated")
<< "class Foo { virtual int foo(int i); virtual int overridden(int i); };\n"
"class Baz : Foo { int foo(int i) override; };\n"
"class Bar : Baz \n{int overridden(int i) override;\n}"
<< CompletionItems{{4, 1}, {"foo(int i)"}};
QTest::newRow("pure")
<< "class Foo { virtual void foo() = 0; virtual void overridden() = 0;};\n"
"class Bar : Foo \n{void overridden() override;\n};"
<< CompletionItems{{3, 0}, {"foo() = 0"}};
QTest::newRow("repeated-pure")
<< "class Foo { virtual void foo() = 0; virtual void overridden() = 0; };\n"
"class Baz : Foo { void foo() override; };\n"
"class Bar : Baz \n{void overridden() override;\n}"
<< CompletionItems{{4, 1}, {"foo()"}};
QTest::newRow("const")
<< "class Foo { virtual void foo(const int b) const; virtual void overridden(const int b) const; }\n;"
"class Bar : Foo \n{void overridden(const int b) const override;\n}"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment