forked from qt-creator/qt-creator
Clang: fix completion after forward-declared class
Do not complete -> and . with global completions if foo is a ptr/ref to forward-declared class. Change-Id: I41e6745ffb07be1d973fe6a8132824f1b3bf7fb1 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
bool hasResults() const;
|
||||
bool hasNoResultsForDotCompletion() const;
|
||||
|
||||
bool hasUnknownContext() const;
|
||||
bool isDotCompletion() const;
|
||||
|
||||
CXCodeCompleteResults *data() const;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
struct Bar;
|
||||
|
||||
void g(Bar *bar)
|
||||
{
|
||||
bar.
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
struct Bar;
|
||||
|
||||
void g(Bar *bar)
|
||||
{
|
||||
bar->
|
||||
// white space preserver
|
||||
}
|
||||
@@ -2,6 +2,6 @@ struct Foo { int member; };
|
||||
|
||||
void g(Foo *foo)
|
||||
{
|
||||
.
|
||||
. // white space preserver
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user