xref: /llvm-project/llvm/unittests/DebugInfo/LogicalView/CompareElementsTest.cpp (revision 7fbcc24409efdb37cec79ad461ef383f6ffc5ef2)
1 //===- llvm/unittest/DebugInfo/LogicalView/CompareElementsTest.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 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
10 #include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
11 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
12 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
13 #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
14 #include "llvm/DebugInfo/LogicalView/Core/LVType.h"
15 #include "llvm/Support/ScopedPrinter.h"
16 #include "llvm/Support/ToolOutputFile.h"
17 #include "llvm/Testing/Support/Error.h"
18 
19 #include "gtest/gtest.h"
20 
21 using namespace llvm;
22 using namespace llvm::logicalview;
23 
24 namespace {
25 
26 //===----------------------------------------------------------------------===//
27 // Basic Reader functionality.
28 class ReaderTestCompare : public LVReader {
29 #define CREATE(VARIABLE, CREATE_FUNCTION, SET_FUNCTION)                        \
30   VARIABLE = CREATE_FUNCTION();                                                \
31   EXPECT_NE(VARIABLE, nullptr);                                                \
32   VARIABLE->SET_FUNCTION();
33 
34 public:
35   // Types.
36   LVType *IntegerType = nullptr;
37   LVType *UnsignedType = nullptr;
38   LVType *GlobalType = nullptr;
39   LVType *LocalType = nullptr;
40   LVType *NestedType = nullptr;
41   LVTypeDefinition *TypeDefinitionOne = nullptr;
42   LVTypeDefinition *TypeDefinitionTwo = nullptr;
43   LVTypeEnumerator *EnumeratorOne = nullptr;
44   LVTypeEnumerator *EnumeratorTwo = nullptr;
45 
46   // Scopes.
47   LVScope *NestedScope = nullptr;
48   LVScope *InnerScope = nullptr;
49   LVScopeAggregate *Aggregate = nullptr;
50   LVScopeEnumeration *Enumeration = nullptr;
51   LVScopeFunction *FunctionOne = nullptr;
52   LVScopeFunction *FunctionTwo = nullptr;
53   LVScopeNamespace *Namespace = nullptr;
54 
55   // Symbols.
56   LVSymbol *GlobalVariable = nullptr;
57   LVSymbol *LocalVariable = nullptr;
58   LVSymbol *ClassMember = nullptr;
59   LVSymbol *NestedVariable = nullptr;
60   LVSymbol *ParameterOne = nullptr;
61   LVSymbol *ParameterTwo = nullptr;
62 
63   // Lines.
64   LVLine *LineOne = nullptr;
65   LVLine *LineTwo = nullptr;
66   LVLine *LineThree = nullptr;
67 
68 protected:
69   void add(LVScope *Parent, LVElement *Element);
70   void set(LVElement *Element, StringRef Name, LVOffset Offset,
71            uint32_t LineNumber = 0, LVElement *Type = nullptr);
72 
73 public:
ReaderTestCompare(ScopedPrinter & W)74   ReaderTestCompare(ScopedPrinter &W) : LVReader("", "", W) {
75     setInstance(this);
76   }
77 
createScopes()78   Error createScopes() { return LVReader::createScopes(); }
printScopes()79   Error printScopes() { return LVReader::printScopes(); }
80 
81   void createElements();
82   void addElements(bool IsReference, bool IsTarget);
83   void initElements();
84 };
85 
86 // Helper function to add a logical element to a given scope.
add(LVScope * Parent,LVElement * Child)87 void ReaderTestCompare::add(LVScope *Parent, LVElement *Child) {
88   Parent->addElement(Child);
89   EXPECT_EQ(Child->getParent(), Parent);
90   EXPECT_EQ(Child->getLevel(), Parent->getLevel() + 1);
91 }
92 
93 // Helper function to set the initial values for a given logical element.
set(LVElement * Element,StringRef Name,LVOffset Offset,uint32_t LineNumber,LVElement * Type)94 void ReaderTestCompare::set(LVElement *Element, StringRef Name, LVOffset Offset,
95                             uint32_t LineNumber, LVElement *Type) {
96   Element->setName(Name);
97   Element->setOffset(Offset);
98   Element->setLineNumber(LineNumber);
99   Element->setType(Type);
100 }
101 
102 //===----------------------------------------------------------------------===//
103 // Create the logical elements.
createElements()104 void ReaderTestCompare::createElements() {
105   // Create scope root.
106   Error Err = createScopes();
107   ASSERT_THAT_ERROR(std::move(Err), Succeeded());
108   Root = getScopesRoot();
109   ASSERT_NE(Root, nullptr);
110 
111   // Create the logical types.
112   CREATE(IntegerType, createType, setIsBase);
113   CREATE(UnsignedType, createType, setIsBase);
114   CREATE(GlobalType, createType, setIsBase);
115   CREATE(LocalType, createType, setIsBase);
116   CREATE(NestedType, createType, setIsBase);
117   CREATE(EnumeratorOne, createTypeEnumerator, setIsEnumerator);
118   CREATE(EnumeratorTwo, createTypeEnumerator, setIsEnumerator);
119   CREATE(TypeDefinitionOne, createTypeDefinition, setIsTypedef);
120   CREATE(TypeDefinitionTwo, createTypeDefinition, setIsTypedef);
121 
122   // Create the logical scopes.
123   CREATE(NestedScope, createScope, setIsLexicalBlock);
124   CREATE(InnerScope, createScope, setIsLexicalBlock);
125   CREATE(Aggregate, createScopeAggregate, setIsAggregate);
126   CREATE(CompileUnit, createScopeCompileUnit, setIsCompileUnit);
127   CREATE(Enumeration, createScopeEnumeration, setIsEnumeration);
128   CREATE(FunctionOne, createScopeFunction, setIsFunction);
129   CREATE(FunctionTwo, createScopeFunction, setIsFunction);
130   CREATE(Namespace, createScopeNamespace, setIsNamespace);
131 
132   // Create the logical symbols.
133   CREATE(GlobalVariable, createSymbol, setIsVariable);
134   CREATE(LocalVariable, createSymbol, setIsVariable);
135   CREATE(ClassMember, createSymbol, setIsMember);
136   CREATE(NestedVariable, createSymbol, setIsVariable);
137   CREATE(ParameterOne, createSymbol, setIsParameter);
138   CREATE(ParameterTwo, createSymbol, setIsParameter);
139 
140   // Create the logical lines.
141   CREATE(LineOne, createLine, setIsLineDebug);
142   CREATE(LineTwo, createLine, setIsLineDebug);
143   CREATE(LineThree, createLine, setIsLineDebug);
144 }
145 
146 // Reference Reader:              Target Reader:
147 // ----------------------         ----------------------
148 // Root                           Root
149 //   CompileUnit                    CompileUnit
150 //     IntegerType                    IntegerType
151 //     UnsignedType                   UnsignedType
152 //     FunctionOne                    FunctionOne
153 //       ParameterOne                   ParameterOne
154 //       LocalVariable                  ---
155 //       LocalType                      LocalType
156 //       LineOne                        LineOne
157 //       NestedScope                    NestedScope
158 //         NestedVariable                 NestedVariable
159 //         NestedType                     NestedType
160 //         LineTwo                        ---
161 //         InnerScope                     InnerScope
162 //           ---                            LineThree
163 //     ---                            FunctionTwo
164 //     ---                              ParameterTwo
165 //     GlobalVariable                 GlobalVariable
166 //     GlobalType                     GlobalType
167 //     Namespace                      Namespace
168 //       Aggregate                      Aggregate
169 //         ClassMember                    ClassMember
170 //       Enumeration                    Enumeration
171 //         EnumeratorOne                  EnumeratorOne
172 //         EnumeratorTwo                  EnumeratorTwo
173 //       TypeDefinitionOne              ---
174 //       ---                            TypeDefinitionTwo
175 
176 // Create the logical view adding the created logical elements.
addElements(bool IsReference,bool IsTarget)177 void ReaderTestCompare::addElements(bool IsReference, bool IsTarget) {
178   Root->setName(IsReference ? "Reference-Reader" : "Target-Reader");
179 
180   auto Insert = [&](bool Insert, auto *Parent, auto *Child) {
181     if (Insert)
182       add(Parent, Child);
183   };
184 
185   setCompileUnit(CompileUnit);
186   add(Root, CompileUnit);
187 
188   // Add elements to CompileUnit.
189   Insert(true, CompileUnit, IntegerType);
190   Insert(true, CompileUnit, UnsignedType);
191   Insert(true, CompileUnit, FunctionOne);
192   Insert(IsTarget, CompileUnit, FunctionTwo);
193   Insert(true, CompileUnit, GlobalVariable);
194   Insert(true, CompileUnit, GlobalType);
195   Insert(true, CompileUnit, Namespace);
196 
197   // Add elements to Namespace.
198   Insert(true, Namespace, Aggregate);
199   Insert(true, Namespace, Enumeration);
200   Insert(IsReference, Namespace, TypeDefinitionOne);
201   Insert(IsTarget, Namespace, TypeDefinitionTwo);
202 
203   // Add elements to FunctionOne.
204   Insert(true, FunctionOne, ParameterOne);
205   Insert(IsReference, FunctionOne, LocalVariable);
206   Insert(true, FunctionOne, LocalType);
207   Insert(true, FunctionOne, LineOne);
208   Insert(true, FunctionOne, NestedScope);
209 
210   // Add elements to FunctionTwo.
211   Insert(IsTarget, FunctionTwo, ParameterTwo);
212 
213   // Add elements to NestedScope.
214   Insert(true, NestedScope, NestedVariable);
215   Insert(true, NestedScope, NestedType);
216   Insert(IsReference, NestedScope, LineTwo);
217   Insert(true, NestedScope, InnerScope);
218 
219   // Add elements to Enumeration.
220   Insert(true, Enumeration, EnumeratorOne);
221   Insert(true, Enumeration, EnumeratorTwo);
222 
223   // Add elements to Aggregate.
224   Insert(true, Aggregate, ClassMember);
225 
226   Insert(IsTarget, InnerScope, LineThree);
227 }
228 
229 // Set initial values to logical elements.
initElements()230 void ReaderTestCompare::initElements() {
231   setFilename("LogicalElements.obj");
232 
233   Root->setFileFormatName("FileFormat");
234 
235   // Types.
236   set(IntegerType, "int", 0x1000);
237   set(UnsignedType, "unsigned", 0x1010);
238   set(GlobalType, "GlobalType", 0x1020, 1020);
239   set(LocalType, "LocalType", 0x1030, 1030);
240   set(NestedType, "NestedType", 0x1040, 1040);
241 
242   set(TypeDefinitionOne, "INTEGER", 0x1050, 1050, IntegerType);
243   set(TypeDefinitionTwo, "INT", 0x1060, 1060, TypeDefinitionOne);
244 
245   set(EnumeratorOne, "One", 0x1070, 1070);
246   EnumeratorOne->setValue("Blue");
247 
248   set(EnumeratorTwo, "Two", 0x1080, 1080);
249   EnumeratorTwo->setValue("Red");
250 
251   // Scopes.
252   set(Aggregate, "Class", 0x2000, 2000);
253   set(Enumeration, "Colors", 0x2010, 2010);
254   set(FunctionOne, "FunctionOne", 0x2020, 2020, GlobalType);
255   set(FunctionTwo, "FunctionTwo", 0x2030, 2030, GlobalType);
256   set(Namespace, "Namespace", 0x2040, 2040);
257   set(NestedScope, "", 0x2050, 2050);
258   set(InnerScope, "", 0x2060, 2060);
259   set(CompileUnit, "test.cpp", 0x2070, 2070);
260 
261   // Symbols.
262   set(GlobalVariable, "GlobalVariable", 0x3000, 3000);
263   set(LocalVariable, "LocalVariable", 0x3010, 3010, UnsignedType);
264   set(ClassMember, "ClassMember", 0x3020, 3020, IntegerType);
265   set(ParameterOne, "ParameterOne", 0x3030, 3030, UnsignedType);
266   set(ParameterTwo, "ParameterTwo", 0x3040, 3040, UnsignedType);
267   set(NestedVariable, "NestedVariable", 0x3050, 3050);
268 
269   // Lines.
270   set(LineOne, "", 0x4000, 4000);
271   set(LineTwo, "", 0x4010, 4010);
272   set(LineThree, "", 0x4020, 4020);
273 }
274 
275 // Compare the logical views.
compareReadersViews(ReaderTestCompare * ReferenceReader,ReaderTestCompare * TargetReader)276 void compareReadersViews(ReaderTestCompare *ReferenceReader,
277                          ReaderTestCompare *TargetReader) {
278   LVCompare Compare(nulls());
279   Error Err = Compare.execute(ReferenceReader, TargetReader);
280   ASSERT_THAT_ERROR(std::move(Err), Succeeded());
281 
282   // Get comparison table.
283   LVPassTable PassTable = Compare.getPassTable();
284   ASSERT_EQ(PassTable.size(), 5u);
285 
286   LVReader *Reader;
287   LVElement *Element;
288   LVComparePass Pass;
289 
290   // Reference: Missing 'FunctionOne'
291   std::tie(Reader, Element, Pass) = PassTable[0];
292   EXPECT_EQ(Reader, ReferenceReader);
293   EXPECT_EQ(Element, ReferenceReader->FunctionOne);
294   EXPECT_EQ(Pass, LVComparePass::Missing);
295 
296   // Reference: Missing 'TypeDefinitionOne'
297   std::tie(Reader, Element, Pass) = PassTable[1];
298   EXPECT_EQ(Reader, ReferenceReader);
299   EXPECT_EQ(Element, ReferenceReader->TypeDefinitionOne);
300   EXPECT_EQ(Pass, LVComparePass::Missing);
301 
302   // Target: Added 'FunctionOne'
303   std::tie(Reader, Element, Pass) = PassTable[2];
304   EXPECT_EQ(Reader, TargetReader);
305   EXPECT_EQ(Element, TargetReader->FunctionOne);
306   EXPECT_EQ(Pass, LVComparePass::Added);
307 
308   // Target: Added 'FunctionTwo'
309   std::tie(Reader, Element, Pass) = PassTable[3];
310   EXPECT_EQ(Reader, TargetReader);
311   EXPECT_EQ(Element, TargetReader->FunctionTwo);
312   EXPECT_EQ(Pass, LVComparePass::Added);
313 
314   // Target: Added 'TypeDefinitionTwo'
315   std::tie(Reader, Element, Pass) = PassTable[4];
316   EXPECT_EQ(Reader, TargetReader);
317   EXPECT_EQ(Element, TargetReader->TypeDefinitionTwo);
318   EXPECT_EQ(Pass, LVComparePass::Added);
319 }
320 
321 // Compare the logical elements.
compareReadersElements(ReaderTestCompare * ReferenceReader,ReaderTestCompare * TargetReader)322 void compareReadersElements(ReaderTestCompare *ReferenceReader,
323                             ReaderTestCompare *TargetReader) {
324   LVCompare Compare(nulls());
325   Error Err = Compare.execute(ReferenceReader, TargetReader);
326   ASSERT_THAT_ERROR(std::move(Err), Succeeded());
327 
328   // Get comparison table.
329   LVPassTable PassTable = Compare.getPassTable();
330   ASSERT_EQ(PassTable.size(), 7u);
331 
332   LVReader *Reader;
333   LVElement *Element;
334   LVComparePass Pass;
335 
336   // Reference: Missing 'LocalVariable'
337   std::tie(Reader, Element, Pass) = PassTable[0];
338   EXPECT_EQ(Reader, ReferenceReader);
339   EXPECT_EQ(Element, ReferenceReader->LocalVariable);
340   EXPECT_EQ(Pass, LVComparePass::Missing);
341 
342   // Reference: Missing 'TypeDefinitionOne'
343   std::tie(Reader, Element, Pass) = PassTable[1];
344   EXPECT_EQ(Reader, ReferenceReader);
345   EXPECT_EQ(Element, ReferenceReader->TypeDefinitionOne);
346   EXPECT_EQ(Pass, LVComparePass::Missing);
347 
348   // Reference: Missing 'LineTwo'
349   std::tie(Reader, Element, Pass) = PassTable[2];
350   EXPECT_EQ(Reader, ReferenceReader);
351   EXPECT_EQ(Element, ReferenceReader->LineTwo);
352   EXPECT_EQ(Pass, LVComparePass::Missing);
353 
354   // Target: Added 'FunctionTwo'
355   std::tie(Reader, Element, Pass) = PassTable[3];
356   EXPECT_EQ(Reader, TargetReader);
357   EXPECT_EQ(Element, TargetReader->FunctionTwo);
358   EXPECT_EQ(Pass, LVComparePass::Added);
359 
360   // Target: Added 'ParameterTwo'
361   std::tie(Reader, Element, Pass) = PassTable[4];
362   EXPECT_EQ(Reader, TargetReader);
363   EXPECT_EQ(Element, TargetReader->ParameterTwo);
364   EXPECT_EQ(Pass, LVComparePass::Added);
365 
366   // Target: Added 'TypeDefinitionTwo'
367   std::tie(Reader, Element, Pass) = PassTable[5];
368   EXPECT_EQ(Reader, TargetReader);
369   EXPECT_EQ(Element, TargetReader->TypeDefinitionTwo);
370   EXPECT_EQ(Pass, LVComparePass::Added);
371 
372   // Target: Added 'LineThree'
373   std::tie(Reader, Element, Pass) = PassTable[6];
374   EXPECT_EQ(Reader, TargetReader);
375   EXPECT_EQ(Element, TargetReader->LineThree);
376   EXPECT_EQ(Pass, LVComparePass::Added);
377 }
378 
TEST(LogicalViewTest,CompareElements)379 TEST(LogicalViewTest, CompareElements) {
380   ScopedPrinter W(outs());
381 
382   // Reader options.
383   LVOptions ReaderOptions;
384   ReaderOptions.setCompareLines();
385   ReaderOptions.setCompareScopes();
386   ReaderOptions.setCompareSymbols();
387   ReaderOptions.setCompareTypes();
388 
389   // The next set-ups are very similar. The only difference is the
390   // comparison type, which must be set before the readers are created.
391   //   Views: setCompareContext()
392   //   Elements: resetCompareContext()
393   {
394     // Compare the logical views as whole unit (--compare-context).
395     ReaderOptions.setCompareContext();
396     ReaderOptions.resolveDependencies();
397     options().setOptions(&ReaderOptions);
398 
399     ReaderTestCompare ReferenceReader(W);
400     ReferenceReader.createElements();
401     ReferenceReader.addElements(/*IsReference=*/true, /*IsTarget=*/false);
402     ReferenceReader.initElements();
403 
404     ReaderTestCompare TargetReader(W);
405     TargetReader.createElements();
406     TargetReader.addElements(/*IsReference=*/false, /*IsTarget=*/true);
407     TargetReader.initElements();
408 
409     compareReadersViews(&ReferenceReader, &TargetReader);
410   }
411   {
412     // Compare the logical elements.
413     ReaderOptions.resetCompareContext();
414     ReaderOptions.resolveDependencies();
415     options().setOptions(&ReaderOptions);
416 
417     ReaderTestCompare ReferenceReader(W);
418     ReferenceReader.createElements();
419     ReferenceReader.addElements(/*IsReference=*/true, /*IsTarget=*/false);
420     ReferenceReader.initElements();
421 
422     ReaderTestCompare TargetReader(W);
423     TargetReader.createElements();
424     TargetReader.addElements(/*IsReference=*/false, /*IsTarget=*/true);
425     TargetReader.initElements();
426 
427     compareReadersElements(&ReferenceReader, &TargetReader);
428   }
429 }
430 
431 } // namespace
432