forked from qt-creator/qt-creator
C++: fix code completion for typedef of pointer array
Example:
struct Foo { int foo; };
typedef Foo *FooArr[10];
void func()
{
FooArr arr;
arr[0]-> // No completion
}
Task-number: QTCREATORBUG-12703
Change-Id: I1898dbf83eaa0a6dfa8c401390f28c78e5739bc4
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@digia.com>
This commit is contained in:
committed by
Nikolai Kosjar
parent
4c6e02ed99
commit
b514d4d7b2
@@ -74,6 +74,131 @@ static QList<_Tp> removeDuplicates(const QList<_Tp> &results)
|
||||
return uniqueList;
|
||||
}
|
||||
|
||||
class TypedefsResolver
|
||||
{
|
||||
public:
|
||||
TypedefsResolver(const LookupContext &context) : _context(context) {}
|
||||
void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding)
|
||||
{
|
||||
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.
|
||||
unsigned maxDepth = 15;
|
||||
for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) {
|
||||
QList<LookupItem> namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding);
|
||||
|
||||
if (Q_UNLIKELY(debug))
|
||||
qDebug() << "-- we have" << namedTypeItems.size() << "candidates";
|
||||
|
||||
if (!findTypedef(namedTypeItems, type, scope, visited))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NamedType *getNamedType(FullySpecifiedType& type) const
|
||||
{
|
||||
NamedType *namedTy = type->asNamedType();
|
||||
if (! namedTy) {
|
||||
if (PointerType *pointerTy = type->asPointerType())
|
||||
namedTy = pointerTy->elementType()->asNamedType();
|
||||
}
|
||||
return namedTy;
|
||||
}
|
||||
|
||||
QList<LookupItem> getNamedTypeItems(const Name *name, Scope *scope,
|
||||
ClassOrNamespace *binding) const
|
||||
{
|
||||
QList<LookupItem> namedTypeItems = typedefsFromScopeUpToFunctionScope(name, scope);
|
||||
if (namedTypeItems.isEmpty()) {
|
||||
if (binding)
|
||||
namedTypeItems = binding->lookup(name);
|
||||
if (ClassOrNamespace *scopeCon = _context.lookupType(scope))
|
||||
namedTypeItems += scopeCon->lookup(name);
|
||||
}
|
||||
|
||||
return namedTypeItems;
|
||||
}
|
||||
|
||||
/// Return all typedefs with given name from given scope up to function scope.
|
||||
static QList<LookupItem> typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope)
|
||||
{
|
||||
QList<LookupItem> results;
|
||||
if (!scope)
|
||||
return results;
|
||||
Scope *enclosingBlockScope = 0;
|
||||
for (Block *block = scope->asBlock(); block;
|
||||
block = enclosingBlockScope ? enclosingBlockScope->asBlock() : 0) {
|
||||
const unsigned memberCount = block->memberCount();
|
||||
for (unsigned i = 0; i < memberCount; ++i) {
|
||||
Symbol *symbol = block->memberAt(i);
|
||||
if (Declaration *declaration = symbol->asDeclaration()) {
|
||||
if (isTypedefWithName(declaration, name)) {
|
||||
LookupItem item;
|
||||
item.setDeclaration(declaration);
|
||||
item.setScope(block);
|
||||
item.setType(declaration->type());
|
||||
results.append(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
enclosingBlockScope = block->enclosingScope();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
static bool isTypedefWithName(const Declaration *declaration, const Name *name)
|
||||
{
|
||||
if (declaration->isTypedef()) {
|
||||
const Identifier *identifier = declaration->name()->identifier();
|
||||
if (name->identifier()->match(identifier))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findTypedef(const QList<LookupItem>& namedTypeItems, FullySpecifiedType *type,
|
||||
Scope **scope, QSet<Symbol *>& visited)
|
||||
{
|
||||
bool foundTypedef = false;
|
||||
foreach (const LookupItem &it, namedTypeItems) {
|
||||
Symbol *declaration = it.declaration();
|
||||
if (declaration && declaration->isTypedef()) {
|
||||
if (visited.contains(declaration))
|
||||
break;
|
||||
visited.insert(declaration);
|
||||
|
||||
// continue working with the typedefed type and scope
|
||||
if (type->type()->isPointerType()) {
|
||||
*type = FullySpecifiedType(
|
||||
_context.bindings()->control()->pointerType(declaration->type()));
|
||||
} else if (type->type()->isReferenceType()) {
|
||||
*type = FullySpecifiedType(
|
||||
_context.bindings()->control()->referenceType(
|
||||
declaration->type(),
|
||||
declaration->type()->asReferenceType()->isRvalueReference()));
|
||||
} else {
|
||||
*type = declaration->type();
|
||||
}
|
||||
|
||||
*scope = it.scope();
|
||||
_binding = it.binding();
|
||||
foundTypedef = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundTypedef;
|
||||
}
|
||||
|
||||
const LookupContext &_context;
|
||||
// binding has to be remembered in case of resolving typedefs for templates
|
||||
ClassOrNamespace *_binding;
|
||||
};
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@@ -766,6 +891,9 @@ bool ResolveExpression::visit(ArrayAccessAST *ast)
|
||||
FullySpecifiedType ty = result.type().simplified();
|
||||
Scope *scope = result.scope();
|
||||
|
||||
TypedefsResolver typedefsResolver(_context);
|
||||
typedefsResolver.resolve(&ty, &scope, result.binding());
|
||||
|
||||
if (PointerType *ptrTy = ty->asPointerType()) {
|
||||
addResult(ptrTy->elementType().simplified(), scope);
|
||||
|
||||
@@ -886,131 +1014,6 @@ ClassOrNamespace *ResolveExpression::findClass(const FullySpecifiedType &origina
|
||||
return binding;
|
||||
}
|
||||
|
||||
class TypedefsResolver
|
||||
{
|
||||
public:
|
||||
TypedefsResolver(const LookupContext &context) : _context(context) {}
|
||||
void resolve(FullySpecifiedType *type, Scope **scope, ClassOrNamespace *binding)
|
||||
{
|
||||
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.
|
||||
unsigned maxDepth = 15;
|
||||
for (NamedType *namedTy = 0; maxDepth && (namedTy = getNamedType(*type)); --maxDepth) {
|
||||
QList<LookupItem> namedTypeItems = getNamedTypeItems(namedTy->name(), *scope, _binding);
|
||||
|
||||
if (Q_UNLIKELY(debug))
|
||||
qDebug() << "-- we have" << namedTypeItems.size() << "candidates";
|
||||
|
||||
if (!findTypedef(namedTypeItems, type, scope, visited))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NamedType *getNamedType(FullySpecifiedType& type) const
|
||||
{
|
||||
NamedType *namedTy = type->asNamedType();
|
||||
if (! namedTy) {
|
||||
if (PointerType *pointerTy = type->asPointerType())
|
||||
namedTy = pointerTy->elementType()->asNamedType();
|
||||
}
|
||||
return namedTy;
|
||||
}
|
||||
|
||||
QList<LookupItem> getNamedTypeItems(const Name *name, Scope *scope,
|
||||
ClassOrNamespace *binding) const
|
||||
{
|
||||
QList<LookupItem> namedTypeItems = typedefsFromScopeUpToFunctionScope(name, scope);
|
||||
if (namedTypeItems.isEmpty()) {
|
||||
if (binding)
|
||||
namedTypeItems = binding->lookup(name);
|
||||
if (ClassOrNamespace *scopeCon = _context.lookupType(scope))
|
||||
namedTypeItems += scopeCon->lookup(name);
|
||||
}
|
||||
|
||||
return namedTypeItems;
|
||||
}
|
||||
|
||||
/// Return all typedefs with given name from given scope up to function scope.
|
||||
static QList<LookupItem> typedefsFromScopeUpToFunctionScope(const Name *name, Scope *scope)
|
||||
{
|
||||
QList<LookupItem> results;
|
||||
if (!scope)
|
||||
return results;
|
||||
Scope *enclosingBlockScope = 0;
|
||||
for (Block *block = scope->asBlock(); block;
|
||||
block = enclosingBlockScope ? enclosingBlockScope->asBlock() : 0) {
|
||||
const unsigned memberCount = block->memberCount();
|
||||
for (unsigned i = 0; i < memberCount; ++i) {
|
||||
Symbol *symbol = block->memberAt(i);
|
||||
if (Declaration *declaration = symbol->asDeclaration()) {
|
||||
if (isTypedefWithName(declaration, name)) {
|
||||
LookupItem item;
|
||||
item.setDeclaration(declaration);
|
||||
item.setScope(block);
|
||||
item.setType(declaration->type());
|
||||
results.append(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
enclosingBlockScope = block->enclosingScope();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
static bool isTypedefWithName(const Declaration *declaration, const Name *name)
|
||||
{
|
||||
if (declaration->isTypedef()) {
|
||||
const Identifier *identifier = declaration->name()->identifier();
|
||||
if (name->identifier()->match(identifier))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findTypedef(const QList<LookupItem>& namedTypeItems, FullySpecifiedType *type,
|
||||
Scope **scope, QSet<Symbol *>& visited)
|
||||
{
|
||||
bool foundTypedef = false;
|
||||
foreach (const LookupItem &it, namedTypeItems) {
|
||||
Symbol *declaration = it.declaration();
|
||||
if (declaration && declaration->isTypedef()) {
|
||||
if (visited.contains(declaration))
|
||||
break;
|
||||
visited.insert(declaration);
|
||||
|
||||
// continue working with the typedefed type and scope
|
||||
if (type->type()->isPointerType()) {
|
||||
*type = FullySpecifiedType(
|
||||
_context.bindings()->control()->pointerType(declaration->type()));
|
||||
} else if (type->type()->isReferenceType()) {
|
||||
*type = FullySpecifiedType(
|
||||
_context.bindings()->control()->referenceType(
|
||||
declaration->type(),
|
||||
declaration->type()->asReferenceType()->isRvalueReference()));
|
||||
} else {
|
||||
*type = declaration->type();
|
||||
}
|
||||
|
||||
*scope = it.scope();
|
||||
_binding = it.binding();
|
||||
foundTypedef = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundTypedef;
|
||||
}
|
||||
|
||||
const LookupContext &_context;
|
||||
// binding has to be remembered in case of resolving typedefs for templates
|
||||
ClassOrNamespace *_binding;
|
||||
};
|
||||
|
||||
ClassOrNamespace *ResolveExpression::baseExpression(const QList<LookupItem> &baseResults,
|
||||
int accessOp,
|
||||
bool *replacedDotOperator) const
|
||||
|
||||
Reference in New Issue
Block a user