C++: add support for resolving typedefs for template arguments

Example:
template <typename T>
struct Base { T t; };
struct Foo { int foo; };
void fun() {
  typedef Foo TypedefedFoo;
  Base<TypedefedFoo> baseFoo;
  baseFoo.t.// no code completion
}

Change-Id: I4822693d3fa1ee2e9b0e4cdd28bb9a8d441fb313
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@digia.com>
parent bf0e0d80
......@@ -82,13 +82,46 @@ public:
{
QSet<Symbol *> visited;
_binding = binding;
// Use a hard limit when trying to resolve typedefs. Typedefs in templates can refer to
// each other, each time enhancing the template argument and thus making it impossible to
// use an "alreadyResolved" container. FIXME: We might overcome this by resolving the
// template parameters.
// Use a hard limit when trying to resolve typedefs.
// TODO: Now that template arguments are resolved, use an 'alreadyResolved' container to
// handle recursive typedefs.
unsigned maxDepth = 15;
for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) {
QList<LookupItem> namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding);
NamedType *orgNamedTy = namedTy;
const Name *name = namedTy->name();
if (const QualifiedNameId *qn = name->asQualifiedNameId()) {
const Name *name = qn->name();
Scope *templateScope = *scope;
if (const TemplateNameId *templateNameId = name->asTemplateNameId()) {
const TemplateNameId *resolvedTemplateNameId =
resolveTemplateParameters(templateNameId, templateScope, binding);
const QualifiedNameId *resolvedQualifiedNamedId =
_context.bindings()->control()->qualifiedNameId(qn->base(),
resolvedTemplateNameId);
namedTy = _context.bindings()->control()->namedType(resolvedQualifiedNamedId);
}
} else if (const TemplateNameId *templateNameId = name->asTemplateNameId()) {
Scope *templateScope = *scope;
const TemplateNameId *resolvedTemplateNameId =
resolveTemplateParameters(templateNameId, templateScope, binding);
namedTy = _context.bindings()->control()->namedType(resolvedTemplateNameId);
}
if (namedTy != orgNamedTy) {
if ((*type)->isPointerType()) {
*type = FullySpecifiedType(_context.bindings()->control()->pointerType(
FullySpecifiedType(namedTy)));
} else if (ReferenceType *referenceType = (*type)->asReferenceType()) {
*type = FullySpecifiedType(_context.bindings()->control()->referenceType(
FullySpecifiedType(namedTy),
referenceType->isRvalueReference()));
} else {
*type = FullySpecifiedType(namedTy);
}
name = namedTy->name();
}
QList<LookupItem> namedTypeItems = getNamedTypeItems(name, *scope, _binding);
if (Q_UNLIKELY(debug))
qDebug() << "-- we have" << namedTypeItems.size() << "candidates";
......@@ -99,6 +132,25 @@ public:
}
private:
const TemplateNameId *resolveTemplateParameters(const TemplateNameId *templateNameId,
Scope *templateScope,
ClassOrNamespace *binding)
{
std::vector<FullySpecifiedType> resolvedTemplateArguments;
const unsigned templArgumentCount = templateNameId->templateArgumentCount();
for (unsigned i = 0; i < templArgumentCount; ++i) {
FullySpecifiedType resolvedTemplateArgumentType
= templateNameId->templateArgumentAt(i);
resolve(&resolvedTemplateArgumentType, &templateScope, binding);
resolvedTemplateArguments.push_back(resolvedTemplateArgumentType);
}
return _context.bindings()->control()->templateNameId(templateNameId->identifier(),
templateNameId->isSpecialization(),
&resolvedTemplateArguments[0],
templArgumentCount);
}
NamedType *getNamedType(FullySpecifiedType& type) const
{
NamedType *namedTy = type->asNamedType();
......
......@@ -2328,6 +2328,34 @@ void CppToolsPlugin::test_completion_data()
<< QLatin1String("foo")
<< QLatin1String("Foo"));
QTest::newRow("resolving_template_argument1") << _(
"template <typename T>\n"
"struct Base { T t; };\n"
"struct Foo { int foo; };\n"
"void fun() {\n"
" typedef Foo TypedefedFoo;\n"
" Base<TypedefedFoo> baseFoo;\n"
" @\n"
"}\n"
) << _("baseFoo.t.") << (QStringList()
<< QLatin1String("foo")
<< QLatin1String("Foo"));
QTest::newRow("resolving_template_argument2") << _(
"namespace NS {\n"
"template <typename T>\n"
"struct Base { T t; };\n"
"}\n"
"struct Foo { int foo; };\n"
"void fun() {\n"
" typedef Foo TypedefedFoo;\n"
" NS::Base<TypedefedFoo> baseFoo;\n"
" @\n"
"}\n"
) << _("baseFoo.t.") << (QStringList()
<< QLatin1String("foo")
<< QLatin1String("Foo"));
// this is not a valid code(is not compile) but it caused a crash
QTest::newRow("template_specialization_and_initialization_with_pointer2") << _(
"template <typename T1, typename T2 = int>\n"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment