Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 5404f001 authored by Sergey Kalinichev's avatar Sergey Kalinichev

Don't add function signature for declaration completion items

This is a slightly different approach which allows us to simplify logic
regarding overloaded functions and also it speeds up code completion
for ~50ms on my hardware.

REVIEW: 124007
parent 224f9f5a
......@@ -174,19 +174,6 @@ public:
return m_matchQuality;
}
if (role == Qt::DisplayRole) {
if (declaration()->isFunctionDeclaration()) {
// As completion filtering uses CodeCompletionModel::Name role, we can't just show the whole function signature on that role, otherwise some unrelated completion items'll be shown.
// Also this makes the "Detailed completion" option work.
if (index.column() == CodeCompletionModel::Name) {
return declaration()->identifier().toString();
} else if (index.column() == CodeCompletionModel::Arguments) {
auto function = declaration()->type<FunctionType>();
return function->partToString(FunctionType::SignatureArguments);
}
}
}
auto ret = CompletionItem<NormalDeclarationCompletionItem>::data(index, role, model);
if (ret.isValid()) {
return ret;
......@@ -420,39 +407,27 @@ QMultiHash<QualifiedIdentifier, Declaration*> generateCache(const DUContextPoint
return declarationsHash;
}
struct FindDeclarationResult
Declaration* findDeclaration(const QualifiedIdentifier& qid, const DUContextPointer& ctx, const CursorInRevision& position, const QMultiHash<QualifiedIdentifier, Declaration*>& declarationsCache, QSet<Declaration*>& handled)
{
Declaration* declaration = nullptr;
bool overloaded = false;
};
FindDeclarationResult findDeclaration(const QualifiedIdentifier& qid, const DUContextPointer& ctx, const CursorInRevision& position, const QMultiHash<QualifiedIdentifier, Declaration*>& declarationsCache, QSet<Declaration*>& handled)
{
FindDeclarationResult result;
auto i = declarationsCache.find(qid);
while (i != declarationsCache.end() && i.key() == qid) {
auto declaration = i.value();
if (!handled.contains(declaration)) {
handled.insert(declaration);
result.overloaded = result.overloaded || (++i != declarationsCache.end() && i.key() == qid);
result.declaration = declaration;
return result;
return declaration;
}
result.overloaded = true;
++i;
}
const auto foundDeclarations = ctx->findDeclarations(qid, position);
result.overloaded = foundDeclarations.size() > 1;
for (auto dec : foundDeclarations) {
if (!handled.contains(dec)) {
handled.insert(dec);
result.declaration = dec;
return result;
return dec;
}
}
return result;
return nullptr;
}
}
......@@ -550,11 +525,21 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
continue;
}
const bool isBuiltin = (result.CursorKind == CXCursor_NotImplemented);
if (isBuiltin && m_filters & NoBuiltins) {
continue;
}
const bool isDeclaration = !isMacroDefinition && !isBuiltin;
if (isDeclaration && m_filters & NoDeclarations) {
continue;
}
const uint chunks = clang_getNumCompletionChunks(result.CompletionString);
// the string that would be neede to type, usually the identifier of something
// the string that would be needed to type, usually the identifier of something. Also we use it as name for code completion declaration items.
QString typed;
// the display string we use in the code completion items, including the function signature
// the display string we use in the simple code completion items, including the function signature.
QString display;
// the return type of a function e.g.
QString resultType;
......@@ -580,6 +565,11 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
continue;
}
// We don't need function signature for declaration items, we can get it directly from the declaration. Also adding the function signature to the "display" would break the "Detailed completion" option.
if(isDeclaration && !typed.isEmpty()){
break;
}
const QString string = ClangString(clang_getCompletionChunkText(result.CompletionString, j)).toString();
switch (kind) {
case CXCompletionChunk_TypedText:
......@@ -623,19 +613,9 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
continue;
}
const bool isBuiltin = (result.CursorKind == CXCursor_NotImplemented);
if (isBuiltin && m_filters & NoBuiltins) {
continue;
}
// ellide text to the right for overly long result types (templates especially)
elideStringRight(resultType, MAX_RETURN_TYPE_STRING_LENGTH);
const bool isDeclaration = !isMacroDefinition && !isBuiltin;
if (isDeclaration && m_filters & NoDeclarations) {
continue;
}
if (isDeclaration) {
const Identifier id(typed);
QualifiedIdentifier qid;
......@@ -649,18 +629,10 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
continue;
}
auto declResult = findDeclaration(qid, ctx, m_position, declarationsCache, handled);
auto found = declResult.declaration;
auto found = findDeclaration(qid, ctx, m_position, declarationsCache, handled);
CompletionTreeItemPointer item;
if (found) {
if (declResult.overloaded && found->isFunctionDeclaration()) {
// In case of overloaded functions we can't use the "display" and the "resultType" provided by clang as it can mismatch declaration's data.
auto function = found->type<FunctionType>();
resultType = function->returnType()->toString();
display = id.toString() + function->partToString(FunctionType::SignatureArguments);
}
auto declarationItem = new DeclarationItem(found, display, resultType, replacement);
const unsigned int completionPriority = clang_getCompletionPriority(result.CompletionString);
......@@ -680,7 +652,11 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
}
if (isValidSpecialCompletionIdentifier(qid)) {
specialItems.append(item);
// If it's a special completion identifier e.g. "operator=(const&)" and we don't have a declaration for it, don't add it into completion list, as this item is completely useless and pollutes the test case.
// This happens e.g. for "class A{}; a.|". At | we have "operator=(const A&)" as a special completion identifier without a declaration.
if(item->declaration()){
specialItems.append(item);
}
} else {
items.append(item);
}
......
......@@ -180,18 +180,15 @@ void TestCodeCompletion::testClangCodeCompletion_data()
"foo",
}, {"bar","foo"}};
QTest::newRow("dotmemberaccess")
<< "class Foo { public: void foo() {} }; int main() { Foo f; \nf. "
<< "class Foo { public: void foo() {} bool operator=(Foo &&) }; int main() { Foo f; \nf. "
<< CompletionItems{{1, 2}, {
"foo",
"operator=(Foo &&)",
"operator=(const Foo &)",
}, {"foo"}};
"operator="
}, {"foo", "operator="}};
QTest::newRow("arrowmemberaccess")
<< "class Foo { public: void foo() {} }; int main() { Foo* f = new Foo; \nf-> }"
<< CompletionItems{{1, 3}, {
"foo",
"operator=(Foo &&)",
"operator=(const Foo &)",
"foo"
}, {"foo"}};
QTest::newRow("enum-case")
<< "enum Foo { foo, bar }; int main() { Foo f; switch (f) {\ncase "
......@@ -203,31 +200,23 @@ void TestCodeCompletion::testClangCodeCompletion_data()
<< "class SomeStruct { private: void priv() {} };\n"
"int main() { SomeStruct s;\ns. "
<< CompletionItems{{2, 2}, {
"operator=(SomeStruct &&)",
"operator=(const SomeStruct &)",
}};
QTest::newRow("private-friend")
<< "class SomeStruct { private: void priv() {} friend int main(); };\n"
"int main() { SomeStruct s;\ns. "
<< CompletionItems{{2, 2}, {
"operator=(SomeStruct &&)",
"operator=(const SomeStruct &)",
"priv",
}, {"priv"}};
QTest::newRow("private-public")
<< "class SomeStruct { public: void pub() {} private: void priv() {} };\n"
"int main() { SomeStruct s;\ns. "
<< CompletionItems{{2, 2}, {
"operator=(SomeStruct &&)",
"operator=(const SomeStruct &)",
"pub",
}, {"pub"}};
QTest::newRow("protected-public")
<< "class SomeStruct { public: void pub() {} protected: void prot() {} };\n"
"int main() { SomeStruct s;\ns. "
<< CompletionItems{{2, 2}, {
"operator=(SomeStruct &&)",
"operator=(const SomeStruct &)",
"pub",
}, {"pub"}};
QTest::newRow("localVariable")
......@@ -251,7 +240,7 @@ void TestCodeCompletion::testClangCodeCompletion_data()
QTest::newRow("parentVariable")
<< "class A{public: int m_variable;};class B : public A{};\nint main() { B b;\nb. "
<< CompletionItems{{2, 2},
{"m_variable", "operator=(A &&)", "operator=(B &&)", "operator=(const A &)", "operator=(const B &)"},
{"m_variable"},
{"m_variable"}
};
QTest::newRow("itemsPriority")
......
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