c++ideintellisensevariadic-templatesclangd

Can C++ IDEs preview variadic argument types or names?


Is there any way to restore these nice IDE hints when forwarding variadic arguments?

The classic example is std::make_unique<>(...) where you suddenly have to start clicking around to find the definition manually, guessing arguments and wading through longer compile errors when you get it wrong.

E.g. (vscode + clangd I think):

enter image description here

I'll even see overloads for templated constructors in this list. Unfortunately, when arguments are forwarded,

enter image description here

Is there a way I can have both features so I don't have to choose?

Clearly some search would be needed to find all the possible overloads for all numbers of arguments, but that's already happening. Since I haven't typed anything yet there is also nothing for the compiler to do template deduction with, but the IDE can already show templated constructors.

Is there something fundamentally preventing IDEs from matching the original feature or is it just much harder?

Is there a workaround or a way I could write perfect forwarding that would help the IDE give more useful information? E.g. by instantiating some known templates for the compiler to generate code for and then search for overloads against. Or maybe something similar to deduction guides.


Solution

  • TL;DR: It's possible, but it's not trivial to implement, and not currently implemented in clangd.


    Clangd actually implements a related feature: if you've typed the make_unique call already, then clangd shows parameter hints (annotations next to argument expressions in function calls which show the name of the corresponding parameter) which are forwarded from the constructor to the make_unique call, as shown in this screenshot:

    screenshot illustrating clangd's parameter hint forwarding feature

    Note the parameter hints integer and character being shown, even those these are parameters not of the function being called directly (make_unique), but of the constructor that it in turn calls.

    (Note that in currently released versions of clangd, this requires running clangd with --parse-forwarding-functions to work. In clangd 21, this will be enabled by default.)


    Getting this to work in clangd took tricky implementation work from a dedicated contributor (you can see the patch and its discussion here).

    Here's an outline of how the feature works:

    A notable obstacle that had to be overcome is that clangd has an optimization where it does not parse the bodies of functions (including function templates) in header files (because that saves a lot of time, and most of the time the bodies of functions in header files are not relevant to providing editing features in a source file). Since make_unique and most similar functions are in fact defined in header files, their definitions were not available.

    To overcome this, clangd invented a heuristic for deciding whether a function is a "likely forwarding function": if it's a function template and its last function parameter is a parameter pack of the form T&&... or T..., where T is a template parameter of the function itself. Clangd then disables the optimization (to skip parsing the function body) for "likely forwarding functions".


    Now, what about the feature you're asking for?

    It's similar in many ways to the parameter hint forwarding feature discussed above, with one important difference: since the call to make_unique<MyObject, int, char> is not written yet, this function template instantiation does not yet exist.

    Clangd would have to perform the instantiation as part of its processing for the "signature help" feature. More precisely, it would have to perform a partial instantiation, since the first template argument (MyObject) is known, but the remaining ones are not. So it would have to substitute _Tp = MyObject into the body of std::make_unique, realize that the resulting substituted function body contains a call to new MyObject(...) (with the arguments not yet known), and then offer signature help for that constructor call.

    This is possible in principle, but it's tricky because the way the clang frontend is organized, performing template instantiation can have side effects such as producing diagnostics. Currently, only the parser proper does such things, and not implementations of editor features like signature help. If clangd were to start performing template insantiation inside its signature help code, the code would need to be refactored carefully to avoid side effects such as diagnostics.


    There are other ways we could imagine this feature working that doesn't involve looking at function definitions (and thus creating function template instantiations).

    For example, clangd could invent a heuristic where it says, if a function template has a name starts with make_, and an explicitly provided first template parameter T, it's probably going to call new T(...) so assume its implementation does that and provide signature help accordingly. That would get many cases right (and probably some cases wrong).

    Contributions of features like this to clangd are welcome :)