Printing "readably"

Hi,

At the risk of over-promising, I'm working on a replacement for SWIG using clang. The basic idea is very simple: create a wrapper for each public function and method that is reachable from the source spec (ideally a system header to make it as friction free as possible). These wrappers will substitute pointers instead of references, objects with constructors, etc.

Obviously, clang makes it easy to get the list of functions and methods, and massaging "dangerous" types to pointers isn't that hard (as an aside, the documentation for PointerType would benefit from a sentence directing you to ASTContext for getting your hands on instances programmatically).
I have been using QualType.print(), but it has a couple of problems:

a) TypedefTypes aren't printed with their appropriate scope, and when I started using QualType.getCanonicalType() before printing (to eliminate typedefs),
b) NullPtrType is printed as "nullptr_t" rather than "std::nullptr_t" (or even "decltype(nullptr)")

Upon deciding to get my hands dirty, I investigated TypePrinter.cpp, and indeed printTypedefBefore() made no attempt to provide the scope of a typedef (even when PrintingPolicy.SuppressScope is false). I tried copying the relevant part of printTag(), which works for most cases, but now I get more subtle errors:

dummy.cc.cc:12176:102: error: 'new_allocator' is not a class, namespace, or scoped enumeration
__gnu_cxx::new_allocator::size_type

__gnu_cxx::new_allocator is a template, but in this case size_type doesn't depend on a template parameter (the source uses std::size_t unconditionally), from what I can gather from the source, the TypedefDecl is given the context of the CXXRecord, (and not the ClassTemplateSpecializationDecl) so it doesn't know that it should be giving template arguments.

If that is correct (is it correct?) then I don't know how I can safely output TypedefTypes without convincing the compiler to parse it differently, which puts me back to using getCanonicalType().

For ElaboratedTypes I need to ignore printing the NestedNameSpecifier, and then NOT enable PrintingPolicy::SuppressScope (which is done by the ElaboratedTypePolicyRAII). My current diff for the method uses SuppressScope to decide whether to print the full scope, which is (obviously) a potentially breaking change. Arguably instead of SuppressScope there should be a tri-state enum AsSource/Suppress/Force but I don't know whether you would be interested in making such a change.

Hi,

At the risk of over-promising, I’m working on a replacement for SWIG
using clang.

Generally, a lot of people wanted to see this done, so I’d guess there’ll be some willingness to provide the functionality you need, as long as it fits within clang’s overall design choices.
It’s also possible to put some of the functionality into LibTooling (don’t know whether you’ve considered using it for your use case).

The basic idea is very simple: create a wrapper for each
public function and method that is reachable from the source spec
(ideally a system header to make it as friction free as possible). These
wrappers will substitute pointers instead of references, objects with
constructors, etc.

Obviously, clang makes it easy to get the list of functions and methods,
and massaging “dangerous” types to pointers isn’t that hard (as an
aside, the documentation for PointerType would benefit from a sentence
directing you to ASTContext for getting your hands on instances
programmatically).

Patches welcome :smiley: Especially when they enhance documentation!

I have been using QualType.print(), but it has a couple of problems:

Generally, the print functions are more for debugging than anything else; my first intuitive response would be to implement some visitor for your types that puts together the correct source code output you need…

a) TypedefTypes aren’t printed with their appropriate scope, and when I
started using QualType.getCanonicalType() before printing (to eliminate
typedefs),
b) NullPtrType is printed as “nullptr_t” rather than “std::nullptr_t”
(or even “decltype(nullptr)”)

Upon deciding to get my hands dirty, I investigated TypePrinter.cpp, and
indeed printTypedefBefore() made no attempt to provide the scope of a
typedef (even when PrintingPolicy.SuppressScope is false). I tried
copying the relevant part of printTag(), which works for most cases, but
now I get more subtle errors:

dummy.cc.cc:12176:102: error: ‘new_allocator’ is not a class, namespace,
or scoped enumeration
__gnu_cxx::new_allocator::size_type

__gnu_cxx::new_allocator is a template, but in this case size_type
doesn’t depend on a template parameter (the source uses std::size_t
unconditionally), from what I can gather from the source, the
TypedefDecl is given the context of the CXXRecord, (and not the
ClassTemplateSpecializationDecl) so it doesn’t know that it should be
giving template arguments.

If that is correct (is it correct?) then I don’t know how I can safely
output TypedefTypes without convincing the compiler to parse it
differently, which puts me back to using getCanonicalType().

For ElaboratedTypes I need to ignore printing the NestedNameSpecifier,
and then NOT enable PrintingPolicy::SuppressScope (which is done by the
ElaboratedTypePolicyRAII). My current diff for the method uses
SuppressScope to decide whether to print the full scope, which is
(obviously) a potentially breaking change. Arguably instead of
SuppressScope there should be a tri-state enum AsSource/Suppress/Force
but I don’t know whether you would be interested in making such a change.

That is a question for Richard…

cheers,
/Manuel