diff --git a/src/tools/clangbackend/ipcsource/clangcodecompleteresults.cpp b/src/tools/clangbackend/ipcsource/clangcodecompleteresults.cpp index 23701037ef9..af80d739bfc 100644 --- a/src/tools/clangbackend/ipcsource/clangcodecompleteresults.cpp +++ b/src/tools/clangbackend/ipcsource/clangcodecompleteresults.cpp @@ -61,6 +61,12 @@ bool ClangCodeCompleteResults::hasNoResultsForDotCompletion() const return !hasResults() && isDotCompletion(); } +bool ClangCodeCompleteResults::hasUnknownContext() const +{ + const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults); + return contexts == CXCompletionContext_Unknown; +} + bool ClangCodeCompleteResults::isDotCompletion() const { const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults); diff --git a/src/tools/clangbackend/ipcsource/clangcodecompleteresults.h b/src/tools/clangbackend/ipcsource/clangcodecompleteresults.h index 157fcf1224c..0b1ae11df8e 100644 --- a/src/tools/clangbackend/ipcsource/clangcodecompleteresults.h +++ b/src/tools/clangbackend/ipcsource/clangcodecompleteresults.h @@ -51,6 +51,7 @@ public: bool hasResults() const; bool hasNoResultsForDotCompletion() const; + bool hasUnknownContext() const; bool isDotCompletion() const; CXCodeCompleteResults *data() const; diff --git a/src/tools/clangbackend/ipcsource/codecompleter.cpp b/src/tools/clangbackend/ipcsource/codecompleter.cpp index 3d31a44c65a..fe746c8cfd8 100644 --- a/src/tools/clangbackend/ipcsource/codecompleter.cpp +++ b/src/tools/clangbackend/ipcsource/codecompleter.cpp @@ -56,6 +56,22 @@ CodeCompletions toCodeCompletions(const ClangCodeCompleteResults &results) return codeCompletions; } +void filterUnknownContextResults(ClangCodeCompleteResults &results, + const UnsavedFile &theUnsavedFile, + uint line, + uint column) +{ + if (results.hasUnknownContext()) { + bool positionIsOk = false; + const uint position = theUnsavedFile.toUtf8Position(line, column - 1, &positionIsOk); + if (positionIsOk && (theUnsavedFile.hasCharacterAt(position, '.') + || (theUnsavedFile.hasCharacterAt(position - 1, '-') + && theUnsavedFile.hasCharacterAt(position, '>')))) { + results = {}; + } + } +} + } // anonymous namespace CodeCompleter::CodeCompleter(const TranslationUnit &translationUnit, @@ -70,7 +86,7 @@ CodeCompletions CodeCompleter::complete(uint line, uint column) neededCorrection_ = CompletionCorrection::NoCorrection; ClangCodeCompleteResults results = completeHelper(line, column); - + filterUnknownContextResults(results, unsavedFile(), line, column); tryDotArrowCorrectionIfNoResults(results, line, column); return toCodeCompletions(results); @@ -139,6 +155,7 @@ ClangCodeCompleteResults CodeCompleter::completeWithArrowInsteadOfDot(uint line, results = completeHelper(line, column + 1); if (results.hasResults()) neededCorrection_ = CompletionCorrection::DotToArrowCorrection; + filterUnknownContextResults(results, unsavedFile(), line, column+1); } return results; diff --git a/tests/unit/unittest/codecompleter-test.cpp b/tests/unit/unittest/codecompleter-test.cpp index 58948c5f2cc..439374d45b7 100644 --- a/tests/unit/unittest/codecompleter-test.cpp +++ b/tests/unit/unittest/codecompleter-test.cpp @@ -176,6 +176,18 @@ protected: readFileContent(QStringLiteral("/complete_withNoDotArrowCorrectionForColonColon.cpp")), true }; + ClangBackEnd::FileContainer dotArrowCorrectionForForwardDeclaredClassPointer{ + Utf8StringLiteral(TESTDATA_DIR"/complete_withDotArrowCorrectionForForwardDeclaredClassPointer.cpp"), + projectPart.projectPartId(), + readFileContent(QStringLiteral("/complete_withDotArrowCorrectionForForwardDeclaredClassPointer.cpp")), + true + }; + ClangBackEnd::FileContainer globalCompletionAfterForwardDeclaredClassPointer{ + Utf8StringLiteral(TESTDATA_DIR"/complete_withGlobalCompletionAfterForwardDeclaredClassPointer.cpp"), + projectPart.projectPartId(), + readFileContent(QStringLiteral("/complete_withGlobalCompletionAfterForwardDeclaredClassPointer.cpp")), + true + }; }; using CodeCompleterSlowTest = CodeCompleter; @@ -425,10 +437,18 @@ TEST_F(CodeCompleterSlowTest, NoDotArrowCorrectionForOnlyDot) const ClangBackEnd::CodeCompletions completions = myCompleter.complete(5, 6); + ASSERT_TRUE(completions.isEmpty()); + ASSERT_THAT(myCompleter.neededCorrection(), ClangBackEnd::CompletionCorrection::NoCorrection); +} + +TEST_F(CodeCompleterSlowTest, GlobalCompletionForSpaceAfterOnlyDot) +{ + auto myCompleter = setupCompleter(noDotArrowCorrectionForOnlyDotFileContainer); + + const ClangBackEnd::CodeCompletions completions = myCompleter.complete(5, 7); ASSERT_THAT(completions, Contains(IsCodeCompletion(Utf8StringLiteral("Foo"), CodeCompletion::ClassCompletionKind))); - ASSERT_THAT(myCompleter.neededCorrection(), ClangBackEnd::CompletionCorrection::NoCorrection); } TEST_F(CodeCompleterSlowTest, NoDotArrowCorrectionForColonColon) @@ -439,6 +459,33 @@ TEST_F(CodeCompleterSlowTest, NoDotArrowCorrectionForColonColon) ASSERT_THAT(myCompleter.neededCorrection(), ClangBackEnd::CompletionCorrection::NoCorrection); } +TEST_F(CodeCompleterSlowTest, DotArrowCorrectionForForwardDeclaredClassPointer) +{ + auto myCompleter = setupCompleter(dotArrowCorrectionForForwardDeclaredClassPointer); + const ClangBackEnd::CodeCompletions completions = myCompleter.complete(5, 9); + + ASSERT_TRUE(completions.isEmpty()); + ASSERT_THAT(myCompleter.neededCorrection(), ClangBackEnd::CompletionCorrection::DotToArrowCorrection); +} + +TEST_F(CodeCompleterSlowTest, NoGlobalCompletionAfterForwardDeclaredClassPointer) +{ + auto myCompleter = setupCompleter(globalCompletionAfterForwardDeclaredClassPointer); + const ClangBackEnd::CodeCompletions completions = myCompleter.complete(5, 10); + + ASSERT_TRUE(completions.isEmpty()); + ASSERT_THAT(myCompleter.neededCorrection(), ClangBackEnd::CompletionCorrection::NoCorrection); +} + +TEST_F(CodeCompleterSlowTest, GlobalCompletionAfterForwardDeclaredClassPointer) +{ + auto myCompleter = setupCompleter(globalCompletionAfterForwardDeclaredClassPointer); + const ClangBackEnd::CodeCompletions completions = myCompleter.complete(6, 4); + + ASSERT_TRUE(!completions.isEmpty()); + ASSERT_THAT(myCompleter.neededCorrection(), ClangBackEnd::CompletionCorrection::NoCorrection); +} + ClangBackEnd::CodeCompleter CodeCompleter::setupCompleter( const ClangBackEnd::FileContainer &fileContainer) { diff --git a/tests/unit/unittest/data/complete_withDotArrowCorrectionForForwardDeclaredClassPointer.cpp b/tests/unit/unittest/data/complete_withDotArrowCorrectionForForwardDeclaredClassPointer.cpp new file mode 100644 index 00000000000..46e7e9d08bb --- /dev/null +++ b/tests/unit/unittest/data/complete_withDotArrowCorrectionForForwardDeclaredClassPointer.cpp @@ -0,0 +1,6 @@ +struct Bar; + +void g(Bar *bar) +{ + bar. +} diff --git a/tests/unit/unittest/data/complete_withGlobalCompletionAfterForwardDeclaredClassPointer.cpp b/tests/unit/unittest/data/complete_withGlobalCompletionAfterForwardDeclaredClassPointer.cpp new file mode 100644 index 00000000000..66ef372934f --- /dev/null +++ b/tests/unit/unittest/data/complete_withGlobalCompletionAfterForwardDeclaredClassPointer.cpp @@ -0,0 +1,7 @@ +struct Bar; + +void g(Bar *bar) +{ + bar-> + // white space preserver +} diff --git a/tests/unit/unittest/data/complete_withNoDotArrowCorrectionForOnlyDot.cpp b/tests/unit/unittest/data/complete_withNoDotArrowCorrectionForOnlyDot.cpp index 4a5d7894c4a..1607d6a6fbd 100644 --- a/tests/unit/unittest/data/complete_withNoDotArrowCorrectionForOnlyDot.cpp +++ b/tests/unit/unittest/data/complete_withNoDotArrowCorrectionForOnlyDot.cpp @@ -2,6 +2,6 @@ struct Foo { int member; }; void g(Foo *foo) { - . + . // white space preserver }