Add attribute convenience functions

This commit is contained in:
Jonathan Müller 2017-10-29 20:54:54 +01:00
commit 10dd893b91
4 changed files with 124 additions and 37 deletions

View file

@ -9,6 +9,7 @@
#include <vector>
#include <type_safe/optional.hpp>
#include <type_safe/optional_ref.hpp>
#include <cppast/cpp_token.hpp>
@ -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 "<error>";
}
} // 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<cpp_token_string> 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<cpp_token_string> arguments);
/// \effects Creates an unknown attribute giving it the optional scope, names, arguments and whether it is variadic.
cpp_attribute(type_safe::optional<std::string> scope, std::string name,
@ -129,6 +96,28 @@ namespace cppast
/// A list of C++ attributes.
using cpp_attribute_list = std::vector<cpp_attribute>;
/// 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<const cpp_attribute> has_attribute(const cpp_attribute_list& attributes,
const std::string& name);
/// \group has_attribute
type_safe::optional_ref<const cpp_attribute> has_attribute(const cpp_attribute_list& attributes,
cpp_attribute_kind kind);
class cpp_entity;
/// \group has_attribute
type_safe::optional_ref<const cpp_attribute> has_attribute(const cpp_entity& e,
const std::string& name);
/// \group has_attribute
type_safe::optional_ref<const cpp_attribute> has_attribute(const cpp_entity& e,
cpp_attribute_kind kind);
} // namespace cppast
#endif // CPPAST_CPP_ATTRIBUTE_HPP_INCLUDED

View file

@ -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)

89
src/cpp_attribute.cpp Normal file
View file

@ -0,0 +1,89 @@
// Copyright (C) 2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.
#include <cppast/cpp_attribute.hpp>
#include <algorithm>
#include <cppast/cpp_entity.hpp>
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 "<error>";
}
}
cpp_attribute::cpp_attribute(cpp_attribute_kind kind,
type_safe::optional<cpp_token_string> arguments)
: cpp_attribute(type_safe::nullopt, get_attribute_name(kind), std::move(arguments), false)
{
kind_ = kind;
}
type_safe::optional_ref<const cpp_attribute> 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<const cpp_attribute> 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<const cpp_attribute> cppast::has_attribute(const cpp_entity& e,
const std::string& name)
{
return has_attribute(e.attributes(), name);
}
type_safe::optional_ref<const cpp_attribute> cppast::has_attribute(const cpp_entity& e,
cpp_attribute_kind kind)
{
return has_attribute(e.attributes(), kind);
}

View file

@ -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, "",