blob: e9c1fbae4e0a72cba176c18373fa72e4c375e53c [file] [log] [blame]
//===- 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