llvm-project/llvm/unittests/DebugInfo/LogicalView/CompareElementsTest.cpp

457 lines
16 KiB
C++

//===- 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 {
// Elements created but not added to any logical scope. They are
// deleted when the logical Reader is destroyed.
LVAutoSmallVector<LVElement *> OrphanElements;
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);
template <typename T, typename F> T *create(F Function) {
// 'Function' will update a specific kind of the logical element to
// have the ability of kind selection.
T *Element = new (std::nothrow) T();
EXPECT_NE(Element, nullptr);
(Element->*Function)();
return 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.
IntegerType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
UnsignedType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
GlobalType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
LocalType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
NestedType = create<LVType, LVTypeSetFunction>(&LVType::setIsBase);
EnumeratorOne =
create<LVTypeEnumerator, LVTypeSetFunction>(&LVType::setIsEnumerator);
EnumeratorTwo =
create<LVTypeEnumerator, LVTypeSetFunction>(&LVType::setIsEnumerator);
TypeDefinitionOne =
create<LVTypeDefinition, LVTypeSetFunction>(&LVType::setIsTypedef);
TypeDefinitionTwo =
create<LVTypeDefinition, LVTypeSetFunction>(&LVType::setIsTypedef);
// Create the logical scopes.
NestedScope =
create<LVScope, LVScopeSetFunction>(&LVScope::setIsLexicalBlock);
InnerScope = create<LVScope, LVScopeSetFunction>(&LVScope::setIsLexicalBlock);
Aggregate =
create<LVScopeAggregate, LVScopeSetFunction>(&LVScope::setIsAggregate);
CompileUnit = create<LVScopeCompileUnit, LVScopeSetFunction>(
&LVScope::setIsCompileUnit);
Enumeration = create<LVScopeEnumeration, LVScopeSetFunction>(
&LVScope::setIsEnumeration);
FunctionOne =
create<LVScopeFunction, LVScopeSetFunction>(&LVScope::setIsFunction);
FunctionTwo =
create<LVScopeFunction, LVScopeSetFunction>(&LVScope::setIsFunction);
Namespace =
create<LVScopeNamespace, LVScopeSetFunction>(&LVScope::setIsNamespace);
// Create the logical symbols.
GlobalVariable =
create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable);
LocalVariable =
create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable);
ClassMember = create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsMember);
NestedVariable =
create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsVariable);
ParameterOne =
create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsParameter);
ParameterTwo =
create<LVSymbol, LVSymbolSetFunction>(&LVSymbol::setIsParameter);
// Create the logical lines.
LineOne = create<LVLine, LVLineSetFunction>(&LVLine::setIsLineDebug);
LineTwo = create<LVLine, LVLineSetFunction>(&LVLine::setIsLineDebug);
LineThree = create<LVLine, LVLineSetFunction>(&LVLine::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);
else
OrphanElements.push_back(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