blob: 1caad536e69aaa6f083e6821210baa136f573f7f [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ZIRCON_SYSTEM_UTEST_FIDL_COMPILER_TEST_LIBRARY_H_
#define ZIRCON_SYSTEM_UTEST_FIDL_COMPILER_TEST_LIBRARY_H_
#include <fidl/flat_ast.h>
#include <fidl/json_generator.h>
#include <fidl/lexer.h>
#include <fidl/linter.h>
#include <fidl/parser.h>
#include <fidl/source_file.h>
static std::unique_ptr<fidl::SourceFile> MakeSourceFile(const std::string& filename,
const std::string& raw_source_code) {
std::string source_code(raw_source_code);
// NUL terminate the string.
source_code.resize(source_code.size() + 1);
return std::make_unique<fidl::SourceFile>(filename, source_code);
}
class SharedAmongstLibraries {
public:
SharedAmongstLibraries()
: typespace(fidl::flat::Typespace::RootTypes(&error_reporter)) {}
fidl::ErrorReporter error_reporter;
fidl::flat::Typespace typespace;
fidl::flat::Libraries all_libraries;
std::set<std::unique_ptr<fidl::SourceFile>> all_sources;
};
class TestLibrary {
public:
explicit TestLibrary(const std::string& raw_source_code)
: TestLibrary("example.fidl", raw_source_code) {}
TestLibrary(const std::string& filename, const std::string& raw_source_code)
: TestLibrary(filename, raw_source_code, &owned_shared_) {}
TestLibrary(const std::string& filename, const std::string& raw_source_code,
SharedAmongstLibraries* shared)
: error_reporter_(&shared->error_reporter),
typespace_(&shared->typespace),
all_libraries_(&shared->all_libraries),
all_sources_(&shared->all_sources),
library_(std::make_unique<fidl::flat::Library>(
all_libraries_, error_reporter_, typespace_)) {
auto source_file = MakeSourceFile(filename, raw_source_code);
source_file_ = source_file.get();
all_sources_->insert(std::move(source_file));
}
bool AddDependentLibrary(TestLibrary dependent_library) {
return all_libraries_->Insert(std::move(dependent_library.library_));
}
void AddAttributeSchema(const std::string& name, fidl::flat::AttributeSchema schema) {
all_libraries_->AddAttributeSchema(name, std::move(schema));
}
bool Parse(std::unique_ptr<fidl::raw::File>& ast_ptr) {
fidl::Lexer lexer(*source_file_, error_reporter_);
fidl::Parser parser(&lexer, error_reporter_);
ast_ptr.reset(parser.Parse().release());
return parser.Ok();
}
bool Compile() {
fidl::Lexer lexer(*source_file_, error_reporter_);
fidl::Parser parser(&lexer, error_reporter_);
auto ast = parser.Parse();
return parser.Ok() &&
library_->ConsumeFile(std::move(ast)) &&
library_->Compile();
}
bool Lint(fidl::Findings* findings) {
fidl::Lexer lexer(*source_file_, error_reporter_);
fidl::Parser parser(&lexer, error_reporter_);
auto ast = parser.Parse();
if (!parser.Ok()) {
std::string_view beginning(source_file_->data().data(), 0);
fidl::SourceLocation source_location(beginning, *source_file_);
findings->emplace_back(source_location, "parser-error",
error_reporter_->errors().front() + "\n");
return false;
}
fidl::linter::Linter linter;
return linter.Lint(ast, findings);
}
bool Lint() {
fidl::Findings findings;
bool passed = Lint(&findings);
fidl::utils::WriteFindingsToErrorReporter(findings, error_reporter_);
return passed;
}
std::string GenerateJSON() {
auto json_generator = fidl::JSONGenerator(library_.get());
auto out = json_generator.Produce();
return out.str();
}
bool AddSourceFile(const std::string& filename, const std::string& raw_source_code) {
auto source_file = MakeSourceFile(filename, raw_source_code);
fidl::Lexer lexer(*source_file, error_reporter_);
fidl::Parser parser(&lexer, error_reporter_);
auto ast = parser.Parse();
return parser.Ok() &&
library_->ConsumeFile(std::move(ast)) &&
library_->Compile();
}
const fidl::flat::Bits* LookupBits(const std::string& name) {
for (const auto& bits_decl : library_->bits_declarations_) {
if (bits_decl->GetName() == name) {
return bits_decl.get();
}
}
return nullptr;
}
const fidl::flat::Const* LookupConstant(const std::string& name) {
for (const auto& const_decl : library_->const_declarations_) {
if (const_decl->GetName() == name) {
return const_decl.get();
}
}
return nullptr;
}
const fidl::flat::Struct* LookupStruct(const std::string& name) {
for (const auto& struct_decl : library_->struct_declarations_) {
if (struct_decl->GetName() == name) {
return struct_decl.get();
}
}
return nullptr;
}
const fidl::flat::Table* LookupTable(const std::string& name) {
for (const auto& table_decl : library_->table_declarations_) {
if (table_decl->GetName() == name) {
return table_decl.get();
}
}
return nullptr;
}
const fidl::flat::Union* LookupUnion(const std::string& name) {
for (const auto& union_decl : library_->union_declarations_) {
if (union_decl->GetName() == name) {
return union_decl.get();
}
}
return nullptr;
}
const fidl::flat::XUnion* LookupXUnion(const std::string& name) {
for (const auto& xunion_decl : library_->xunion_declarations_) {
if (xunion_decl->GetName() == name) {
return xunion_decl.get();
}
}
return nullptr;
}
const fidl::flat::Interface* LookupInterface(const std::string& name) {
for (const auto& interface_decl : library_->interface_declarations_) {
if (interface_decl->GetName() == name) {
return interface_decl.get();
}
}
return nullptr;
}
void set_warnings_as_errors(bool value) {
error_reporter_->set_warnings_as_errors(value);
}
const fidl::flat::Library* library() const {
return library_.get();
}
const fidl::SourceFile& source_file() const {
return *source_file_;
}
std::string filename() const {
return std::string(source_file().filename());
}
std::string FileData() const {
return std::string(source_file().data());
}
std::string FileLocation(std::string within, std::string to_find) const {
std::istringstream lines(within);
std::string line;
size_t line_number = 0;
while (std::getline(lines, line)) {
line_number++;
size_t column_index = line.find(to_find);
if (column_index != std::string::npos) {
std::stringstream position;
position << filename() << ":" << line_number << ":" << (column_index + 1);
return position.str();
}
}
assert(false); // Bug in test
return "never reached";
}
std::string FileLocation(std::string to_find) const {
return FileLocation(FileData(), to_find);
}
const std::vector<std::string>& errors() const {
return error_reporter_->errors();
}
const std::vector<std::string>& warnings() const {
return error_reporter_->warnings();
}
const std::vector<fidl::flat::Decl*> declaration_order() const {
return library_->declaration_order_;
}
protected:
SharedAmongstLibraries owned_shared_;
fidl::ErrorReporter* error_reporter_;
fidl::flat::Typespace* typespace_;
fidl::flat::Libraries* all_libraries_;
std::set<std::unique_ptr<fidl::SourceFile>>* all_sources_;
fidl::SourceFile* source_file_;
std::unique_ptr<fidl::flat::Library> library_;
};
#endif // ZIRCON_SYSTEM_UTEST_FIDL_COMPILER_TEST_LIBRARY_H_