Clang: Treat brace initialization as constructor completion

Try to complete constructor after left brace with fallback
to normal completion.

Task-number: QTCREATORBUG-20957
Change-Id: I6c33790a3ee1e623a3d8abe9a44cfd821b6f3106
Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-08-20 13:15:13 +02:00
parent b8989f1a8a
commit 8d0391a4f9
8 changed files with 54 additions and 17 deletions

View File

@@ -262,7 +262,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const
if (tk.is(T_EOF_SYMBOL)) { if (tk.is(T_EOF_SYMBOL)) {
break; break;
} else if (tk.is(T_LPAREN)) { } else if (tk.is(T_LPAREN) || tk.is(T_LBRACE)) {
return scanner.startPosition() + tk.utf16charsBegin(); return scanner.startPosition() + tk.utf16charsBegin();
} else if (tk.is(T_RPAREN)) { } else if (tk.is(T_RPAREN)) {
int matchingBrace = scanner.startOfMatchingBrace(index); int matchingBrace = scanner.startOfMatchingBrace(index);

View File

@@ -83,7 +83,7 @@ void ActivationSequenceContextProcessor::process()
processComment(); processComment();
processInclude(); processInclude();
processSlashOutsideOfAString(); processSlashOutsideOfAString();
processLeftParen(); processLeftParenOrBrace();
processPreprocessorInclude(); processPreprocessorInclude();
} }
@@ -163,9 +163,9 @@ void ActivationSequenceContextProcessor::processSlashOutsideOfAString()
m_completionKind = CPlusPlus::T_EOF_SYMBOL; m_completionKind = CPlusPlus::T_EOF_SYMBOL;
} }
void ActivationSequenceContextProcessor::processLeftParen() void ActivationSequenceContextProcessor::processLeftParenOrBrace()
{ {
if (m_completionKind == CPlusPlus::T_LPAREN) { if (m_completionKind == CPlusPlus::T_LPAREN || m_completionKind == CPlusPlus::T_LBRACE) {
if (m_tokenIndex > 0) { if (m_tokenIndex > 0) {
// look at the token at the left of T_LPAREN // look at the token at the left of T_LPAREN
const CPlusPlus::Token &previousToken = m_tokens.at(m_tokenIndex - 1); const CPlusPlus::Token &previousToken = m_tokens.at(m_tokenIndex - 1);

View File

@@ -67,7 +67,7 @@ protected:
void processComment(); void processComment();
void processInclude(); void processInclude();
void processSlashOutsideOfAString(); void processSlashOutsideOfAString();
void processLeftParen(); void processLeftParenOrBrace();
void processPreprocessorInclude(); void processPreprocessorInclude();
void resetPositionsForEOFCompletionKind(); void resetPositionsForEOFCompletionKind();

View File

@@ -90,6 +90,7 @@ void ActivationSequenceProcessor::process()
processDot(); processDot();
processComma(); processComma();
processLeftParen(); processLeftParen();
processLeftBrace();
processColonColon(); processColonColon();
processArrow(); processArrow();
processDotStar(); processDotStar();
@@ -125,6 +126,14 @@ void ActivationSequenceProcessor::processLeftParen()
} }
} }
void ActivationSequenceProcessor::processLeftBrace()
{
if (m_char3 == QLatin1Char('{') && m_wantFunctionCall) {
m_completionKind = CPlusPlus::T_LBRACE;
m_offset = 1;
}
}
void ActivationSequenceProcessor::processColonColon() void ActivationSequenceProcessor::processColonColon()
{ {
if (m_char2 == QLatin1Char(':') && m_char3 == QLatin1Char(':')) { if (m_char2 == QLatin1Char(':') && m_char3 == QLatin1Char(':')) {

View File

@@ -49,6 +49,7 @@ private:
void processDot(); void processDot();
void processComma(); void processComma();
void processLeftParen(); void processLeftParen();
void processLeftBrace();
void processColonColon(); void processColonColon();
void processArrow(); void processArrow();
void processDotStar(); void processDotStar();

View File

@@ -188,7 +188,8 @@ IAssistProposal *ClangCompletionAssistProcessor::perform(const AssistInterface *
static CodeCompletions filterFunctionSignatures(const CodeCompletions &completions) static CodeCompletions filterFunctionSignatures(const CodeCompletions &completions)
{ {
return ::Utils::filtered(completions, [](const CodeCompletion &completion) { return ::Utils::filtered(completions, [](const CodeCompletion &completion) {
return completion.completionKind == CodeCompletion::FunctionOverloadCompletionKind; return completion.completionKind == CodeCompletion::FunctionOverloadCompletionKind
|| completion.completionKind == CodeCompletion::ConstructorCompletionKind;
}); });
} }
@@ -197,19 +198,24 @@ void ClangCompletionAssistProcessor::handleAvailableCompletions(
{ {
QTC_CHECK(m_completions.isEmpty()); QTC_CHECK(m_completions.isEmpty());
if (m_sentRequestType == NormalCompletion) { if (m_sentRequestType == FunctionHintCompletion){
const CodeCompletions functionSignatures = filterFunctionSignatures(completions);
if (!functionSignatures.isEmpty()) {
setAsyncProposalAvailable(createFunctionHintProposal(functionSignatures));
return;
}
// else: Proceed with a normal completion in case:
// 1) it was not a function call, but e.g. a function declaration like "void f("
// 2) '{' meant not a constructor call.
}
//m_sentRequestType == NormalCompletion or function signatures were empty
m_completions = toAssistProposalItems(completions, m_interface.data()); m_completions = toAssistProposalItems(completions, m_interface.data());
if (m_addSnippets && !m_completions.isEmpty()) if (m_addSnippets && !m_completions.isEmpty())
addSnippets(); addSnippets();
setAsyncProposalAvailable(createProposal()); setAsyncProposalAvailable(createProposal());
} else {
const CodeCompletions functionSignatures = filterFunctionSignatures(completions);
if (!functionSignatures.isEmpty())
setAsyncProposalAvailable(createFunctionHintProposal(functionSignatures));
// else: Not a function call, but e.g. a function declaration like "void f("
}
} }
const TextEditorWidget *ClangCompletionAssistProcessor::textEditorWidget() const const TextEditorWidget *ClangCompletionAssistProcessor::textEditorWidget() const

View File

@@ -145,7 +145,7 @@ void ClangCompletionContextAnalyzer::handleCommaInFunctionCall()
void ClangCompletionContextAnalyzer::handleFunctionCall(int afterOperatorPosition) void ClangCompletionContextAnalyzer::handleFunctionCall(int afterOperatorPosition)
{ {
if (m_completionOperator == T_LPAREN) { if (m_completionOperator == T_LPAREN || m_completionOperator == T_LBRACE) {
ExpressionUnderCursor expressionUnderCursor(m_languageFeatures); ExpressionUnderCursor expressionUnderCursor(m_languageFeatures);
QTextCursor textCursor(m_interface->textDocument()); QTextCursor textCursor(m_interface->textDocument());
textCursor.setPosition(m_positionEndOfExpression); textCursor.setPosition(m_positionEndOfExpression);

View File

@@ -269,6 +269,27 @@ TEST_F(ClangCompletionContextAnalyzer, WhitespaceAfterFunctionName)
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText)); ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText));
} }
TEST_F(ClangCompletionContextAnalyzer, ConstructorCallWithBraceInitializer)
{
auto analyzer = runAnalyzer("f{@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText));
}
TEST_F(ClangCompletionContextAnalyzer, ArgumentTwoWithSpaceAtConstructorCallWithBraceInitializer)
{
auto analyzer = runAnalyzer("f{1, @");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, -3, -3, positionInText));
}
TEST_F(ClangCompletionContextAnalyzer, WhitespaceBeforeConstructorCallWithBraceInitializer)
{
auto analyzer = runAnalyzer("foo {@");
ASSERT_THAT(analyzer, HasResult(CCA::PassThroughToLibClangAfterLeftParen, 0, 0, positionInText));
}
TEST_F(ClangCompletionContextAnalyzer, AfterOpeningParenthesis) TEST_F(ClangCompletionContextAnalyzer, AfterOpeningParenthesis)
{ {
auto analyzer = runAnalyzer("(@"); auto analyzer = runAnalyzer("(@");