Updated remove_compile_flags option

This commit is contained in:
Bartek Kryza
2023-05-05 20:28:49 +02:00
parent f912e7ae5d
commit d349f3e01c
14 changed files with 343 additions and 80 deletions

View File

@@ -0,0 +1,104 @@
/**
* src/common/compilation_database.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* 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 "compilation_database.h"
namespace clanguml::common {
std::unique_ptr<compilation_database>
compilation_database::auto_detect_from_directory(
const clanguml::config::config &cfg)
{
std::string error_message;
auto res = clang::tooling::CompilationDatabase::autoDetectFromDirectory(
cfg.compilation_database_dir(), error_message);
if (!error_message.empty())
throw compilation_database_error(error_message);
return std::make_unique<compilation_database>(std::move(res), cfg);
}
compilation_database::compilation_database(
std::unique_ptr<clang::tooling::CompilationDatabase> base,
const clanguml::config::config &cfg)
: base_{std::move(base)}
, config_{cfg}
{
}
const clanguml::config::config &compilation_database::config() const
{
return config_;
}
const clang::tooling::CompilationDatabase &compilation_database::base() const
{
return *base_;
}
std::vector<std::string> compilation_database::getAllFiles() const
{
return base().getAllFiles();
}
std::vector<clang::tooling::CompileCommand>
compilation_database::getCompileCommands(clang::StringRef FilePath) const
{
auto commands = base().getCompileCommands(FilePath);
adjust_compilation_database(commands);
return commands;
}
std::vector<clang::tooling::CompileCommand>
compilation_database::getAllCompileCommands() const
{
auto commands = base().getAllCompileCommands();
adjust_compilation_database(commands);
return commands;
}
void compilation_database::adjust_compilation_database(
std::vector<clang::tooling::CompileCommand> &commands) const
{
if (config().add_compile_flags && !config().add_compile_flags().empty()) {
for (auto &compile_command : commands) {
compile_command.CommandLine.insert(
// Add flags after argv[0]
compile_command.CommandLine.begin() + 1,
config().add_compile_flags().begin(),
config().add_compile_flags().end());
}
}
if (config().remove_compile_flags &&
!config().remove_compile_flags().empty()) {
for (auto &compile_command : commands) {
for (const auto &flag : config().remove_compile_flags()) {
util::erase_if(compile_command.CommandLine,
[&flag](const auto &arg) { return flag == arg; });
}
}
}
}
} // namespace clanguml::common

View File

@@ -0,0 +1,78 @@
/**
* src/common/compilation_database.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* 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.
*/
#pragma once
#include "common/model/enums.h"
#include "common/model/namespace.h"
#include "common/model/template_parameter.h"
#include "config/config.h"
#include "types.h"
#include "util/util.h"
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Tooling/CompilationDatabase.h>
#include <clang/Tooling/Tooling.h>
#include <deque>
#include <filesystem>
#include <string>
namespace clanguml::common {
class compilation_database_error : public std::runtime_error {
using std::runtime_error::runtime_error;
};
class compilation_database : public clang::tooling::CompilationDatabase {
public:
compilation_database(
std::unique_ptr<clang::tooling::CompilationDatabase> base,
const clanguml::config::config &cfg);
~compilation_database() override = default;
static std::unique_ptr<compilation_database> auto_detect_from_directory(
const clanguml::config::config &cfg);
std::vector<clang::tooling::CompileCommand> getCompileCommands(
clang::StringRef FilePath) const override;
std::vector<std::string> getAllFiles() const override;
std::vector<clang::tooling::CompileCommand>
getAllCompileCommands() const override;
const clanguml::config::config &config() const;
const clang::tooling::CompilationDatabase &base() const;
private:
void adjust_compilation_database(
std::vector<clang::tooling::CompileCommand> &commands) const;
// Actual instance of the compilation database is stored in here
// The inheritance is just to keep the interface
std::unique_ptr<clang::tooling::CompilationDatabase> base_;
// Reference to the clang-uml config
const clanguml::config::config &config_;
};
using compilation_database_ptr = std::unique_ptr<compilation_database>;
} // namespace clanguml::common

View File

@@ -79,7 +79,7 @@ void generate_diagram_select_generator(const std::string &od,
template <typename DiagramConfig>
void generate_diagram_impl(const std::string &od, const std::string &name,
std::shared_ptr<clanguml::config::diagram> diagram,
const clang::tooling::CompilationDatabase &db,
const common::compilation_database &db,
const std::vector<std::string> &translation_units,
const std::vector<clanguml::common::generator_type_t> &generators,
bool verbose)
@@ -107,7 +107,7 @@ void generate_diagram_impl(const std::string &od, const std::string &name,
void generate_diagram(const std::string &od, const std::string &name,
std::shared_ptr<clanguml::config::diagram> diagram,
const clang::tooling::CompilationDatabase &db,
const common::compilation_database &db,
const std::vector<std::string> &translation_units,
const std::vector<clanguml::common::generator_type_t> &generators,
bool verbose)
@@ -139,9 +139,9 @@ void generate_diagram(const std::string &od, const std::string &name,
}
void generate_diagrams(const std::vector<std::string> &diagram_names,
clanguml::config::config &config, const std::string &od,
const std::unique_ptr<clang::tooling::CompilationDatabase> &db,
const int verbose, const unsigned int thread_count,
config::config &config, const std::string &od,
const common::compilation_database_ptr &db, const int verbose,
const unsigned int thread_count,
const std::vector<clanguml::common::generator_type_t> &generators,
const std::map<std::string, std::vector<std::string>>
&translation_units_map)
@@ -184,17 +184,4 @@ void generate_diagrams(const std::vector<std::string> &diagram_names,
}
}
void adjust_compilation_database(const clanguml::config::config &config,
clang::tooling::CompilationDatabase &db)
{
if (config.add_compile_flags && !config.add_compile_flags().empty()) {
for (auto &compile_command : db.getAllCompileCommands()) {
compile_command.CommandLine.insert(
compile_command.CommandLine.begin() + 1,
config.add_compile_flags().begin(),
config.add_compile_flags().end());
}
}
}
} // namespace clanguml::common::generators

View File

@@ -20,6 +20,7 @@
#include "class_diagram/generators/json/class_diagram_generator.h"
#include "class_diagram/generators/plantuml/class_diagram_generator.h"
#include "cli/cli_handler.h"
#include "common/compilation_database.h"
#include "common/generators/generators.h"
#include "common/model/diagram_filter.h"
#include "config/config.h"
@@ -33,7 +34,6 @@
#include "version.h"
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Tooling/CompilationDatabase.h>
#include <clang/Tooling/Tooling.h>
#include <cstring>
@@ -139,9 +139,6 @@ void find_translation_units_for_diagrams(
const std::vector<std::string> &compilation_database_files,
std::map<std::string, std::vector<std::string>> &translation_units_map);
void adjust_compilation_database(const clanguml::config::config &config,
clang::tooling::CompilationDatabase &db);
template <typename DiagramModel, typename DiagramConfig,
typename TranslationUnitVisitor>
class diagram_ast_consumer : public clang::ASTConsumer {
@@ -229,10 +226,9 @@ private:
template <typename DiagramModel, typename DiagramConfig,
typename DiagramVisitor>
std::unique_ptr<DiagramModel> generate(
const clang::tooling::CompilationDatabase &db, const std::string &name,
DiagramConfig &config, const std::vector<std::string> &translation_units,
bool /*verbose*/ = false)
std::unique_ptr<DiagramModel> generate(const common::compilation_database &db,
const std::string &name, DiagramConfig &config,
const std::vector<std::string> &translation_units, bool /*verbose*/ = false)
{
LOG_INFO("Generating diagram {}", name);
@@ -262,14 +258,14 @@ std::unique_ptr<DiagramModel> generate(
void generate_diagram(const std::string &od, const std::string &name,
std::shared_ptr<clanguml::config::diagram> diagram,
const clang::tooling::CompilationDatabase &db,
const common::compilation_database &db,
const std::vector<std::string> &translation_units,
const std::vector<clanguml::common::generator_type_t> &generators,
bool verbose);
void generate_diagrams(const std::vector<std::string> &diagram_names,
clanguml::config::config &config, const std::string &od,
const std::unique_ptr<clang::tooling::CompilationDatabase> &db, int verbose,
const common::compilation_database_ptr &db, int verbose,
unsigned int thread_count,
const std::vector<clanguml::common::generator_type_t> &generators,
const std::map<std::string, std::vector<std::string>>

View File

@@ -226,6 +226,8 @@ struct config : public inheritable_diagram_options {
option<std::string> compilation_database_dir{
"compilation_database_dir", "."};
option<std::vector<std::string>> add_compile_flags{"add_compile_flags"};
option<std::vector<std::string>> remove_compile_flags{
"remove_compile_flags"};
option<std::string> output_directory{"output_directory"};
option<std::map<std::string, diagram_template>> diagram_templates{

View File

@@ -588,6 +588,7 @@ template <> struct convert<config> {
get_option(node, rhs.output_directory);
get_option(node, rhs.compilation_database_dir);
get_option(node, rhs.add_compile_flags);
get_option(node, rhs.remove_compile_flags);
get_option(node, rhs.include_relations_also_as_members);
get_option(node, rhs.puml);
get_option(node, rhs.generate_method_arguments);

View File

@@ -188,6 +188,7 @@ YAML::Emitter &operator<<(YAML::Emitter &out, const config &c)
out << c.compilation_database_dir;
out << c.output_directory;
out << c.add_compile_flags;
out << c.remove_compile_flags;
out << dynamic_cast<const inheritable_diagram_options &>(c);

View File

@@ -17,6 +17,7 @@
*/
#include "cli/cli_handler.h"
#include "common/compilation_database.h"
#include "common/generators/generators.h"
#include "include_diagram/generators/plantuml/include_diagram_generator.h"
#include "util/util.h"
@@ -53,15 +54,10 @@ int main(int argc, const char *argv[])
if (res == cli::cli_flow_t::kError)
return 1;
std::string err{};
auto db = clang::tooling::CompilationDatabase::autoDetectFromDirectory(
cli.config.compilation_database_dir(), err);
if (!err.empty()) {
LOG_ERROR("Failed to load compilation database from {}",
cli.config.compilation_database_dir());
return 1;
}
try {
const auto db =
clanguml::common::compilation_database::auto_detect_from_directory(
cli.config);
const auto compilation_database_files = db->getAllFiles();
@@ -69,22 +65,22 @@ int main(int argc, const char *argv[])
std::vector<std::string> /*translation units*/>
translation_units_map;
// We have to generate the translation units list for each diagram before
// scheduling tasks, because std::filesystem::current_path cannot be trusted
// with multiple threads
// We have to generate the translation units list for each diagram
// before scheduling tasks, because std::filesystem::current_path cannot
// be trusted with multiple threads
clanguml::common::generators::find_translation_units_for_diagrams(
cli.diagram_names, cli.config, compilation_database_files,
translation_units_map);
//
// Inject any additional compilation flags from the config to the
// compilation database
//
clanguml::common::generators::adjust_compilation_database(cli.config, *db);
clanguml::common::generators::generate_diagrams(cli.diagram_names,
cli.config, cli.effective_output_directory, db, cli.verbose,
cli.thread_count, cli.generators, translation_units_map);
}
catch (clanguml::common::compilation_database_error &e) {
LOG_ERROR("Failed to load compilation database from {} due to: {}",
cli.config.compilation_database_dir(), e.what());
return 1;
}
return 0;
}

View File

@@ -1,7 +1,9 @@
file(GLOB_RECURSE TEST_CASE_SOURCES t*/*.cc t*/*.c t*/src/*.c)
file(GLOB_RECURSE TEST_CASE_CONFIGS t*/.clang-uml)
file(GLOB_RECURSE TEST_CONFIG_YMLS test_config_data/*.yml)
file(GLOB_RECURSE TEST_CONFIG_YMLS test_config_data/*.yml
test_compilation_database_data/*.yml
test_compilation_database_data/*.json)
set(TEST_CASES_REQUIRING_CXX20 t00056 t00058 t00059)
@@ -36,6 +38,7 @@ set(TEST_CASES
test_util
test_model
test_cases
test_compilation_database
test_decorator_parser
test_config
test_cli_handler

View File

@@ -19,6 +19,7 @@
#include "test_cases.h"
#include "cli/cli_handler.h"
#include "common/compilation_database.h"
#include "common/generators/generators.h"
#include <spdlog/spdlog.h>
@@ -33,32 +34,28 @@ void inject_diagram_options(std::shared_ptr<clanguml::config::diagram> diagram)
diagram->generate_links.set(links_config);
}
std::pair<clanguml::config::config,
std::unique_ptr<clang::tooling::CompilationDatabase>>
std::pair<clanguml::config::config, clanguml::common::compilation_database_ptr>
load_config(const std::string &test_name)
{
auto config = clanguml::config::load(test_name + "/.clang-uml", true);
std::pair<clanguml::config::config,
clanguml::common::compilation_database_ptr>
res;
res.first = clanguml::config::load(test_name + "/.clang-uml", true);
LOG_DBG("Loading compilation database from {}",
config.compilation_database_dir());
res.first.compilation_database_dir());
std::string err{};
auto compilation_database =
clang::tooling::CompilationDatabase::autoDetectFromDirectory(
config.compilation_database_dir(), err);
res.second =
clanguml::common::compilation_database::auto_detect_from_directory(
res.first);
if (!err.empty()) {
LOG_ERROR("Failed to load compilation database from {}",
config.compilation_database_dir());
throw std::runtime_error{err};
}
return std::make_pair(std::move(config), std::move(compilation_database));
return res;
}
namespace detail {
template <typename DiagramConfig>
auto generate_diagram_impl(clang::tooling::CompilationDatabase &db,
auto generate_diagram_impl(clanguml::common::compilation_database &db,
std::shared_ptr<clanguml::config::diagram> diagram)
{
using diagram_config = DiagramConfig;
@@ -117,7 +114,7 @@ auto generate_diagram_json(
}
std::unique_ptr<clanguml::class_diagram::model::diagram> generate_class_diagram(
clang::tooling::CompilationDatabase &db,
clanguml::common::compilation_database &db,
std::shared_ptr<clanguml::config::diagram> diagram)
{
return detail::generate_diagram_impl<clanguml::config::class_diagram>(
@@ -125,7 +122,7 @@ std::unique_ptr<clanguml::class_diagram::model::diagram> generate_class_diagram(
}
std::unique_ptr<clanguml::sequence_diagram::model::diagram>
generate_sequence_diagram(clang::tooling::CompilationDatabase &db,
generate_sequence_diagram(clanguml::common::compilation_database &db,
std::shared_ptr<clanguml::config::diagram> diagram)
{
return detail::generate_diagram_impl<clanguml::config::sequence_diagram>(
@@ -133,7 +130,7 @@ generate_sequence_diagram(clang::tooling::CompilationDatabase &db,
}
std::unique_ptr<clanguml::package_diagram::model::diagram>
generate_package_diagram(clang::tooling::CompilationDatabase &db,
generate_package_diagram(clanguml::common::compilation_database &db,
std::shared_ptr<clanguml::config::diagram> diagram)
{
return detail::generate_diagram_impl<clanguml::config::package_diagram>(
@@ -141,7 +138,7 @@ generate_package_diagram(clang::tooling::CompilationDatabase &db,
}
std::unique_ptr<clanguml::include_diagram::model::diagram>
generate_include_diagram(clang::tooling::CompilationDatabase &db,
generate_include_diagram(clanguml::common::compilation_database &db,
std::shared_ptr<clanguml::config::diagram> diagram)
{
return detail::generate_diagram_impl<clanguml::config::include_diagram>(

View File

@@ -23,6 +23,7 @@
#include "class_diagram/model/diagram.h"
#include "class_diagram/visitor/translation_unit_visitor.h"
#include "common/clang_utils.h"
#include "common/compilation_database.h"
#include "config/config.h"
#include "include_diagram/generators/plantuml/include_diagram_generator.h"
#include "include_diagram/visitor/translation_unit_visitor.h"
@@ -54,8 +55,7 @@ using Catch::Matchers::VectorContains;
using namespace clanguml::util;
std::pair<clanguml::config::config,
std::unique_ptr<clang::tooling::CompilationDatabase>>
std::pair<clanguml::config::config, clanguml::common::compilation_database_ptr>
load_config(const std::string &test_name);
std::string generate_sequence_puml(

View File

@@ -0,0 +1,86 @@
/**
* tests/test_compilation_database.cc
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* 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.
*/
#define CATCH_CONFIG_MAIN
#include "common/compilation_database.h"
#include "util/util.h"
#include "catch.h"
#include <spdlog/sinks/ostream_sink.h>
#include <spdlog/spdlog.h>
std::shared_ptr<spdlog::logger> make_sstream_logger(std::ostream &ostr)
{
auto oss_sink = std::make_shared<spdlog::sinks::ostream_sink_mt>(ostr);
return std::make_shared<spdlog::logger>(
"clanguml-logger", std::move(oss_sink));
}
TEST_CASE("Test compilation_database should work", "[unit-test]")
{
using clanguml::common::compilation_database;
using clanguml::common::compilation_database_ptr;
using clanguml::common::model::access_t;
using clanguml::common::model::relationship_t;
using clanguml::util::contains;
auto cfg =
clanguml::config::load("./test_compilation_database_data/config.yml");
try {
const auto db =
clanguml::common::compilation_database::auto_detect_from_directory(
cfg);
auto all_files = db->getAllFiles();
REQUIRE(all_files.size() == 3);
REQUIRE(all_files.at(0) ==
"src/class_diagram/generators/json/class_diagram_generator.cc");
REQUIRE(all_files.at(1) ==
"src/class_diagram/generators/plantuml/"
"class_diagram_generator.cc");
REQUIRE(all_files.at(2) == "src/class_diagram/model/class.cc");
auto ccs = db->getAllCompileCommands();
REQUIRE(contains(ccs.at(0).CommandLine, "-Wno-error"));
REQUIRE(contains(ccs.at(0).CommandLine, "-Wno-unknown-warning-option"));
REQUIRE(
!contains(ccs.at(0).CommandLine, "-Wno-deprecated-declarations"));
}
catch (clanguml::common::compilation_database_error &e) {
REQUIRE(false);
}
}
TEST_CASE("Test compilation_database should throw", "[unit-test]")
{
using clanguml::common::compilation_database;
using clanguml::common::compilation_database_error;
using clanguml::common::compilation_database_ptr;
using clanguml::util::contains;
auto cfg = clanguml::config::load(
"./test_compilation_database_data/config_bad.yml");
REQUIRE_THROWS_AS(
clanguml::common::compilation_database::auto_detect_from_directory(cfg),
compilation_database_error);
}

View File

@@ -0,0 +1,7 @@
compilation_database_dir: .
output_directory: .
add_compile_flags: [-Wno-unknown-warning-option, -Wno-error]
remove_compile_flags: [-Wno-deprecated-declarations]
diagrams:
class_main:
type: class

View File

@@ -0,0 +1,5 @@
compilation_database_dir: /tmp/no_such_directory___
output_directory: .
diagrams:
class_main:
type: class