Clang: Fix adding completion snippets after {

...e.g. as in "void f() {".

The criteria whether to change snippets got invalidated with

    commit 8d0391a4f9
    Clang: Treat brace initialization as constructor completion

as the completion operator might be T_LBRACE now instead of T_EOF_SYMBOL
for normal completions.

This fixes the plugin test ClangCodeCompletionTest::testCompleteGlobals.

Add also unit tests.

Change-Id: I85cf522b9b307359c5c3e25198dd228cbb68ded0
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Nikolai Kosjar
2018-10-24 10:05:53 +02:00
parent 7d3686359a
commit d946ff5403
4 changed files with 60 additions and 47 deletions

View File

@@ -262,6 +262,7 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper()
analyzer.analyze();
m_completionOperator = analyzer.completionOperator();
m_positionForProposal = analyzer.positionForProposal();
m_addSnippets = analyzer.addSnippets();
QByteArray modifiedFileContent;
@@ -285,7 +286,6 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper()
analyzer.positionEndOfExpression());
Q_FALLTHROUGH();
case ClangCompletionContextAnalyzer::PassThroughToLibClang: {
m_addSnippets = m_completionOperator == T_EOF_SYMBOL;
m_sentRequestType = NormalCompletion;
m_requestSent = sendCompletionRequest(analyzer.positionForClang(),
modifiedFileContent);

View File

@@ -169,6 +169,7 @@ void ClangCompletionContextAnalyzer::handleFunctionCall(int afterOperatorPositio
m_positionForProposal,
functionNameStart);
} else { // e.g. "(" without any function name in front
m_addSnippets = true;
m_positionForProposal = afterOperatorPosition;
setActionAndClangPosition(PassThroughToLibClang, afterOperatorPosition);
}
@@ -179,6 +180,8 @@ void ClangCompletionContextAnalyzer::handleFunctionCall(int afterOperatorPositio
bool ClangCompletionContextAnalyzer::handleNonFunctionCall(int position)
{
if (isTokenForPassThrough(m_completionOperator)) {
if (m_completionOperator == T_EOF_SYMBOL)
m_addSnippets = true;
setActionAndClangPosition(PassThroughToLibClang, position);
return true;
} else if (m_completionOperator == T_DOXY_COMMENT) {

View File

@@ -58,6 +58,7 @@ public:
int positionForClang() const { return m_positionForClang; }
int functionNameStart() const { return m_functionNameStart; }
int positionEndOfExpression() const { return m_positionEndOfExpression; }
bool addSnippets() const { return m_addSnippets; }
private:
ClangCompletionContextAnalyzer();
@@ -84,6 +85,7 @@ private:
int m_positionForClang = -1;
int m_functionNameStart = -1;
int m_positionEndOfExpression = -1;
bool m_addSnippets = false;
};
} // namespace Internal

View File

@@ -92,25 +92,29 @@ MATCHER(IsPassThroughToClang, std::string(negation ? "isn't" : "is") + " passed
}
// Offsets are relative to positionInText
MATCHER_P4(HasResult,
MATCHER_P5(HasResult,
completionAction,
positionForClangOffset,
positionForProposalOffset,
positionInText,
addSnippets,
std::string(negation ? "hasn't" : "has")
+ " result of completion action " + PrintToString(completionAction)
+ " and offset for clang " + PrintToString(positionForClangOffset)
+ " and offset for proprosal " + PrintToString(positionForProposalOffset))
+ " and offset for proprosal " + PrintToString(positionForProposalOffset)
+ " and addSnippets " + PrintToString(addSnippets))
{
const int actualPositionForClangOffset = arg.positionForClang() - positionInText;
const int actualPositionForProposalOffset = arg.positionForProposal() - positionInText;
if (arg.completionAction() != completionAction
|| actualPositionForClangOffset != positionForClangOffset
|| actualPositionForProposalOffset != positionForProposalOffset) {
|| actualPositionForProposalOffset != positionForProposalOffset
|| addSnippets != arg.addSnippets()) {
*result_listener << "completion action is " << PrintToString(arg.completionAction())
<< " and offset for clang is " << PrintToString(actualPositionForClangOffset)
<< " and offset for proprosal is " << PrintToString(actualPositionForProposalOffset);
<< " and offset for proprosal is " << PrintToString(actualPositionForProposalOffset)
<< " and addSnippets is " << PrintToString(arg.addSnippets());
return false;
}
@@ -118,24 +122,28 @@ MATCHER_P4(HasResult,
}
// Offsets are relative to positionInText
MATCHER_P4(HasResultWithoutClangDifference,
MATCHER_P5(HasResultWithoutClangDifference,
completionAction,
positionForClangOffset,
positionForProposalOffset,
positionInText,
addSnippets,
std::string(negation ? "hasn't" : "has")
+ " result of completion action " + PrintToString(completionAction)
+ " and offset for clang " + PrintToString(positionForClangOffset)
+ " and offset for proprosal " + PrintToString(positionForProposalOffset))
+ " and offset for proprosal " + PrintToString(positionForProposalOffset)
+ " and addSnippets " + PrintToString(addSnippets))
{
const int actualPositionForProposalOffset = arg.positionForProposal() - positionInText;
if (arg.completionAction() != completionAction
|| arg.positionForClang() != positionForClangOffset
|| actualPositionForProposalOffset != positionForProposalOffset) {
|| actualPositionForProposalOffset != positionForProposalOffset
|| addSnippets != arg.addSnippets()) {
*result_listener << "completion action is " << PrintToString(arg.completionAction())
<< " and offset for clang is " << PrintToString(arg.positionForClang())
<< " and offset for proprosal is " << PrintToString(actualPositionForProposalOffset);
<< " and offset for proprosal is " << PrintToString(actualPositionForProposalOffset)
<< " and addSnippets is " << PrintToString(arg.addSnippets());
return false;
}
@@ -168,224 +176,224 @@ TEST_F(ClangCompletionContextAnalyzer, WordsBeforeCursor)
{
auto analyzer = runAnalyzer("foo bar@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, true));
}
TEST_F(ClangCompletionContextAnalyzer, AfterSpace)
{
auto analyzer = runAnalyzer("foo @");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true));
}
TEST_F(ClangCompletionContextAnalyzer, AfterQualification)
{
auto analyzer = runAnalyzer(" Foo::@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AtEndOfDotMember)
{
auto analyzer = runAnalyzer("o.mem@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AtEndOfDotMemberWithSpaceInside)
{
auto analyzer = runAnalyzer("o. mem@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AtBeginOfDotMember)
{
auto analyzer = runAnalyzer("o.@mem");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AtBeginOfDotMemberWithSpaceInside)
{
auto analyzer = runAnalyzer("o. @mem");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AtEndOfArrow)
{
auto analyzer = runAnalyzer("o->mem@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AtEndOfArrowWithSpaceInside)
{
auto analyzer = runAnalyzer("o-> mem@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AtBeginOfArrow)
{
auto analyzer = runAnalyzer("o->@mem");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AtBeginOfArrowWithSpaceInside)
{
auto analyzer = runAnalyzer("o-> @mem");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentOneAtCall)
{
auto analyzer = runAnalyzer("f(@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentTwoAtCall)
{
auto analyzer = runAnalyzer("f(1,@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -2, -2, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -2, -2, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentTwoWithSpaceAtCall)
{
auto analyzer = runAnalyzer("f(1, @");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, WhitespaceAfterFunctionName)
{
auto analyzer = runAnalyzer("foo (@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, ConstructorCallWithBraceInitializer)
{
auto analyzer = runAnalyzer("f{@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentTwoWithSpaceAtConstructorCallWithBraceInitializer)
{
auto analyzer = runAnalyzer("f{1, @");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, WhitespaceBeforeConstructorCallWithBraceInitializer)
{
auto analyzer = runAnalyzer("foo {@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, OpenFunctionScopeNotAConstructor)
{
auto analyzer = runAnalyzer("foo() {@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true));
}
TEST_F(ClangCompletionContextAnalyzer, AfterOpeningParenthesis)
{
auto analyzer = runAnalyzer("(@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentOneAtSignal)
{
auto analyzer = runAnalyzer("SIGNAL(@");
ASSERT_THAT(analyzer, HasResult(CCA::CompleteSignal, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::CompleteSignal, 0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentOneWithLettersAtSignal)
{
auto analyzer = runAnalyzer("SIGNAL(foo@");
ASSERT_THAT(analyzer, HasResult(CCA::CompleteSignal, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::CompleteSignal, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentOneAtSlot)
{
auto analyzer = runAnalyzer("SLOT(@");
ASSERT_THAT(analyzer, HasResult(CCA::CompleteSlot, -0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::CompleteSlot, -0, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentOneWithLettersAtSlot)
{
auto analyzer = runAnalyzer("SLOT(foo@");
ASSERT_THAT(analyzer, HasResult(CCA::CompleteSlot, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::CompleteSlot, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, DoxygenWithBackslash)
{
auto analyzer = runAnalyzer("//! \\@");
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, 0, positionInText));
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, DoxygenWithAt)
{
auto analyzer = runAnalyzer("//! @@");
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, 0, positionInText));
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, DoxygenWithParameter)
{
auto analyzer = runAnalyzer("//! \\par@");
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, -3, positionInText));
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteDoxygenKeyword, -1, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, Preprocessor)
{
auto analyzer = runAnalyzer("#@");
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompletePreprocessorDirective, -1, 0, positionInText));
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompletePreprocessorDirective, -1, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, PreprocessorIf)
{
auto analyzer = runAnalyzer("#if@");
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompletePreprocessorDirective, -1, -2, positionInText));
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompletePreprocessorDirective, -1, -2, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, LocalInclude)
{
auto analyzer = runAnalyzer("#include \"foo@\"");
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, -3, positionInText));
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, GlobalInclude)
{
auto analyzer = runAnalyzer("#include <foo@>");
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, -3, positionInText));
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, GlocalIncludeWithDirectory)
{
auto analyzer = runAnalyzer("#include <foo/@>");
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, 0, positionInText));
ASSERT_THAT(analyzer, HasResultWithoutClangDifference(CCA::CompleteIncludePath, -1, 0, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, AfterQuote)
@@ -463,7 +471,7 @@ TEST_F(ClangCompletionContextAnalyzer, AfterOneLineCommentLine)
auto analyzer = runAnalyzer("// comment\n"
"@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true));
}
TEST_F(ClangCompletionContextAnalyzer, AfterEmptyOneLineComment)
@@ -471,7 +479,7 @@ TEST_F(ClangCompletionContextAnalyzer, AfterEmptyOneLineComment)
auto analyzer = runAnalyzer("//\n"
"@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true));
}
TEST_F(ClangCompletionContextAnalyzer, AfterOneLineDoxygenComment1)
@@ -479,7 +487,7 @@ TEST_F(ClangCompletionContextAnalyzer, AfterOneLineDoxygenComment1)
auto analyzer = runAnalyzer("/// comment\n"
"@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true));
}
TEST_F(ClangCompletionContextAnalyzer, AfterOneLineDoxygenComment2)
@@ -487,7 +495,7 @@ TEST_F(ClangCompletionContextAnalyzer, AfterOneLineDoxygenComment2)
auto analyzer = runAnalyzer("//! comment \n"
"@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClang, 0, 0, positionInText, true));
}
TEST_F(ClangCompletionContextAnalyzer, BeginEndComment)
@@ -529,7 +537,7 @@ TEST_F(ClangCompletionContextAnalyzer, TemplatedFunctionSecondArgument)
{
auto analyzer = runAnalyzer("f < decltype(bar -> member) > (1, @");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText));
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText, false));
}
TEST_F(ClangCompletionContextAnalyzer, FunctionNameStartPosition)