llvm-project/lld/unittests/DriverTests/InputGraphTest.cpp
Rui Ueyama 5632e26d36 Greatly simplify InputGraph.
InputGraph has too many knobs and controls that are not being used. This
patch is to remove dead code, unused features and a class. There are two
things that worth noting, besides simple dead code removal:

1. ControlNode class is removed. We had it as the base class of Group
class, but it provides no functionality particularly meaningful. We now
have shallower class hierarchy that is easier to understand.

2. InputGraph provides a feature to replace a node with its internal data.
It is being used to "expand" some type of node, such as a Linker Script
node, with its actual files. We used to have two options when replacing
it -- ExpandOnly or ExpandAndReplace. ExpandOnly was to expand it but not
remove the node from the tree. There is no use of that option in the code,
so it was a dead feature.

Differential Revision: http://llvm-reviews.chandlerc.com/D3252

llvm-svn: 205363
2014-04-01 21:55:36 +00:00

439 lines
16 KiB
C++

//===- lld/unittest/InputGraphTest.cpp -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief InputGraph Tests
///
//===----------------------------------------------------------------------===//
#include <stdarg.h>
#include "gtest/gtest.h"
#include "lld/Core/InputGraph.h"
#include "lld/Core/Resolver.h"
#include "lld/ReaderWriter/Simple.h"
using namespace lld;
namespace {
class MyLinkingContext : public LinkingContext {
public:
Writer &writer() const override { llvm_unreachable("no writer!"); }
bool validateImpl(raw_ostream &) override { return true; }
};
class MyFileNode : public FileNode {
public:
MyFileNode(StringRef path, int64_t ordinal) : FileNode(path, ordinal) {}
error_code parse(const LinkingContext &, raw_ostream &) override {
return error_code::success();
}
ErrorOr<File &> getNextFile() override {
if (_nextFileIndex == _files.size())
return make_error_code(InputGraphError::no_more_files);
return *_files[_nextFileIndex++];
}
};
class MyGroupNode : public Group {
public:
MyGroupNode(int64_t ordinal) : Group(ordinal) {}
error_code parse(const LinkingContext &, raw_ostream &) override {
return error_code::success();
}
};
class MyExpandFileNode : public FileNode {
public:
MyExpandFileNode(StringRef path, int64_t ordinal)
: FileNode(path, ordinal) {}
error_code parse(const LinkingContext &, raw_ostream &) override {
return error_code::success();
}
ErrorOr<File &> getNextFile() override {
if (_nextFileIndex == _files.size())
return make_error_code(InputGraphError::no_more_files);
return *_files[_nextFileIndex++];
}
/// \brief How do we want to expand the current node ?
bool shouldExpand() const override { return true; }
/// \brief Get the elements that we want to expand with.
range<InputGraph::InputElementIterT> expandElements() override {
return make_range(_expandElements.begin(), _expandElements.end());
}
/// Process the input Elemenet
virtual bool addElement(std::unique_ptr<InputElement> element) {
_expandElements.push_back(std::move(element));
return true;
}
private:
InputGraph::InputElementVectorT _expandElements;
};
class InputGraphTest : public testing::Test {
public:
InputGraphTest() {
_inputGraph.reset(new InputGraph());
_context.setInputGraph(std::move(_inputGraph));
}
virtual LinkingContext &linkingContext() { return _context; }
InputElement &inputElement(unsigned index) {
return linkingContext().inputGraph()[index];
}
virtual InputGraph &inputGraph() { return linkingContext().inputGraph(); }
int inputFileCount() { return linkingContext().inputGraph().size(); }
protected:
MyLinkingContext _context;
std::unique_ptr<InputGraph> _inputGraph;
};
} // end anonymous namespace
TEST_F(InputGraphTest, Basic) {
EXPECT_EQ(0, inputFileCount());
ErrorOr<InputElement *> nextElement = inputGraph().getNextInputElement();
EXPECT_EQ(InputGraphError::no_more_elements, nextElement.getError());
}
TEST_F(InputGraphTest, AddAFile) {
std::unique_ptr<MyFileNode> myfile(new MyFileNode("file1", 0));
EXPECT_EQ(true, inputGraph().addInputElement(std::move(myfile)));
EXPECT_EQ(1, inputFileCount());
ErrorOr<InputElement *> nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, nextElement.getError());
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
FileNode *fileNode = llvm::dyn_cast<FileNode>(*nextElement);
StringRef path = fileNode->getUserPath();
EXPECT_EQ(0, path.compare("file1"));
nextElement = inputGraph().getNextInputElement();
EXPECT_EQ(InputGraphError::no_more_elements, nextElement.getError());
}
TEST_F(InputGraphTest, AddAFileWithLLDFiles) {
std::unique_ptr<MyFileNode> myfile(new MyFileNode("multi_files", 0));
std::vector<std::unique_ptr<File> > objfiles;
std::unique_ptr<SimpleFile> obj1(new SimpleFile("objfile1"));
std::unique_ptr<SimpleFile> obj2(new SimpleFile("objfile2"));
objfiles.push_back(std::move(obj1));
objfiles.push_back(std::move(obj2));
myfile->addFiles(std::move(objfiles));
EXPECT_EQ(true, inputGraph().addInputElement(std::move(myfile)));
EXPECT_EQ(1, inputFileCount());
ErrorOr<InputElement *> nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, nextElement.getError());
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
FileNode *fileNode = llvm::dyn_cast<FileNode>(*nextElement);
StringRef path = fileNode->getUserPath();
EXPECT_EQ(0, path.compare("multi_files"));
ErrorOr<File &> objfile = fileNode->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile1", (*objfile).path());
objfile = fileNode->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile2", (*objfile).path());
objfile = fileNode->getNextFile();
EXPECT_EQ(InputGraphError::no_more_files, objfile.getError());
fileNode->resetNextIndex();
objfile = fileNode->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile1", (*objfile).path());
nextElement = inputGraph().getNextInputElement();
EXPECT_EQ(InputGraphError::no_more_elements, nextElement.getError());
}
TEST_F(InputGraphTest, AddNodeWithFilesAndGroup) {
std::unique_ptr<MyFileNode> myfile(new MyFileNode("multi_files1", 0));
std::vector<std::unique_ptr<File> > objfiles;
std::unique_ptr<SimpleFile> obj1(new SimpleFile("objfile1"));
std::unique_ptr<SimpleFile> obj2(new SimpleFile("objfile2"));
objfiles.push_back(std::move(obj1));
objfiles.push_back(std::move(obj2));
myfile->addFiles(std::move(objfiles));
EXPECT_EQ(true, inputGraph().addInputElement(std::move(myfile)));
// Create a group node with two elements
// an file node which looks like an archive and
// two file nodes
std::unique_ptr<MyGroupNode> mygroup(new MyGroupNode(1));
std::unique_ptr<MyFileNode> myarchive(new MyFileNode("archive_file", 2));
std::vector<std::unique_ptr<File> > objfiles_group;
std::unique_ptr<SimpleFile> obj_1(new SimpleFile("objfile_1"));
std::unique_ptr<SimpleFile> obj_2(new SimpleFile("objfile_2"));
objfiles_group.push_back(std::move(obj_1));
objfiles_group.push_back(std::move(obj_2));
myarchive->addFiles(std::move(objfiles_group));
EXPECT_EQ(true, mygroup->addFile(std::move(myarchive)));
std::unique_ptr<MyFileNode> mygroupobjfile_1(
new MyFileNode("group_objfile1", 3));
std::vector<std::unique_ptr<File> > objfiles_group1;
std::unique_ptr<SimpleFile> mygroupobj1(
new SimpleFile("group_objfile1"));
objfiles_group1.push_back(std::move(mygroupobj1));
mygroupobjfile_1->addFiles(std::move(objfiles_group1));
EXPECT_EQ(true, mygroup->addFile(std::move(mygroupobjfile_1)));
std::unique_ptr<MyFileNode> mygroupobjfile_2(
new MyFileNode("group_objfile2", 4));
std::vector<std::unique_ptr<File> > objfiles_group2;
std::unique_ptr<SimpleFile> mygroupobj2(
new SimpleFile("group_objfile2"));
objfiles_group2.push_back(std::move(mygroupobj2));
mygroupobjfile_2->addFiles(std::move(objfiles_group2));
EXPECT_EQ(true, mygroup->addFile(std::move(mygroupobjfile_2)));
// Add the group to the InputGraph.
EXPECT_EQ(true, inputGraph().addInputElement(std::move(mygroup)));
EXPECT_EQ(2, inputFileCount());
ErrorOr<InputElement *> nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, nextElement.getError());
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
FileNode *fileNode = llvm::dyn_cast<FileNode>(*nextElement);
StringRef path = fileNode->getUserPath();
EXPECT_EQ(0, path.compare("multi_files1"));
ErrorOr<File &> objfile = fileNode->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile1", (*objfile).path());
objfile = fileNode->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile2", (*objfile).path());
objfile = fileNode->getNextFile();
EXPECT_EQ(InputGraphError::no_more_files, objfile.getError());
nextElement = inputGraph().getNextInputElement();
Group *group = llvm::dyn_cast<Group>(*nextElement);
assert(group);
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile_1", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile_2", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("group_objfile1", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("group_objfile2", (*objfile).path());
nextElement = inputGraph().getNextInputElement();
EXPECT_EQ(InputGraphError::no_more_elements, nextElement.getError());
}
// Iterate through the group
TEST_F(InputGraphTest, AddNodeWithGroupIteration) {
std::unique_ptr<MyFileNode> myfile(new MyFileNode("multi_files1", 0));
std::vector<std::unique_ptr<File> > objfiles;
std::unique_ptr<SimpleFile> obj1(new SimpleFile("objfile1"));
std::unique_ptr<SimpleFile> obj2(new SimpleFile("objfile2"));
objfiles.push_back(std::move(obj1));
objfiles.push_back(std::move(obj2));
myfile->addFiles(std::move(objfiles));
EXPECT_EQ(true, inputGraph().addInputElement(std::move(myfile)));
// Create a group node with two elements
// an file node which looks like an archive and
// two file nodes
std::unique_ptr<MyGroupNode> mygroup(new MyGroupNode(1));
std::unique_ptr<MyFileNode> myarchive(new MyFileNode("archive_file", 2));
std::vector<std::unique_ptr<File> > objfiles_group;
std::unique_ptr<SimpleFile> obj_1(new SimpleFile("objfile_1"));
std::unique_ptr<SimpleFile> obj_2(new SimpleFile("objfile_2"));
objfiles_group.push_back(std::move(obj_1));
objfiles_group.push_back(std::move(obj_2));
myarchive->addFiles(std::move(objfiles_group));
EXPECT_EQ(true, mygroup->addFile(std::move(myarchive)));
std::unique_ptr<MyFileNode> mygroupobjfile_1(
new MyFileNode("group_objfile1", 3));
std::vector<std::unique_ptr<File> > objfiles_group1;
std::unique_ptr<SimpleFile> mygroupobj1(
new SimpleFile("group_objfile1"));
objfiles_group1.push_back(std::move(mygroupobj1));
mygroupobjfile_1->addFiles(std::move(objfiles_group1));
EXPECT_EQ(true, mygroup->addFile(std::move(mygroupobjfile_1)));
std::unique_ptr<MyFileNode> mygroupobjfile_2(
new MyFileNode("group_objfile2", 4));
std::vector<std::unique_ptr<File> > objfiles_group2;
std::unique_ptr<SimpleFile> mygroupobj2(
new SimpleFile("group_objfile2"));
objfiles_group2.push_back(std::move(mygroupobj2));
mygroupobjfile_2->addFiles(std::move(objfiles_group2));
EXPECT_EQ(true, mygroup->addFile(std::move(mygroupobjfile_2)));
// Add the group to the InputGraph.
EXPECT_EQ(true, inputGraph().addInputElement(std::move(mygroup)));
EXPECT_EQ(2, inputFileCount());
ErrorOr<InputElement *> nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, nextElement.getError());
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
FileNode *fileNode = llvm::dyn_cast<FileNode>(*nextElement);
StringRef path = fileNode->getUserPath();
EXPECT_EQ(0, path.compare("multi_files1"));
ErrorOr<File &> objfile = fileNode->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile1", (*objfile).path());
objfile = fileNode->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile2", (*objfile).path());
objfile = fileNode->getNextFile();
EXPECT_EQ(InputGraphError::no_more_files, objfile.getError());
nextElement = inputGraph().getNextInputElement();
Group *group = llvm::dyn_cast<Group>(*nextElement);
assert(group);
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile_1", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile_2", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("group_objfile1", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("group_objfile2", (*objfile).path());
group->setResolveState(Resolver::StateNewDefinedAtoms);
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile_1", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("objfile_2", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("group_objfile1", (*objfile).path());
objfile = group->getNextFile();
EXPECT_NE(InputGraphError::no_more_files, objfile.getError());
EXPECT_EQ("group_objfile2", (*objfile).path());
}
// Node expansion tests.
TEST_F(InputGraphTest, ExpandAndReplaceInputGraphNode) {
std::unique_ptr<MyFileNode> myfile(new MyFileNode("multi_files1", 0));
std::vector<std::unique_ptr<File> > objfiles;
std::unique_ptr<SimpleFile> obj1(new SimpleFile("objfile1"));
std::unique_ptr<SimpleFile> obj2(new SimpleFile("objfile2"));
objfiles.push_back(std::move(obj1));
objfiles.push_back(std::move(obj2));
myfile->addFiles(std::move(objfiles));
EXPECT_EQ(true, inputGraph().addInputElement(std::move(myfile)));
objfiles.clear();
std::unique_ptr<MyExpandFileNode> expandFile(new MyExpandFileNode(
"expand_node", 1));
std::unique_ptr<MyFileNode> filenode1(new MyFileNode("expand_file1", 2));
std::unique_ptr<SimpleFile> obj3(new SimpleFile("objfile3"));
objfiles.push_back(std::move(obj3));
filenode1->addFiles(std::move(objfiles));
expandFile->addElement(std::move(filenode1));
objfiles.clear();
std::unique_ptr<MyFileNode> filenode2(new MyFileNode("expand_file2", 3));
std::unique_ptr<SimpleFile> obj4(new SimpleFile("objfile4"));
objfiles.push_back(std::move(obj4));
filenode2->addFiles(std::move(objfiles));
expandFile->addElement(std::move(filenode2));
objfiles.clear();
// Add expand file to InputGraph
EXPECT_EQ(true, inputGraph().addInputElement(std::move(expandFile)));
std::unique_ptr<MyFileNode> filenode3(new MyFileNode("obj_after_expand", 4));
std::unique_ptr<SimpleFile> obj5(new SimpleFile("objfile5"));
std::unique_ptr<SimpleFile> obj6(new SimpleFile("objfile6"));
objfiles.push_back(std::move(obj5));
objfiles.push_back(std::move(obj6));
filenode3->addFiles(std::move(objfiles));
// Add an extra obj after the expand node
EXPECT_EQ(true, inputGraph().addInputElement(std::move(filenode3)));
inputGraph().normalize();
ErrorOr<InputElement *> nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, nextElement.getError());
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
FileNode *fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("multi_files1", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, nextElement.getError());
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("expand_file1", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, nextElement.getError());
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("expand_file2", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_NE(InputGraphError::no_more_elements, nextElement.getError());
EXPECT_EQ(InputElement::Kind::File, (*nextElement)->kind());
fileNode = llvm::dyn_cast<FileNode>(*nextElement);
EXPECT_EQ("obj_after_expand", (*fileNode).getUserPath());
nextElement = inputGraph().getNextInputElement();
EXPECT_EQ(InputGraphError::no_more_elements, nextElement.getError());
}