jessevdk / cldoc

clang based documentation generator for C and C++
GNU General Public License v2.0
553 stars 59 forks source link

Default template parameter values are included in the type signature #51

Closed rhdunn closed 6 years ago

rhdunn commented 10 years ago

Given:

std::list<std::string> foo();

The XML output for the return type is:

<return>
  <type name="std::list&lt;std::basic_string&lt;char&gt;, std::allocator&lt;std::basic_string&lt;char&gt; &gt; &gt;" qualifier=" const &amp;" />
</return>

This is including the allocator argument which is the default version from the template declaration. Thus, the allocator should not be present in the output, which should be:

<return>
  <type name="std::list&lt;std::basic_string&lt;char&gt; &gt;" qualifier=" const &amp;" />
</return>

With issue #50 fixed, this should be:

<return>
  <type name="std::list&lt;std::string&gt;" qualifier=" const &amp;" />
</return>
jessevdk commented 10 years ago

So I found out why this happens, at least. So I don't forget, basically the use of a template instantiates a new class, to which the new type refers. The information about this being a templated class is lost, instead you'll obtain the concrete class. At this point it's not possible to easily get back to the templated definition as far as I know. What is possible though, is to get the cursor at the location of the template instantiation, which coincides with the original template declaration, and obtain a cursor to the template.

From there we still need to figure out with which arguments the template was actually instantiated, which might not be trivial to do robustly.

jessevdk commented 10 years ago

Actually, we can get the templated cursor back, there was just some binding missing.

rhdunn commented 10 years ago

Is this related to the Unhandled cursor: CursorKind.TEMPLATE_REF messages I am seeing when building the documentation?

To do this robustly, you need to:

  1. know what each template parameter expands to;
  2. know which parameters are defined in terms of other parameters (e.g. for std::list, Allocator is defined in terms of T);
  3. reverse the type expansion for parameters identified in (2);
  4. remove the template parameters whose signature matches the default parameters.

Thus, for:

std::list<std::string, std::allocator<std::string>>

you have:

1: T = std::string , Allocator = std::allocator<std::string>
3: T = std::string , Allocator = std::allocator<T>
4:T = std::string

Unless libclang provides a way of getting this information in the way it has structured the types.

jessevdk commented 10 years ago

It seems this would be pretty hard to get right currently. It looks like there might be API coming in the next version of libclang (https://github.com/llvm-mirror/clang/blob/master/include/clang-c/Index.h#L3110), but for now it's not available.

jessevdk commented 6 years ago

This has been fixed in latest master, but from the looks of it this will only be possible from clang 4.0 or later (3.9 does not expose this information). I'm considering only supporting 4.0 and upwards.