diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index a535656c737..9fa20e4fab9 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -322,6 +322,8 @@ int ClangCompletionAssistProcessor::startOfOperator(int positionInDocument, const Tokens &tokens = tokenize(tc.block().text(), BackwardsScanner::previousBlockState(tc.block())); const int tokenIdx = SimpleLexer::tokenBefore(tokens, qMax(0, tc.positionInBlock() - 1)); // get the token at the left of the cursor const Token tk = (tokenIdx == -1) ? Token() : tokens.at(tokenIdx); + const QChar characterBeforePositionInDocument + = m_interface->characterAt(positionInDocument - 1); if (*kind == T_DOXY_COMMENT && !(tk.is(T_DOXY_COMMENT) || tk.is(T_CPP_DOXY_COMMENT))) { *kind = T_EOF_SYMBOL; @@ -329,7 +331,8 @@ int ClangCompletionAssistProcessor::startOfOperator(int positionInDocument, } // Don't complete in comments or strings, but still check for include completion else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT) - || tk.is(T_CPP_DOXY_COMMENT) || tk.is(T_DOXY_COMMENT) + || ((tk.is(T_CPP_DOXY_COMMENT) || tk.is(T_DOXY_COMMENT)) + && !isDoxygenTagCompletionCharacter(characterBeforePositionInDocument)) || (tk.isLiteral() && (*kind != T_STRING_LITERAL && *kind != T_ANGLE_STRING_LITERAL && *kind != T_SLASH))) { diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index ad12c5b621d..e761004e8bc 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "cppcompletionassist.h" +#include "cppdoxygen.h" #include "cppmodelmanager.h" #include "cpptoolsplugin.h" #include "cpptoolstestcase.h" @@ -171,6 +172,17 @@ bool isProbablyGlobalCompletion(const QStringList &list) && list.contains(QLatin1String("bool")); } +bool isDoxygenTagCompletion(const QStringList &list) +{ + for (int i = 1; i < T_DOXY_LAST_TAG; ++i) { + const QString doxygenTag = QString::fromLatin1(doxygenTagSpell(i)); + if (!list.contains(doxygenTag)) + return false; + } + + return true; +} + } // anonymous namespace void CppToolsPlugin::test_completion_basic_1() @@ -384,6 +396,29 @@ void CppToolsPlugin::test_global_completion() QVERIFY(completions.toSet().contains(requiredCompletionItems.toSet())); } +void CppToolsPlugin::test_doxygen_tag_completion_data() +{ + QTest::addColumn("code"); + + QTest::newRow("C++ comment") + << _("/// @"); + + QTest::newRow("C comment single line") + << _("/*! @ */"); +} + +void CppToolsPlugin::test_doxygen_tag_completion() +{ + QFETCH(QByteArray, code); + + const QByteArray prefix = "\\"; + + CompletionTestCase test(code, prefix); + QVERIFY(test.succeededSoFar()); + const QStringList completions = test.getCompletions(); + QVERIFY(isDoxygenTagCompletion(completions)); +} + static void enumTestCase(const QByteArray &tag, const QByteArray &source, const QByteArray &prefix = QByteArray()) { diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp index b5b986eed79..98a433015b3 100644 --- a/src/plugins/cpptools/cppcompletionassist.cpp +++ b/src/plugins/cpptools/cppcompletionassist.cpp @@ -991,7 +991,8 @@ int InternalCppCompletionAssistProcessor::startOfOperator(int pos, } // Don't complete in comments or strings, but still check for include completion else if (tk.is(T_COMMENT) || tk.is(T_CPP_COMMENT) - || tk.is(T_CPP_DOXY_COMMENT) || tk.is(T_DOXY_COMMENT) + || ((tk.is(T_CPP_DOXY_COMMENT) || tk.is(T_DOXY_COMMENT)) + && !isDoxygenTagCompletionCharacter(ch)) || (tk.isLiteral() && (*kind != T_STRING_LITERAL && *kind != T_ANGLE_STRING_LITERAL && *kind != T_SLASH diff --git a/src/plugins/cpptools/cppcompletionassistprocessor.cpp b/src/plugins/cpptools/cppcompletionassistprocessor.cpp index bcc7e9507df..abda6e4a50f 100644 --- a/src/plugins/cpptools/cppcompletionassistprocessor.cpp +++ b/src/plugins/cpptools/cppcompletionassistprocessor.cpp @@ -70,4 +70,10 @@ void CppCompletionAssistProcessor::addSnippets() m_completions.append(m_snippetCollector.collect()); } +bool CppCompletionAssistProcessor::isDoxygenTagCompletionCharacter(const QChar &character) +{ + return character == QLatin1Char('\\') + || character == QLatin1Char('@') ; +} + } // namespace CppTools diff --git a/src/plugins/cpptools/cppcompletionassistprocessor.h b/src/plugins/cpptools/cppcompletionassistprocessor.h index 862d77f53f0..70fa2f75ecf 100644 --- a/src/plugins/cpptools/cppcompletionassistprocessor.h +++ b/src/plugins/cpptools/cppcompletionassistprocessor.h @@ -43,6 +43,8 @@ public: protected: void addSnippets(); + static bool isDoxygenTagCompletionCharacter(const QChar &character); + int m_positionForProposal; QList m_completions; QStringList m_preprocessorCompletions; diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index b0f86095d16..46c2a0622f0 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -109,6 +109,9 @@ private slots: void test_global_completion_data(); void test_global_completion(); + void test_doxygen_tag_completion_data(); + void test_doxygen_tag_completion(); + void test_completion_member_access_operator_data(); void test_completion_member_access_operator();