diff --git a/include/cppast/cpp_preprocessor.hpp b/include/cppast/cpp_preprocessor.hpp index eced975..0f321e4 100644 --- a/include/cppast/cpp_preprocessor.hpp +++ b/include/cppast/cpp_preprocessor.hpp @@ -16,6 +16,8 @@ namespace cppast class cpp_macro_definition final : public cpp_entity { public: + static cpp_entity_kind kind() noexcept; + /// \returns A newly built macro definition. /// \notes It is not meant to be registered in the [cppast::cpp_entity_index](), /// as no other [cppast::cpp_entity]() can refer to it. diff --git a/src/cpp_preprocessor.cpp b/src/cpp_preprocessor.cpp index 8722f2e..c6266ca 100644 --- a/src/cpp_preprocessor.cpp +++ b/src/cpp_preprocessor.cpp @@ -8,11 +8,16 @@ using namespace cppast; -cpp_entity_kind cpp_macro_definition::do_get_entity_kind() const noexcept +cpp_entity_kind cpp_macro_definition::kind() noexcept { return cpp_entity_kind::macro_definition_t; } +cpp_entity_kind cpp_macro_definition::do_get_entity_kind() const noexcept +{ + return kind(); +} + cpp_entity_kind cpp_include_directive::do_get_entity_kind() const noexcept { return cpp_entity_kind::include_directive_t; diff --git a/test/cpp_preprocessor.cpp b/test/cpp_preprocessor.cpp new file mode 100644 index 0000000..daba84b --- /dev/null +++ b/test/cpp_preprocessor.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2017 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + +#include + +#include "test_parser.hpp" + +using namespace cppast; + +TEST_CASE("cpp_macro_definition") +{ + auto code = R"( +#include +#define G +#define A +#define B hello +#define C(x, y) x##_name +#define D(...) __VA_ARGS__ +#define E() bar\ +baz +#define F () bar +#undef G +)"; + + auto check_macro = [](const cpp_macro_definition& macro, const char* replacement, + const char* args) { + REQUIRE(macro.replacement() == replacement); + if (args) + { + REQUIRE(macro.is_function_like()); + REQUIRE(macro.parameters().value() == args); + } + else + { + REQUIRE(!macro.is_function_like()); + REQUIRE(!macro.parameters().has_value()); + } + }; + + auto file = parse({}, "cpp_macro_definition.cpp", code); + auto count = test_visit(*file, [&](const cpp_macro_definition& macro) { + if (macro.name() == "A") + check_macro(macro, "", nullptr); + else if (macro.name() == "B") + check_macro(macro, "hello", nullptr); + else if (macro.name() == "C") + check_macro(macro, "x##_name", "x,y"); + else if (macro.name() == "D") + check_macro(macro, "__VA_ARGS__", "..."); + else if (macro.name() == "E") + check_macro(macro, "barbaz", ""); + else if (macro.name() == "F") + check_macro(macro, "() bar", nullptr); + else + REQUIRE(false); + }); + REQUIRE(count == 6u); +} diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 0000000..60ae472 --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,6 @@ +// Copyright (C) 2017 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + +#define CATCH_CONFIG_MAIN +#include diff --git a/test/test_parser.hpp b/test/test_parser.hpp new file mode 100644 index 0000000..34fbcc7 --- /dev/null +++ b/test/test_parser.hpp @@ -0,0 +1,54 @@ +// Copyright (C) 2017 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + +#ifndef CPPAST_TEST_PARSER_HPP_INCLUDED +#define CPPAST_TEST_PARSER_HPP_INCLUDED + +#include + +#include + +#include +#include +#include + +void write_file(const char* name, const char* code) +{ + std::ofstream file(name); + file << code; +} + +std::unique_ptr parse(const cppast::cpp_entity_index& idx, const char* name, + const char* code) +{ + using namespace cppast; + + write_file(name, code); + + libclang_compile_config config; + config.set_flags(cpp_standard::cpp_latest); + + libclang_parser p; + return p.parse(idx, name, config); +} + +template +unsigned test_visit(const cppast::cpp_file& file, Func f) +{ + auto count = 0u; + cppast::visit(file, [&](const cppast::cpp_entity& e, cppast::visitor_info) { + if (e.kind() == T::kind()) + { + auto& obj = static_cast(e); + f(obj); + ++count; + } + + return true; + }); + + return count; +} + +#endif // CPPAST_TEST_PARSER_HPP_INCLUDED