standardese / cppast

Library to parse and work with the C++ AST
Other
1.7k stars 165 forks source link

Getting the fully qualified name of a base class in a sibling namespace #124

Closed RamblingMadMan closed 2 years ago

RamblingMadMan commented 3 years ago

I'm currently using this great library with clang 13 to generate code for a reflection utility and have come across the issue of being unable to get the fully qualified name of a base class in a sibling namespace.

Description

When a class has a base class in a sibling namespace like so:

namespace my::bases{
    class ObjectBase{};
}

namespace my::derived{
    class Object: public bases::ObjectBase{};
}

after parsing the source and getting the entity references:

const cpp_class &cls = /* ... */;
const cpp_base_class &base = /* ... */;

to get the qualified name of base I would normally use to_string(base.type()), but in this case it returns "bases::ObjectBase" rather than "my::bases::ObjectBase".

Workaround

Currently I call set_user_data on each entity within a cpp_namespace like so:

void set_namespace_data(const cpp_namespace &ns){
    for(auto &&e : ns){
        e.set_user_data(std::bit_cast<void*>(&ns));
        if(e.kind() == cpp_entity_kind::namespace_t){
            set_namespace_data(static_cast<const cpp_namespace&>(e));
        }
    }
}

Then use get_class(entityIndex, base) to retrieve the namespaces and manually build a prefix.

This is extremely ugly and I'm not even sure casting away const with std::bit_cast is allowed.

Conclusion

I would expect type names to be usable from the global scope, but if this is the intended output what would be the correct/idiomatic way to retrieve the fully qualified name?

foonathan commented 3 years ago

This is the intended output: the name is the name as it is written in the source code.

.type() should be a cpp_type_ref, you can then use lookup()/lookup_definition() on the cpp_entity_index to get the cpp_class object. You can then build the fully qualified name by repeatedly calling .parent() and .scope_name(). Note that this doesn't work for inner classes of templates, unfortunately.

RamblingMadMan commented 3 years ago

.type() should be a cpp_type_ref, you can then use lookup()/lookup_definition() on the cpp_entity_index to get the cpp_class object. You can then build the fully qualified name by repeatedly calling .parent() and .scope_name().

This would be great if cpp_base_class::type() returned a cpp_type_ref, otherwise I'm stumped as to how to use lookup_definition() with a cpp_base_class.

foonathan commented 2 years ago

Sorry for the delay. You can downcast the result of type() to cpp_user_defined_type, which has entity() returning a cpp_type_ref.