diff --git a/include/cppast/libclang_parser.hpp b/include/cppast/libclang_parser.hpp index add114f..6ff4b48 100644 --- a/include/cppast/libclang_parser.hpp +++ b/include/cppast/libclang_parser.hpp @@ -12,6 +12,7 @@ namespace cppast { class libclang_compile_config; + class libclang_compilation_database; namespace detail { @@ -23,6 +24,9 @@ namespace cppast static const std::vector& flags(const libclang_compile_config& config); }; + + void for_each_file(const libclang_compilation_database& database, void* user_data, + void (*callback)(void*, std::string)); } // namespace detail /// The exception thrown when a fatal parse error occurs. @@ -77,6 +81,8 @@ namespace cppast database database_; friend libclang_compile_config; + friend void detail::for_each_file(const libclang_compilation_database& database, + void* user_data, void (*callback)(void*, std::string)); }; /// Compilation config for the [cppast::libclang_parser](). @@ -168,7 +174,7 @@ namespace cppast /// /// \throws [cppast::libclang_error]() if no configuration for a given file could be found in the database. /// - /// \requires `FileParser` must use [cppast::libclang_parser](), + /// \requires `FileParser` must use the libclang parser. /// i.e. `FileParser::parser` must be an alias of [cppast::libclang_parser](). template void parse_files(FileParser& parser, Range&& file_names, @@ -183,6 +189,32 @@ namespace cppast return config.value(); }); } + + /// Parses the files specified in a compilation database using a [cppast::libclang_parser](). + /// + /// \effects For each file specified in a compilation database, + /// uses the `FileParser` to parse the file with the configuration specified in the database. + /// + /// \requires `FileParser` must have the same requirements as for [cppast::parse_files](standardese://parse_files_basic/). + /// It must also use the libclang parser, + /// i.e. `FileParser::parser` must be an alias of [cppast::libclang_parser](). + template + void parse_database(FileParser& parser, const libclang_compilation_database& database) + { + static_assert(std::is_same::value, + "must use the libclang parser"); + struct data_t + { + FileParser& parser; + const libclang_compilation_database& database; + } data{parser, database}; + detail::for_each_file(database, &data, [](void* ptr, std::string file) { + auto& data = *static_cast(ptr); + + libclang_compile_config config(data.database, file); + data.parser.parse(std::move(file), std::move(config)); + }); + } } // namespace cppast #endif // CPPAST_LIBCLANG_PARSER_HPP_INCLUDED diff --git a/src/libclang/libclang_parser.cpp b/src/libclang/libclang_parser.cpp index 7d3ab71..93d121d 100644 --- a/src/libclang/libclang_parser.cpp +++ b/src/libclang/libclang_parser.cpp @@ -103,6 +103,35 @@ namespace }; using cxcompile_commands = detail::raii_wrapper; + + std::string get_full_path(const detail::cxstring& dir, const std::string& file) + { + if (file.front() == '/' || file.front() == '\\') + // absolute file + return file; + else if (dir[dir.length() - 1] != '/' && dir[dir.length() - 1] != '\\') + // relative needing separator + return dir.std_str() + '/' + file; + else + // relative w/o separator + return dir.std_str() + file; + } +} + +void detail::for_each_file(const libclang_compilation_database& database, void* user_data, + void (*callback)(void*, std::string)) +{ + cxcompile_commands commands( + clang_CompilationDatabase_getAllCompileCommands(database.database_)); + auto no = clang_CompileCommands_getSize(commands.get()); + for (auto i = 0u; i != no; ++i) + { + auto cmd = clang_CompileCommands_getCommand(commands.get(), i); + + auto dir = cxstring(clang_CompileCommand_getDirectory(cmd)); + callback(user_data, + get_full_path(dir, cxstring(clang_CompileCommand_getFilename(cmd)).std_str())); + } } namespace @@ -182,29 +211,16 @@ libclang_compile_config::libclang_compile_config(const libclang_compilation_data auto dir = detail::cxstring(clang_CompileCommand_getDirectory(cmd)); parse_flags(cmd, [&](std::string flag, std::string args) { if (flag == "-I") - { - if (args.front() == '/' || args.front() == '\\') - { - add_flag(std::move(flag) + std::move(args)); - } - else - { - // path relative to the directory - if (dir[dir.length() - 1] != '/' && dir[dir.length() - 1] != '\\') - add_flag(std::move(flag) + dir.std_str() + '/' + std::move(args)); - else - add_flag(std::move(flag) + dir.std_str() + std::move(args)); - } - } + add_flag(std::move(flag) + get_full_path(dir, args)); else if (flag == "-D" || flag == "-U") // preprocessor options - this->add_flag(std::move(flag) + std::move(args)); + add_flag(std::move(flag) + std::move(args)); else if (flag == "-std") // standard - this->add_flag(std::move(flag) + "=" + std::move(args)); + add_flag(std::move(flag) + "=" + std::move(args)); else if (flag == "-f" && (args == "ms-compatibility" || args == "ms-extensions")) // other options - this->add_flag(std::move(flag) + std::move(args)); + add_flag(std::move(flag) + std::move(args)); }); } }