273 lines · cpp
1//===- SynthesisTest.cpp --------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file tests synthesis API for syntax trees.10//11//===----------------------------------------------------------------------===//12 13#include "TreeTestBase.h"14#include "clang/Tooling/Syntax/BuildTree.h"15#include "clang/Tooling/Syntax/Nodes.h"16#include "gtest/gtest.h"17 18using namespace clang;19using namespace clang::syntax;20 21namespace {22 23class SynthesisTest : public SyntaxTreeTest {24protected:25 ::testing::AssertionResult treeDumpEqual(syntax::Node *Root, StringRef Dump) {26 if (!Root)27 return ::testing::AssertionFailure()28 << "Root was not built successfully.";29 30 auto Actual = StringRef(Root->dump(*TM)).trim().str();31 auto Expected = Dump.trim().str();32 // EXPECT_EQ shows the diff between the two strings if they are different.33 EXPECT_EQ(Expected, Actual);34 if (Actual != Expected) {35 return ::testing::AssertionFailure();36 }37 return ::testing::AssertionSuccess();38 }39};40 41INSTANTIATE_TEST_SUITE_P(42 SynthesisTests, SynthesisTest, ::testing::ValuesIn(allTestClangConfigs()),43 [](const testing::TestParamInfo<TestClangConfig> &Info) {44 return Info.param.toShortString();45 });46 47TEST_P(SynthesisTest, Leaf_Punctuation) {48 buildTree("", GetParam());49 50 auto *Leaf = createLeaf(*Arena, *TM, tok::comma);51 52 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(53',' Detached synthesized54 )txt"));55}56 57TEST_P(SynthesisTest, Leaf_Punctuation_CXX) {58 if (!GetParam().isCXX())59 return;60 61 buildTree("", GetParam());62 63 auto *Leaf = createLeaf(*Arena, *TM, tok::coloncolon);64 65 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(66'::' Detached synthesized67 )txt"));68}69 70TEST_P(SynthesisTest, Leaf_Keyword) {71 buildTree("", GetParam());72 73 auto *Leaf = createLeaf(*Arena, *TM, tok::kw_if);74 75 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(76'if' Detached synthesized77 )txt"));78}79 80TEST_P(SynthesisTest, Leaf_Keyword_CXX11) {81 if (!GetParam().isCXX11OrLater())82 return;83 84 buildTree("", GetParam());85 86 auto *Leaf = createLeaf(*Arena, *TM, tok::kw_nullptr);87 88 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(89'nullptr' Detached synthesized90 )txt"));91}92 93TEST_P(SynthesisTest, Leaf_Identifier) {94 buildTree("", GetParam());95 96 auto *Leaf = createLeaf(*Arena, *TM, tok::identifier, "a");97 98 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(99'a' Detached synthesized100 )txt"));101}102 103TEST_P(SynthesisTest, Leaf_Number) {104 buildTree("", GetParam());105 106 auto *Leaf = createLeaf(*Arena, *TM, tok::numeric_constant, "1");107 108 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(109'1' Detached synthesized110 )txt"));111}112 113TEST_P(SynthesisTest, Tree_Empty) {114 buildTree("", GetParam());115 116 auto *Tree = createTree(*Arena, {}, NodeKind::UnknownExpression);117 118 EXPECT_TRUE(treeDumpEqual(Tree, R"txt(119UnknownExpression Detached synthesized120 )txt"));121}122 123TEST_P(SynthesisTest, Tree_Flat) {124 buildTree("", GetParam());125 126 auto *LeafLParen = createLeaf(*Arena, *TM, tok::l_paren);127 auto *LeafRParen = createLeaf(*Arena, *TM, tok::r_paren);128 auto *TreeParen = createTree(*Arena,129 {{LeafLParen, NodeRole::LeftHandSide},130 {LeafRParen, NodeRole::RightHandSide}},131 NodeKind::ParenExpression);132 133 EXPECT_TRUE(treeDumpEqual(TreeParen, R"txt(134ParenExpression Detached synthesized135|-'(' LeftHandSide synthesized136`-')' RightHandSide synthesized137 )txt"));138}139 140TEST_P(SynthesisTest, Tree_OfTree) {141 buildTree("", GetParam());142 143 auto *Leaf1 = createLeaf(*Arena, *TM, tok::numeric_constant, "1");144 auto *Int1 = createTree(*Arena, {{Leaf1, NodeRole::LiteralToken}},145 NodeKind::IntegerLiteralExpression);146 147 auto *LeafPlus = createLeaf(*Arena, *TM, tok::plus);148 149 auto *Leaf2 = createLeaf(*Arena, *TM, tok::numeric_constant, "2");150 auto *Int2 = createTree(*Arena, {{Leaf2, NodeRole::LiteralToken}},151 NodeKind::IntegerLiteralExpression);152 153 auto *TreeBinaryOperator = createTree(*Arena,154 {{Int1, NodeRole::LeftHandSide},155 {LeafPlus, NodeRole::OperatorToken},156 {Int2, NodeRole::RightHandSide}},157 NodeKind::BinaryOperatorExpression);158 159 EXPECT_TRUE(treeDumpEqual(TreeBinaryOperator, R"txt(160BinaryOperatorExpression Detached synthesized161|-IntegerLiteralExpression LeftHandSide synthesized162| `-'1' LiteralToken synthesized163|-'+' OperatorToken synthesized164`-IntegerLiteralExpression RightHandSide synthesized165 `-'2' LiteralToken synthesized166 )txt"));167}168 169TEST_P(SynthesisTest, DeepCopy_Synthesized) {170 buildTree("", GetParam());171 172 auto *LeafContinue = createLeaf(*Arena, *TM, tok::kw_continue);173 auto *LeafSemiColon = createLeaf(*Arena, *TM, tok::semi);174 auto *StatementContinue = createTree(*Arena,175 {{LeafContinue, NodeRole::LiteralToken},176 {LeafSemiColon, NodeRole::Unknown}},177 NodeKind::ContinueStatement);178 179 auto *Copy = deepCopyExpandingMacros(*Arena, *TM, StatementContinue);180 EXPECT_TRUE(treeDumpEqual(Copy, StatementContinue->dump(*TM)));181 // FIXME: Test that copy is independent of original, once the Mutations API is182 // more developed.183}184 185TEST_P(SynthesisTest, DeepCopy_Original) {186 auto *OriginalTree = buildTree("int a;", GetParam());187 188 auto *Copy = deepCopyExpandingMacros(*Arena, *TM, OriginalTree);189 EXPECT_TRUE(treeDumpEqual(Copy, R"txt(190TranslationUnit Detached synthesized191`-SimpleDeclaration synthesized192 |-'int' synthesized193 |-DeclaratorList Declarators synthesized194 | `-SimpleDeclarator ListElement synthesized195 | `-'a' synthesized196 `-';' synthesized197 )txt"));198}199 200TEST_P(SynthesisTest, DeepCopy_Child) {201 auto *OriginalTree = buildTree("int a;", GetParam());202 203 auto *Copy =204 deepCopyExpandingMacros(*Arena, *TM, OriginalTree->getFirstChild());205 EXPECT_TRUE(treeDumpEqual(Copy, R"txt(206SimpleDeclaration Detached synthesized207|-'int' synthesized208|-DeclaratorList Declarators synthesized209| `-SimpleDeclarator ListElement synthesized210| `-'a' synthesized211`-';' synthesized212 )txt"));213}214 215TEST_P(SynthesisTest, DeepCopy_Macro) {216 auto *OriginalTree = buildTree(R"cpp(217#define HALF_IF if (1+218#define HALF_IF_2 1) {}219void test() {220 HALF_IF HALF_IF_2 else {}221})cpp",222 GetParam());223 224 auto *Copy = deepCopyExpandingMacros(*Arena, *TM, OriginalTree);225 226 // The syntax tree stores already expanded Tokens, we can only see whether the227 // macro was expanded when computing replacements. The dump does show that228 // nodes in the copy are `modifiable`.229 EXPECT_TRUE(treeDumpEqual(Copy, R"txt(230TranslationUnit Detached synthesized231`-SimpleDeclaration synthesized232 |-'void' synthesized233 |-DeclaratorList Declarators synthesized234 | `-SimpleDeclarator ListElement synthesized235 | |-'test' synthesized236 | `-ParametersAndQualifiers synthesized237 | |-'(' OpenParen synthesized238 | `-')' CloseParen synthesized239 `-CompoundStatement synthesized240 |-'{' OpenParen synthesized241 |-IfStatement Statement synthesized242 | |-'if' IntroducerKeyword synthesized243 | |-'(' synthesized244 | |-ExpressionStatement Condition synthesized245 | | `-BinaryOperatorExpression Expression synthesized246 | | |-IntegerLiteralExpression LeftHandSide synthesized247 | | | `-'1' LiteralToken synthesized248 | | |-'+' OperatorToken synthesized249 | | `-IntegerLiteralExpression RightHandSide synthesized250 | | `-'1' LiteralToken synthesized251 | |-')' synthesized252 | |-CompoundStatement ThenStatement synthesized253 | | |-'{' OpenParen synthesized254 | | `-'}' CloseParen synthesized255 | |-'else' ElseKeyword synthesized256 | `-CompoundStatement ElseStatement synthesized257 | |-'{' OpenParen synthesized258 | `-'}' CloseParen synthesized259 `-'}' CloseParen synthesized260 )txt"));261}262 263TEST_P(SynthesisTest, Statement_EmptyStatement) {264 buildTree("", GetParam());265 266 auto *S = createEmptyStatement(*Arena, *TM);267 EXPECT_TRUE(treeDumpEqual(S, R"txt(268EmptyStatement Detached synthesized269`-';' synthesized270 )txt"));271}272} // namespace273