forked from qt-creator/qt-creator
CppEditor: Support implicit pointers in Qt5 connect conversion
Task-number: QTCREATORBUG-14104 Change-Id: I157dbcb0e06ed1bf49d2df01bdbad215e35a4c3a Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
committed by
Orgad Shaneh
parent
683540bee7
commit
dbb9891f43
@@ -4543,6 +4543,12 @@ void CppEditorPlugin::test_quickfix_ConvertQt4Connect_connectWithinClass_data()
|
|||||||
"conne@ct(p.t, SIGNAL(sigFoo(int)), p.t, SLOT(setProp(int)));")
|
"conne@ct(p.t, SIGNAL(sigFoo(int)), p.t, SLOT(setProp(int)));")
|
||||||
<< QByteArray("Pointer<TestClass> p;\n"
|
<< QByteArray("Pointer<TestClass> p;\n"
|
||||||
"connect(p.t, &TestClass::sigFoo, p.t, &TestClass::setProp);");
|
"connect(p.t, &TestClass::sigFoo, p.t, &TestClass::setProp);");
|
||||||
|
|
||||||
|
QTest::newRow("implicit-pointer")
|
||||||
|
<< QByteArray("Pointer<TestClass> p;\n"
|
||||||
|
"conne@ct(p, SIGNAL(sigFoo(int)), p, SLOT(setProp(int)));")
|
||||||
|
<< QByteArray("Pointer<TestClass> p;\n"
|
||||||
|
"connect(p.data(), &TestClass::sigFoo, p.data(), &TestClass::setProp);");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppEditorPlugin::test_quickfix_ConvertQt4Connect_connectWithinClass()
|
void CppEditorPlugin::test_quickfix_ConvertQt4Connect_connectWithinClass()
|
||||||
@@ -4555,6 +4561,8 @@ void CppEditorPlugin::test_quickfix_ConvertQt4Connect_connectWithinClass()
|
|||||||
"struct Pointer\n"
|
"struct Pointer\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" T *t;\n"
|
" T *t;\n"
|
||||||
|
" operator T*() const { return t; }\n"
|
||||||
|
" T *data() const { return t; }\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"class QObject {};\n"
|
"class QObject {};\n"
|
||||||
"class TestClass : public QObject\n"
|
"class TestClass : public QObject\n"
|
||||||
|
@@ -5578,10 +5578,75 @@ Symbol *skipForwardDeclarations(const QList<Symbol *> &symbols)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool findRawAccessFunction(Class *klass, PointerType *pointerType, QString *objAccessFunction)
|
||||||
|
{
|
||||||
|
QList<Function *> candidates;
|
||||||
|
for (auto it = klass->memberBegin(), end = klass->memberEnd(); it != end; ++it) {
|
||||||
|
if (Function *func = (*it)->asFunction()) {
|
||||||
|
const Name *funcName = func->name();
|
||||||
|
if (!funcName->isOperatorNameId()
|
||||||
|
&& !funcName->isConversionNameId()
|
||||||
|
&& func->returnType().type() == pointerType
|
||||||
|
&& func->isConst()
|
||||||
|
&& func->argumentCount() == 0) {
|
||||||
|
candidates << func;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Name *funcName = 0;
|
||||||
|
switch (candidates.size()) {
|
||||||
|
case 0:
|
||||||
|
return false;
|
||||||
|
case 1:
|
||||||
|
funcName = candidates.first()->name();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Multiple candidates - prefer a function named data
|
||||||
|
foreach (Function *func, candidates) {
|
||||||
|
if (!strcmp(func->name()->identifier()->chars(), "data")) {
|
||||||
|
funcName = func->name();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!funcName)
|
||||||
|
funcName = candidates.first()->name();
|
||||||
|
}
|
||||||
|
const Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
|
||||||
|
*objAccessFunction = QLatin1Char('.') + oo.prettyName(funcName) + QLatin1String("()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerType *determineConvertedType(NamedType *namedType, const LookupContext &context,
|
||||||
|
Scope *scope, QString *objAccessFunction)
|
||||||
|
{
|
||||||
|
if (!namedType)
|
||||||
|
return 0;
|
||||||
|
if (ClassOrNamespace *binding = context.lookupType(namedType->name(), scope)) {
|
||||||
|
if (Symbol *objectClassSymbol = skipForwardDeclarations(binding->symbols())) {
|
||||||
|
if (Class *klass = objectClassSymbol->asClass()) {
|
||||||
|
for (auto it = klass->memberBegin(), end = klass->memberEnd(); it != end; ++it) {
|
||||||
|
if (Function *func = (*it)->asFunction()) {
|
||||||
|
if (const ConversionNameId *conversionName =
|
||||||
|
func->name()->asConversionNameId()) {
|
||||||
|
if (PointerType *type = conversionName->type()->asPointerType()) {
|
||||||
|
if (findRawAccessFunction(klass, type, objAccessFunction))
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Class *senderOrReceiverClass(const CppQuickFixInterface &interface,
|
Class *senderOrReceiverClass(const CppQuickFixInterface &interface,
|
||||||
const CppRefactoringFilePtr &file,
|
const CppRefactoringFilePtr &file,
|
||||||
const ExpressionAST *objectPointerAST,
|
const ExpressionAST *objectPointerAST,
|
||||||
Scope *objectPointerScope)
|
Scope *objectPointerScope,
|
||||||
|
QString *objAccessFunction)
|
||||||
{
|
{
|
||||||
const LookupContext &context = interface.context();
|
const LookupContext &context = interface.context();
|
||||||
|
|
||||||
@@ -5602,6 +5667,10 @@ Class *senderOrReceiverClass(const CppQuickFixInterface &interface,
|
|||||||
QTC_ASSERT(objectPointerTypeBase, return 0);
|
QTC_ASSERT(objectPointerTypeBase, return 0);
|
||||||
|
|
||||||
PointerType *objectPointerType = objectPointerTypeBase->asPointerType();
|
PointerType *objectPointerType = objectPointerTypeBase->asPointerType();
|
||||||
|
if (!objectPointerType) {
|
||||||
|
objectPointerType = determineConvertedType(objectPointerTypeBase->asNamedType(), context,
|
||||||
|
objectPointerScope, objAccessFunction);
|
||||||
|
}
|
||||||
QTC_ASSERT(objectPointerType, return 0);
|
QTC_ASSERT(objectPointerType, return 0);
|
||||||
|
|
||||||
Type *objectTypeBase = objectPointerType->elementType().type(); // Dereference
|
Type *objectTypeBase = objectPointerType->elementType().type(); // Dereference
|
||||||
@@ -5624,7 +5693,8 @@ bool findConnectReplacement(const CppQuickFixInterface &interface,
|
|||||||
const ExpressionAST *objectPointerAST,
|
const ExpressionAST *objectPointerAST,
|
||||||
const QtMethodAST *methodAST,
|
const QtMethodAST *methodAST,
|
||||||
const CppRefactoringFilePtr &file,
|
const CppRefactoringFilePtr &file,
|
||||||
QString *replacement)
|
QString *replacement,
|
||||||
|
QString *objAccessFunction)
|
||||||
{
|
{
|
||||||
// Get name of method
|
// Get name of method
|
||||||
if (!methodAST->declarator || !methodAST->declarator->core_declarator)
|
if (!methodAST->declarator || !methodAST->declarator->core_declarator)
|
||||||
@@ -5640,7 +5710,8 @@ bool findConnectReplacement(const CppQuickFixInterface &interface,
|
|||||||
|
|
||||||
// Lookup object pointer type
|
// Lookup object pointer type
|
||||||
Scope *scope = file->scopeAt(methodAST->firstToken());
|
Scope *scope = file->scopeAt(methodAST->firstToken());
|
||||||
Class *objectClass = senderOrReceiverClass(interface, file, objectPointerAST, scope);
|
Class *objectClass = senderOrReceiverClass(interface, file, objectPointerAST, scope,
|
||||||
|
objAccessFunction);
|
||||||
QTC_ASSERT(objectClass, return false);
|
QTC_ASSERT(objectClass, return false);
|
||||||
|
|
||||||
// Look up member function in call, including base class members.
|
// Look up member function in call, including base class members.
|
||||||
@@ -5762,17 +5833,22 @@ void ConvertQt4Connect::match(const CppQuickFixInterface &interface, QuickFixOpe
|
|||||||
const CppRefactoringFilePtr file = interface.currentFile();
|
const CppRefactoringFilePtr file = interface.currentFile();
|
||||||
|
|
||||||
QString newSignal;
|
QString newSignal;
|
||||||
if (!findConnectReplacement(interface, arg1, arg2, file, &newSignal))
|
QString senderAccessFunc;
|
||||||
|
if (!findConnectReplacement(interface, arg1, arg2, file, &newSignal, &senderAccessFunc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
QString newMethod;
|
QString newMethod;
|
||||||
if (!findConnectReplacement(interface, arg3, arg4, file, &newMethod))
|
QString receiverAccessFunc;
|
||||||
|
if (!findConnectReplacement(interface, arg3, arg4, file, &newMethod, &receiverAccessFunc))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ChangeSet changes;
|
ChangeSet changes;
|
||||||
|
changes.replace(file->endOf(arg1), file->endOf(arg1), senderAccessFunc);
|
||||||
changes.replace(file->startOf(arg2), file->endOf(arg2), newSignal);
|
changes.replace(file->startOf(arg2), file->endOf(arg2), newSignal);
|
||||||
if (!arg3)
|
if (!arg3)
|
||||||
newMethod.prepend(QLatin1String("this, "));
|
newMethod.prepend(QLatin1String("this, "));
|
||||||
|
else
|
||||||
|
changes.replace(file->endOf(arg3), file->endOf(arg3), receiverAccessFunc);
|
||||||
changes.replace(file->startOf(arg4), file->endOf(arg4), newMethod);
|
changes.replace(file->startOf(arg4), file->endOf(arg4), newMethod);
|
||||||
|
|
||||||
result.append(new ConvertQt4ConnectOperation(interface, changes));
|
result.append(new ConvertQt4ConnectOperation(interface, changes));
|
||||||
|
Reference in New Issue
Block a user