forked from qt-creator/qt-creator
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: Nikolai Kosjar <nikolai.kosjar@digia.com>
This commit is contained in:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user