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;
|
QSet<Symbol *> visited;
|
||||||
_binding = binding;
|
_binding = binding;
|
||||||
// Use a hard limit when trying to resolve typedefs. Typedefs in templates can refer to
|
// Use a hard limit when trying to resolve typedefs.
|
||||||
// each other, each time enhancing the template argument and thus making it impossible to
|
// TODO: Now that template arguments are resolved, use an 'alreadyResolved' container to
|
||||||
// use an "alreadyResolved" container. FIXME: We might overcome this by resolving the
|
// handle recursive typedefs.
|
||||||
// template parameters.
|
|
||||||
unsigned maxDepth = 15;
|
unsigned maxDepth = 15;
|
||||||
for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) {
|
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))
|
if (Q_UNLIKELY(debug))
|
||||||
qDebug() << "-- we have" << namedTypeItems.size() << "candidates";
|
qDebug() << "-- we have" << namedTypeItems.size() << "candidates";
|
||||||
@@ -99,6 +132,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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 *getNamedType(FullySpecifiedType& type) const
|
||||||
{
|
{
|
||||||
NamedType *namedTy = type->asNamedType();
|
NamedType *namedTy = type->asNamedType();
|
||||||
|
|||||||
@@ -2328,6 +2328,34 @@ void CppToolsPlugin::test_completion_data()
|
|||||||
<< QLatin1String("foo")
|
<< QLatin1String("foo")
|
||||||
<< 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
|
// this is not a valid code(is not compile) but it caused a crash
|
||||||
QTest::newRow("template_specialization_and_initialization_with_pointer2") << _(
|
QTest::newRow("template_specialization_and_initialization_with_pointer2") << _(
|
||||||
"template <typename T1, typename T2 = int>\n"
|
"template <typename T1, typename T2 = int>\n"
|
||||||
|
|||||||
Reference in New Issue
Block a user