forked from qt-creator/qt-creator
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:
2
src/libs/3rdparty/cplusplus/AST.h
vendored
2
src/libs/3rdparty/cplusplus/AST.h
vendored
@@ -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;
|
||||||
|
|||||||
4
src/libs/3rdparty/cplusplus/ASTClone.cpp
vendored
4
src/libs/3rdparty/cplusplus/ASTClone.cpp
vendored
@@ -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;
|
||||||
|
|||||||
10
src/libs/3rdparty/cplusplus/ASTMatcher.cpp
vendored
10
src/libs/3rdparty/cplusplus/ASTMatcher.cpp
vendored
@@ -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))
|
||||||
|
|||||||
2
src/libs/3rdparty/cplusplus/ASTVisit.cpp
vendored
2
src/libs/3rdparty/cplusplus/ASTVisit.cpp
vendored
@@ -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);
|
||||||
|
|||||||
4
src/libs/3rdparty/cplusplus/Bind.cpp
vendored
4
src/libs/3rdparty/cplusplus/Bind.cpp
vendored
@@ -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);
|
||||||
|
|||||||
27
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
27
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
@@ -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))
|
||||||
|
|||||||
1
src/libs/3rdparty/cplusplus/Token.h
vendored
1
src/libs/3rdparty/cplusplus/Token.h
vendored
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user