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)) {
break;
} else if (tk.is(T_LPAREN)) {
} else if (tk.is(T_LPAREN) || tk.is(T_LBRACE)) {
return scanner.startPosition() + tk.utf16charsBegin();
} else if (tk.is(T_RPAREN)) {
int matchingBrace = scanner.startOfMatchingBrace(index);

View File

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

View File

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

View File

@@ -90,6 +90,7 @@ void ActivationSequenceProcessor::process()
processDot();
processComma();
processLeftParen();
processLeftBrace();
processColonColon();
processArrow();
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()
{
if (m_char2 == QLatin1Char(':') && m_char3 == QLatin1Char(':')) {

View File

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

View File

@@ -188,7 +188,8 @@ IAssistProposal *ClangCompletionAssistProcessor::perform(const AssistInterface *
static CodeCompletions filterFunctionSignatures(const CodeCompletions &completions)
{
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());
if (m_sentRequestType == NormalCompletion) {
m_completions = toAssistProposalItems(completions, m_interface.data());
if (m_addSnippets && !m_completions.isEmpty())
addSnippets();
setAsyncProposalAvailable(createProposal());
} else {
if (m_sentRequestType == FunctionHintCompletion){
const CodeCompletions functionSignatures = filterFunctionSignatures(completions);
if (!functionSignatures.isEmpty())
if (!functionSignatures.isEmpty()) {
setAsyncProposalAvailable(createFunctionHintProposal(functionSignatures));
// else: Not a function call, but e.g. a function declaration like "void f("
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());
if (m_addSnippets && !m_completions.isEmpty())
addSnippets();
setAsyncProposalAvailable(createProposal());
}
const TextEditorWidget *ClangCompletionAssistProcessor::textEditorWidget() const

View File

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

View File

@@ -269,6 +269,27 @@ TEST_F(ClangCompletionContextAnalyzer, WhitespaceAfterFunctionName)
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)
{
auto analyzer = runAnalyzer("(@");