diff options
author | Przemyslaw Gorszkowski <pgorszkowski@gmail.com> | 2014-07-21 22:38:19 +0200 |
---|---|---|
committer | Nikolai Kosjar <nikolai.kosjar@digia.com> | 2014-08-18 09:02:57 +0200 |
commit | b514d4d7b2214b82583348c4e995bbd48fd46522 (patch) | |
tree | 0cb99dc15339fdd64933c73884d7a3ef7c282176 /src/libs/cplusplus/ResolveExpression.cpp | |
parent | 4c6e02ed99e93f3149023d99982c0f7d3f4e050a (diff) | |
download | qt-creator-b514d4d7b2214b82583348c4e995bbd48fd46522.tar.gz |
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>
Diffstat (limited to 'src/libs/cplusplus/ResolveExpression.cpp')
-rw-r--r-- | src/libs/cplusplus/ResolveExpression.cpp | 253 |
1 files changed, 128 insertions, 125 deletions
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 3474eac0aa..bdf7a5a2d1 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -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 |