432 lines
15 KiB
C++
432 lines
15 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 {
|
||
|
#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
|