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