forked from qt-creator/qt-creator
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:
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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();
|
||||||
|
|
||||||
|
@@ -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(':')) {
|
||||||
|
@@ -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();
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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("(@");
|
||||||
|
Reference in New Issue
Block a user