//===- llvm/unittest/DebugInfo/LogicalView/CompareElementsTest.cpp --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" #include "llvm/DebugInfo/LogicalView/Core/LVLine.h" #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" #include "llvm/DebugInfo/LogicalView/Core/LVType.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" using namespace llvm; using namespace llvm::logicalview; namespace { //===----------------------------------------------------------------------===// // Basic Reader functionality. class ReaderTestCompare : public LVReader { #define CREATE(VARIABLE, CREATE_FUNCTION, SET_FUNCTION) \ VARIABLE = CREATE_FUNCTION(); \ EXPECT_NE(VARIABLE, nullptr); \ VARIABLE->SET_FUNCTION(); public: // Types. LVType *IntegerType = nullptr; LVType *UnsignedType = nullptr; LVType *GlobalType = nullptr; LVType *LocalType = nullptr; LVType *NestedType = nullptr; LVTypeDefinition *TypeDefinitionOne = nullptr; LVTypeDefinition *TypeDefinitionTwo = nullptr; LVTypeEnumerator *EnumeratorOne = nullptr; LVTypeEnumerator *EnumeratorTwo = nullptr; // Scopes. LVScope *NestedScope = nullptr; LVScope *InnerScope = nullptr; LVScopeAggregate *Aggregate = nullptr; LVScopeEnumeration *Enumeration = nullptr; LVScopeFunction *FunctionOne = nullptr; LVScopeFunction *FunctionTwo = nullptr; LVScopeNamespace *Namespace = nullptr; // Symbols. LVSymbol *GlobalVariable = nullptr; LVSymbol *LocalVariable = nullptr; LVSymbol *ClassMember = nullptr; LVSymbol *NestedVariable = nullptr; LVSymbol *ParameterOne = nullptr; LVSymbol *ParameterTwo = nullptr; // Lines. LVLine *LineOne = nullptr; LVLine *LineTwo = nullptr; LVLine *LineThree = nullptr; protected: void add(LVScope *Parent, LVElement *Element); void set(LVElement *Element, StringRef Name, LVOffset Offset, uint32_t LineNumber = 0, LVElement *Type = nullptr); public: ReaderTestCompare(ScopedPrinter &W) : LVReader("", "", W) { setInstance(this); } Error createScopes() { return LVReader::createScopes(); } Error printScopes() { return LVReader::printScopes(); } void createElements(); void addElements(bool IsReference, bool IsTarget); void initElements(); }; // Helper function to add a logical element to a given scope. void ReaderTestCompare::add(LVScope *Parent, LVElement *Child) { Parent->addElement(Child); EXPECT_EQ(Child->getParent(), Parent); EXPECT_EQ(Child->getLevel(), Parent->getLevel() + 1); } // Helper function to set the initial values for a given logical element. void ReaderTestCompare::set(LVElement *Element, StringRef Name, LVOffset Offset, uint32_t LineNumber, LVElement *Type) { Element->setName(Name); Element->setOffset(Offset); Element->setLineNumber(LineNumber); Element->setType(Type); } //===----------------------------------------------------------------------===// // Create the logical elements. void ReaderTestCompare::createElements() { // Create scope root. Error Err = createScopes(); ASSERT_THAT_ERROR(std::move(Err), Succeeded()); Root = getScopesRoot(); ASSERT_NE(Root, nullptr); // Create the logical types. CREATE(IntegerType, createType, setIsBase); CREATE(UnsignedType, createType, setIsBase); CREATE(GlobalType, createType, setIsBase); CREATE(LocalType, createType, setIsBase); CREATE(NestedType, createType, setIsBase); CREATE(EnumeratorOne, createTypeEnumerator, setIsEnumerator); CREATE(EnumeratorTwo, createTypeEnumerator, setIsEnumerator); CREATE(TypeDefinitionOne, createTypeDefinition, setIsTypedef); CREATE(TypeDefinitionTwo, createTypeDefinition, setIsTypedef); // Create the logical scopes. CREATE(NestedScope, createScope, setIsLexicalBlock); CREATE(InnerScope, createScope, setIsLexicalBlock); CREATE(Aggregate, createScopeAggregate, setIsAggregate); CREATE(CompileUnit, createScopeCompileUnit, setIsCompileUnit); CREATE(Enumeration, createScopeEnumeration, setIsEnumeration); CREATE(FunctionOne, createScopeFunction, setIsFunction); CREATE(FunctionTwo, createScopeFunction, setIsFunction); CREATE(Namespace, createScopeNamespace, setIsNamespace); // Create the logical symbols. CREATE(GlobalVariable, createSymbol, setIsVariable); CREATE(LocalVariable, createSymbol, setIsVariable); CREATE(ClassMember, createSymbol, setIsMember); CREATE(NestedVariable, createSymbol, setIsVariable); CREATE(ParameterOne, createSymbol, setIsParameter); CREATE(ParameterTwo, createSymbol, setIsParameter); // Create the logical lines. CREATE(LineOne, createLine, setIsLineDebug); CREATE(LineTwo, createLine, setIsLineDebug); CREATE(LineThree, createLine, setIsLineDebug); } // Reference Reader: Target Reader: // ---------------------- ---------------------- // Root Root // CompileUnit CompileUnit // IntegerType IntegerType // UnsignedType UnsignedType // FunctionOne FunctionOne // ParameterOne ParameterOne // LocalVariable --- // LocalType LocalType // LineOne LineOne // NestedScope NestedScope // NestedVariable NestedVariable // NestedType NestedType // LineTwo --- // InnerScope InnerScope // --- LineThree // --- FunctionTwo // --- ParameterTwo // GlobalVariable GlobalVariable // GlobalType GlobalType // Namespace Namespace // Aggregate Aggregate // ClassMember ClassMember // Enumeration Enumeration // EnumeratorOne EnumeratorOne // EnumeratorTwo EnumeratorTwo // TypeDefinitionOne --- // --- TypeDefinitionTwo // Create the logical view adding the created logical elements. void ReaderTestCompare::addElements(bool IsReference, bool IsTarget) { Root->setName(IsReference ? "Reference-Reader" : "Target-Reader"); auto Insert = [&](bool Insert, auto *Parent, auto *Child) { if (Insert) add(Parent, Child); }; setCompileUnit(CompileUnit); add(Root, CompileUnit); // Add elements to CompileUnit. Insert(true, CompileUnit, IntegerType); Insert(true, CompileUnit, UnsignedType); Insert(true, CompileUnit, FunctionOne); Insert(IsTarget, CompileUnit, FunctionTwo); Insert(true, CompileUnit, GlobalVariable); Insert(true, CompileUnit, GlobalType); Insert(true, CompileUnit, Namespace); // Add elements to Namespace. Insert(true, Namespace, Aggregate); Insert(true, Namespace, Enumeration); Insert(IsReference, Namespace, TypeDefinitionOne); Insert(IsTarget, Namespace, TypeDefinitionTwo); // Add elements to FunctionOne. Insert(true, FunctionOne, ParameterOne); Insert(IsReference, FunctionOne, LocalVariable); Insert(true, FunctionOne, LocalType); Insert(true, FunctionOne, LineOne); Insert(true, FunctionOne, NestedScope); // Add elements to FunctionTwo. Insert(IsTarget, FunctionTwo, ParameterTwo); // Add elements to NestedScope. Insert(true, NestedScope, NestedVariable); Insert(true, NestedScope, NestedType); Insert(IsReference, NestedScope, LineTwo); Insert(true, NestedScope, InnerScope); // Add elements to Enumeration. Insert(true, Enumeration, EnumeratorOne); Insert(true, Enumeration, EnumeratorTwo); // Add elements to Aggregate. Insert(true, Aggregate, ClassMember); Insert(IsTarget, InnerScope, LineThree); } // Set initial values to logical elements. void ReaderTestCompare::initElements() { setFilename("LogicalElements.obj"); Root->setFileFormatName("FileFormat"); // Types. set(IntegerType, "int", 0x1000); set(UnsignedType, "unsigned", 0x1010); set(GlobalType, "GlobalType", 0x1020, 1020); set(LocalType, "LocalType", 0x1030, 1030); set(NestedType, "NestedType", 0x1040, 1040); set(TypeDefinitionOne, "INTEGER", 0x1050, 1050, IntegerType); set(TypeDefinitionTwo, "INT", 0x1060, 1060, TypeDefinitionOne); set(EnumeratorOne, "One", 0x1070, 1070); EnumeratorOne->setValue("Blue"); set(EnumeratorTwo, "Two", 0x1080, 1080); EnumeratorTwo->setValue("Red"); // Scopes. set(Aggregate, "Class", 0x2000, 2000); set(Enumeration, "Colors", 0x2010, 2010); set(FunctionOne, "FunctionOne", 0x2020, 2020, GlobalType); set(FunctionTwo, "FunctionTwo", 0x2030, 2030, GlobalType); set(Namespace, "Namespace", 0x2040, 2040); set(NestedScope, "", 0x2050, 2050); set(InnerScope, "", 0x2060, 2060); set(CompileUnit, "test.cpp", 0x2070, 2070); // Symbols. set(GlobalVariable, "GlobalVariable", 0x3000, 3000); set(LocalVariable, "LocalVariable", 0x3010, 3010, UnsignedType); set(ClassMember, "ClassMember", 0x3020, 3020, IntegerType); set(ParameterOne, "ParameterOne", 0x3030, 3030, UnsignedType); set(ParameterTwo, "ParameterTwo", 0x3040, 3040, UnsignedType); set(NestedVariable, "NestedVariable", 0x3050, 3050); // Lines. set(LineOne, "", 0x4000, 4000); set(LineTwo, "", 0x4010, 4010); set(LineThree, "", 0x4020, 4020); } // Compare the logical views. void compareReadersViews(ReaderTestCompare *ReferenceReader, ReaderTestCompare *TargetReader) { LVCompare Compare(nulls()); Error Err = Compare.execute(ReferenceReader, TargetReader); ASSERT_THAT_ERROR(std::move(Err), Succeeded()); // Get comparison table. LVPassTable PassTable = Compare.getPassTable(); ASSERT_EQ(PassTable.size(), 5u); LVReader *Reader; LVElement *Element; LVComparePass Pass; // Reference: Missing 'FunctionOne' std::tie(Reader, Element, Pass) = PassTable[0]; EXPECT_EQ(Reader, ReferenceReader); EXPECT_EQ(Element, ReferenceReader->FunctionOne); EXPECT_EQ(Pass, LVComparePass::Missing); // Reference: Missing 'TypeDefinitionOne' std::tie(Reader, Element, Pass) = PassTable[1]; EXPECT_EQ(Reader, ReferenceReader); EXPECT_EQ(Element, ReferenceReader->TypeDefinitionOne); EXPECT_EQ(Pass, LVComparePass::Missing); // Target: Added 'FunctionOne' std::tie(Reader, Element, Pass) = PassTable[2]; EXPECT_EQ(Reader, TargetReader); EXPECT_EQ(Element, TargetReader->FunctionOne); EXPECT_EQ(Pass, LVComparePass::Added); // Target: Added 'FunctionTwo' std::tie(Reader, Element, Pass) = PassTable[3]; EXPECT_EQ(Reader, TargetReader); EXPECT_EQ(Element, TargetReader->FunctionTwo); EXPECT_EQ(Pass, LVComparePass::Added); // Target: Added 'TypeDefinitionTwo' std::tie(Reader, Element, Pass) = PassTable[4]; EXPECT_EQ(Reader, TargetReader); EXPECT_EQ(Element, TargetReader->TypeDefinitionTwo); EXPECT_EQ(Pass, LVComparePass::Added); } // Compare the logical elements. void compareReadersElements(ReaderTestCompare *ReferenceReader, ReaderTestCompare *TargetReader) { LVCompare Compare(nulls()); Error Err = Compare.execute(ReferenceReader, TargetReader); ASSERT_THAT_ERROR(std::move(Err), Succeeded()); // Get comparison table. LVPassTable PassTable = Compare.getPassTable(); ASSERT_EQ(PassTable.size(), 7u); LVReader *Reader; LVElement *Element; LVComparePass Pass; // Reference: Missing 'LocalVariable' std::tie(Reader, Element, Pass) = PassTable[0]; EXPECT_EQ(Reader, ReferenceReader); EXPECT_EQ(Element, ReferenceReader->LocalVariable); EXPECT_EQ(Pass, LVComparePass::Missing); // Reference: Missing 'TypeDefinitionOne' std::tie(Reader, Element, Pass) = PassTable[1]; EXPECT_EQ(Reader, ReferenceReader); EXPECT_EQ(Element, ReferenceReader->TypeDefinitionOne); EXPECT_EQ(Pass, LVComparePass::Missing); // Reference: Missing 'LineTwo' std::tie(Reader, Element, Pass) = PassTable[2]; EXPECT_EQ(Reader, ReferenceReader); EXPECT_EQ(Element, ReferenceReader->LineTwo); EXPECT_EQ(Pass, LVComparePass::Missing); // Target: Added 'FunctionTwo' std::tie(Reader, Element, Pass) = PassTable[3]; EXPECT_EQ(Reader, TargetReader); EXPECT_EQ(Element, TargetReader->FunctionTwo); EXPECT_EQ(Pass, LVComparePass::Added); // Target: Added 'ParameterTwo' std::tie(Reader, Element, Pass) = PassTable[4]; EXPECT_EQ(Reader, TargetReader); EXPECT_EQ(Element, TargetReader->ParameterTwo); EXPECT_EQ(Pass, LVComparePass::Added); // Target: Added 'TypeDefinitionTwo' std::tie(Reader, Element, Pass) = PassTable[5]; EXPECT_EQ(Reader, TargetReader); EXPECT_EQ(Element, TargetReader->TypeDefinitionTwo); EXPECT_EQ(Pass, LVComparePass::Added); // Target: Added 'LineThree' std::tie(Reader, Element, Pass) = PassTable[6]; EXPECT_EQ(Reader, TargetReader); EXPECT_EQ(Element, TargetReader->LineThree); EXPECT_EQ(Pass, LVComparePass::Added); } TEST(LogicalViewTest, CompareElements) { ScopedPrinter W(outs()); // Reader options. LVOptions ReaderOptions; ReaderOptions.setCompareLines(); ReaderOptions.setCompareScopes(); ReaderOptions.setCompareSymbols(); ReaderOptions.setCompareTypes(); // The next set-ups are very similar. The only difference is the // comparison type, which must be set before the readers are created. // Views: setCompareContext() // Elements: resetCompareContext() { // Compare the logical views as whole unit (--compare-context). ReaderOptions.setCompareContext(); ReaderOptions.resolveDependencies(); options().setOptions(&ReaderOptions); ReaderTestCompare ReferenceReader(W); ReferenceReader.createElements(); ReferenceReader.addElements(/*IsReference=*/true, /*IsTarget=*/false); ReferenceReader.initElements(); ReaderTestCompare TargetReader(W); TargetReader.createElements(); TargetReader.addElements(/*IsReference=*/false, /*IsTarget=*/true); TargetReader.initElements(); compareReadersViews(&ReferenceReader, &TargetReader); } { // Compare the logical elements. ReaderOptions.resetCompareContext(); ReaderOptions.resolveDependencies(); options().setOptions(&ReaderOptions); ReaderTestCompare ReferenceReader(W); ReferenceReader.createElements(); ReferenceReader.addElements(/*IsReference=*/true, /*IsTarget=*/false); ReferenceReader.initElements(); ReaderTestCompare TargetReader(W); TargetReader.createElements(); TargetReader.addElements(/*IsReference=*/false, /*IsTarget=*/true); TargetReader.initElements(); compareReadersElements(&ReferenceReader, &TargetReader); } } } // namespace