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();
|
return !hasResults() && isDotCompletion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClangCodeCompleteResults::hasUnknownContext() const
|
||||||
|
{
|
||||||
|
const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults);
|
||||||
|
return contexts == CXCompletionContext_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
bool ClangCodeCompleteResults::isDotCompletion() const
|
bool ClangCodeCompleteResults::isDotCompletion() const
|
||||||
{
|
{
|
||||||
const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults);
|
const unsigned long long contexts = clang_codeCompleteGetContexts(cxCodeCompleteResults);
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public:
|
|||||||
bool hasResults() const;
|
bool hasResults() const;
|
||||||
bool hasNoResultsForDotCompletion() const;
|
bool hasNoResultsForDotCompletion() const;
|
||||||
|
|
||||||
|
bool hasUnknownContext() const;
|
||||||
bool isDotCompletion() const;
|
bool isDotCompletion() const;
|
||||||
|
|
||||||
CXCodeCompleteResults *data() const;
|
CXCodeCompleteResults *data() const;
|
||||||
|
|||||||
@@ -56,6 +56,22 @@ CodeCompletions toCodeCompletions(const ClangCodeCompleteResults &results)
|
|||||||
return codeCompletions;
|
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
|
} // anonymous namespace
|
||||||
|
|
||||||
CodeCompleter::CodeCompleter(const TranslationUnit &translationUnit,
|
CodeCompleter::CodeCompleter(const TranslationUnit &translationUnit,
|
||||||
@@ -70,7 +86,7 @@ CodeCompletions CodeCompleter::complete(uint line, uint column)
|
|||||||
neededCorrection_ = CompletionCorrection::NoCorrection;
|
neededCorrection_ = CompletionCorrection::NoCorrection;
|
||||||
|
|
||||||
ClangCodeCompleteResults results = completeHelper(line, column);
|
ClangCodeCompleteResults results = completeHelper(line, column);
|
||||||
|
filterUnknownContextResults(results, unsavedFile(), line, column);
|
||||||
tryDotArrowCorrectionIfNoResults(results, line, column);
|
tryDotArrowCorrectionIfNoResults(results, line, column);
|
||||||
|
|
||||||
return toCodeCompletions(results);
|
return toCodeCompletions(results);
|
||||||
@@ -139,6 +155,7 @@ ClangCodeCompleteResults CodeCompleter::completeWithArrowInsteadOfDot(uint line,
|
|||||||
results = completeHelper(line, column + 1);
|
results = completeHelper(line, column + 1);
|
||||||
if (results.hasResults())
|
if (results.hasResults())
|
||||||
neededCorrection_ = CompletionCorrection::DotToArrowCorrection;
|
neededCorrection_ = CompletionCorrection::DotToArrowCorrection;
|
||||||
|
filterUnknownContextResults(results, unsavedFile(), line, column+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
|||||||
@@ -176,6 +176,18 @@ protected:
|
|||||||
readFileContent(QStringLiteral("/complete_withNoDotArrowCorrectionForColonColon.cpp")),
|
readFileContent(QStringLiteral("/complete_withNoDotArrowCorrectionForColonColon.cpp")),
|
||||||
true
|
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;
|
using CodeCompleterSlowTest = CodeCompleter;
|
||||||
@@ -425,10 +437,18 @@ TEST_F(CodeCompleterSlowTest, NoDotArrowCorrectionForOnlyDot)
|
|||||||
|
|
||||||
const ClangBackEnd::CodeCompletions completions = myCompleter.complete(5, 6);
|
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,
|
ASSERT_THAT(completions,
|
||||||
Contains(IsCodeCompletion(Utf8StringLiteral("Foo"),
|
Contains(IsCodeCompletion(Utf8StringLiteral("Foo"),
|
||||||
CodeCompletion::ClassCompletionKind)));
|
CodeCompletion::ClassCompletionKind)));
|
||||||
ASSERT_THAT(myCompleter.neededCorrection(), ClangBackEnd::CompletionCorrection::NoCorrection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CodeCompleterSlowTest, NoDotArrowCorrectionForColonColon)
|
TEST_F(CodeCompleterSlowTest, NoDotArrowCorrectionForColonColon)
|
||||||
@@ -439,6 +459,33 @@ TEST_F(CodeCompleterSlowTest, NoDotArrowCorrectionForColonColon)
|
|||||||
ASSERT_THAT(myCompleter.neededCorrection(), ClangBackEnd::CompletionCorrection::NoCorrection);
|
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(
|
ClangBackEnd::CodeCompleter CodeCompleter::setupCompleter(
|
||||||
const ClangBackEnd::FileContainer &fileContainer)
|
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)
|
void g(Foo *foo)
|
||||||
{
|
{
|
||||||
.
|
. // white space preserver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user