Commit 3e79d33d authored by Nikolai Kosjar's avatar Nikolai Kosjar

CppEditor: Trigger override search for reference types

...if the access token is T_DOT.

Task-number: QTCREATORBUG-10286
Change-Id: I85621a8166d4f18b3099488ac0ac05a0d6982c43
Reviewed-by: Orgad Shaneh's avatarOrgad Shaneh <orgads@gmail.com>
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent dcb50625
......@@ -138,6 +138,8 @@ private slots:
void test_FollowSymbolUnderCursor_virtualFunctionCall_allOverrides();
void test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides1();
void test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides2();
void test_FollowSymbolUnderCursor_virtualFunctionCall_onDotMemberAccessOfReferenceTypes();
void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDotMemberAccessOfNonReferenceType();
void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnQualified();
void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDeclaration();
void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDefinition();
......
......@@ -55,35 +55,57 @@ typedef BaseTextEditorWidget::Link Link;
namespace {
bool lookupVirtualFunctionOverrides(const QString &expression, Function *function, Scope *scope,
bool lookupVirtualFunctionOverrides(TypeOfExpression &typeOfExpression,
const Document::Ptr &document,
const Function *function,
Scope *scope,
const Snapshot &snapshot)
{
if (expression.isEmpty() || !function || !scope || scope->isClass() || snapshot.isEmpty())
if (!document || !function || !scope || scope->isClass() || snapshot.isEmpty())
return false;
ExpressionAST *expressionAST = typeOfExpression.expressionAST();
if (!expressionAST)
return false;
CallAST *callAST = expressionAST->asCall();
if (!callAST)
return false;
ExpressionAST *baseExpressionAST = callAST->base_expression;
if (!baseExpressionAST)
return false;
bool result = false;
Document::Ptr expressionDocument = documentForExpression(expression.toUtf8());
if (ExpressionAST *expressionAST = extractExpressionAST(expressionDocument)) {
if (CallAST *callAST = expressionAST->asCall()) {
if (ExpressionAST *baseExpressionAST = callAST->base_expression) {
if (IdExpressionAST *idExpressionAST = baseExpressionAST->asIdExpression()) {
NameAST *name = idExpressionAST->name;
result = name && !name->asQualifiedName();
const bool nameIsQualified = name && name->asQualifiedName();
result = !nameIsQualified && FunctionHelper::isVirtualFunction(function, snapshot);
} else if (MemberAccessAST *memberAccessAST = baseExpressionAST->asMemberAccess()) {
NameAST *name = memberAccessAST->member_name;
const bool nameIsQualified = name && name->asQualifiedName();
if (!nameIsQualified && FunctionHelper::isVirtualFunction(function, snapshot)) {
const Document::Ptr expressionDocument
= typeOfExpression.context().expressionDocument();
QTC_ASSERT(expressionDocument, return false);
TranslationUnit *unit = expressionDocument->translationUnit();
QTC_ASSERT(unit, return false);
const int tokenKind = unit->tokenKind(memberAccessAST->access_token);
result = tokenKind == T_ARROW && !nameIsQualified;
const int accessTokenKind = unit->tokenKind(memberAccessAST->access_token);
if (accessTokenKind == T_ARROW) {
result = true;
} else if (accessTokenKind == T_DOT) {
const QList<LookupItem> items = typeOfExpression.reference(
memberAccessAST->base_expression, document, scope);
if (!items.isEmpty()) {
const LookupItem item = items.first();
if (Symbol *declaration = item.declaration())
result = declaration->type()->isReferenceType();
}
}
}
}
return result && FunctionHelper::isVirtualFunction(function, snapshot);
return result;
}
Link findMacroLink_helper(const QByteArray &name, Document::Ptr doc, const Snapshot &snapshot,
......@@ -530,7 +552,7 @@ BaseTextEditorWidget::Link FollowSymbolUnderCursor::findLink(const QTextCursor &
// Consider to show a pop-up displaying overrides for the function
Function *function = symbol->type()->asFunctionType();
if (lookupVirtualFunctionOverrides(expression, function, scope, snapshot)) {
if (lookupVirtualFunctionOverrides(typeOfExpression, doc, function, scope, snapshot)) {
Class *klass = symbolFinder->findMatchingClassDeclaration(function, snapshot);
QTC_CHECK(klass);
......
......@@ -1316,6 +1316,40 @@ void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_possibleO
test.run();
}
/// Check: Trigger on a.virt() if a is of type &A.
void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_onDotMemberAccessOfReferenceTypes()
{
const QByteArray source =
"struct A { virtual void virt() = 0; };\n"
"void A::virt() {}\n"
"\n"
"void client(A &o) { o.$@virt(); }\n"
;
const QStringList immediateResults = QStringList()
<< QLatin1String("A::virt")
<< QLatin1String("...searching overrides");
const QStringList finalResults = QStringList()
<< QLatin1String("A::virt");
TestCase test(TestCase::FollowSymbolUnderCursorAction, source, immediateResults, finalResults);
test.run();
}
/// Check: Do not trigger on a.virt() if a is of type A.
void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDotMemberAccessOfNonReferenceType()
{
const QByteArray source =
"struct A { virtual void virt(); };\n"
"void A::$virt() {}\n"
"\n"
"void client(A o) { o.@virt(); }\n"
;
TestCase test(TestCase::FollowSymbolUnderCursorAction, source);
test.run();
}
/// Check: Do not trigger on qualified function calls.
void CppEditorPlugin::test_FollowSymbolUnderCursor_virtualFunctionCall_notOnQualified()
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment