Merge remote-tracking branch 'upstream/master'

Sync lodepng project.
This commit is contained in:
Andrei Medar 2020-09-29 19:32:08 +00:00
commit 95ef6fc683
28 changed files with 474 additions and 214 deletions

4
.bazelignore Normal file
View File

@ -0,0 +1,4 @@
# Using CMake or own WORKSPACE
oss-internship-2020
# Uses its own WORKSPACE
sandboxed_api/examples/hello_sapi

View File

@ -44,6 +44,9 @@ include(SapiBuildDefs)
# Allow the header generator to auto-configure include paths # Allow the header generator to auto-configure include paths
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Allow the header generator to auto-configure include paths
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if (SAPI_FORCE_COLOR_OUTPUT) if (SAPI_FORCE_COLOR_OUTPUT)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # GCC if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # GCC
add_compile_options(-fdiagnostics-color=always) add_compile_options(-fdiagnostics-color=always)

View File

@ -132,44 +132,44 @@ function(add_sapi_library)
set(_sapi_embed_dir "${CMAKE_CURRENT_BINARY_DIR}") set(_sapi_embed_dir "${CMAKE_CURRENT_BINARY_DIR}")
set(_sapi_embed_name "${_sapi_NAME}") set(_sapi_embed_name "${_sapi_NAME}")
endif() endif()
set(_sapi_isystem "${_sapi_NAME}.isystem}")
list(APPEND _sapi_generator_args
"--sapi_name=${_sapi_LIBRARY_NAME}"
"--sapi_out=${_sapi_gen_header}"
"--sapi_embed_dir=${_sapi_embed_dir}"
"--sapi_embed_name=${_sapi_embed_name}"
"--sapi_functions=${_sapi_funcs}"
"--sapi_ns=${_sapi_NAMESPACE}"
"--sapi_isystem=${_sapi_isystem}"
)
list(JOIN _sapi_full_inputs "," _sapi_full_inputs)
if(SAPI_ENABLE_GENERATOR) if(SAPI_ENABLE_GENERATOR)
add_custom_command( list(APPEND _sapi_generator_command
OUTPUT "${_sapi_gen_header}" sapi_generator_tool
COMMAND sapi_generator_tool -p "${CMAKE_CURRENT_BINARY_DIR}"
"--sapi_name=${_sapi_LIBRARY_NAME}" ${_sapi_generator_args}
"--sapi_out=${_sapi_gen_header}" ${_sapi_full_inputs}
"--sapi_embed_dir=${_sapi_embed_dir}"
"--sapi_embed_name=${_sapi_embed_name}"
"--sapi_functions=${_sapi_funcs}"
"--sapi_ns=${_sapi_NAMESPACE}"
${_sapi_full_inputs}
COMMENT "Generating interface"
DEPENDS ${_sapi_INPUTS}
VERBATIM
) )
else() else()
set(_sapi_isystem "${_sapi_NAME}.isystem") list(APPEND _sapi_generator_command
list(JOIN _sapi_full_inputs "," _sapi_full_inputs) "${SAPI_PYTHON3_EXECUTABLE}" -B
add_custom_command( "${SAPI_SOURCE_DIR}/sandboxed_api/tools/generator2/sapi_generator.py"
OUTPUT "${_sapi_gen_header}" "${_sapi_isystem}" ${_sapi_generator_args}
COMMAND sh -c "--sapi_in=${_sapi_full_inputs}"
"${CMAKE_CXX_COMPILER} -E -x c++ -v /dev/null 2>&1 | \
awk '/> search starts here:/{f=1;next}/^End of search/{f=0}f{print $1}' \
> \"${_sapi_isystem}\""
COMMAND "${SAPI_PYTHON3_EXECUTABLE}" -B
"${SAPI_SOURCE_DIR}/sandboxed_api/tools/generator2/sapi_generator.py"
"--sapi_name=${_sapi_LIBRARY_NAME}"
"--sapi_out=${_sapi_gen_header}"
"--sapi_embed_dir=${_sapi_embed_dir}"
"--sapi_embed_name=${_sapi_embed_name}"
"--sapi_functions=${_sapi_funcs}"
"--sapi_ns=${_sapi_NAMESPACE}"
"--sapi_isystem=${_sapi_isystem}"
"--sapi_in=${_sapi_full_inputs}"
COMMENT "Generating interface"
VERBATIM
) )
endif() endif()
add_custom_command(
OUTPUT "${_sapi_gen_header}" "${_sapi_isystem}"
COMMAND sh -c
"${CMAKE_CXX_COMPILER} -E -x c++ -v /dev/null 2>&1 | \
awk '/> search starts here:/{f=1;next}/^End of search/{f=0}f{print $1}' \
> \"${_sapi_isystem}\""
COMMAND ${_sapi_generator_command}
COMMENT "Generating interface"
DEPENDS ${_sapi_INPUTS}
VERBATIM
)
# Library with the interface # Library with the interface
if(NOT _sapi_SOURCES) if(NOT _sapi_SOURCES)

@ -0,0 +1 @@
Subproject commit cbe7fad20d969626a5c4eb0501a273dfe812bcd3

View File

@ -24,6 +24,7 @@ cc_library(
srcs = ["guetzli_entry_points.cc"], srcs = ["guetzli_entry_points.cc"],
hdrs = ["guetzli_entry_points.h"], hdrs = ["guetzli_entry_points.h"],
deps = [ deps = [
"@com_google_absl//absl/status:statusor",
"@com_google_sandboxed_api//sandboxed_api:lenval_core", "@com_google_sandboxed_api//sandboxed_api:lenval_core",
"@com_google_sandboxed_api//sandboxed_api:vars", "@com_google_sandboxed_api//sandboxed_api:vars",
"@guetzli//:guetzli_lib", "@guetzli//:guetzli_lib",
@ -53,9 +54,7 @@ sapi_library(
cc_binary( cc_binary(
name = "guetzli_sandboxed", name = "guetzli_sandboxed",
srcs = ["guetzli_sandboxed.cc"], srcs = ["guetzli_sandboxed.cc"],
deps = [ deps = [":guetzli_sapi"],
":guetzli_sapi",
],
) )
cc_test( cc_test(

View File

@ -25,8 +25,8 @@
#include "guetzli/jpeg_data_reader.h" #include "guetzli/jpeg_data_reader.h"
#include "guetzli/quality.h" #include "guetzli/quality.h"
#include "png.h" // NOLINT(build/include) #include "png.h" // NOLINT(build/include)
#include "absl/status/statusor.h"
#include "sandboxed_api/sandbox2/util/fileops.h" #include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/util/statusor.h"
namespace { namespace {
@ -51,7 +51,7 @@ sapi::LenValStruct CreateLenValFromData(const void* data, size_t size) {
return {size, new_data}; return {size, new_data};
} }
sapi::StatusOr<std::string> ReadFromFd(int fd) { absl::StatusOr<std::string> ReadFromFd(int fd) {
struct stat file_data; struct stat file_data;
int status = fstat(fd, &file_data); int status = fstat(fd, &file_data);
@ -70,9 +70,9 @@ sapi::StatusOr<std::string> ReadFromFd(int fd) {
return result; return result;
} }
sapi::StatusOr<GuetzliInitData> PrepareDataForProcessing( absl::StatusOr<GuetzliInitData> PrepareDataForProcessing(
const ProcessingParams& processing_params) { const ProcessingParams& processing_params) {
sapi::StatusOr<std::string> input = ReadFromFd(processing_params.remote_fd); absl::StatusOr<std::string> input = ReadFromFd(processing_params.remote_fd);
if (!input.ok()) { if (!input.ok()) {
return input.status(); return input.status();
@ -96,7 +96,7 @@ inline uint8_t BlendOnBlack(const uint8_t val, const uint8_t alpha) {
} }
// Modified version of ReadPNG from original guetzli.cc // Modified version of ReadPNG from original guetzli.cc
sapi::StatusOr<ImageData> ReadPNG(const std::string& data) { absl::StatusOr<ImageData> ReadPNG(const std::string& data) {
std::vector<uint8_t> rgb; std::vector<uint8_t> rgb;
int xsize, ysize; int xsize, ysize;
png_structp png_ptr = png_structp png_ptr =

View File

@ -17,7 +17,6 @@
#include "guetzli_transaction.h" // NOLINT(build/include) #include "guetzli_transaction.h" // NOLINT(build/include)
#include "sandboxed_api/sandbox2/util/fileops.h" #include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/util/statusor.h"
namespace { namespace {

View File

@ -83,7 +83,7 @@ TEST_F(GuetzliSapiTest, ProcessRGB) {
*processing_params.mutable_data() = { *processing_params.mutable_data() = {
in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb}; in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb};
sapi::v::LenVal output(0); sapi::v::LenVal output(0);
sapi::StatusOr<bool> processing_result = absl::StatusOr<bool> processing_result =
api_->ProcessRgb(processing_params.PtrBefore(), output.PtrBoth()); api_->ProcessRgb(processing_params.PtrBefore(), output.PtrBoth());
ASSERT_TRUE(processing_result.value_or(false)) << "Error processing rgb data"; ASSERT_TRUE(processing_result.value_or(false)) << "Error processing rgb data";
std::string reference_data = std::string reference_data =
@ -108,7 +108,7 @@ TEST_F(GuetzliSapiTest, ProcessJpeg) {
*processing_params.mutable_data() = { *processing_params.mutable_data() = {
in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb}; in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb};
sapi::v::LenVal output(0); sapi::v::LenVal output(0);
sapi::StatusOr<bool> processing_result = absl::StatusOr<bool> processing_result =
api_->ProcessJpeg(processing_params.PtrBefore(), output.PtrBoth()); api_->ProcessJpeg(processing_params.PtrBefore(), output.PtrBoth());
ASSERT_TRUE(processing_result.value_or(false)) << "Error processing jpg data"; ASSERT_TRUE(processing_result.value_or(false)) << "Error processing jpg data";
std::string reference_data = std::string reference_data =

View File

@ -99,7 +99,7 @@ absl::Status GuetzliTransaction::LinkOutFile(int out_fd) const {
return absl::OkStatus(); return absl::OkStatus();
} }
sapi::StatusOr<ImageType> GuetzliTransaction::GetImageTypeFromFd(int fd) const { absl::StatusOr<ImageType> GuetzliTransaction::GetImageTypeFromFd(int fd) const {
static const unsigned char kPNGMagicBytes[] = { static const unsigned char kPNGMagicBytes[] = {
0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n', 0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n',
}; };

View File

@ -48,7 +48,7 @@ class GuetzliTransaction : public sapi::Transaction {
absl::Status Main() final; absl::Status Main() final;
absl::Status LinkOutFile(int out_fd) const; absl::Status LinkOutFile(int out_fd) const;
sapi::StatusOr<ImageType> GetImageTypeFromFd(int fd) const; absl::StatusOr<ImageType> GetImageTypeFromFd(int fd) const;
const TransactionParams params_; const TransactionParams params_;
ImageType image_type_ = ImageType::kJpeg; ImageType image_type_ = ImageType::kJpeg;

View File

@ -73,12 +73,12 @@ int main(int argc, char* argv[]) {
sapi::v::ConstCStr in_file_v(in_file.c_str()); sapi::v::ConstCStr in_file_v(in_file.c_str());
// Initialize library's main data-holders. // Initialize library's main data-holders.
sapi::StatusOr<opj_stream_t*> stream = absl::StatusOr<opj_stream_t*> stream =
api.opj_stream_create_default_file_stream(in_file_v.PtrBefore(), 1); api.opj_stream_create_default_file_stream(in_file_v.PtrBefore(), 1);
CHECK(stream.ok()) << "Stream initialization failed: " << stream.status(); CHECK(stream.ok()) << "Stream initialization failed: " << stream.status();
sapi::v::RemotePtr stream_pointer(stream.value()); sapi::v::RemotePtr stream_pointer(stream.value());
sapi::StatusOr<opj_codec_t*> codec = api.opj_create_decompress(OPJ_CODEC_JP2); absl::StatusOr<opj_codec_t*> codec = api.opj_create_decompress(OPJ_CODEC_JP2);
CHECK(codec.ok()) << "Codec initialization failed: " << stream.status(); CHECK(codec.ok()) << "Codec initialization failed: " << stream.status();
sapi::v::RemotePtr codec_pointer(codec.value()); sapi::v::RemotePtr codec_pointer(codec.value());
@ -86,7 +86,7 @@ int main(int argc, char* argv[]) {
status = api.opj_set_default_decoder_parameters(parameters.PtrBoth()); status = api.opj_set_default_decoder_parameters(parameters.PtrBoth());
CHECK(status.ok()) << "Parameters initialization failed " << status; CHECK(status.ok()) << "Parameters initialization failed " << status;
sapi::StatusOr<OPJ_BOOL> bool_status = absl::StatusOr<OPJ_BOOL> bool_status =
api.opj_setup_decoder(&codec_pointer, parameters.PtrBefore()); api.opj_setup_decoder(&codec_pointer, parameters.PtrBefore());
CHECK(bool_status.ok() && bool_status.value()) << "Decoder setup failed"; CHECK(bool_status.ok() && bool_status.value()) << "Decoder setup failed";

@ -0,0 +1 @@
Subproject commit 65c8f577d2f057e80040e98958eae80ca76c6b94

@ -0,0 +1 @@
Subproject commit 74d7261be17cf659d5930d4830609406bd7553e3

View File

@ -40,7 +40,6 @@ sapi_library(
cc_binary( cc_binary(
name = "hello", name = "hello",
srcs = ["hello_main.cc"], srcs = ["hello_main.cc"],
includes = ["."], # To find the generated header
deps = [":hello_sapi"], deps = [":hello_sapi"],
) )
@ -50,7 +49,6 @@ cc_binary(
cc_binary( cc_binary(
name = "hello_transacted", name = "hello_transacted",
srcs = ["hello_transacted.cc"], srcs = ["hello_transacted.cc"],
includes = ["."], # To find the generated header
deps = [ deps = [
":hello_sapi", ":hello_sapi",
"@com_google_absl//absl/memory", "@com_google_absl//absl/memory",

View File

@ -45,6 +45,7 @@ target_link_libraries(sapi_generator PUBLIC
absl::memory absl::memory
absl::random_random absl::random_random
absl::status absl::status
absl::statusor
absl::strings absl::strings
clangFormat clangFormat
clangFrontendTool clangFrontendTool
@ -59,12 +60,15 @@ add_executable(sapi_generator_tool
) )
target_link_libraries(sapi_generator_tool PRIVATE target_link_libraries(sapi_generator_tool PRIVATE
sapi::base sapi::base
sandbox2::file_helpers
sandbox2::fileops sandbox2::fileops
sapi::generator sapi::generator
) )
if(SAPI_ENABLE_TESTS) if(SAPI_ENABLE_TESTS)
add_executable(sapi_generator_test add_executable(sapi_generator_test
frontend_action_test_util.cc
frontend_action_test_util.h
emitter_test.cc emitter_test.cc
) )
target_link_libraries(sapi_generator_test PRIVATE target_link_libraries(sapi_generator_test PRIVATE

View File

@ -23,9 +23,13 @@
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/strings/str_join.h" #include "absl/strings/str_join.h"
#include "absl/strings/str_replace.h" #include "absl/strings/str_replace.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h" #include "absl/strings/strip.h"
#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "clang/Format/Format.h"
#include "sandboxed_api/tools/clang_generator/diagnostics.h" #include "sandboxed_api/tools/clang_generator/diagnostics.h"
#include "sandboxed_api/tools/clang_generator/generator.h"
#include "sandboxed_api/util/status_macros.h" #include "sandboxed_api/util/status_macros.h"
namespace sapi { namespace sapi {
@ -106,6 +110,30 @@ constexpr absl::string_view kClassFooterTemplate = R"(
}; };
)"; )";
namespace internal {
absl::StatusOr<std::string> ReformatGoogleStyle(const std::string& filename,
const std::string& code) {
// Configure code style based on Google style, but enforce pointer alignment
clang::format::FormatStyle style =
clang::format::getGoogleStyle(clang::format::FormatStyle::LK_Cpp);
style.DerivePointerAlignment = false;
style.PointerAlignment = clang::format::FormatStyle::PAS_Left;
clang::tooling::Replacements replacements = clang::format::reformat(
style, code, llvm::makeArrayRef(clang::tooling::Range(0, code.size())),
filename);
llvm::Expected<std::string> formatted_header =
clang::tooling::applyAllReplacements(code, replacements);
if (!formatted_header) {
return absl::InternalError(llvm::toString(formatted_header.takeError()));
}
return *formatted_header;
}
} // namespace internal
std::string GetIncludeGuard(absl::string_view filename) { std::string GetIncludeGuard(absl::string_view filename) {
if (filename.empty()) { if (filename.empty()) {
static auto* bit_gen = new absl::BitGen(); static auto* bit_gen = new absl::BitGen();
@ -250,7 +278,8 @@ absl::StatusOr<std::string> EmitFunction(const clang::FunctionDecl* decl) {
} }
absl::StatusOr<std::string> EmitHeader( absl::StatusOr<std::string> EmitHeader(
std::vector<clang::FunctionDecl*> functions, const QualTypeSet& types, const std::vector<std::string>& functions,
const Emitter::RenderedTypesMap& rendered_types,
const GeneratorOptions& options) { const GeneratorOptions& options) {
std::string out; std::string out;
const std::string include_guard = GetIncludeGuard(options.out_file); const std::string include_guard = GetIncludeGuard(options.out_file);
@ -276,45 +305,19 @@ absl::StatusOr<std::string> EmitHeader(
} }
// Emit type dependencies // Emit type dependencies
// TODO(cblichmann): Coalesce namespaces if (!rendered_types.empty()) {
std::string out_types = "// Types this API depends on\n"; absl::StrAppend(&out, "// Types this API depends on\n");
bool added_types = false; for (const auto& [ns_name, types] : rendered_types) {
for (const clang::QualType& qual : types) { if (!ns_name.empty()) {
clang::TypeDecl* decl = nullptr; absl::StrAppend(&out, "namespace ", ns_name, " {\n");
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) { }
decl = typedef_type->getDecl(); for (const auto& type : types) {
} else if (const auto* enum_type = qual->getAs<clang::EnumType>()) { absl::StrAppend(&out, type, ";\n");
decl = enum_type->getDecl(); }
} else { if (!ns_name.empty()) {
decl = qual->getAsRecordDecl(); absl::StrAppend(&out, "} // namespace ", ns_name, "\n\n");
}
if (!decl) {
continue;
}
const std::vector<std::string> ns_path = GetNamespacePath(decl);
std::string nested_ns_name;
if (!ns_path.empty()) {
if (const auto& ns_root = ns_path.front();
ns_root == "std" || ns_root == "sapi" || ns_root == "__gnu_cxx") {
// Filter out any and all declarations from the C++ standard library,
// from SAPI itself and from other well-known namespaces. This avoids
// re-declaring things like standard integer types, for example.
continue;
} }
nested_ns_name = absl::StrCat(ns_path[0].empty() ? "" : " ",
absl::StrJoin(ns_path, "::"));
absl::StrAppend(&out_types, "namespace", nested_ns_name, " {\n");
} }
absl::StrAppend(&out_types, PrintAstDecl(decl), ";");
if (!ns_path.empty()) {
absl::StrAppend(&out_types, "\n} // namespace", nested_ns_name);
}
absl::StrAppend(&out_types, "\n");
added_types = true;
}
if (added_types) {
absl::StrAppend(&out, out_types);
} }
// Optionally emit a default sandbox that instantiates an embedded sandboxee // Optionally emit a default sandbox that instantiates an embedded sandboxee
@ -329,11 +332,7 @@ absl::StatusOr<std::string> EmitHeader(
// TODO(cblichmann): Make the "Api" suffix configurable or at least optional. // TODO(cblichmann): Make the "Api" suffix configurable or at least optional.
absl::StrAppendFormat(&out, kClassHeaderTemplate, absl::StrAppendFormat(&out, kClassHeaderTemplate,
absl::StrCat(options.name, "Api")); absl::StrCat(options.name, "Api"));
std::string out_func; absl::StrAppend(&out, absl::StrJoin(functions, "\n"));
for (const clang::FunctionDecl* decl : functions) {
SAPI_ASSIGN_OR_RETURN(out_func, EmitFunction(decl));
absl::StrAppend(&out, out_func);
}
absl::StrAppend(&out, kClassFooterTemplate); absl::StrAppend(&out, kClassFooterTemplate);
// Close out the header: close namespace (if needed) and end include guard // Close out the header: close namespace (if needed) and end include guard
@ -344,4 +343,45 @@ absl::StatusOr<std::string> EmitHeader(
return out; return out;
} }
void Emitter::CollectType(clang::QualType qual) {
clang::TypeDecl* decl = nullptr;
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) {
decl = typedef_type->getDecl();
} else if (const auto* enum_type = qual->getAs<clang::EnumType>()) {
decl = enum_type->getDecl();
} else {
decl = qual->getAsRecordDecl();
}
if (!decl) {
return;
}
const std::vector<std::string> ns_path = GetNamespacePath(decl);
std::string ns_name;
if (!ns_path.empty()) {
if (const auto& ns_root = ns_path.front();
ns_root == "std" || ns_root == "sapi" || ns_root == "__gnu_cxx") {
// Filter out any and all declarations from the C++ standard library,
// from SAPI itself and from other well-known namespaces. This avoids
// re-declaring things like standard integer types, for example.
return;
}
ns_name = absl::StrCat(ns_path[0].empty() ? "" : " ",
absl::StrJoin(ns_path, "::"));
}
rendered_types_[ns_name].push_back(PrintAstDecl(decl));
}
void Emitter::CollectFunction(clang::FunctionDecl* decl) {
functions_.push_back(*EmitFunction(decl)); // Cannot currently fail
}
absl::StatusOr<std::string> Emitter::EmitHeader(
const GeneratorOptions& options) {
SAPI_ASSIGN_OR_RETURN(const std::string header,
::sapi::EmitHeader(functions_, rendered_types_, options));
return internal::ReformatGoogleStyle(options.out_file, header);
}
} // namespace sapi } // namespace sapi

View File

@ -16,16 +16,44 @@
#define SANDBOXED_API_TOOLS_CLANG_GENERATOR_EMITTER_H_ #define SANDBOXED_API_TOOLS_CLANG_GENERATOR_EMITTER_H_
#include <string> #include <string>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "sandboxed_api/tools/clang_generator/generator.h"
#include "sandboxed_api/tools/clang_generator/types.h" #include "sandboxed_api/tools/clang_generator/types.h"
namespace sapi { namespace sapi {
namespace internal {
absl::StatusOr<std::string> ReformatGoogleStyle(const std::string& filename,
const std::string& code);
} // namespace internal
class GeneratorOptions;
class Emitter {
public:
using RenderedTypesMap =
absl::flat_hash_map<std::string, std::vector<std::string>>;
void CollectType(clang::QualType qual);
void CollectFunction(clang::FunctionDecl* decl);
// Outputs a formatted header for a list of functions and their related types.
absl::StatusOr<std::string> EmitHeader(const GeneratorOptions& options);
protected:
// Maps namespace to a list of spellings for types
RenderedTypesMap rendered_types_;
// Functions for sandboxed API, including their bodies
std::vector<std::string> functions_;
};
// Constructs an include guard name for the given filename. The name is of the // Constructs an include guard name for the given filename. The name is of the
// same form as the include guards in this project. // same form as the include guards in this project.
@ -35,11 +63,6 @@ namespace sapi {
// SANDBOXED_API_EXAMPLES_ZLIB_ZLIB_SAPI_SAPI_H_ // SANDBOXED_API_EXAMPLES_ZLIB_ZLIB_SAPI_SAPI_H_
std::string GetIncludeGuard(absl::string_view filename); std::string GetIncludeGuard(absl::string_view filename);
// Outputs a formatted header for a list of functions and their related types.
absl::StatusOr<std::string> EmitHeader(
std::vector<clang::FunctionDecl*> functions, const QualTypeSet& types,
const GeneratorOptions& options);
} // namespace sapi } // namespace sapi
#endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_EMITTER_H_ #endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_EMITTER_H_

View File

@ -14,18 +14,48 @@
#include "sandboxed_api/tools/clang_generator/emitter.h" #include "sandboxed_api/tools/clang_generator/emitter.h"
#include <initializer_list>
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "sandboxed_api/sandbox2/testing.h"
#include "sandboxed_api/tools/clang_generator/frontend_action_test_util.h"
#include "sandboxed_api/tools/clang_generator/generator.h"
#include "sandboxed_api/util/status_matchers.h" #include "sandboxed_api/util/status_matchers.h"
namespace sapi { namespace sapi {
namespace { namespace {
using ::testing::MatchesRegex; using ::testing::MatchesRegex;
using ::testing::SizeIs;
using ::testing::StrEq; using ::testing::StrEq;
using ::testing::StrNe; using ::testing::StrNe;
class EmitterForTesting : public Emitter {
public:
using Emitter::functions_;
};
class EmitterTest : public FrontendActionTest {};
TEST_F(EmitterTest, BasicFunctionality) {
GeneratorOptions options;
options.out_file = "input.h";
options.set_function_names<std::initializer_list<std::string>>(
{"ExposedFunction"});
EmitterForTesting emitter;
RunFrontendAction(R"(extern "C" void ExposedFunction() {})",
absl::make_unique<GeneratorAction>(emitter, options));
EXPECT_THAT(emitter.functions_, SizeIs(1));
absl::StatusOr<std::string> header = emitter.EmitHeader(options);
EXPECT_THAT(header, IsOk());
}
TEST(IncludeGuard, CreatesRandomizedGuardForEmptyFilename) { TEST(IncludeGuard, CreatesRandomizedGuardForEmptyFilename) {
// Copybara will transform the string. This is intentional. // Copybara will transform the string. This is intentional.
constexpr absl::string_view kGeneratedHeaderPrefix = constexpr absl::string_view kGeneratedHeaderPrefix =

View File

@ -0,0 +1,70 @@
// Copyright 2020 google llc
//
// licensed under the apache license, version 2.0 (the "license");
// you may not use this file except in compliance with the license.
// you may obtain a copy of the license at
//
// http://www.apache.org/licenses/license-2.0
//
// unless required by applicable law or agreed to in writing, software
// distributed under the license is distributed on an "as is" basis,
// without warranties or conditions of any kind, either express or implied.
// see the license for the specific language governing permissions and
// limitations under the license.
#include "sandboxed_api/tools/clang_generator/frontend_action_test_util.h"
#include <vector>
#include "absl/status/status.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/VirtualFileSystem.h"
namespace sapi {
namespace internal {
absl::Status RunClangTool(
const std::vector<std::string> command_line,
const absl::flat_hash_map<std::string, std::string> file_contents,
std::unique_ptr<clang::FrontendAction> action) {
// Setup an in-memory virtual filesystem
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> fs(
new llvm::vfs::InMemoryFileSystem());
llvm::IntrusiveRefCntPtr<clang::FileManager> files =
new clang::FileManager(clang::FileSystemOptions(), fs);
for (const auto& [filename, content] : file_contents) {
if (!fs->addFile(filename, /*ModificationTime=*/0,
llvm::MemoryBuffer::getMemBuffer(content))) {
return absl::UnknownError(
absl::StrCat("Couldn't add file to in-memory VFS: ", filename));
}
}
#if LLVM_VERSION_MAJOR >= 10
clang::tooling::ToolInvocation invocation(command_line, std::move(action),
files.get());
#else
clang::tooling::ToolInvocation invocation(command_line, action.get(),
files.get());
#endif
if (!invocation.run()) {
return absl::UnknownError("Tool invocation failed");
}
return absl::OkStatus();
}
} // namespace internal
std::vector<std::string> FrontendActionTest::GetCommandLineFlagsForTesting(
absl::string_view input_file) {
return {"tool", "-fsyntax-only", "--std=c++17",
"-I.", "-Wno-error", std::string(input_file)};
}
} // namespace sapi

View File

@ -0,0 +1,83 @@
// Copyright 2020 google llc
//
// licensed under the apache license, version 2.0 (the "license");
// you may not use this file except in compliance with the license.
// you may obtain a copy of the license at
//
// http://www.apache.org/licenses/license-2.0
//
// unless required by applicable law or agreed to in writing, software
// distributed under the license is distributed on an "as is" basis,
// without warranties or conditions of any kind, either express or implied.
// see the license for the specific language governing permissions and
// limitations under the license.
#ifndef SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_
#define SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_
#include <memory>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/flat_hash_map.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "clang/Frontend/FrontendAction.h"
#include "sandboxed_api/util/status_matchers.h"
namespace sapi {
namespace internal {
absl::Status RunClangTool(
const std::vector<std::string> command_line,
const absl::flat_hash_map<std::string, std::string> file_contents,
std::unique_ptr<clang::FrontendAction> action);
} // namespace internal
class FrontendActionTest : public ::testing::Test {
protected:
// Adds code to a virtual filesystem with the given filename.
void AddCode(const std::string& filename, absl::string_view code) {
absl::StrAppend(&file_contents_[filename], code);
}
// Changes the name of the virtual input file. Useful for special cases where
// the filenames of compiled sources matter.
void set_input_file(absl::string_view value) {
input_file_ = std::string(value);
}
virtual std::vector<std::string> GetCommandLineFlagsForTesting(
absl::string_view input_file);
// Runs the specified frontend action on in-memory source code.
void RunFrontendAction(absl::string_view code,
std::unique_ptr<clang::FrontendAction> action) {
std::vector<std::string> command_line =
GetCommandLineFlagsForTesting(input_file_);
AddCode(input_file_, code);
ASSERT_THAT(
internal::RunClangTool(command_line, file_contents_, std::move(action)),
IsOk());
}
// Runs the specified frontend action. Provided for compatibility with LLVM <
// 10. Takes ownership.
void RunFrontendAction(absl::string_view code,
clang::FrontendAction* action) {
RunFrontendAction(code, absl::WrapUnique(action));
}
private:
std::string input_file_ = "input.cc";
absl::flat_hash_map<std::string, std::string> file_contents_;
};
} // namespace sapi
#endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_FRONTEND_ACTION_TEST_UTIL_H_

View File

@ -19,6 +19,7 @@
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "clang/AST/Type.h"
#include "clang/Format/Format.h" #include "clang/Format/Format.h"
#include "sandboxed_api/sandbox2/util/fileops.h" #include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/tools/clang_generator/diagnostics.h" #include "sandboxed_api/tools/clang_generator/diagnostics.h"
@ -39,88 +40,46 @@ std::string ReplaceFileExtension(absl::string_view path,
return absl::StrCat(path.substr(0, pos), new_extension); return absl::StrCat(path.substr(0, pos), new_extension);
} }
std::string GetOutputFilename(absl::string_view source_file) {
return ReplaceFileExtension(source_file, ".sapi.h");
}
inline absl::string_view ToStringView(llvm::StringRef ref) { inline absl::string_view ToStringView(llvm::StringRef ref) {
return absl::string_view(ref.data(), ref.size()); return absl::string_view(ref.data(), ref.size());
} }
} // namespace } // namespace
std::string GetOutputFilename(absl::string_view source_file) {
return ReplaceFileExtension(source_file, ".sapi.h");
}
bool GeneratorASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) { bool GeneratorASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) {
if (!decl->isCXXClassMember() && // Skip classes if (!decl->isCXXClassMember() && // Skip classes
decl->isExternC() && // Skip non external functions decl->isExternC() && // Skip non external functions
!decl->isTemplated() && // Skip function templates !decl->isTemplated() && // Skip function templates
// Process either all function or just the requested ones // Process either all function or just the requested ones
(options_->function_names.empty() || (options_.function_names.empty() ||
options_->function_names.count(ToStringView(decl->getName())) > 0)) { options_.function_names.count(ToStringView(decl->getName())) > 0)) {
functions_.push_back(decl); functions_.push_back(decl);
GatherRelatedTypes(decl->getDeclaredReturnType(), &types_);
CollectRelatedTypes(decl->getDeclaredReturnType(), &types_);
for (const clang::ParmVarDecl* param : decl->parameters()) { for (const clang::ParmVarDecl* param : decl->parameters()) {
GatherRelatedTypes(param->getType(), &types_); CollectRelatedTypes(param->getType(), &types_);
} }
} }
return true; return true;
} }
namespace internal {
absl::StatusOr<std::string> ReformatGoogleStyle(const std::string& filename,
const std::string& code) {
// Configure code style based on Google style, but enforce pointer alignment
clang::format::FormatStyle style =
clang::format::getGoogleStyle(clang::format::FormatStyle::LK_Cpp);
style.DerivePointerAlignment = false;
style.PointerAlignment = clang::format::FormatStyle::PAS_Left;
clang::tooling::Replacements replacements = clang::format::reformat(
style, code, llvm::makeArrayRef(clang::tooling::Range(0, code.size())),
filename);
llvm::Expected<std::string> formatted_header =
clang::tooling::applyAllReplacements(code, replacements);
if (!formatted_header) {
return absl::InternalError(llvm::toString(formatted_header.takeError()));
}
return *formatted_header;
}
} // namespace internal
absl::Status GeneratorASTConsumer::GenerateAndSaveHeader() {
const std::string out_file =
options_->out_file.empty() ? GetOutputFilename(in_file_)
: sandbox2::file_util::fileops::MakeAbsolute(
options_->out_file, options_->work_dir);
SAPI_ASSIGN_OR_RETURN(const std::string header,
EmitHeader(visitor_.functions_, visitor_.types_, *options_));
SAPI_ASSIGN_OR_RETURN(const std::string formatted_header,
internal::ReformatGoogleStyle(in_file_, header));
std::ofstream os(out_file, std::ios::out | std::ios::trunc);
os << formatted_header;
if (!os) {
return absl::UnknownError("I/O error");
}
return absl::OkStatus();
}
void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) { void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) {
absl::Status status; std::cout << "Processing " << in_file_ << "\n";
if (!visitor_.TraverseDecl(context.getTranslationUnitDecl())) { if (!visitor_.TraverseDecl(context.getTranslationUnitDecl())) {
status = absl::InternalError("AST traversal exited early"); ReportFatalError(context.getDiagnostics(),
} else { context.getTranslationUnitDecl()->getBeginLoc(),
status = GenerateAndSaveHeader(); "AST traversal exited early");
} }
if (!status.ok()) { for (clang::QualType qual : visitor_.types_) {
ReportFatalError(context.getDiagnostics(), emitter_.CollectType(qual);
GetDiagnosticLocationFromStatus(status).value_or( }
context.getTranslationUnitDecl()->getBeginLoc()), for (clang::FunctionDecl* func : visitor_.functions_) {
status.message()); emitter_.CollectFunction(func);
} }
} }

View File

@ -26,6 +26,7 @@
#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h" #include "clang/Tooling/Tooling.h"
#include "sandboxed_api/tools/clang_generator/emitter.h"
#include "sandboxed_api/tools/clang_generator/types.h" #include "sandboxed_api/tools/clang_generator/types.h"
namespace sapi { namespace sapi {
@ -46,85 +47,86 @@ struct GeneratorOptions {
std::string work_dir; std::string work_dir;
std::string name; // Name of the Sandboxed API std::string name; // Name of the Sandboxed API
std::string namespace_name; // Namespace to wrap the SAPI in std::string namespace_name; // Namespace to wrap the SAPI in
std::string out_file; // Output path of the generated header // Output path of the generated header. Used to build the header include
std::string embed_dir; // Directory with embedded includes // guard.
std::string embed_name; // Identifier of the embed object std::string out_file;
std::string embed_dir; // Directory with embedded includes
std::string embed_name; // Identifier of the embed object
}; };
class GeneratorASTVisitor class GeneratorASTVisitor
: public clang::RecursiveASTVisitor<GeneratorASTVisitor> { : public clang::RecursiveASTVisitor<GeneratorASTVisitor> {
public: public:
explicit GeneratorASTVisitor(const GeneratorOptions& options)
: options_(options) {}
bool VisitFunctionDecl(clang::FunctionDecl* decl); bool VisitFunctionDecl(clang::FunctionDecl* decl);
private: private:
friend class GeneratorASTConsumer; friend class GeneratorASTConsumer;
const GeneratorOptions* options_ = nullptr;
std::vector<clang::FunctionDecl*> functions_; std::vector<clang::FunctionDecl*> functions_;
QualTypeSet types_; QualTypeSet types_;
const GeneratorOptions& options_;
}; };
namespace internal {
absl::StatusOr<std::string> ReformatGoogleStyle(const std::string& filename,
const std::string& code);
} // namespace internal
class GeneratorASTConsumer : public clang::ASTConsumer { class GeneratorASTConsumer : public clang::ASTConsumer {
public: public:
GeneratorASTConsumer(std::string in_file, const GeneratorOptions* options) GeneratorASTConsumer(std::string in_file, Emitter& emitter,
: in_file_(std::move(in_file)), options_(options) { const GeneratorOptions& options)
visitor_.options_ = options_; : in_file_(std::move(in_file)), visitor_(options), emitter_(emitter) {}
}
private: private:
void HandleTranslationUnit(clang::ASTContext& context) override; void HandleTranslationUnit(clang::ASTContext& context) override;
absl::Status GenerateAndSaveHeader();
std::string in_file_; std::string in_file_;
const GeneratorOptions* options_;
GeneratorASTVisitor visitor_; GeneratorASTVisitor visitor_;
Emitter& emitter_;
}; };
class GeneratorAction : public clang::ASTFrontendAction { class GeneratorAction : public clang::ASTFrontendAction {
public: public:
explicit GeneratorAction(const GeneratorOptions* options) GeneratorAction(Emitter& emitter, const GeneratorOptions& options)
: options_(options) {} : emitter_(emitter), options_(options) {}
private: private:
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer( std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
clang::CompilerInstance&, llvm::StringRef in_file) override { clang::CompilerInstance&, llvm::StringRef in_file) override {
return absl::make_unique<GeneratorASTConsumer>(std::string(in_file), return absl::make_unique<GeneratorASTConsumer>(std::string(in_file),
options_); emitter_, options_);
} }
bool hasCodeCompletionSupport() const override { return false; } bool hasCodeCompletionSupport() const override { return false; }
const GeneratorOptions* options_; Emitter& emitter_;
const GeneratorOptions& options_;
}; };
class GeneratorFactory : public clang::tooling::FrontendActionFactory { class GeneratorFactory : public clang::tooling::FrontendActionFactory {
public: public:
explicit GeneratorFactory(GeneratorOptions options = {}) // Does not take ownership
: options_(std::move(options)) {} GeneratorFactory(Emitter& emitter, const GeneratorOptions& options)
: emitter_(emitter), options_(options) {}
private: private:
#if LLVM_VERSION_MAJOR >= 10 #if LLVM_VERSION_MAJOR >= 10
std::unique_ptr<clang::FrontendAction> create() override { std::unique_ptr<clang::FrontendAction> create() override {
return absl::make_unique<GeneratorAction>(&options_); return absl::make_unique<GeneratorAction>(emitter_, options_);
} }
#else #else
clang::FrontendAction* create() override { clang::FrontendAction* create() override {
return new GeneratorAction(&options_); return new GeneratorAction(emitter_, options_);
} }
#endif #endif
GeneratorOptions options_; Emitter& emitter_;
const GeneratorOptions& options_;
}; };
std::string GetOutputFilename(absl::string_view source_file);
} // namespace sapi } // namespace sapi
#endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_GENERATOR_H_ #endif // SANDBOXED_API_TOOLS_CLANG_GENERATOR_GENERATOR_H_

View File

@ -12,16 +12,23 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <cstdlib>
#include <string> #include <string>
#include <vector> #include <vector>
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_split.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/CommonOptionsParser.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "sandboxed_api/sandbox2/util/file_helpers.h"
#include "sandboxed_api/sandbox2/util/fileops.h" #include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/tools/clang_generator/generator.h" #include "sandboxed_api/tools/clang_generator/generator.h"
#include "sandboxed_api/util/status_macros.h"
namespace sapi { namespace sapi {
namespace { namespace {
@ -49,11 +56,11 @@ static auto* g_sapi_functions = new llvm::cl::list<std::string>(
llvm::cl::cat(*g_tool_category)); llvm::cl::cat(*g_tool_category));
static auto* g_sapi_in = new llvm::cl::list<std::string>( static auto* g_sapi_in = new llvm::cl::list<std::string>(
"sapi_in", llvm::cl::CommaSeparated, "sapi_in", llvm::cl::CommaSeparated,
llvm::cl::desc("List of input files to analyze. Deprecated, use positional " llvm::cl::desc("List of input files to analyze."),
"arguments instead."),
llvm::cl::cat(*g_tool_category)); llvm::cl::cat(*g_tool_category));
static auto* g_sapi_isystem = new llvm::cl::opt<std::string>( static auto* g_sapi_isystem = new llvm::cl::opt<std::string>(
"sapi_isystem", llvm::cl::desc("Extra system include paths"), "sapi_isystem",
llvm::cl::desc("Parameter file with extra system include paths"),
llvm::cl::cat(*g_tool_category)); llvm::cl::cat(*g_tool_category));
static auto* g_sapi_limit_scan_depth = new llvm::cl::opt<bool>( static auto* g_sapi_limit_scan_depth = new llvm::cl::opt<bool>(
"sapi_limit_scan_depth", "sapi_limit_scan_depth",
@ -69,28 +76,28 @@ static auto* g_sapi_ns = new llvm::cl::opt<std::string>(
static auto* g_sapi_out = new llvm::cl::opt<std::string>( static auto* g_sapi_out = new llvm::cl::opt<std::string>(
"sapi_out", "sapi_out",
llvm::cl::desc( llvm::cl::desc(
"Ouput path of the generated header. If empty, simply appends .sapi.h " "Output path of the generated header. If empty, simply appends .sapi.h "
"to the basename of the first source file specified."), "to the basename of the first source file specified."),
llvm::cl::cat(*g_tool_category)); llvm::cl::cat(*g_tool_category));
} // namespace } // namespace
GeneratorOptions GeneratorOptionsFromFlags() { GeneratorOptions GeneratorOptionsFromFlags(
const std::vector<std::string>& sources) {
GeneratorOptions options; GeneratorOptions options;
options.function_names.insert(g_sapi_functions->begin(), options.function_names.insert(g_sapi_functions->begin(),
g_sapi_functions->end()); g_sapi_functions->end());
options.work_dir = sandbox2::file_util::fileops::GetCWD(); options.work_dir = sandbox2::file_util::fileops::GetCWD();
options.name = *g_sapi_name; options.name = *g_sapi_name;
options.namespace_name = *g_sapi_ns; options.namespace_name = *g_sapi_ns;
options.out_file = *g_sapi_out; options.out_file =
!g_sapi_out->empty() ? *g_sapi_out : GetOutputFilename(sources.front());
options.embed_dir = *g_sapi_embed_dir; options.embed_dir = *g_sapi_embed_dir;
options.embed_name = *g_sapi_embed_name; options.embed_name = *g_sapi_embed_name;
return options; return options;
} }
} // namespace sapi absl::Status GeneratorMain(int argc, const char** argv) {
int main(int argc, const char** argv) {
clang::tooling::CommonOptionsParser opt_parser( clang::tooling::CommonOptionsParser opt_parser(
argc, argv, *sapi::g_tool_category, llvm::cl::ZeroOrMore, argc, argv, *sapi::g_tool_category, llvm::cl::ZeroOrMore,
"Generates a Sandboxed API header for C/C++ translation units."); "Generates a Sandboxed API header for C/C++ translation units.");
@ -98,9 +105,45 @@ int main(int argc, const char** argv) {
for (const auto& sapi_in : *sapi::g_sapi_in) { for (const auto& sapi_in : *sapi::g_sapi_in) {
sources.push_back(sapi_in); sources.push_back(sapi_in);
} }
if (sources.empty()) {
return absl::InvalidArgumentError("error: no input files");
}
auto options = sapi::GeneratorOptionsFromFlags(sources);
sapi::Emitter emitter;
clang::tooling::ClangTool tool(opt_parser.getCompilations(), sources); clang::tooling::ClangTool tool(opt_parser.getCompilations(), sources);
return tool.run(absl::make_unique<sapi::GeneratorFactory>( if (!sapi::g_sapi_isystem->empty()) {
sapi::GeneratorOptionsFromFlags()) std::string isystem_lines;
.get()); SAPI_RETURN_IF_ERROR(sandbox2::file::GetContents(
*sapi::g_sapi_isystem, &isystem_lines, sandbox2::file::Defaults()));
std::vector<std::string> isystem =
absl::StrSplit(isystem_lines, '\n', absl::SkipWhitespace());
for (std::string& line : isystem) {
line.insert(0, "-isystem");
}
tool.appendArgumentsAdjuster(clang::tooling::getInsertArgumentAdjuster(
isystem, clang::tooling::ArgumentInsertPosition::BEGIN));
}
if (int result = tool.run(
absl::make_unique<sapi::GeneratorFactory>(emitter, options).get());
result != 0) {
return absl::UnknownError("header generation failed");
}
SAPI_ASSIGN_OR_RETURN(std::string header, emitter.EmitHeader(options));
SAPI_RETURN_IF_ERROR(sandbox2::file::SetContents(options.out_file, header,
sandbox2::file::Defaults()));
return absl::OkStatus();
}
} // namespace sapi
int main(int argc, const char** argv) {
if (absl::Status status = sapi::GeneratorMain(argc, argv); !status.ok()) {
absl::FPrintF(stderr, "error: %s\n", status.message());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
} }

View File

@ -30,9 +30,9 @@ bool IsFunctionReferenceType(clang::QualType qual) {
} // namespace } // namespace
void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types) { void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types) {
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) { if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) {
GatherRelatedTypes(typedef_type->getDecl()->getUnderlyingType(), types); CollectRelatedTypes(typedef_type->getDecl()->getUnderlyingType(), types);
types->insert(qual); types->insert(qual);
return; return;
} }
@ -43,9 +43,9 @@ void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types) {
->getAs<clang::FunctionProtoType>()) { ->getAs<clang::FunctionProtoType>()) {
// Note: Do not add the function type itself, as this will always be a // Note: Do not add the function type itself, as this will always be a
// pointer argument. We only need to collect all its related types. // pointer argument. We only need to collect all its related types.
GatherRelatedTypes(function_type->getReturnType(), types); CollectRelatedTypes(function_type->getReturnType(), types);
for (const clang::QualType& param : function_type->getParamTypes()) { for (const clang::QualType& param : function_type->getParamTypes()) {
GatherRelatedTypes(param, types); CollectRelatedTypes(param, types);
} }
return; return;
} }
@ -56,13 +56,13 @@ void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types) {
while (IsPointerOrReference(pointee)) { while (IsPointerOrReference(pointee)) {
pointee = pointee->getPointeeType(); pointee = pointee->getPointeeType();
} }
GatherRelatedTypes(pointee, types); CollectRelatedTypes(pointee, types);
return; return;
} }
// C array with specified constant size (i.e. int a[42])? // C array with specified constant size (i.e. int a[42])?
if (const clang::ArrayType* array_type = qual->getAsArrayTypeUnsafe()) { if (const clang::ArrayType* array_type = qual->getAsArrayTypeUnsafe()) {
GatherRelatedTypes(array_type->getElementType(), types); CollectRelatedTypes(array_type->getElementType(), types);
return; return;
} }
@ -71,7 +71,7 @@ void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types) {
// Collect the underlying integer type of enum classes as well, as it may // Collect the underlying integer type of enum classes as well, as it may
// be a typedef. // be a typedef.
if (const clang::EnumDecl* decl = enum_type->getDecl(); decl->isFixed()) { if (const clang::EnumDecl* decl = enum_type->getDecl(); decl->isFixed()) {
GatherRelatedTypes(decl->getIntegerType(), types); CollectRelatedTypes(decl->getIntegerType(), types);
} }
} }
types->insert(qual); types->insert(qual);
@ -81,7 +81,7 @@ void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types) {
if (const auto* record_type = qual->getAs<clang::RecordType>()) { if (const auto* record_type = qual->getAs<clang::RecordType>()) {
const clang::RecordDecl* decl = record_type->getDecl(); const clang::RecordDecl* decl = record_type->getDecl();
for (const clang::FieldDecl* field : decl->fields()) { for (const clang::FieldDecl* field : decl->fields()) {
GatherRelatedTypes(field->getType(), types); CollectRelatedTypes(field->getType(), types);
} }
types->insert(qual); types->insert(qual);
return; return;

View File

@ -54,7 +54,7 @@ inline bool IsPointerOrReference(clang::QualType qual) {
// int // int
// SubStruct // SubStruct
// bool // bool
void GatherRelatedTypes(clang::QualType qual, QualTypeSet* types); void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types);
// Maps a qualified type to a fully qualified SAPI-compatible type name. This // Maps a qualified type to a fully qualified SAPI-compatible type name. This
// is used for the generated code that invokes the actual function call RPC. // is used for the generated code that invokes the actual function call RPC.

View File

@ -580,12 +580,11 @@ class _TranslationUnit(object):
for i, cursor in enumerate(self._walk_preorder()): for i, cursor in enumerate(self._walk_preorder()):
# Workaround for issue#32 # Workaround for issue#32
# ignore all the cursors with kinds not implemented in python bindings
try: try:
cursor.kind cursor.kind
except ValueError: except ValueError:
if cursor._kind_id >= 440: # pylint: disable=protected-access continue
continue
raise
# naive way to order types: they should be ordered when walking the tree # naive way to order types: they should be ordered when walking the tree
if cursor.kind.is_declaration(): if cursor.kind.is_declaration():
self.order[cursor.hash] = i self.order[cursor.hash] = i
@ -911,7 +910,7 @@ class Generator(object):
result.append('#include "sandboxed_api/sandbox.h"') result.append('#include "sandboxed_api/sandbox.h"')
result.append('#include "sandboxed_api/vars.h"') result.append('#include "sandboxed_api/vars.h"')
if (embed_dir is not None) and (embed_name is not None): if embed_dir and embed_name:
result.append( result.append(
Generator.EMBED_INCLUDE.format( Generator.EMBED_INCLUDE.format(
os.path.join(embed_dir, embed_name) + '_embed.h')) os.path.join(embed_dir, embed_name) + '_embed.h'))
@ -928,7 +927,7 @@ class Generator(object):
result.append('') result.append('')
if (embed_dir is not None) and (embed_name is not None): if embed_dir and embed_name:
result.append( result.append(
Generator.EMBED_CLASS.format(name, embed_name.replace('-', '_'))) Generator.EMBED_CLASS.format(name, embed_name.replace('-', '_')))

View File

@ -46,6 +46,7 @@ cc_library(
name = "statusor", name = "statusor",
hdrs = ["statusor.h"], hdrs = ["statusor.h"],
deprecation = "Migrate to `absl::StatusOr<T>`", deprecation = "Migrate to `absl::StatusOr<T>`",
visibility = ["//visibility:public"],
deps = [ deps = [
"@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/status:statusor", "@com_google_absl//absl/status:statusor",