forked from qt-creator/qt-creator
CppEditor: make convert from/to pointer aware of auto
Change-Id: Ic378ea1f7fc58fdb9351c9eaa9e9602e568d5ac9 Task-number: QTCREATORBUG-13605 Reviewed-by: Robert Loehning <robert.loehning@theqtcompany.com> Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
@@ -1497,6 +1497,57 @@ void CppEditorPlugin::test_quickfix_data()
|
|||||||
" f1(*str);\n"
|
" f1(*str);\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
|
|
||||||
|
QTest::newRow("ConvertAutoFromPointer")
|
||||||
|
<< CppQuickFixFactoryPtr(new ConvertFromAndToPointer)
|
||||||
|
<< _("void foo() {\n"
|
||||||
|
" auto @str = new QString(QLatin1String(\"foo\"));\n"
|
||||||
|
" if (!str->isEmpty())\n"
|
||||||
|
" str->clear();\n"
|
||||||
|
" f1(*str);\n"
|
||||||
|
" f2(str);\n"
|
||||||
|
"}\n")
|
||||||
|
<< _("void foo() {\n"
|
||||||
|
" auto str = QString(QLatin1String(\"foo\"));\n"
|
||||||
|
" if (!str.isEmpty())\n"
|
||||||
|
" str.clear();\n"
|
||||||
|
" f1(str);\n"
|
||||||
|
" f2(&str);\n"
|
||||||
|
"}\n");
|
||||||
|
|
||||||
|
QTest::newRow("ConvertAutoFromPointer2")
|
||||||
|
<< CppQuickFixFactoryPtr(new ConvertFromAndToPointer)
|
||||||
|
<< _("void foo() {\n"
|
||||||
|
" auto *@str = new QString;\n"
|
||||||
|
" if (!str->isEmpty())\n"
|
||||||
|
" str->clear();\n"
|
||||||
|
" f1(*str);\n"
|
||||||
|
" f2(str);\n"
|
||||||
|
"}\n")
|
||||||
|
<< _("void foo() {\n"
|
||||||
|
" auto str = QString();\n"
|
||||||
|
" if (!str.isEmpty())\n"
|
||||||
|
" str.clear();\n"
|
||||||
|
" f1(str);\n"
|
||||||
|
" f2(&str);\n"
|
||||||
|
"}\n");
|
||||||
|
|
||||||
|
QTest::newRow("ConvertAutoToPointer")
|
||||||
|
<< CppQuickFixFactoryPtr(new ConvertFromAndToPointer)
|
||||||
|
<< _("void foo() {\n"
|
||||||
|
" auto @str = QString(QLatin1String(\"foo\"));\n"
|
||||||
|
" if (!str.isEmpty())\n"
|
||||||
|
" str.clear();\n"
|
||||||
|
" f1(str);\n"
|
||||||
|
" f2(&str);\n"
|
||||||
|
"}\n")
|
||||||
|
<< _("void foo() {\n"
|
||||||
|
" auto @str = new QString(QLatin1String(\"foo\"));\n"
|
||||||
|
" if (!str->isEmpty())\n"
|
||||||
|
" str->clear();\n"
|
||||||
|
" f1(*str);\n"
|
||||||
|
" f2(str);\n"
|
||||||
|
"}\n");
|
||||||
|
|
||||||
QTest::newRow("InsertQtPropertyMembers_noTriggerInvalidCode")
|
QTest::newRow("InsertQtPropertyMembers_noTriggerInvalidCode")
|
||||||
<< CppQuickFixFactoryPtr(new InsertQtPropertyMembers)
|
<< CppQuickFixFactoryPtr(new InsertQtPropertyMembers)
|
||||||
<< _("class C { @Q_PROPERTY(typeid foo READ foo) };\n")
|
<< _("class C { @Q_PROPERTY(typeid foo READ foo) };\n")
|
||||||
|
|||||||
@@ -3862,12 +3862,14 @@ public:
|
|||||||
enum Mode { FromPointer, FromVariable, FromReference };
|
enum Mode { FromPointer, FromVariable, FromReference };
|
||||||
|
|
||||||
ConvertFromAndToPointerOp(const CppQuickFixInterface &interface, int priority, Mode mode,
|
ConvertFromAndToPointerOp(const CppQuickFixInterface &interface, int priority, Mode mode,
|
||||||
|
bool isAutoDeclaration,
|
||||||
const SimpleDeclarationAST *simpleDeclaration,
|
const SimpleDeclarationAST *simpleDeclaration,
|
||||||
const DeclaratorAST *declaratorAST,
|
const DeclaratorAST *declaratorAST,
|
||||||
const SimpleNameAST *identifierAST,
|
const SimpleNameAST *identifierAST,
|
||||||
Symbol *symbol)
|
Symbol *symbol)
|
||||||
: CppQuickFixOperation(interface, priority)
|
: CppQuickFixOperation(interface, priority)
|
||||||
, m_mode(mode)
|
, m_mode(mode)
|
||||||
|
, m_isAutoDeclaration(isAutoDeclaration)
|
||||||
, m_simpleDeclaration(simpleDeclaration)
|
, m_simpleDeclaration(simpleDeclaration)
|
||||||
, m_declaratorAST(declaratorAST)
|
, m_declaratorAST(declaratorAST)
|
||||||
, m_identifierAST(identifierAST)
|
, m_identifierAST(identifierAST)
|
||||||
@@ -3906,6 +3908,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
void removePointerOperator(ChangeSet &changes) const
|
void removePointerOperator(ChangeSet &changes) const
|
||||||
{
|
{
|
||||||
|
if (!m_declaratorAST->ptr_operator_list)
|
||||||
|
return;
|
||||||
PointerAST *ptrAST = m_declaratorAST->ptr_operator_list->value->asPointer();
|
PointerAST *ptrAST = m_declaratorAST->ptr_operator_list->value->asPointer();
|
||||||
QTC_ASSERT(ptrAST, return);
|
QTC_ASSERT(ptrAST, return);
|
||||||
const int pos = m_file->startOf(ptrAST->star_token);
|
const int pos = m_file->startOf(ptrAST->star_token);
|
||||||
@@ -3942,12 +3946,26 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void removeNewKeyword(ChangeSet &changes, NewExpressionAST *newExprAST) const
|
||||||
|
{
|
||||||
|
// remove 'new' keyword before initializer
|
||||||
|
changes.remove(m_file->startOf(newExprAST->new_token),
|
||||||
|
m_file->startOf(newExprAST->new_type_id));
|
||||||
|
}
|
||||||
|
|
||||||
void convertToStackVariable(ChangeSet &changes) const
|
void convertToStackVariable(ChangeSet &changes) const
|
||||||
{
|
{
|
||||||
// Handle the initializer.
|
// Handle the initializer.
|
||||||
if (m_declaratorAST->initializer) {
|
if (m_declaratorAST->initializer) {
|
||||||
if (NewExpressionAST *newExpression = m_declaratorAST->initializer->asNewExpression())
|
if (NewExpressionAST *newExpression = m_declaratorAST->initializer->asNewExpression()) {
|
||||||
removeNewExpression(changes, newExpression);
|
if (m_isAutoDeclaration) {
|
||||||
|
if (!newExpression->new_initializer)
|
||||||
|
changes.insert(m_file->endOf(newExpression), QStringLiteral("()"));
|
||||||
|
removeNewKeyword(changes, newExpression);
|
||||||
|
} else {
|
||||||
|
removeNewExpression(changes, newExpression);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix all occurrences of the identifier in this function.
|
// Fix all occurrences of the identifier in this function.
|
||||||
@@ -3955,10 +3973,15 @@ private:
|
|||||||
foreach (const SemanticInfo::Use &use, semanticInfo().localUses.value(m_symbol)) {
|
foreach (const SemanticInfo::Use &use, semanticInfo().localUses.value(m_symbol)) {
|
||||||
const QList<AST *> path = astPath(use.line, use.column);
|
const QList<AST *> path = astPath(use.line, use.column);
|
||||||
AST *idAST = path.last();
|
AST *idAST = path.last();
|
||||||
|
bool declarationFound = false;
|
||||||
bool starFound = false;
|
bool starFound = false;
|
||||||
int ampersandPos = 0;
|
int ampersandPos = 0;
|
||||||
bool memberAccess = false;
|
bool memberAccess = false;
|
||||||
for (int i = path.count() - 2; i >= 0; --i) {
|
for (int i = path.count() - 2; i >= 0; --i) {
|
||||||
|
if (path.at(i) == m_declaratorAST) {
|
||||||
|
declarationFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (MemberAccessAST *memberAccessAST = path.at(i)->asMemberAccess()) {
|
if (MemberAccessAST *memberAccessAST = path.at(i)->asMemberAccess()) {
|
||||||
if (m_file->tokenAt(memberAccessAST->access_token).kind() != T_ARROW)
|
if (m_file->tokenAt(memberAccessAST->access_token).kind() != T_ARROW)
|
||||||
continue;
|
continue;
|
||||||
@@ -3987,7 +4010,7 @@ private:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!starFound && !memberAccess) {
|
if (!declarationFound && !starFound && !memberAccess) {
|
||||||
if (ampersandPos) {
|
if (ampersandPos) {
|
||||||
changes.insert(ampersandPos, QLatin1String("&("));
|
changes.insert(ampersandPos, QLatin1String("&("));
|
||||||
changes.insert(m_file->endOf(idAST->firstToken()), QLatin1String(")"));
|
changes.insert(m_file->endOf(idAST->firstToken()), QLatin1String(")"));
|
||||||
@@ -4017,11 +4040,13 @@ private:
|
|||||||
void insertNewExpression(ChangeSet &changes, CallAST *callAST) const
|
void insertNewExpression(ChangeSet &changes, CallAST *callAST) const
|
||||||
{
|
{
|
||||||
const QString typeName = typeNameOfDeclaration();
|
const QString typeName = typeNameOfDeclaration();
|
||||||
if (typeName.isEmpty())
|
if (typeName.isEmpty()) {
|
||||||
return;
|
changes.insert(m_file->startOf(callAST), QLatin1String("new "));
|
||||||
changes.insert(m_file->startOf(callAST),
|
} else {
|
||||||
QLatin1String("new ") + typeName + QLatin1Char('('));
|
changes.insert(m_file->startOf(callAST),
|
||||||
changes.insert(m_file->startOf(callAST->lastToken()), QLatin1String(")"));
|
QLatin1String("new ") + typeName + QLatin1Char('('));
|
||||||
|
changes.insert(m_file->startOf(callAST->lastToken()), QLatin1String(")"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertNewExpression(ChangeSet &changes, ExpressionListParenAST *exprListAST) const
|
void insertNewExpression(ChangeSet &changes, ExpressionListParenAST *exprListAST) const
|
||||||
@@ -4054,6 +4079,10 @@ private:
|
|||||||
AST *idAST = path.last();
|
AST *idAST = path.last();
|
||||||
bool insertStar = true;
|
bool insertStar = true;
|
||||||
for (int i = path.count() - 2; i >= 0; --i) {
|
for (int i = path.count() - 2; i >= 0; --i) {
|
||||||
|
if (m_isAutoDeclaration && path.at(i) == m_declaratorAST) {
|
||||||
|
insertStar = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (MemberAccessAST *memberAccessAST = path.at(i)->asMemberAccess()) {
|
if (MemberAccessAST *memberAccessAST = path.at(i)->asMemberAccess()) {
|
||||||
const int pos = m_file->startOf(memberAccessAST->access_token);
|
const int pos = m_file->startOf(memberAccessAST->access_token);
|
||||||
changes.replace(pos, pos + 1, QLatin1String("->"));
|
changes.replace(pos, pos + 1, QLatin1String("->"));
|
||||||
@@ -4076,6 +4105,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Mode m_mode;
|
const Mode m_mode;
|
||||||
|
const bool m_isAutoDeclaration;
|
||||||
const SimpleDeclarationAST * const m_simpleDeclaration;
|
const SimpleDeclarationAST * const m_simpleDeclaration;
|
||||||
const DeclaratorAST * const m_declaratorAST;
|
const DeclaratorAST * const m_declaratorAST;
|
||||||
const SimpleNameAST * const m_identifierAST;
|
const SimpleNameAST * const m_identifierAST;
|
||||||
@@ -4129,7 +4159,23 @@ void ConvertFromAndToPointer::match(const CppQuickFixInterface &interface,
|
|||||||
if (!symbol)
|
if (!symbol)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (declarator->ptr_operator_list) {
|
bool isAutoDeclaration = false;
|
||||||
|
if (symbol->storage() == Symbol::Auto) {
|
||||||
|
// For auto variables we must deduce the type from the initializer.
|
||||||
|
if (!declarator->initializer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
isAutoDeclaration = true;
|
||||||
|
TypeOfExpression typeOfExpression;
|
||||||
|
typeOfExpression.init(interface.semanticInfo().doc, interface.snapshot());
|
||||||
|
typeOfExpression.setExpandTemplates(true);
|
||||||
|
CppRefactoringFilePtr file = interface.currentFile();
|
||||||
|
Scope *scope = file->scopeAt(declarator->firstToken());
|
||||||
|
QList<LookupItem> result = typeOfExpression(file->textOf(declarator->initializer).toUtf8(),
|
||||||
|
scope, TypeOfExpression::Preprocess);
|
||||||
|
if (!result.isEmpty() && result.first().type()->isPointerType())
|
||||||
|
mode = ConvertFromAndToPointerOp::FromPointer;
|
||||||
|
} else if (declarator->ptr_operator_list) {
|
||||||
for (PtrOperatorListAST *ops = declarator->ptr_operator_list; ops; ops = ops->next) {
|
for (PtrOperatorListAST *ops = declarator->ptr_operator_list; ops; ops = ops->next) {
|
||||||
if (ops != declarator->ptr_operator_list) {
|
if (ops != declarator->ptr_operator_list) {
|
||||||
// Bail out on more complex pointer types (e.g. pointer of pointer,
|
// Bail out on more complex pointer types (e.g. pointer of pointer,
|
||||||
@@ -4144,8 +4190,8 @@ void ConvertFromAndToPointer::match(const CppQuickFixInterface &interface,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int priority = path.size() - 1;
|
const int priority = path.size() - 1;
|
||||||
result.append(new ConvertFromAndToPointerOp(interface, priority, mode, simpleDeclaration,
|
result.append(new ConvertFromAndToPointerOp(interface, priority, mode, isAutoDeclaration,
|
||||||
declarator, identifier, symbol));
|
simpleDeclaration, declarator, identifier, symbol));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
Reference in New Issue
Block a user