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 6885bbd1 authored by Sergey Kalinichev's avatar Sergey Kalinichev

Added argument-hint code completion

Now we show a separate list with argument-hint items.

E.g. "function(|"
At | the "function" is added to the argument-hint list

There are still some issues, like:
-no declaration found for argument-hint items
-default parameters not supported yet
-the current parameter is not market out
-and probably other

But, they are not so important, and most of them can be fixed later on.

REVIEW: 125371
parent dc4b9d73
......@@ -275,8 +275,19 @@ public:
m_inheritanceDepth = depth;
}
int argumentHintDepth() const override
{
return m_depth;
}
void setArgumentHintDepth(int depth)
{
m_depth = depth;
}
private:
int m_matchQuality = 0;
int m_depth = 0;
QString m_replacement;
};
......@@ -863,16 +874,25 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
//END function signature parsing
for (uint j = 0; j < chunks; ++j) {
const auto kind = clang_getCompletionChunkKind(result.CompletionString, j);
if (kind == CXCompletionChunk_CurrentParameter || kind == CXCompletionChunk_Optional) {
// TODO: Use it for default parameters of CXCursor_OverloadCandidate
if (kind == CXCompletionChunk_Optional) {
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()){
if (isDeclaration && !typed.isEmpty()) {
#if CINDEX_VERSION_MINOR >= 30
// TODO: When parent context for CXCursor_OverloadCandidate is fixed remove this check
if (result.CursorKind != CXCursor_OverloadCandidate) {
break;
}
#else
break;
#endif
}
const QString string = ClangString(clang_getCompletionChunkText(result.CompletionString, j)).toString();
switch (kind) {
case CXCompletionChunk_TypedText:
display += string;
......@@ -883,8 +903,6 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
resultType = string;
continue;
case CXCompletionChunk_Placeholder:
//TODO:consider KTextEditor::TemplateInterface possibility
//replacement += "/*" + string + "*/";
if (signatureState == Inside) {
display += string;
}
......@@ -902,19 +920,22 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
signatureState = After;
}
break;
case CXCompletionChunk_Text:
#if CINDEX_VERSION_MINOR >= 30
if (result.CursorKind == CXCursor_OverloadCandidate) {
display += string;
typed += string;
}
#endif
break;
default:
break;
}
//replacement += string;
if (signatureState == Inside) {
display += string;
}
}
if(typed.isEmpty()){
continue;
}
// ellide text to the right for overly long result types (templates especially)
elideStringRight(resultType, MAX_RETURN_TYPE_STRING_LENGTH);
......@@ -954,7 +975,7 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
}
}
auto declarationItem = new DeclarationItem(found, display, resultType, replacement);
auto declarationItem = new DeclarationItem(found, typed, resultType, replacement);
const unsigned int completionPriority = adjustPriorityForDeclaration(found, clang_getCompletionPriority(result.CompletionString));
const bool bestMatch = completionPriority <= CCP_SuperCompletion;
......@@ -971,11 +992,28 @@ QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(boo
lookAheadMatcher.addDeclarations(found);
}
#if CINDEX_VERSION_MINOR >= 30
if (result.CursorKind == CXCursor_OverloadCandidate) {
declarationItem->setArgumentHintDepth(1);
}
#endif
item = declarationItem;
} else {
// still, let's trust that Clang found something useful and put it into the completion result list
clangDebug() << "Could not find declaration for" << qid;
item = CompletionTreeItemPointer(new SimpleItem(display, resultType, replacement));
#if CINDEX_VERSION_MINOR >= 30
if (result.CursorKind == CXCursor_OverloadCandidate) {
// TODO: No parent context for CXCursor_OverloadCandidate items, hence qid is broken -> no declaration found
auto di = new DeclarationItem({}, display, resultType, replacement);
di->setArgumentHintDepth(1);
item = di;
} else {
#endif
// still, let's trust that Clang found something useful and put it into the completion result list
clangDebug() << "Could not find declaration for" << qid;
item = CompletionTreeItemPointer(new SimpleItem(display, resultType, replacement));
#if CINDEX_VERSION_MINOR >= 30
}
#endif
}
if (isValidSpecialCompletionIdentifier(qid)) {
......
......@@ -159,6 +159,7 @@ void executeCompletionTest(const QString& code, const CompletionItems& expectedC
QEXPECT_FAIL("look-ahead template parameter substitution", "No parameters substitution so far", Continue);
QEXPECT_FAIL("look-ahead auto item", "Auto type, like many other types, is not exposed through LibClang. We assign DelayedType to it instead of IdentifiedType", Continue);
QEXPECT_FAIL("deleted-overload-global", "The range for a global function defintion ends after the '=' so 'delete' after that is not detected.", Continue);
QEXPECT_FAIL("default parameters", "Default parameters not supported yet", Continue);
QCOMPARE(tester.names, expectedCompletionItems.completions);
}
......@@ -366,7 +367,11 @@ void TestCodeCompletion::testClangCodeCompletion_data()
QTest::newRow("itemsPriority")
<< "class A; class B; void f(A); int main(){ A c; B b;f(\n} "
<< CompletionItems{{1, 0},
{"A", "B", "b", "c", "f", "main"},
{"A", "B", "b", "c", "f",
#if CINDEX_VERSION_MINOR >= 30
"f(A)",
#endif
"main"},
{"c", "A", "b", "B"}
};
QTest::newRow("function-arguments")
......@@ -394,6 +399,9 @@ void TestCodeCompletion::testClangCodeCompletion_data()
"int main() {LookAhead* pInstance; LookAhead instance; function(\n }"
<< CompletionItems{{1, 0}, {
"Class", "LookAhead", "function",
#if CINDEX_VERSION_MINOR >= 30
"function(Class cl)",
#endif
"instance", "instance.classItem",
"main", "pInstance", "pInstance->classItem",
}};
......@@ -940,3 +948,69 @@ void TestCodeCompletion::testVariableScope()
VERIFY(item);
QCOMPARE(item->declaration()->range().start, CursorInRevision(1, 14));
}
void TestCodeCompletion::testArgumentHintCompletion()
{
QFETCH(QString, code);
QFETCH(CompletionItems, expectedItems);
executeCompletionTest(code, expectedItems);
}
void TestCodeCompletion::testArgumentHintCompletion_data()
{
#if CINDEX_VERSION_MINOR < 30
QSKIP("You need at least LibClang 3.7");
#endif
QTest::addColumn<QString>("code");
QTest::addColumn<CompletionItems>("expectedItems");
QTest::newRow("global function")
<< "void foo(int);\n"
"int main() { \nfoo( "
<< CompletionItems{{2,4}, {
"foo", "foo(int)",
"main"
}};
QTest::newRow("member function")
<< "struct Struct{ void foo(int);}\n"
"int main() {Struct s; \ns.foo( "
<< CompletionItems{{2,6}, {
"Struct", "foo(int)",
"main", "s"
}};
QTest::newRow("template function")
<< "template <typename T> void foo(T);\n"
"int main() { \nfoo( "
<< CompletionItems{{2,6}, {
"foo", "foo(T)",
"main"
}};
QTest::newRow("overloaded functions")
<< "void foo(int); void foo(int, double)\n"
"int main() { \nfoo( "
<< CompletionItems{{2,6}, {
"foo", "foo", "foo(int)", "foo(int, double)",
"main"
}};
QTest::newRow("overloaded functions2")
<< "void foo(int); void foo(int, double)\n"
"int main() { foo(1,\n "
<< CompletionItems{{2,1}, {
"foo", "foo", "foo(int, double)",
"main"
}};
QTest::newRow("default parameters")
<< "void foo(int i = 0);\n"
"int main() { \nfoo( "
<< CompletionItems{{2,4}, {
"foo", "foo(int i = 0)",
"main"
}};
}
......@@ -48,6 +48,8 @@ private slots:
void testCompletionPriority_data();
void testReplaceMemberAccess();
void testReplaceMemberAccess_data();
void testArgumentHintCompletion();
void testArgumentHintCompletion_data();
void testOverloadedFunctions();
void testVariableScope();
......
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