Commit ca443e74 authored by Kevin Funk's avatar Kevin Funk

Don't offer completions in comments

parent 73a51f59
......@@ -210,6 +210,40 @@ private:
*/
using SimpleItem = CompletionItem<CompletionTreeItem>;
/**
* Return true in case position @p position represents a cursor inside a comment
*/
bool isInsideComment(CXTranslationUnit unit, CXFile file, const KDevelop::SimpleCursor& position)
{
if (!position.isValid()) {
return false;
}
// TODO: This may get very slow for a large TU, investigate if we can improve this function
auto begin = clang_getLocation(unit, file, 1, 1);
auto end = clang_getLocation(unit, file, position.line + 1, position.column + 1);
CXSourceRange range = clang_getRange(begin, end);
// tokenize the whole range from the start until 'position'
// if we detect a comment token at this position, return true
CXToken* tokens = nullptr;
unsigned int nTokens = 0;
clang_tokenize(unit, range, &tokens, &nTokens);
for (unsigned int i = 0; i < nTokens; ++i) {
CXToken token = tokens[i];
CXTokenKind tokenKind = clang_getTokenKind(token);
if (tokenKind != CXToken_Comment) {
continue;
}
auto range = ClangRange(clang_getTokenExtent(unit, token));
if (range.toSimpleRange().contains(position)) {
return true;
}
}
return false;
}
}
ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& context,
......@@ -220,6 +254,7 @@ ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& c
: CodeCompletionContext(context, text, CursorInRevision::castFromSimpleCursor(position), 0)
, m_results(nullptr, clang_disposeCodeCompleteResults)
, m_completionHelper(session.unit(), position, ClangString(clang_getFileName(session.file())).c_str())
, m_parseSession(session)
{
ClangString file(clang_getFileName(session.file()));
......@@ -233,14 +268,29 @@ ClangCodeCompletionContext::ClangCodeCompletionContext(const DUContextPointer& c
position.line + 1, position.column + 1,
&unsaved, 1,
clang_defaultCodeCompleteOptions()) );
// check 'isValidPosition' after parsing the new content
if (!isValidPosition()) {
m_valid = false;
return;
}
}
ClangCodeCompletionContext::~ClangCodeCompletionContext()
{
}
bool ClangCodeCompletionContext::isValidPosition() const
{
return !isInsideComment(m_parseSession.unit(), m_parseSession.file(), m_position.castToSimpleCursor());
}
QList<CompletionTreeItemPointer> ClangCodeCompletionContext::completionItems(bool& abort, bool fullCompletion)
{
if (!m_valid || !m_duContext || !m_results) {
return {};
}
QList<CompletionTreeItemPointer> items;
QList<CompletionTreeItemPointer> macros;
QList<CompletionTreeItemPointer> builtin;
......
......@@ -22,6 +22,8 @@
#ifndef CLANGCODECOMPLETIONCONTEXT_H
#define CLANGCODECOMPLETIONCONTEXT_H
#include <duchain/parsesession.h>
#include <language/codecompletion/codecompletioncontext.h>
#include <clang-c/Index.h>
......@@ -30,7 +32,6 @@
#include "completionhelper.h"
class ParseSession;
class ClangCodeCompletionContext : public KDevelop::CodeCompletionContext
{
public:
......@@ -51,9 +52,13 @@ private:
/// Creates the group named @p name and adds it to m_ungrouped if items @p items is not empty
void eventuallyAddGroup(const QString& name, int priority, const QList<KDevelop::CompletionTreeItemPointer>& items);
/// Returns whether the we are at a valid completion-position
bool isValidPosition() const;
std::unique_ptr<CXCodeCompleteResults, void(*)(CXCodeCompleteResults*)> m_results;
QList<KDevelop::CompletionTreeElementPointer> m_ungrouped;
CompletionHelper m_completionHelper;
ParseSession m_parseSession;
};
#endif // CLANGCODECOMPLETIONCONTEXT_H
......@@ -252,6 +252,29 @@ void TestCodeCompletion::testImplement_data()
QTest::newRow("const")
<< "class Foo { int bar() const; };"
<< CompletionItemsList{{{3, 1}, {"Foo::bar() const"}}};
}
void TestCodeCompletion::testInvalidCompletions()
{
QFETCH(QString, code);
QFETCH(CompletionItemsList, expectedItems);
executeCompletionTest(code, expectedItems);
}
void TestCodeCompletion::testInvalidCompletions_data()
{
QTest::addColumn<QString>("code");
QTest::addColumn<CompletionItemsList>("expectedItems");
QTest::newRow("invalid-context-infunction")
<< "class Foo { int bar() const; };\nint somefunc() {\n}"
<< CompletionItemsList{{{2, 0}, {}}};
QTest::newRow("invalid-context-incomment")
<< "class Foo { int bar() const; };\n/*\n*/"
<< CompletionItemsList{{{2, 0}, {}}};
}
#include "test_codecompletion.moc"
......@@ -36,6 +36,8 @@ private slots:
void testVirtualOverride_data();
void testImplement();
void testImplement_data();
void testInvalidCompletions();
void testInvalidCompletions_data();
};
#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