diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -800,6 +800,30 @@ return true; } + bool TraverseIfStmt(IfStmt *S) { + bool Result = [&, this]() { + if (S->getInit() && !TraverseStmt(S->getInit())) { + return false; + } + // In cases where the condition is an initialized declaration in a + // statement, we want to preserve the declaration and ignore the + // implicit condition expression in the syntax tree. + if (S->hasVarStorage()) { + if (!TraverseStmt(S->getConditionVariableDeclStmt())) + return false; + } else if (S->getCond() && !TraverseStmt(S->getCond())) + return false; + + if (S->getThen() && !TraverseStmt(S->getThen())) + return false; + if (S->getElse() && !TraverseStmt(S->getElse())) + return false; + return true; + }(); + WalkUpFromIfStmt(S); + return Result; + } + bool TraverseCXXForRangeStmt(CXXForRangeStmt *S) { // We override to traverse range initializer as VarDecl. // RAV traverses it as a statement, we produce invalid node kinds in that @@ -1426,6 +1450,10 @@ bool WalkUpFromIfStmt(IfStmt *S) { Builder.markChildToken(S->getIfLoc(), syntax::NodeRole::IntroducerKeyword); + Stmt *ConditionStatement = S->getCond(); + if (S->hasVarStorage()) + ConditionStatement = S->getConditionVariableDeclStmt(); + Builder.markStmtChild(ConditionStatement, syntax::NodeRole::Condition); Builder.markStmtChild(S->getThen(), syntax::NodeRole::ThenStatement); Builder.markChildToken(S->getElseLoc(), syntax::NodeRole::ElseKeyword); Builder.markStmtChild(S->getElse(), syntax::NodeRole::ElseStatement); diff --git a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp --- a/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/BuildTreeTest.cpp @@ -204,8 +204,9 @@ IfStatement Statement |-'if' IntroducerKeyword |-'(' -|-IntegerLiteralExpression -| `-'1' LiteralToken +|-ExpressionStatement Condition +| `-IntegerLiteralExpression Expression +| `-'1' LiteralToken |-')' `-CompoundStatement ThenStatement |-'{' OpenParen @@ -215,8 +216,9 @@ IfStatement Statement |-'if' IntroducerKeyword |-'(' -|-IntegerLiteralExpression -| `-'1' LiteralToken +|-ExpressionStatement Condition +| `-IntegerLiteralExpression Expression +| `-'1' LiteralToken |-')' |-CompoundStatement ThenStatement | |-'{' OpenParen @@ -225,8 +227,9 @@ `-IfStatement ElseStatement |-'if' IntroducerKeyword |-'(' - |-IntegerLiteralExpression - | `-'0' LiteralToken + |-ExpressionStatement Condition + | `-IntegerLiteralExpression Expression + | `-'0' LiteralToken |-')' `-CompoundStatement ThenStatement |-'{' OpenParen @@ -234,6 +237,61 @@ )txt"})); } +TEST_P(BuildSyntaxTreeTest, IfDecl) { + if (!GetParam().isCXX17OrLater()) { + return; + } + EXPECT_TRUE(treeDumpEqualOnAnnotations( + R"cpp( +void test() { + [[if (int a = 5) {}]] + [[if (int a; a == 5) {}]] +} +)cpp", + {R"txt( +IfStatement Statement +|-'if' IntroducerKeyword +|-'(' +|-DeclarationStatement Condition +| `-SimpleDeclaration +| |-'int' +| `-DeclaratorList Declarators +| `-SimpleDeclarator ListElement +| |-'a' +| |-'=' +| `-IntegerLiteralExpression +| `-'5' LiteralToken +|-')' +`-CompoundStatement ThenStatement + |-'{' OpenParen + `-'}' CloseParen + )txt", + R"txt( +IfStatement Statement +|-'if' IntroducerKeyword +|-'(' +|-DeclarationStatement +| |-SimpleDeclaration +| | |-'int' +| | `-DeclaratorList Declarators +| | `-SimpleDeclarator ListElement +| | `-'a' +| `-';' +|-ExpressionStatement Condition +| `-BinaryOperatorExpression Expression +| |-IdExpression LeftHandSide +| | `-UnqualifiedId UnqualifiedId +| | `-'a' +| |-'==' OperatorToken +| `-IntegerLiteralExpression RightHandSide +| `-'5' LiteralToken +|-')' +`-CompoundStatement ThenStatement + |-'{' OpenParen + `-'}' CloseParen +)txt"})); +} + TEST_P(BuildSyntaxTreeTest, For) { EXPECT_TRUE(treeDumpEqualOnAnnotations( R"cpp( @@ -420,8 +478,9 @@ |-IfStatement Statement | |-'if' IntroducerKeyword | |-'(' - | |-IntegerLiteralExpression - | | `-'1' LiteralToken + | |-ExpressionStatement Condition + | | `-IntegerLiteralExpression Expression + | | `-'1' LiteralToken | |-')' | |-ExpressionStatement ThenStatement | | |-CallExpression Expression @@ -3992,12 +4051,13 @@ |-IfStatement Statement | |-'if' IntroducerKeyword unmodifiable | |-'(' unmodifiable - | |-BinaryOperatorExpression unmodifiable - | | |-IntegerLiteralExpression LeftHandSide unmodifiable - | | | `-'1' LiteralToken unmodifiable - | | |-'+' OperatorToken unmodifiable - | | `-IntegerLiteralExpression RightHandSide unmodifiable - | | `-'1' LiteralToken unmodifiable + | |-ExpressionStatement Condition unmodifiable + | | `-BinaryOperatorExpression Expression unmodifiable + | | |-IntegerLiteralExpression LeftHandSide unmodifiable + | | | `-'1' LiteralToken unmodifiable + | | |-'+' OperatorToken unmodifiable + | | `-IntegerLiteralExpression RightHandSide unmodifiable + | | `-'1' LiteralToken unmodifiable | |-')' unmodifiable | |-CompoundStatement ThenStatement unmodifiable | | |-'{' OpenParen unmodifiable @@ -4076,12 +4136,13 @@ |-IfStatement Statement | |-'if' IntroducerKeyword unmodifiable | |-'(' unmodifiable - | |-BinaryOperatorExpression unmodifiable - | | |-IntegerLiteralExpression LeftHandSide - | | | `-'1' LiteralToken - | | |-'&&' OperatorToken unmodifiable - | | `-IntegerLiteralExpression RightHandSide - | | `-'0' LiteralToken + | |-ExpressionStatement Condition unmodifiable + | | `-BinaryOperatorExpression Expression unmodifiable + | | |-IntegerLiteralExpression LeftHandSide + | | | `-'1' LiteralToken + | | |-'&&' OperatorToken unmodifiable + | | `-IntegerLiteralExpression RightHandSide + | | `-'0' LiteralToken | |-')' unmodifiable | |-CompoundStatement ThenStatement unmodifiable | | |-'{' OpenParen unmodifiable diff --git a/clang/unittests/Tooling/Syntax/SynthesisTest.cpp b/clang/unittests/Tooling/Syntax/SynthesisTest.cpp --- a/clang/unittests/Tooling/Syntax/SynthesisTest.cpp +++ b/clang/unittests/Tooling/Syntax/SynthesisTest.cpp @@ -238,12 +238,13 @@ |-IfStatement Statement synthesized | |-'if' IntroducerKeyword synthesized | |-'(' synthesized - | |-BinaryOperatorExpression synthesized - | | |-IntegerLiteralExpression LeftHandSide synthesized - | | | `-'1' LiteralToken synthesized - | | |-'+' OperatorToken synthesized - | | `-IntegerLiteralExpression RightHandSide synthesized - | | `-'1' LiteralToken synthesized + | |-ExpressionStatement Condition synthesized + | | `-BinaryOperatorExpression Expression synthesized + | | |-IntegerLiteralExpression LeftHandSide synthesized + | | | `-'1' LiteralToken synthesized + | | |-'+' OperatorToken synthesized + | | `-IntegerLiteralExpression RightHandSide synthesized + | | `-'1' LiteralToken synthesized | |-')' synthesized | |-CompoundStatement ThenStatement synthesized | | |-'{' OpenParen synthesized