forked from qt-creator/qt-creator
		
	CppEditor: Handle classes that do not override
...when searching the overrides for virtual functions. In case there is no override for the static type of a function call expression, make sure to: 1) include the last provided override (look up bases) 2) and all overrides whose classes are derived from that static type Task-number: QTCREATORBUG-10470 Change-Id: I2c01bfdc6cb35c5a01a000ebd81a2b322ce2b795 Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
		@@ -35,6 +35,7 @@
 | 
			
		||||
#include <cplusplus/ASTPath.h>
 | 
			
		||||
#include <cplusplus/BackwardsScanner.h>
 | 
			
		||||
#include <cplusplus/ExpressionUnderCursor.h>
 | 
			
		||||
#include <cplusplus/ResolveExpression.h>
 | 
			
		||||
#include <cplusplus/SimpleLexer.h>
 | 
			
		||||
#include <cplusplus/TypeOfExpression.h>
 | 
			
		||||
#include <cpptools/cppmodelmanagerinterface.h>
 | 
			
		||||
@@ -60,75 +61,85 @@ public:
 | 
			
		||||
    VirtualFunctionHelper(const TypeOfExpression &typeOfExpression,
 | 
			
		||||
                          Scope *scope,
 | 
			
		||||
                          const Document::Ptr &document,
 | 
			
		||||
                          const Snapshot &snapshot);
 | 
			
		||||
                          const Snapshot &snapshot,
 | 
			
		||||
                          SymbolFinder *symbolFinder);
 | 
			
		||||
 | 
			
		||||
    bool canLookupVirtualFunctionOverrides(const Function *function) const;
 | 
			
		||||
    bool canLookupVirtualFunctionOverrides(Function *function);
 | 
			
		||||
 | 
			
		||||
    /// Returns != 0 if canLookupVirtualFunctionOverrides() succeeded.
 | 
			
		||||
    Class *staticClassOfFunctionCallExpression() const
 | 
			
		||||
    { return m_staticClassOfFunctionCallExpression; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    VirtualFunctionHelper();
 | 
			
		||||
    Q_DISABLE_COPY(VirtualFunctionHelper)
 | 
			
		||||
 | 
			
		||||
    ExpressionAST *getBaseExpressionAST() const
 | 
			
		||||
    {
 | 
			
		||||
        if (!m_expressionAST)
 | 
			
		||||
            return 0;
 | 
			
		||||
        CallAST *callAST = m_expressionAST->asCall();
 | 
			
		||||
        if (!callAST)
 | 
			
		||||
            return 0;
 | 
			
		||||
        if (ExpressionAST *baseExpressionAST = callAST->base_expression)
 | 
			
		||||
            return baseExpressionAST;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    Class *staticClassOfFunctionCallExpression_internal() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Provided
 | 
			
		||||
    const QSharedPointer<TypeOfExpression> m_typeOfExpression;
 | 
			
		||||
    ExpressionAST *m_expressionAST;
 | 
			
		||||
    const Document::Ptr m_expressionDocument;
 | 
			
		||||
    Scope *m_scope;
 | 
			
		||||
    const Document::Ptr &m_document;
 | 
			
		||||
    const Snapshot &m_snapshot;
 | 
			
		||||
    SymbolFinder *m_finder;
 | 
			
		||||
 | 
			
		||||
    // Determined
 | 
			
		||||
    ExpressionAST *m_baseExpressionAST;
 | 
			
		||||
    Function *m_function;
 | 
			
		||||
    int m_accessTokenKind;
 | 
			
		||||
    Class *m_staticClassOfFunctionCallExpression; // Output
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
VirtualFunctionHelper::VirtualFunctionHelper(const TypeOfExpression &typeOfExpression,
 | 
			
		||||
                                             Scope *scope,
 | 
			
		||||
                                             const Document::Ptr &document,
 | 
			
		||||
                                             const Snapshot &snapshot)
 | 
			
		||||
    : m_expressionAST(typeOfExpression.expressionAST())
 | 
			
		||||
    , m_expressionDocument(typeOfExpression.context().expressionDocument())
 | 
			
		||||
                                             const Snapshot &snapshot,
 | 
			
		||||
                                             SymbolFinder *finder)
 | 
			
		||||
    : m_expressionDocument(typeOfExpression.context().expressionDocument())
 | 
			
		||||
    , m_scope(scope)
 | 
			
		||||
    , m_document(document)
 | 
			
		||||
    , m_snapshot(snapshot)
 | 
			
		||||
    , m_finder(finder)
 | 
			
		||||
    , m_baseExpressionAST(0)
 | 
			
		||||
    , m_function(0)
 | 
			
		||||
    , m_accessTokenKind(0)
 | 
			
		||||
    , m_staticClassOfFunctionCallExpression(0)
 | 
			
		||||
{
 | 
			
		||||
    if (ExpressionAST *expressionAST = typeOfExpression.expressionAST()) {
 | 
			
		||||
        if (CallAST *callAST = expressionAST->asCall()) {
 | 
			
		||||
            if (ExpressionAST *baseExpressionAST = callAST->base_expression)
 | 
			
		||||
                m_baseExpressionAST = baseExpressionAST;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool VirtualFunctionHelper::canLookupVirtualFunctionOverrides(const Function *function) const
 | 
			
		||||
bool VirtualFunctionHelper::canLookupVirtualFunctionOverrides(Function *function)
 | 
			
		||||
{
 | 
			
		||||
    if (!m_expressionDocument || !m_document || !function || !m_scope || m_scope->isClass()
 | 
			
		||||
            || m_snapshot.isEmpty()) {
 | 
			
		||||
    m_function = function;
 | 
			
		||||
    if (!m_function || !m_baseExpressionAST || !m_expressionDocument || !m_document || !m_scope
 | 
			
		||||
            || m_scope->isClass() || m_snapshot.isEmpty()) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ExpressionAST *baseExpressionAST = getBaseExpressionAST();
 | 
			
		||||
    if (!baseExpressionAST)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    bool result = false;
 | 
			
		||||
 | 
			
		||||
    if (IdExpressionAST *idExpressionAST = baseExpressionAST->asIdExpression()) {
 | 
			
		||||
    if (IdExpressionAST *idExpressionAST = m_baseExpressionAST->asIdExpression()) {
 | 
			
		||||
        NameAST *name = idExpressionAST->name;
 | 
			
		||||
        const bool nameIsQualified = name && name->asQualifiedName();
 | 
			
		||||
        result = !nameIsQualified && FunctionHelper::isVirtualFunction(function, m_snapshot);
 | 
			
		||||
    } else if (MemberAccessAST *memberAccessAST = baseExpressionAST->asMemberAccess()) {
 | 
			
		||||
    } else if (MemberAccessAST *memberAccessAST = m_baseExpressionAST->asMemberAccess()) {
 | 
			
		||||
        NameAST *name = memberAccessAST->member_name;
 | 
			
		||||
        const bool nameIsQualified = name && name->asQualifiedName();
 | 
			
		||||
        if (!nameIsQualified && FunctionHelper::isVirtualFunction(function, m_snapshot)) {
 | 
			
		||||
            TranslationUnit *unit = m_expressionDocument->translationUnit();
 | 
			
		||||
            QTC_ASSERT(unit, return false);
 | 
			
		||||
            const int accessTokenKind = unit->tokenKind(memberAccessAST->access_token);
 | 
			
		||||
            m_accessTokenKind = unit->tokenKind(memberAccessAST->access_token);
 | 
			
		||||
 | 
			
		||||
            if (accessTokenKind == T_ARROW) {
 | 
			
		||||
            if (m_accessTokenKind == T_ARROW) {
 | 
			
		||||
                result = true;
 | 
			
		||||
            } else if (accessTokenKind == T_DOT) {
 | 
			
		||||
            } else if (m_accessTokenKind == T_DOT) {
 | 
			
		||||
                TypeOfExpression typeOfExpression;
 | 
			
		||||
                typeOfExpression.init(m_document, m_snapshot);
 | 
			
		||||
                typeOfExpression.setExpandTemplates(true);
 | 
			
		||||
@@ -143,6 +154,50 @@ bool VirtualFunctionHelper::canLookupVirtualFunctionOverrides(const Function *fu
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!result)
 | 
			
		||||
        return false;
 | 
			
		||||
    return (m_staticClassOfFunctionCallExpression = staticClassOfFunctionCallExpression_internal());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// For "f()" in "class C { void g() { f(); };" return class C.
 | 
			
		||||
/// For "c->f()" in "{ C *c; c->f(); }" return class C.
 | 
			
		||||
Class *VirtualFunctionHelper::staticClassOfFunctionCallExpression_internal() const
 | 
			
		||||
{
 | 
			
		||||
    if (!m_finder)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    Class *result = 0;
 | 
			
		||||
 | 
			
		||||
    if (m_baseExpressionAST->asIdExpression()) {
 | 
			
		||||
        for (Scope *s = m_scope; s ; s = s->enclosingScope()) {
 | 
			
		||||
            if (Function *function = s->asFunction()) {
 | 
			
		||||
                result = m_finder->findMatchingClassDeclaration(function, m_snapshot);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else if (MemberAccessAST *memberAccessAST = m_baseExpressionAST->asMemberAccess()) {
 | 
			
		||||
        QTC_ASSERT(m_accessTokenKind == T_ARROW || m_accessTokenKind == T_DOT, return result);
 | 
			
		||||
        TypeOfExpression typeOfExpression;
 | 
			
		||||
        typeOfExpression.init(m_document, m_snapshot);
 | 
			
		||||
        typeOfExpression.setExpandTemplates(true);
 | 
			
		||||
        const QList<LookupItem> items = typeOfExpression(memberAccessAST->base_expression,
 | 
			
		||||
                                                         m_document, m_scope);
 | 
			
		||||
        ResolveExpression resolveExpression(typeOfExpression.context());
 | 
			
		||||
        ClassOrNamespace *binding = resolveExpression.baseExpression(items, m_accessTokenKind);
 | 
			
		||||
        if (binding) {
 | 
			
		||||
            if (Class *klass = binding->rootClass()) {
 | 
			
		||||
                result = klass;
 | 
			
		||||
            } else {
 | 
			
		||||
                const QList<Symbol *> symbols = binding->symbols();
 | 
			
		||||
                if (!symbols.isEmpty()) {
 | 
			
		||||
                    Symbol * const first = symbols.first();
 | 
			
		||||
                    if (first->isForwardClassDeclaration())
 | 
			
		||||
                        result = m_finder->findMatchingClassDeclaration(first, m_snapshot);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -590,11 +645,12 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &
 | 
			
		||||
 | 
			
		||||
            // Consider to show a pop-up displaying overrides for the function
 | 
			
		||||
            Function *function = symbol->type()->asFunctionType();
 | 
			
		||||
            VirtualFunctionHelper helper(*typeOfExpression, scope, doc, snapshot);
 | 
			
		||||
            VirtualFunctionHelper helper(*typeOfExpression, scope, doc, snapshot, symbolFinder);
 | 
			
		||||
 | 
			
		||||
            if (helper.canLookupVirtualFunctionOverrides(function)) {
 | 
			
		||||
                VirtualFunctionAssistProvider::Parameters params;
 | 
			
		||||
                params.function = function;
 | 
			
		||||
                params.staticClass = helper.staticClassOfFunctionCallExpression();
 | 
			
		||||
                params.typeOfExpression = typeOfExpression;
 | 
			
		||||
                params.snapshot = snapshot;
 | 
			
		||||
                params.cursorPosition = cursor.position();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user