Closed deadlocklogic closed 2 years ago
This should work, lookup gives you a vector of references to cpp_entity
you can then downcast to cpp_class
.
However, if you're in a position to use libtooling (i.e. integrate with clang, deal with breaking interface changes etc.), I recommend you do so. I wouldn't use libclang directly, however, it doesn't expose as much info as cppast.
I would really appreciate it if I can use cppast
only, because it is clean, concise and safe.
My problem is like so, consider I want to parse the class cpp_function_template
of the cppast
itself just for testing and list all its bases classes/functions etc...
void list_all_base_classes(cppast::cpp_entity_index& idx, const cppast::cpp_class& _class) {
for (auto& _base : _class.bases()) {
auto& _type = _base.type();
if (_type.kind() == cppast::cpp_type_kind::user_defined_t) {
std::cout << "type resolved" << std::endl;
auto& _user_defined_type = static_cast<const cppast::cpp_user_defined_type&>(_type);
auto _ids = _user_defined_type.entity().id();
for (auto _id : _ids) {
auto _entity = idx.lookup(_id);
if (_entity) {
std::cout << "base class resolved" << std::endl;
}
}
}
}
}
int main() {
auto _path =
"C:/Users/user/Desktop/cppast/include/cppast/cpp_function_template.hpp";
cppast::cpp_entity_index _idx;
cppast::libclang_parser _parser;
cppast::libclang_compile_config _config;
_config.set_flags(cppast::cpp_standard::cpp_latest);
_config.add_include_dir("C:/Users/user/Desktop/cppast/include/");
_config.add_include_dir("C:/Users/user/Desktop/Library/cmake-build-debug-mingw/_deps/type_safe-src/include/");
_config.add_include_dir("C:/Users/user/Desktop/Library/cmake-build-debug-mingw/_deps/type_safe-src/external/debug_assert/");
std::unique_ptr<cppast::cpp_file> _file = _parser.parse(_idx, _path, _config);
cppast::visit(*_file, [&](const cppast::cpp_entity& e, cppast::visitor_info info) {
if (info.event != cppast::visitor_info::container_entity_exit) {
if (e.kind() == cppast::cpp_entity_kind::class_t) {
if (e.scope_name().has_value() && e.scope_name().value().name() == "cpp_function_template") {
list_all_base_classes(_idx, static_cast<const cppast::cpp_class&>(e));
}
}
}
return true;
});
return 0;
}
The problem is that lookup
always returns an empty optional_ref
.
So @foonathan what is going wrong here?
lookup() only works if you have parsed the definition as well. You have to not only parse the file of the derived class but also of the base class.
Anything that is defined in a header included by a file will not be processed by cppast.
So you mean I should use this?https://github.com/foonathan/cppast/blob/bf7ec70ea5b46add55d04ba03c8bc4269d4a391c/include/cppast/parser.hpp#L190
Is there a specific example in tests which I could rely on? Because I am not integrating with CMake
, just I am doing external parsing.
What is the best approach to parse multiple external files with cppast
? I can't really use https://github.com/foonathan/cppast/blob/main/test/integration.cpp because I am not integrating with CMake
so no generated compile_commands.json
.
So basically I reworked my code using parse_files
but still the lookup
returns empty, even though now I have 2 parsed files.
int main() {
cppast::cpp_entity_index _idx;
cppast::simple_file_parser<libclang_parser> _parser(type_safe::ref(_idx), default_logger());
cppast::libclang_compile_config _config;
_config.set_flags(cppast::cpp_standard::cpp_latest);
_config.add_include_dir("C:/Users/user/Desktop/cppast/include/");
_config.add_include_dir("C:/Users/user/Desktop/Library/cmake-build-debug-mingw/_deps/type_safe-src/include/");
_config.add_include_dir("C:/Users/user/Desktop/Library/cmake-build-debug-mingw/_deps/type_safe-src/external/debug_assert/");
cppast::parse_files(_parser,
std::vector<std::string>{
"C:/Users/user/Desktop/cppast/include/cppast/cpp_template.hpp",
"C:/Users/user/Desktop/cppast/include/cppast/cpp_function_template.hpp",
},
_config);
for (auto& _file : _parser.files()) {
cppast::visit(_file, [&](const cppast::cpp_entity& e, cppast::visitor_info info) {
if (info.event != cppast::visitor_info::container_entity_exit) {
if (e.kind() == cppast::cpp_entity_kind::class_t) {
if (e.scope_name().has_value() && e.scope_name().value().name() == "cpp_function_template") {
list_all_base_classes(_idx, static_cast<const cppast::cpp_class&>(e));
}
}
}
return true;
});
}
return 0;
}
@foonathan is there something wrong with this snippet?
After using parse_files
, apparently, this works:
auto& _user_defined_type = static_cast<const cppast::cpp_user_defined_type&>(_type);
auto _resolutions = _user_defined_type.entity().get(idx);
if (_resolutions.size() > 0) {
auto _resolution = _resolutions[0];
std::cout << "resolved kind: " << cppast::to_string(_resolution.get().kind()) << std::endl;
std::cout << "resolved name: " << _resolution.get().name() << std::endl;
}
but this doesn't and I don't know why:
auto _ids = _user_defined_type.entity().id();
for (auto _id : _ids) {
auto _resolution = idx.lookup(_id);
if (_resolution) {
std::cout << "resolved kind: " << cppast::to_string(_resolution.get().kind()) << std::endl;
std::cout << "resolved name: " << _resolution.get().name() << std::endl;
}
}
I am trying to navigate a parsed file
C.h
for instance:where
B.h
:So far with the referring
cpp_class
ofC
I can only getB
as base class, unfortunatelyB
type cannot be converted to acpp_class
usinglookup/lookup_definition
. So basically I cannot query any information from the outer base classB
and the API doesn't provide any hints about the outer file path if I want to do separate parsing. Any ideas how to work it out? @foonathan as most likely you have good knowledge withlibclang/lib tooling
, do you think that these api can solve my problem better? Even thought I really liked your lib.