Fix include handling support
Can't be tested until clang 4.0.
This commit is contained in:
parent
58cc481318
commit
2e1dce2ffd
5 changed files with 98 additions and 17 deletions
|
|
@ -32,13 +32,10 @@ namespace cppast
|
|||
return target_;
|
||||
}
|
||||
|
||||
/// \returns The [cppast::cpp_entity]() it refers to.
|
||||
/// \requires An entity of matching kind must be registered in the [cppast::cpp_entity_index]() using the given id.
|
||||
const T& get(const cpp_entity_index& idx) const noexcept
|
||||
/// \returns An optional reference to the [cppast::cpp_entity]() it refers to.
|
||||
type_safe::optional_ref<const T> get(const cpp_entity_index& idx) const noexcept
|
||||
{
|
||||
auto entity = idx.lookup(target_);
|
||||
DEBUG_ASSERT(Predicate{}(entity.value()), detail::precondition_error_handler{},
|
||||
"invalid entity");
|
||||
return static_cast<const T&>(entity.value());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ namespace cppast
|
|||
class cpp_include_directive final : public cpp_entity
|
||||
{
|
||||
public:
|
||||
static cpp_entity_kind kind() noexcept;
|
||||
|
||||
/// \returns A newly built include directive.
|
||||
/// \notes It is not meant to be registered in the [cppast::cpp_entity_index](),
|
||||
/// as no other [cppast::cpp_entity]() can refer to it.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,12 @@ 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
|
||||
cpp_entity_kind cpp_include_directive::kind() noexcept
|
||||
{
|
||||
return cpp_entity_kind::include_directive_t;
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_include_directive::do_get_entity_kind() const noexcept
|
||||
{
|
||||
return kind();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,9 +35,10 @@ namespace
|
|||
// -E: print preprocessor output
|
||||
// -CC: keep comments, even in macro
|
||||
// -dD: print macro definitions as well
|
||||
// -dI: print include directives as well
|
||||
// -Wno-pragma-once-outside-header: hide wrong warning
|
||||
std::string cmd(detail::libclang_compile_config_access::clang_binary(c)
|
||||
+ " -E -CC -dD -Wno-pragma-once-outside-header ");
|
||||
+ " -E -CC -dD -dI -Wno-pragma-once-outside-header ");
|
||||
|
||||
// add other flags
|
||||
for (auto& flag : detail::libclang_compile_config_access::flags(c))
|
||||
|
|
@ -240,6 +241,43 @@ namespace
|
|||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_include_directive> parse_include(position& p)
|
||||
{
|
||||
// format (at new line, literal <>): #include <filename>
|
||||
// or: #include "filename"
|
||||
if (!p.was_newl() || !starts_with(p, "#include"))
|
||||
return nullptr;
|
||||
p.skip(std::strlen("#include"));
|
||||
skip_spaces(p);
|
||||
|
||||
auto include_kind = cpp_include_kind::system;
|
||||
auto end_str = "";
|
||||
if (starts_with(p, "\""))
|
||||
{
|
||||
include_kind = cpp_include_kind::local;
|
||||
end_str = "\"";
|
||||
}
|
||||
else if (starts_with(p, "<"))
|
||||
{
|
||||
include_kind = cpp_include_kind::system;
|
||||
end_str = ">";
|
||||
}
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
p.skip();
|
||||
|
||||
std::string filename;
|
||||
for (; !starts_with(p, "\"") && !starts_with(p, ">"); p.skip())
|
||||
filename += *p.ptr();
|
||||
DEBUG_ASSERT(starts_with(p, end_str), detail::assert_handler{}, "bad termination");
|
||||
p.skip();
|
||||
DEBUG_ASSERT(starts_with(p, "\n"), detail::assert_handler{});
|
||||
// don't skip newline
|
||||
|
||||
return cpp_include_directive::build(cpp_file_ref(cpp_entity_id(filename), filename),
|
||||
include_kind);
|
||||
}
|
||||
|
||||
bool skip_pragma(position& p)
|
||||
{
|
||||
// format (at new line): #pragma <stuff..>\n
|
||||
|
|
@ -356,6 +394,11 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
|
|||
}),
|
||||
result.entities.end());
|
||||
}
|
||||
else if (auto include = parse_include(p))
|
||||
{
|
||||
if (file_depth == 0u)
|
||||
result.entities.push_back({std::move(include), p.cur_line()});
|
||||
}
|
||||
else if (skip_pragma(p))
|
||||
continue;
|
||||
else if (auto lm = parse_linemarker(p))
|
||||
|
|
@ -370,16 +413,8 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
|
|||
if (file_depth == 0u && lm.value().file.front() != '<')
|
||||
{
|
||||
// this file is directly included by the given file
|
||||
// so build entity (first, the write updates the line count)
|
||||
result.entities.push_back(
|
||||
{cpp_include_directive::build(cpp_file_ref(cpp_entity_id(lm.value().file),
|
||||
lm.value().file),
|
||||
// not really correct, but nice approximation
|
||||
lm.value().is_system ?
|
||||
cpp_include_kind::system :
|
||||
cpp_include_kind::local),
|
||||
p.cur_line()});
|
||||
// but also write the include directive again
|
||||
// write include with full path
|
||||
// note: don't build include here, do it when an #include is encountered
|
||||
p.write_str("#include \"" + lm.value().file + "\"\n");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,3 +57,45 @@ baz
|
|||
});
|
||||
REQUIRE(count == 6u);
|
||||
}
|
||||
|
||||
// requires clang 4.0, currently not available for testing
|
||||
#if 0
|
||||
TEST_CASE("cpp_include_directive")
|
||||
{
|
||||
write_file("cpp_include_directive-header.hpp", R"(
|
||||
#define FOO
|
||||
)");
|
||||
|
||||
auto header_a = R"(
|
||||
#include <iostream>
|
||||
#include "cpp_include_directive-header.hpp"
|
||||
)";
|
||||
|
||||
auto header_b = R"(
|
||||
#include "header_a.hpp"
|
||||
)";
|
||||
|
||||
cpp_entity_index idx;
|
||||
auto file_a = parse(idx, "header_a.hpp", header_a);
|
||||
auto file_b = parse(idx, "header_b.hpp", header_b);
|
||||
|
||||
auto count =
|
||||
test_visit<cpp_include_directive>(*file_a, [&](const cpp_include_directive& include) {
|
||||
if (include.name() == "iostream")
|
||||
{
|
||||
REQUIRE(include.target().name() == include.name());
|
||||
REQUIRE(include.include_kind() == cppast::cpp_include_kind::system);
|
||||
REQUIRE(!include.target().get(idx));
|
||||
}
|
||||
else if (include.name() == "cpp_include_directive-header.hpp")
|
||||
{
|
||||
REQUIRE(include.target().name() == include.name());
|
||||
REQUIRE(include.include_kind() == cppast::cpp_include_kind::local);
|
||||
REQUIRE(!include.target().get(idx));
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
});
|
||||
REQUIRE(count == 2u);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue