CppEditor: Add support for init statements in if conditions

Fixes: QTCREATORBUG-29182
Change-Id: I9b7969da694b368236246123ad0028d8e754e903
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Christian Kandeler
2023-05-24 15:18:48 +02:00
parent 07764bdf15
commit c8f29b9e01
9 changed files with 68 additions and 6 deletions

View File

@@ -1779,6 +1779,8 @@ public:
int if_token = 0; int if_token = 0;
int constexpr_token = 0; int constexpr_token = 0;
int lparen_token = 0; int lparen_token = 0;
DeclarationAST *initDecl = nullptr;
StatementAST *initStmt = nullptr;
ExpressionAST *condition = nullptr; ExpressionAST *condition = nullptr;
int rparen_token = 0; int rparen_token = 0;
StatementAST *statement = nullptr; StatementAST *statement = nullptr;

View File

@@ -785,6 +785,10 @@ IfStatementAST *IfStatementAST::clone(MemoryPool *pool) const
ast->if_token = if_token; ast->if_token = if_token;
ast->constexpr_token = constexpr_token; ast->constexpr_token = constexpr_token;
ast->lparen_token = lparen_token; ast->lparen_token = lparen_token;
if (initDecl)
ast->initDecl = initDecl->clone(pool);
if (initStmt)
ast->initStmt = initStmt->clone(pool);
if (condition) if (condition)
ast->condition = condition->clone(pool); ast->condition = condition->clone(pool);
ast->rparen_token = rparen_token; ast->rparen_token = rparen_token;

View File

@@ -1318,6 +1318,16 @@ bool ASTMatcher::match(IfStatementAST *node, IfStatementAST *pattern)
pattern->lparen_token = node->lparen_token; pattern->lparen_token = node->lparen_token;
if (!pattern->initDecl)
pattern->initDecl = node->initDecl;
else if (!AST::match(node->initDecl, pattern->initDecl, this))
return false;
if (!pattern->initStmt)
pattern->initStmt = node->initStmt;
else if (!AST::match(node->initStmt, pattern->initStmt, this))
return false;
if (! pattern->condition) if (! pattern->condition)
pattern->condition = node->condition; pattern->condition = node->condition;
else if (! AST::match(node->condition, pattern->condition, this)) else if (! AST::match(node->condition, pattern->condition, this))

View File

@@ -563,6 +563,8 @@ void ForStatementAST::accept0(ASTVisitor *visitor)
void IfStatementAST::accept0(ASTVisitor *visitor) void IfStatementAST::accept0(ASTVisitor *visitor)
{ {
if (visitor->visit(this)) { if (visitor->visit(this)) {
accept(initDecl, visitor);
accept(initStmt, visitor);
accept(condition, visitor); accept(condition, visitor);
accept(statement, visitor); accept(statement, visitor);
accept(else_statement, visitor); accept(else_statement, visitor);

View File

@@ -1528,6 +1528,10 @@ bool Bind::visit(IfStatementAST *ast)
ast->symbol = block; ast->symbol = block;
Scope *previousScope = switchScope(block); Scope *previousScope = switchScope(block);
if (ast->initDecl)
this->declaration(ast->initDecl);
else if (ast->initStmt)
this->statement(ast->initStmt);
/*ExpressionTy condition =*/ this->expression(ast->condition); /*ExpressionTy condition =*/ this->expression(ast->condition);
this->statement(ast->statement); this->statement(ast->statement);
this->statement(ast->else_statement); this->statement(ast->else_statement);

View File

@@ -3511,12 +3511,14 @@ bool Parser::parseExpressionStatement(StatementAST *&node)
ExpressionAST *expression = nullptr; ExpressionAST *expression = nullptr;
if (parseExpression(expression)) { if (parseExpression(expression)) {
ExpressionStatementAST *ast = new (previousPool) ExpressionStatementAST; if (LA() == T_SEMICOLON) {
if (expression) ExpressionStatementAST *ast = new (previousPool) ExpressionStatementAST;
ast->expression = expression->clone(previousPool); ast->semicolon_token = consumeToken();
match(T_SEMICOLON, &ast->semicolon_token); if (expression)
node = ast; ast->expression = expression->clone(previousPool);
parsed = true; node = ast;
parsed = true;
}
} }
_inExpressionStatement = wasInExpressionStatement; _inExpressionStatement = wasInExpressionStatement;
@@ -4072,6 +4074,19 @@ bool Parser::parseIfStatement(StatementAST *&node)
ast->constexpr_token = consumeToken(); ast->constexpr_token = consumeToken();
} }
match(T_LPAREN, &ast->lparen_token); match(T_LPAREN, &ast->lparen_token);
// C++17: init-statement
if (_languageFeatures.cxx17Enabled) {
const int savedCursor = cursor();
const bool savedBlockErrors = _translationUnit->blockErrors(true);
if (!parseSimpleDeclaration(ast->initDecl)) {
rewind(savedCursor);
if (!parseExpressionStatement(ast->initStmt))
rewind(savedCursor);
}
_translationUnit->blockErrors(savedBlockErrors);
}
parseCondition(ast->condition); parseCondition(ast->condition);
match(T_RPAREN, &ast->rparen_token); match(T_RPAREN, &ast->rparen_token);
if (! parseStatement(ast->statement)) if (! parseStatement(ast->statement))

View File

@@ -455,6 +455,7 @@ struct LanguageFeatures
unsigned int cxxEnabled : 1; unsigned int cxxEnabled : 1;
unsigned int cxx11Enabled : 1; unsigned int cxx11Enabled : 1;
unsigned int cxx14Enabled : 1; unsigned int cxx14Enabled : 1;
unsigned int cxx17Enabled : 1;
unsigned int cxx20Enabled : 1; unsigned int cxx20Enabled : 1;
unsigned int objCEnabled : 1; unsigned int objCEnabled : 1;
unsigned int c99Enabled : 1; unsigned int c99Enabled : 1;

View File

@@ -163,6 +163,7 @@ CPlusPlus::LanguageFeatures ProjectPart::deriveLanguageFeatures() const
CPlusPlus::LanguageFeatures features; CPlusPlus::LanguageFeatures features;
features.cxx11Enabled = languageVersion >= Utils::LanguageVersion::CXX11; features.cxx11Enabled = languageVersion >= Utils::LanguageVersion::CXX11;
features.cxx14Enabled = languageVersion >= Utils::LanguageVersion::CXX14; features.cxx14Enabled = languageVersion >= Utils::LanguageVersion::CXX14;
features.cxx17Enabled = languageVersion >= Utils::LanguageVersion::CXX17;
features.cxx20Enabled = languageVersion >= Utils::LanguageVersion::CXX20; features.cxx20Enabled = languageVersion >= Utils::LanguageVersion::CXX20;
features.cxxEnabled = hasCxx; features.cxxEnabled = hasCxx;
features.c99Enabled = languageVersion >= Utils::LanguageVersion::C99; features.c99Enabled = languageVersion >= Utils::LanguageVersion::C99;

View File

@@ -150,6 +150,7 @@ private Q_SLOTS:
void requiresClause(); void requiresClause();
void coroutines(); void coroutines();
void genericLambdas(); void genericLambdas();
void ifStatementWithInitialization();
}; };
@@ -550,5 +551,27 @@ int main()
QVERIFY(!hasErrors); QVERIFY(!hasErrors);
} }
void tst_cxx11::ifStatementWithInitialization()
{
LanguageFeatures features;
features.cxxEnabled = true;
features.cxx11Enabled = features.cxx14Enabled = features.cxx17Enabled = true;
const QString source = R"(
int main()
{
if (bool b = true; b)
b = false;
}
)";
QByteArray errors;
Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile"));
processDocument(doc, source.toUtf8(), features, &errors);
const bool hasErrors = !errors.isEmpty();
if (hasErrors)
qDebug().noquote() << errors;
QVERIFY(!hasErrors);
}
QTEST_APPLESS_MAIN(tst_cxx11) QTEST_APPLESS_MAIN(tst_cxx11)
#include "tst_cxx11.moc" #include "tst_cxx11.moc"