Commit 9b12ca13 authored by Milian Wolff's avatar Milian Wolff

Don't add () when completing a function that is followed by a ( already.

parent 8b49e373
......@@ -240,7 +240,10 @@ public:
}
if(m_declaration->isFunctionDeclaration()) {
repl += QLatin1String("()");
auto doc = view->document();
if (doc->characterAt(word.end()) != QLatin1Char('(')) {
repl += QLatin1String("()");
}
view->document()->replaceText(word, repl);
auto f = m_declaration->type<FunctionType>();
if (f && f->indexedArgumentsSize()) {
......
......@@ -53,6 +53,9 @@ Q_DECLARE_METATYPE(KTextEditor::Cursor);
QTEST_MAIN(TestCodeCompletion);
static const auto NoMacroOrBuiltin = ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins | ClangCodeCompletionContext::NoMacros);
using namespace KDevelop;
using ClangCodeCompletionItemTester = CodeCompletionItemTester<ClangCodeCompletionContext>;
......@@ -118,10 +121,17 @@ void TestCodeCompletion::cleanupTestCase()
namespace {
struct NoopTestFunction
{
void operator()(const ClangCodeCompletionItemTester& /*tester*/) const
{
}
};
template<typename CustomTestFunction = NoopTestFunction>
void executeCompletionTest(const ReferencedTopDUContext& top, const CompletionItems& expectedCompletionItems,
const ClangCodeCompletionContext::ContextFilters& filters = ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins |
ClangCodeCompletionContext::NoMacros))
const ClangCodeCompletionContext::ContextFilters& filters = NoMacroOrBuiltin,
CustomTestFunction customTestFunction = {})
{
DUChainReadLocker lock;
const ParseSessionData::Ptr sessionData(dynamic_cast<ParseSessionData*>(top->ast().data()));
......@@ -153,22 +163,22 @@ void executeCompletionTest(const ReferencedTopDUContext& top, const CompletionIt
qDebug() << "different results:\nactual:" << tester.names << "\nexpected:" << expectedCompletionItems.completions;
}
QCOMPARE(tester.names, expectedCompletionItems.completions);
customTestFunction(tester);
}
template<typename CustomTestFunction = NoopTestFunction>
void executeCompletionTest(const QString& code, const CompletionItems& expectedCompletionItems,
const ClangCodeCompletionContext::ContextFilters& filters = ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins |
ClangCodeCompletionContext::NoMacros))
const ClangCodeCompletionContext::ContextFilters& filters = NoMacroOrBuiltin,
CustomTestFunction customTestFunction = {})
{
TestFile file(code, "cpp");
QVERIFY(file.parseAndWait(TopDUContext::AllDeclarationsContextsUsesAndAST));
executeCompletionTest(file.topContext(), expectedCompletionItems, filters);
executeCompletionTest(file.topContext(), expectedCompletionItems, filters, customTestFunction);
}
void executeCompletionPriorityTest(const QString& code, const CompletionPriorityItems& expectedCompletionItems,
const ClangCodeCompletionContext::ContextFilters& filters = ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins |
ClangCodeCompletionContext::NoMacros))
const ClangCodeCompletionContext::ContextFilters& filters = NoMacroOrBuiltin)
{
TestFile file(code, "cpp");
QVERIFY(file.parseAndWait(TopDUContext::AllDeclarationsContextsUsesAndAST));
......@@ -205,9 +215,7 @@ void executeCompletionPriorityTest(const QString& code, const CompletionPriority
}
void executeMemberAccessReplacerTest(const QString& code, const CompletionItems& expectedCompletionItems,
const ClangCodeCompletionContext::ContextFilters& filters = ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins |
ClangCodeCompletionContext::NoMacros))
const ClangCodeCompletionContext::ContextFilters& filters = NoMacroOrBuiltin)
{
TestFile file(code, "cpp");
......@@ -447,7 +455,7 @@ void TestCodeCompletion::testClangCodeCompletion_data()
"instance.itemT", "main",
"pInstance", "pInstance->itemT",
}};
QTest::newRow("look-ahead item access")
QTest::newRow("look-ahead item access")
<< "class Class { public: int publicInt; protected: int protectedInt; private: int privateInt;};"
"int main() {Class cl; int i =\n "
<< CompletionItems{{1, 0}, {
......@@ -456,7 +464,7 @@ void TestCodeCompletion::testClangCodeCompletion_data()
"i", "main",
}};
QTest::newRow("look-ahead auto item")
QTest::newRow("look-ahead auto item")
<< "struct LookAhead { int intItem; };"
"int main() {auto instance = LookAhead(); int i = \n "
<< CompletionItems{{1, 0}, {
......@@ -800,6 +808,30 @@ void TestCodeCompletion::testIncludePathCompletion_data()
<< QString("bar/") << QString("#include \"foo/bar/\"");
}
struct DeleteDocument
{
void operator()(KTextEditor::View* view) const
{
delete view->document();
}
};
static std::unique_ptr<KTextEditor::View, DeleteDocument> createView(const QUrl& url, QObject* parent)
{
KTextEditor::Editor* editor = KTextEditor::Editor::instance();
Q_ASSERT(editor);
auto doc = editor->createDocument(parent);
Q_ASSERT(doc);
bool opened = doc->openUrl(url);
Q_ASSERT(opened);
Q_UNUSED(opened);
auto view = doc->createView(nullptr);
Q_ASSERT(view);
return std::unique_ptr<KTextEditor::View, DeleteDocument>(view);
}
void TestCodeCompletion::testIncludePathCompletion()
{
QFETCH(QString, code);
......@@ -818,16 +850,11 @@ void TestCodeCompletion::testIncludePathCompletion()
auto item = tester.findItem(itemId);
QVERIFY(item);
KTextEditor::Editor* editor = KTextEditor::Editor::instance();
QVERIFY(editor);
auto doc = std::unique_ptr<KTextEditor::Document>(editor->createDocument(this));
QVERIFY(doc.get());
QVERIFY(doc->openUrl(file.url().toUrl()));
QWidget parent;
auto view = doc->createView(&parent);
item->execute(view, KTextEditor::Range(cursor, cursor));
auto view = createView(file.url().toUrl(), this);
qDebug() << view.get();
QVERIFY(view.get());
auto doc = view->document();
item->execute(view.get(), KTextEditor::Range(cursor, cursor));
QCOMPARE(doc->text(), result);
const auto newCursor = view->cursorPosition();
......@@ -866,9 +893,7 @@ void TestCodeCompletion::testOverloadedFunctions()
lock.unlock();
const auto context = new ClangCodeCompletionContext(topPtr, sessionData, file.url().toUrl(), {1, 0}, QString());
context->setFilters(ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins |
ClangCodeCompletionContext::NoMacros));
context->setFilters(NoMacroOrBuiltin);
lock.lock();
const auto tester = ClangCodeCompletionItemTester(QExplicitlySharedDataPointer<ClangCodeCompletionContext>(context));
QCOMPARE(tester.items.size(), 3);
......@@ -957,9 +982,7 @@ void TestCodeCompletion::testVariableScope()
lock.unlock();
const auto context = new ClangCodeCompletionContext(topPtr, sessionData, file.url().toUrl(), {2, 0}, QString());
context->setFilters(ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins |
ClangCodeCompletionContext::NoMacros));
context->setFilters(NoMacroOrBuiltin);
lock.lock();
const auto tester = ClangCodeCompletionItemTester(QExplicitlySharedDataPointer<ClangCodeCompletionContext>(context));
......@@ -1045,9 +1068,7 @@ void TestCodeCompletion::testArgumentHintCompletionDefaultParameters()
lock.unlock();
const auto context = new ClangCodeCompletionContext(topPtr, sessionData, file.url().toUrl(), {1, 2}, QString());
context->setFilters(ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins |
ClangCodeCompletionContext::NoMacros));
context->setFilters(NoMacroOrBuiltin);
lock.lock();
const auto tester = ClangCodeCompletionItemTester(QExplicitlySharedDataPointer<ClangCodeCompletionContext>(context));
QExplicitlySharedDataPointer<KDevelop::CompletionTreeItem> f;
......@@ -1064,3 +1085,40 @@ void TestCodeCompletion::testArgumentHintCompletionDefaultParameters()
const QString itemDisplay = tester.itemData(f).toString() + tester.itemData(f, KTextEditor:: CodeCompletionModel::Arguments).toString();
QCOMPARE(QStringLiteral("f(int i, int j, double k)"), itemDisplay);
}
void TestCodeCompletion::testCompleteFunction()
{
QFETCH(QString, code);
QFETCH(CompletionItems, expectedItems);
QFETCH(QString, itemToExecute);
QFETCH(QString, expectedCode);
auto executeItem = [=] (const ClangCodeCompletionItemTester& tester) {
auto item = tester.findItem(itemToExecute);
QVERIFY(item);
auto view = createView(tester.completionContext->duContext()->url().toUrl(), this);
item->execute(view.get(), view->document()->wordRangeAt(expectedItems.position));
QCOMPARE(view->document()->text(), expectedCode);
};
executeCompletionTest(code, expectedItems, NoMacroOrBuiltin, executeItem);
}
void TestCodeCompletion::testCompleteFunction_data()
{
QTest::addColumn<QString>("code");
QTest::addColumn<CompletionItems>("expectedItems");
QTest::addColumn<QString>("itemToExecute");
QTest::addColumn<QString>("expectedCode");
QTest::newRow("add-parens")
<< "int foo();\nint main() {\n\n}"
<< CompletionItems({2, 0}, {"foo", "main"})
<< "foo"
<< "int foo();\nint main() {\nfoo()\n}";
QTest::newRow("keep-parens")
<< "int foo();\nint main() {\nfoo();\n}"
<< CompletionItems({2, 0}, {"foo", "main"})
<< "main"
<< "int foo();\nint main() {\nmain();\n}";
}
......@@ -55,6 +55,9 @@ private slots:
void testOverloadedFunctions();
void testVariableScope();
void testArgumentHintCompletionDefaultParameters();
void testCompleteFunction_data();
void testCompleteFunction();
};
#endif // TESTCODECOMPLETION_H
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