It's often hard to provide completion suggestions for dependent types in C++, before a template is truly instantiated, we cannot make any accurate assumptions about it. But for code completion, accuracy is not so important; providing more possible results usually is more useful.
Currently, clangd (in fact, clangd just uses the result generated by SemaComplete) can provide completion in the above code. The result is based on the main template of vector, rather than vector<bool>. It is not precise, but it is really useful. However, it can only handle dependent TemplateSpecializationType.
In this case, clangd will give you no completion. Why? This is because the type of vec2[0] is std::vector<std::vector<T>>::reference, which is a DependentNameType. SemaComplete cannot handle it before actual instantiation. But, according to the C++ standard, of course we know the result of std::vector<std::vector<T>>::reference is std::vector<T>&, which can be further regarded as a TemplateSpecializationType. And then SemaComplete can provide completion for it.
The process of transforming a complex dependent type into a simple dependent type or even a non-dependent type is just pseudo template instantiation.
Although we can dig some holes for types in std, I want user-defined types to have the same status as types in the C++ standard library. So there must be a general way to implement such simplifications.
After lots of attempts, I made some progress. I wrote a resolver which can simplify std::vector<T>::reference and std::list<T>::reference in libstdc++ (the definition in libstdc++ is really complex and many nested templates) to T&.
The main process of the resolver is:
For the most complex dependent type, type<...>::([template] name)*, we can simplify it recursively, so just considering type<Ts...>::name.
According to the main template of type<Ts...>, lookup the name in it. If not found, find in its dependent base classes. If still not found, find in its partial specializations.
If the result is a decl, and there is no template keyword before name, it must be a TypeAliasDecl or TypedefDecl; retrieve its type and use Sema::SubstType to substitute the template parameters in it. If there is a template keyword, it must be a ClassTemplateDecl or TypeAliasTemplateDecl; recursively simplify it.
Issues in clangd:
It's often hard to provide completion suggestions for dependent types in C++, before a template is truly instantiated, we cannot make any accurate assumptions about it. But for code completion, accuracy is not so important; providing more possible results usually is more useful.
Currently, clangd (in fact, clangd just uses the result generated by
SemaComplete
) can provide completion in the above code. The result is based on the main template ofvector
, rather thanvector<bool>
. It is not precise, but it is really useful. However, it can only handle dependentTemplateSpecializationType
.In this case, clangd will give you no completion. Why? This is because the type of
vec2[0]
isstd::vector<std::vector<T>>::reference
, which is aDependentNameType
.SemaComplete
cannot handle it before actual instantiation. But, according to the C++ standard, of course we know the result ofstd::vector<std::vector<T>>::reference
isstd::vector<T>&
, which can be further regarded as aTemplateSpecializationType
. And thenSemaComplete
can provide completion for it.The process of transforming a complex dependent type into a simple dependent type or even a non-dependent type is just pseudo template instantiation.
Although we can dig some holes for types in
std
, I want user-defined types to have the same status as types in the C++ standard library. So there must be a general way to implement such simplifications.After lots of attempts, I made some progress. I wrote a resolver which can simplify
std::vector<T>::reference
andstd::list<T>::reference
in libstdc++ (the definition in libstdc++ is really complex and many nested templates) toT&
.The main process of the resolver is:
For the most complex dependent type,
type<...>::([template] name)*
, we can simplify it recursively, so just consideringtype<Ts...>::name
.According to the main template of
type<Ts...>
, lookup thename
in it. If not found, find in its dependent base classes. If still not found, find in its partial specializations.If the result is a decl, and there is no
template
keyword beforename
, it must be aTypeAliasDecl
orTypedefDecl
; retrieve its type and useSema::SubstType
to substitute the template parameters in it. If there is atemplate
keyword, it must be aClassTemplateDecl
orTypeAliasTemplateDecl
; recursively simplify it.