diff --git a/include/cppast/cpp_attribute.hpp b/include/cppast/cpp_attribute.hpp index e1c5f3e..59070b0 100644 --- a/include/cppast/cpp_attribute.hpp +++ b/include/cppast/cpp_attribute.hpp @@ -9,6 +9,7 @@ #include #include +#include #include @@ -30,35 +31,6 @@ namespace cppast unknown, //< An unknown attribute. }; - namespace detail - { - inline const char* get_attribute_name(cpp_attribute_kind kind) - { - switch (kind) - { - case cpp_attribute_kind::alignas_: - return "alignas"; - case cpp_attribute_kind::carries_dependency: - return "carries_dependency"; - case cpp_attribute_kind::deprecated: - return "deprecated"; - case cpp_attribute_kind::fallthrough: - return "fallthrough"; - case cpp_attribute_kind::maybe_unused: - return "maybe_unused"; - case cpp_attribute_kind::nodiscard: - return "nodiscard"; - case cpp_attribute_kind::noreturn: - return "noreturn"; - - case cpp_attribute_kind::unknown: - return "unknown"; - } - - return ""; - } - } // namespace detail - /// A C++ attribute, including `alignas` specifiers. /// /// It consists of a name, an optional namespace scope and optional arguments. @@ -72,12 +44,7 @@ namespace cppast { public: /// \effects Creates a known attribute, potentially with arguments. - cpp_attribute(cpp_attribute_kind kind, type_safe::optional arguments) - : cpp_attribute(type_safe::nullopt, detail::get_attribute_name(kind), std::move(arguments), - false) - { - kind_ = kind; - } + cpp_attribute(cpp_attribute_kind kind, type_safe::optional arguments); /// \effects Creates an unknown attribute giving it the optional scope, names, arguments and whether it is variadic. cpp_attribute(type_safe::optional scope, std::string name, @@ -129,6 +96,28 @@ namespace cppast /// A list of C++ attributes. using cpp_attribute_list = std::vector; + + /// Checks whether an attribute is given. + /// \returns `true` if the given attribute list (1-2) / entity (3-4) contain + /// an attribute of the given name (1+3) / kind (2+4). + /// `false` otherwise. + /// \group has_attribute + type_safe::optional_ref has_attribute(const cpp_attribute_list& attributes, + const std::string& name); + + /// \group has_attribute + type_safe::optional_ref has_attribute(const cpp_attribute_list& attributes, + cpp_attribute_kind kind); + + class cpp_entity; + + /// \group has_attribute + type_safe::optional_ref has_attribute(const cpp_entity& e, + const std::string& name); + + /// \group has_attribute + type_safe::optional_ref has_attribute(const cpp_entity& e, + cpp_attribute_kind kind); } // namespace cppast #endif // CPPAST_CPP_ATTRIBUTE_HPP_INCLUDED diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a381d17..c45d7bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,6 +51,7 @@ set(header set(source code_generator.cpp cpp_alias_template.cpp + cpp_attribute.cpp cpp_class.cpp cpp_class_template.cpp cpp_entity.cpp @@ -79,6 +80,8 @@ set(source visitor.cpp) set(libclang_source libclang/class_parser.cpp + libclang/cxtokenizer.cpp + libclang/cxtokenizer.hpp libclang/debug_helper.cpp libclang/debug_helper.hpp libclang/enum_parser.cpp @@ -96,8 +99,6 @@ set(libclang_source libclang/preprocessor.hpp libclang/raii_wrapper.hpp libclang/template_parser.cpp - libclang/cxtokenizer.cpp - libclang/cxtokenizer.hpp libclang/type_parser.cpp libclang/variable_parser.cpp) diff --git a/src/cpp_attribute.cpp b/src/cpp_attribute.cpp new file mode 100644 index 0000000..85bb9aa --- /dev/null +++ b/src/cpp_attribute.cpp @@ -0,0 +1,89 @@ +// 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 + +#include + +using namespace cppast; + +namespace +{ + const char* get_attribute_name(cpp_attribute_kind kind) noexcept + { + switch (kind) + { + case cpp_attribute_kind::alignas_: + return "alignas"; + case cpp_attribute_kind::carries_dependency: + return "carries_dependency"; + case cpp_attribute_kind::deprecated: + return "deprecated"; + case cpp_attribute_kind::fallthrough: + return "fallthrough"; + case cpp_attribute_kind::maybe_unused: + return "maybe_unused"; + case cpp_attribute_kind::nodiscard: + return "nodiscard"; + case cpp_attribute_kind::noreturn: + return "noreturn"; + + case cpp_attribute_kind::unknown: + return "unknown"; + } + + return ""; + } +} + +cpp_attribute::cpp_attribute(cpp_attribute_kind kind, + type_safe::optional arguments) +: cpp_attribute(type_safe::nullopt, get_attribute_name(kind), std::move(arguments), false) +{ + kind_ = kind; +} + +type_safe::optional_ref cppast::has_attribute( + const cpp_attribute_list& attributes, const std::string& name) +{ + auto iter = + std::find_if(attributes.begin(), attributes.end(), [&](const cpp_attribute& attribute) { + if (attribute.scope()) + return attribute.scope().value() + "::" + attribute.name() == name; + else + return attribute.name() == name; + }); + + if (iter == attributes.end()) + return nullptr; + else + return type_safe::ref(*iter); +} + +type_safe::optional_ref cppast::has_attribute( + const cpp_attribute_list& attributes, cpp_attribute_kind kind) +{ + auto iter = + std::find_if(attributes.begin(), attributes.end(), + [&](const cpp_attribute& attribute) { return attribute.kind() == kind; }); + + if (iter == attributes.end()) + return nullptr; + else + return type_safe::ref(*iter); +} + +type_safe::optional_ref cppast::has_attribute(const cpp_entity& e, + const std::string& name) +{ + return has_attribute(e.attributes(), name); +} + +type_safe::optional_ref cppast::has_attribute(const cpp_entity& e, + cpp_attribute_kind kind) +{ + return has_attribute(e.attributes(), kind); +} diff --git a/test/cpp_attribute.cpp b/test/cpp_attribute.cpp index 0a88538..72ea3f4 100644 --- a/test/cpp_attribute.cpp +++ b/test/cpp_attribute.cpp @@ -68,6 +68,8 @@ alignas(type) int var; if (e.name() == "a" || e.name() == "b") { REQUIRE(attributes.size() == 2u); + REQUIRE(has_attribute(e, "attribute1")); + REQUIRE(has_attribute(e, "attribute2")); check_attribute(attr, "attribute1", type_safe::nullopt, false); check_attribute(attributes[1u], "attribute2", @@ -77,7 +79,10 @@ alignas(type) int var; check_attribute(attr, "variadic", type_safe::nullopt, true); else if (e.name() == "d") + { + REQUIRE(has_attribute(e, "ns::attribute")); check_attribute(attr, "attribute", "ns", false); + } else if (e.name() == "e") check_attribute(attr, "attribute", type_safe::nullopt, false, R"(arg1,arg2,+(){},42,"Hello!")"); @@ -89,8 +94,11 @@ alignas(type) int var; type_safe::nullopt, false); } else if (e.name() == "g") + { + REQUIRE(has_attribute(e, cpp_attribute_kind::deprecated)); check_attribute(attr, "deprecated", type_safe::nullopt, false, "", cpp_attribute_kind::deprecated); + } else if (e.name() == "h") check_attribute(attr, "maybe_unused", type_safe::nullopt, false, "",