[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / lldb / unittests / Symbol / PostfixExpressionTest.cpp
blobd56df476ebaab68fd8b444fa80990e3aff012dae
1 //===-- PostfixExpressionTest.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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Symbol/PostfixExpression.h"
10 #include "lldb/Utility/DataExtractor.h"
11 #include "lldb/Utility/StreamString.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/DebugInfo/DIContext.h"
14 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
15 #include "llvm/Support/FormatVariadic.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
20 using namespace lldb_private;
21 using namespace lldb_private::postfix;
23 static std::string ToString(BinaryOpNode::OpType type) {
24 switch (type) {
25 case BinaryOpNode::Align:
26 return "@";
27 case BinaryOpNode::Minus:
28 return "-";
29 case BinaryOpNode::Plus:
30 return "+";
32 llvm_unreachable("Fully covered switch!");
35 static std::string ToString(UnaryOpNode::OpType type) {
36 switch (type) {
37 case UnaryOpNode::Deref:
38 return "^";
40 llvm_unreachable("Fully covered switch!");
43 struct ASTPrinter : public Visitor<std::string> {
44 protected:
45 std::string Visit(BinaryOpNode &binary, Node *&) override {
46 return std::string(
47 llvm::formatv("{0}({1}, {2})", ToString(binary.GetOpType()),
48 Dispatch(binary.Left()), Dispatch(binary.Right())));
51 std::string Visit(InitialValueNode &, Node *&) override { return "InitialValue"; }
53 std::string Visit(IntegerNode &integer, Node *&) override {
54 return std::string(llvm::formatv("int({0})", integer.GetValue()));
57 std::string Visit(RegisterNode &reg, Node *&) override {
58 return std::string(llvm::formatv("reg({0})", reg.GetRegNum()));
61 std::string Visit(SymbolNode &symbol, Node *&) override {
62 return std::string(symbol.GetName());
65 std::string Visit(UnaryOpNode &unary, Node *&) override {
66 return std::string(llvm::formatv("{0}({1})", ToString(unary.GetOpType()),
67 Dispatch(unary.Operand())));
70 public:
71 static std::string Print(Node *node) {
72 if (node)
73 return ASTPrinter().Dispatch(node);
74 return "nullptr";
78 static std::string ParseOneAndStringify(llvm::StringRef expr) {
79 llvm::BumpPtrAllocator alloc;
80 return ASTPrinter::Print(ParseOneExpression(expr, alloc));
83 TEST(PostfixExpression, ParseOneExpression) {
84 EXPECT_EQ("int(47)", ParseOneAndStringify("47"));
85 EXPECT_EQ("$foo", ParseOneAndStringify("$foo"));
86 EXPECT_EQ("+(int(1), int(2))", ParseOneAndStringify("1 2 +"));
87 EXPECT_EQ("-(int(1), int(2))", ParseOneAndStringify("1 2 -"));
88 EXPECT_EQ("@(int(1), int(2))", ParseOneAndStringify("1 2 @"));
89 EXPECT_EQ("+(int(1), +(int(2), int(3)))", ParseOneAndStringify("1 2 3 + +"));
90 EXPECT_EQ("+(+(int(1), int(2)), int(3))", ParseOneAndStringify("1 2 + 3 +"));
91 EXPECT_EQ("^(int(1))", ParseOneAndStringify("1 ^"));
92 EXPECT_EQ("^(^(int(1)))", ParseOneAndStringify("1 ^ ^"));
93 EXPECT_EQ("^(+(int(1), ^(int(2))))", ParseOneAndStringify("1 2 ^ + ^"));
94 EXPECT_EQ("-($foo, int(47))", ParseOneAndStringify("$foo 47 -"));
95 EXPECT_EQ("+(int(47), int(-42))", ParseOneAndStringify("47 -42 +"));
97 EXPECT_EQ("nullptr", ParseOneAndStringify("+"));
98 EXPECT_EQ("nullptr", ParseOneAndStringify("^"));
99 EXPECT_EQ("nullptr", ParseOneAndStringify("1 +"));
100 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 ^"));
101 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2 3 +"));
102 EXPECT_EQ("nullptr", ParseOneAndStringify("^ 1"));
103 EXPECT_EQ("nullptr", ParseOneAndStringify("+ 1 2"));
104 EXPECT_EQ("nullptr", ParseOneAndStringify("1 + 2"));
105 EXPECT_EQ("nullptr", ParseOneAndStringify("1 2"));
106 EXPECT_EQ("nullptr", ParseOneAndStringify(""));
109 static std::vector<std::pair<std::string, std::string>>
110 ParseFPOAndStringify(llvm::StringRef prog) {
111 llvm::BumpPtrAllocator alloc;
112 std::vector<std::pair<llvm::StringRef, Node *>> parsed =
113 ParseFPOProgram(prog, alloc);
114 std::vector<std::pair<std::string, std::string>> result;
115 for (const auto &p : parsed)
116 result.emplace_back(p.first.str(), ASTPrinter::Print(p.second));
117 return result;
120 TEST(PostfixExpression, ParseFPOProgram) {
121 EXPECT_THAT(ParseFPOAndStringify("a 1 ="),
122 testing::ElementsAre(std::make_pair("a", "int(1)")));
123 EXPECT_THAT(ParseFPOAndStringify("a 1 = b 2 3 + ="),
124 testing::ElementsAre(std::make_pair("a", "int(1)"),
125 std::make_pair("b", "+(int(2), int(3))")));
127 EXPECT_THAT(ParseFPOAndStringify(""), testing::IsEmpty());
128 EXPECT_THAT(ParseFPOAndStringify("="), testing::IsEmpty());
129 EXPECT_THAT(ParseFPOAndStringify("a 1"), testing::IsEmpty());
130 EXPECT_THAT(ParseFPOAndStringify("a 1 = ="), testing::IsEmpty());
131 EXPECT_THAT(ParseFPOAndStringify("a 1 + ="), testing::IsEmpty());
132 EXPECT_THAT(ParseFPOAndStringify("= a 1 ="), testing::IsEmpty());
135 static std::string ParseAndGenerateDWARF(llvm::StringRef expr) {
136 llvm::BumpPtrAllocator alloc;
137 Node *ast = ParseOneExpression(expr, alloc);
138 if (!ast)
139 return "Parse failed.";
140 if (!ResolveSymbols(ast, [&](SymbolNode &symbol) -> Node * {
141 if (symbol.GetName() == "INIT")
142 return MakeNode<InitialValueNode>(alloc);
144 uint32_t num;
145 if (to_integer(symbol.GetName().drop_front(), num))
146 return MakeNode<RegisterNode>(alloc, num);
147 return nullptr;
148 })) {
149 return "Resolution failed.";
152 const size_t addr_size = 4;
153 StreamString dwarf(Stream::eBinary, addr_size, lldb::eByteOrderLittle);
154 ToDWARF(*ast, dwarf);
156 // print dwarf expression to comparable textual representation
157 llvm::DataExtractor extractor(dwarf.GetString(), /*IsLittleEndian=*/true,
158 addr_size);
160 std::string result;
161 llvm::raw_string_ostream os(result);
162 llvm::DWARFExpression(extractor, addr_size, llvm::dwarf::DWARF32)
163 .print(os, llvm::DIDumpOptions(), nullptr);
164 return result;
167 TEST(PostfixExpression, ToDWARF) {
168 EXPECT_EQ("DW_OP_consts +0", ParseAndGenerateDWARF("0"));
170 EXPECT_EQ("DW_OP_breg1 +0", ParseAndGenerateDWARF("R1"));
172 EXPECT_EQ("DW_OP_bregx 0x41 +0", ParseAndGenerateDWARF("R65"));
174 EXPECT_EQ("DW_OP_pick 0x0", ParseAndGenerateDWARF("INIT"));
176 EXPECT_EQ("DW_OP_pick 0x0, DW_OP_pick 0x1, DW_OP_plus",
177 ParseAndGenerateDWARF("INIT INIT +"));
179 EXPECT_EQ("DW_OP_breg1 +0, DW_OP_pick 0x1, DW_OP_plus",
180 ParseAndGenerateDWARF("R1 INIT +"));
182 EXPECT_EQ("DW_OP_consts +1, DW_OP_pick 0x1, DW_OP_deref, DW_OP_plus",
183 ParseAndGenerateDWARF("1 INIT ^ +"));
185 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_plus",
186 ParseAndGenerateDWARF("4 5 +"));
188 EXPECT_EQ("DW_OP_consts +4, DW_OP_consts +5, DW_OP_minus",
189 ParseAndGenerateDWARF("4 5 -"));
191 EXPECT_EQ("DW_OP_consts +4, DW_OP_deref", ParseAndGenerateDWARF("4 ^"));
193 EXPECT_EQ("DW_OP_breg6 +0, DW_OP_consts +128, DW_OP_lit1, DW_OP_minus, "
194 "DW_OP_not, DW_OP_and",
195 ParseAndGenerateDWARF("R6 128 @"));