diff --git a/src/libclang/libclang_parser.cpp b/src/libclang/libclang_parser.cpp index a565613..b9fe2b7 100644 --- a/src/libclang/libclang_parser.cpp +++ b/src/libclang/libclang_parser.cpp @@ -158,6 +158,15 @@ namespace return tu; } + + unsigned get_line_no(const CXCursor& cursor) + { + auto loc = clang_getCursorLocation(cursor); + + unsigned line; + clang_getPresumedLocation(loc, nullptr, &line, nullptr); + return line; + } } std::unique_ptr libclang_parser::do_parse(const cpp_entity_index& idx, std::string path, @@ -172,21 +181,26 @@ std::unique_ptr libclang_parser::do_parse(const cpp_entity_index& idx, auto tu = get_cxunit(pimpl_->index, config, path.c_str(), preprocessed.source); auto file = clang_getFile(tu.get(), path.c_str()); - // convert entity hierachies cpp_file::builder builder(path); + auto preprocessed_iter = preprocessed.entities.begin(); - // add all preprocessor entities up-front - // TODO: add them in the correct place - for (auto& e : preprocessed.entities) - builder.add_child(std::move(e.entity)); - + // convert entity hierachies detail::parse_context context{tu.get(), file, type_safe::ref(logger()), type_safe::ref(idx)}; detail::visit_tu(tu, path.c_str(), [&](const CXCursor& cur) { + // add macro if needed + for (auto line = get_line_no(cur); + preprocessed_iter != preprocessed.entities.end() && preprocessed_iter->line <= line; + ++preprocessed_iter) + builder.add_child(std::move(preprocessed_iter->entity)); + auto entity = detail::parse_entity(context, cur); if (entity) builder.add_child(std::move(entity)); }); + for (; preprocessed_iter != preprocessed.entities.end(); ++preprocessed_iter) + builder.add_child(std::move(preprocessed_iter->entity)); + return builder.finish(idx); } catch (detail::parse_error& ex) diff --git a/test/cpp_preprocessor.cpp b/test/cpp_preprocessor.cpp index 1f10a19..cdc6554 100644 --- a/test/cpp_preprocessor.cpp +++ b/test/cpp_preprocessor.cpp @@ -10,18 +10,23 @@ using namespace cppast; TEST_CASE("cpp_macro_definition") { - auto code = R"( + auto code = R"( #include #define G #define A #define B hello +namespace ns {} #define C(x, y) x##_name #define D(...) __VA_ARGS__ #define E() bar\ baz +namespace ns2 +{ #define F () bar #undef G +} )"; + const char* order[] = {"A", "B", "ns", "C", "D", "E", "ns2", "F"}; auto check_macro = [](const cpp_macro_definition& macro, const char* replacement, const char* args) { @@ -56,9 +61,18 @@ baz REQUIRE(false); }); REQUIRE(count == 6u); + + auto index = 0u; + for (auto& child : *file) + { + if (child.kind() == cpp_entity_kind::include_directive_t) + continue; + REQUIRE(child.name() == order[index++]); + } } // requires clang 4.0, currently not available for testing +// TODO: #if 0 TEST_CASE("cpp_include_directive") {