diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 8a2a2ad3263..ee12f960b7f 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -608,6 +608,8 @@ void RewriteLogicalAnd::match(const CppQuickFixInterface &interface, QuickFixOpe QSharedPointer op(new RewriteLogicalAndOp(interface)); + ASTMatcher matcher; + if (expression->match(op->pattern, &matcher) && file->tokenAt(op->pattern->binary_op_token).is(T_AMPER_AMPER) && file->tokenAt(op->left->unary_op_token).is(T_EXCLAIM) && @@ -619,7 +621,7 @@ void RewriteLogicalAnd::match(const CppQuickFixInterface &interface, QuickFixOpe } } -bool SplitSimpleDeclaration::checkDeclaration(SimpleDeclarationAST *declaration) +static bool checkDeclarationForSplit(SimpleDeclarationAST *declaration) { if (!declaration->semicolon_token) return false; @@ -714,7 +716,7 @@ void SplitSimpleDeclaration::match(const CppQuickFixInterface &interface, if (CoreDeclaratorAST *coreDecl = node->asCoreDeclarator()) { core_declarator = coreDecl; } else if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) { - if (checkDeclaration(simpleDecl)) { + if (checkDeclarationForSplit(simpleDecl)) { SimpleDeclarationAST *declaration = simpleDecl; const int startOfDeclSpecifier = file->startOf(declaration->decl_specifier_list->firstToken()); @@ -1091,10 +1093,82 @@ void SplitIfStatement::match(const CppQuickFixInterface &interface, QuickFixOper /* Analze a string/character literal like "x", QLatin1String("x") and return the literal * (StringLiteral or NumericLiteral for characters) and its type * and the enclosing function (QLatin1String, tr...) */ -ExpressionAST *WrapStringLiteral::analyze(const QList &path, - const CppRefactoringFilePtr &file, Type *type, - QByteArray *enclosingFunction /* = 0 */, - CallAST **enclosingFunctionCall /* = 0 */) + +enum StringLiteralType { TypeString, TypeObjCString, TypeChar, TypeNone }; + +enum ActionFlags { + EncloseInQLatin1CharAction = 0x1, + EncloseInQLatin1StringAction = 0x2, + EncloseInQStringLiteralAction = 0x4, + EncloseActionMask = EncloseInQLatin1CharAction + | EncloseInQLatin1StringAction | EncloseInQStringLiteralAction, + TranslateTrAction = 0x8, + TranslateQCoreApplicationAction = 0x10, + TranslateNoopAction = 0x20, + TranslationMask = TranslateTrAction + | TranslateQCoreApplicationAction | TranslateNoopAction, + RemoveObjectiveCAction = 0x40, + ConvertEscapeSequencesToCharAction = 0x100, + ConvertEscapeSequencesToStringAction = 0x200, + SingleQuoteAction = 0x400, + DoubleQuoteAction = 0x800 +}; + + +/* Convert single-character string literals into character literals with some + * special cases "a" --> 'a', "'" --> '\'', "\n" --> '\n', "\"" --> '"'. */ +static QByteArray stringToCharEscapeSequences(const QByteArray &content) +{ + if (content.size() == 1) + return content.at(0) == '\'' ? QByteArray("\\'") : content; + if (content.size() == 2 && content.at(0) == '\\') + return content == "\\\"" ? QByteArray(1, '"') : content; + return QByteArray(); +} + +/* Convert character literal into a string literal with some special cases + * 'a' -> "a", '\n' -> "\n", '\'' --> "'", '"' --> "\"". */ +static QByteArray charToStringEscapeSequences(const QByteArray &content) +{ + if (content.size() == 1) + return content.at(0) == '"' ? QByteArray("\\\"") : content; + if (content.size() == 2) + return content == "\\'" ? QByteArray("'") : content; + return QByteArray(); +} + +static QString msgQtStringLiteralDescription(const QString &replacement, int qtVersion) +{ + return QApplication::translate("CppTools::QuickFix", "Enclose in %1(...) (Qt %2)") + .arg(replacement).arg(qtVersion); +} + +static QString msgQtStringLiteralDescription(const QString &replacement) +{ + return QApplication::translate("CppTools::QuickFix", "Enclose in %1(...)").arg(replacement); +} + +static QString stringLiteralReplacement(unsigned actions) +{ + if (actions & EncloseInQLatin1CharAction) + return QLatin1String("QLatin1Char"); + if (actions & EncloseInQLatin1StringAction) + return QLatin1String("QLatin1String"); + if (actions & EncloseInQStringLiteralAction) + return QLatin1String("QStringLiteral"); + if (actions & TranslateTrAction) + return QLatin1String("tr"); + if (actions & TranslateQCoreApplicationAction) + return QLatin1String("QCoreApplication::translate"); + if (actions & TranslateNoopAction) + return QLatin1String("QT_TRANSLATE_NOOP"); + return QString(); +} + +static ExpressionAST *analyzeStringLiteral(const QList &path, + const CppRefactoringFilePtr &file, StringLiteralType *type, + QByteArray *enclosingFunction = nullptr, + CallAST **enclosingFunctionCall = nullptr) { *type = TypeNone; if (enclosingFunction) @@ -1140,8 +1214,6 @@ namespace { class WrapStringLiteralOp : public CppQuickFixOperation { public: - typedef WrapStringLiteral Factory; - WrapStringLiteralOp(const CppQuickFixInterface &interface, int priority, unsigned actions, const QString &description, ExpressionAST *literal, const QString &translationContext = QString()) @@ -1162,46 +1234,46 @@ public: const int endPos = currentFile->endOf(m_literal); // kill leading '@'. No need to adapt endPos, that is done by ChangeSet - if (m_actions & Factory::RemoveObjectiveCAction) + if (m_actions & RemoveObjectiveCAction) changes.remove(startPos, startPos + 1); // Fix quotes - if (m_actions & (Factory::SingleQuoteAction | Factory::DoubleQuoteAction)) { - const QString newQuote((m_actions & Factory::SingleQuoteAction) + if (m_actions & (SingleQuoteAction | DoubleQuoteAction)) { + const QString newQuote((m_actions & SingleQuoteAction) ? QLatin1Char('\'') : QLatin1Char('"')); changes.replace(startPos, startPos + 1, newQuote); changes.replace(endPos - 1, endPos, newQuote); } // Convert single character strings into character constants - if (m_actions & Factory::ConvertEscapeSequencesToCharAction) { + if (m_actions & ConvertEscapeSequencesToCharAction) { StringLiteralAST *stringLiteral = m_literal->asStringLiteral(); QTC_ASSERT(stringLiteral, return ;); const QByteArray oldContents(currentFile->tokenAt(stringLiteral->literal_token).identifier->chars()); - const QByteArray newContents = Factory::stringToCharEscapeSequences(oldContents); + const QByteArray newContents = stringToCharEscapeSequences(oldContents); QTC_ASSERT(!newContents.isEmpty(), return ;); if (oldContents != newContents) changes.replace(startPos + 1, endPos -1, QString::fromLatin1(newContents)); } // Convert character constants into strings constants - if (m_actions & Factory::ConvertEscapeSequencesToStringAction) { + if (m_actions & ConvertEscapeSequencesToStringAction) { NumericLiteralAST *charLiteral = m_literal->asNumericLiteral(); // char 'c' constants are numerical. QTC_ASSERT(charLiteral, return ;); const QByteArray oldContents(currentFile->tokenAt(charLiteral->literal_token).identifier->chars()); - const QByteArray newContents = Factory::charToStringEscapeSequences(oldContents); + const QByteArray newContents = charToStringEscapeSequences(oldContents); QTC_ASSERT(!newContents.isEmpty(), return ;); if (oldContents != newContents) changes.replace(startPos + 1, endPos -1, QString::fromLatin1(newContents)); } // Enclose in literal or translation function, macro. - if (m_actions & (Factory::EncloseActionMask | Factory::TranslationMask)) { + if (m_actions & (EncloseActionMask | TranslationMask)) { changes.insert(endPos, QString(QLatin1Char(')'))); - QString leading = Factory::replacement(m_actions); + QString leading = stringLiteralReplacement(m_actions); leading += QLatin1Char('('); if (m_actions - & (Factory::TranslateQCoreApplicationAction | Factory::TranslateNoopAction)) { + & (TranslateQCoreApplicationAction | TranslateNoopAction)) { leading += QLatin1Char('"'); leading += m_translationContext; leading += QLatin1String("\", "); @@ -1223,11 +1295,11 @@ private: void WrapStringLiteral::match(const CppQuickFixInterface &interface, QuickFixOperations &result) { - Type type = TypeNone; + StringLiteralType type = TypeNone; QByteArray enclosingFunction; const QList &path = interface.path(); CppRefactoringFilePtr file = interface.currentFile(); - ExpressionAST *literal = analyze(path, file, &type, &enclosingFunction); + ExpressionAST *literal = analyzeStringLiteral(path, file, &type, &enclosingFunction); if (!literal || type == TypeNone) return; if ((type == TypeChar && enclosingFunction == "QLatin1Char") @@ -1238,7 +1310,7 @@ void WrapStringLiteral::match(const CppQuickFixInterface &interface, QuickFixOpe const int priority = path.size() - 1; // very high priority if (type == TypeChar) { unsigned actions = EncloseInQLatin1CharAction; - QString description = msgQtStringLiteralDescription(replacement(actions)); + QString description = msgQtStringLiteralDescription(stringLiteralReplacement(actions)); result << new WrapStringLiteralOp(interface, priority, actions, description, literal); if (NumericLiteralAST *charLiteral = literal->asNumericLiteral()) { const QByteArray contents(file->tokenAt(charLiteral->literal_token).identifier->chars()); @@ -1272,74 +1344,23 @@ void WrapStringLiteral::match(const CppQuickFixInterface &interface, QuickFixOpe } actions = EncloseInQLatin1StringAction | objectiveCActions; result << new WrapStringLiteralOp(interface, priority, actions, - msgQtStringLiteralDescription(replacement(actions), 4), literal); + msgQtStringLiteralDescription(stringLiteralReplacement(actions), 4), literal); actions = EncloseInQStringLiteralAction | objectiveCActions; result << new WrapStringLiteralOp(interface, priority, actions, - msgQtStringLiteralDescription(replacement(actions), 5), literal); + msgQtStringLiteralDescription(stringLiteralReplacement(actions), 5), literal); } } -QString WrapStringLiteral::replacement(unsigned actions) -{ - if (actions & EncloseInQLatin1CharAction) - return QLatin1String("QLatin1Char"); - if (actions & EncloseInQLatin1StringAction) - return QLatin1String("QLatin1String"); - if (actions & EncloseInQStringLiteralAction) - return QLatin1String("QStringLiteral"); - if (actions & TranslateTrAction) - return QLatin1String("tr"); - if (actions & TranslateQCoreApplicationAction) - return QLatin1String("QCoreApplication::translate"); - if (actions & TranslateNoopAction) - return QLatin1String("QT_TRANSLATE_NOOP"); - return QString(); -} - -/* Convert single-character string literals into character literals with some - * special cases "a" --> 'a', "'" --> '\'', "\n" --> '\n', "\"" --> '"'. */ -QByteArray WrapStringLiteral::stringToCharEscapeSequences(const QByteArray &content) -{ - if (content.size() == 1) - return content.at(0) == '\'' ? QByteArray("\\'") : content; - if (content.size() == 2 && content.at(0) == '\\') - return content == "\\\"" ? QByteArray(1, '"') : content; - return QByteArray(); -} - -/* Convert character literal into a string literal with some special cases - * 'a' -> "a", '\n' -> "\n", '\'' --> "'", '"' --> "\"". */ -QByteArray WrapStringLiteral::charToStringEscapeSequences(const QByteArray &content) -{ - if (content.size() == 1) - return content.at(0) == '"' ? QByteArray("\\\"") : content; - if (content.size() == 2) - return content == "\\'" ? QByteArray("'") : content; - return QByteArray(); -} - -inline QString WrapStringLiteral::msgQtStringLiteralDescription(const QString &replacement, - int qtVersion) -{ - return QApplication::translate("CppTools::QuickFix", "Enclose in %1(...) (Qt %2)") - .arg(replacement).arg(qtVersion); -} - -inline QString WrapStringLiteral::msgQtStringLiteralDescription(const QString &replacement) -{ - return QApplication::translate("CppTools::QuickFix", "Enclose in %1(...)").arg(replacement); -} - void TranslateStringLiteral::match(const CppQuickFixInterface &interface, QuickFixOperations &result) { // Initialize - WrapStringLiteral::Type type = WrapStringLiteral::TypeNone; + StringLiteralType type = TypeNone; QByteArray enclosingFunction; const QList &path = interface.path(); CppRefactoringFilePtr file = interface.currentFile(); - ExpressionAST *literal = WrapStringLiteral::analyze(path, file, &type, &enclosingFunction); - if (!literal || type != WrapStringLiteral::TypeString + ExpressionAST *literal = analyzeStringLiteral(path, file, &type, &enclosingFunction); + if (!literal || type != TypeString || isQtStringLiteral(enclosingFunction) || isQtStringTranslation(enclosingFunction)) return; @@ -1361,7 +1382,7 @@ void TranslateStringLiteral::match(const CppQuickFixInterface &interface, if (s->type()->isFunctionType()) { // no context required for tr result << new WrapStringLiteralOp(interface, path.size() - 1, - WrapStringLiteral::TranslateTrAction, + TranslateTrAction, description, literal); return; } @@ -1379,7 +1400,7 @@ void TranslateStringLiteral::match(const CppQuickFixInterface &interface, if (trContext.isEmpty()) trContext = QLatin1String("GLOBAL"); result << new WrapStringLiteralOp(interface, path.size() - 1, - WrapStringLiteral::TranslateQCoreApplicationAction, + TranslateQCoreApplicationAction, description, literal, trContext); return; } @@ -1387,7 +1408,7 @@ void TranslateStringLiteral::match(const CppQuickFixInterface &interface, // We need to use Q_TRANSLATE_NOOP result << new WrapStringLiteralOp(interface, path.size() - 1, - WrapStringLiteral::TranslateNoopAction, + TranslateNoopAction, description, literal, trContext); } @@ -1440,13 +1461,13 @@ void ConvertCStringToNSString::match(const CppQuickFixInterface &interface, if (!interface.editor()->cppEditorDocument()->isObjCEnabled()) return; - WrapStringLiteral::Type type = WrapStringLiteral::TypeNone; + StringLiteralType type = TypeNone; QByteArray enclosingFunction; CallAST *qlatin1Call; const QList &path = interface.path(); - ExpressionAST *literal = WrapStringLiteral::analyze(path, file, &type, &enclosingFunction, - &qlatin1Call); - if (!literal || type != WrapStringLiteral::TypeString) + ExpressionAST *literal = analyzeStringLiteral(path, file, &type, &enclosingFunction, + &qlatin1Call); + if (!literal || type != TypeString) return; if (!isQtStringLiteral(enclosingFunction)) qlatin1Call = 0; @@ -2310,7 +2331,7 @@ public: QStringList values; }; -Enum *findEnum(const QList &results, const LookupContext &ctxt) +static Enum *findEnum(const QList &results, const LookupContext &ctxt) { foreach (const LookupItem &result, results) { const FullySpecifiedType fst = result.type(); diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h index 59fae927382..5cbcd17e9a2 100644 --- a/src/plugins/cppeditor/cppquickfixes.h +++ b/src/plugins/cppeditor/cppquickfixes.h @@ -128,9 +128,6 @@ class RewriteLogicalAnd: public CppQuickFixFactory { public: void match(const CppQuickFixInterface &interface, QuickFixOperations &result) override; - -private: - ASTMatcher matcher; }; /*! @@ -213,40 +210,7 @@ public: class WrapStringLiteral: public CppQuickFixFactory { public: - enum ActionFlags { - EncloseInQLatin1CharAction = 0x1, - EncloseInQLatin1StringAction = 0x2, - EncloseInQStringLiteralAction = 0x4, - EncloseActionMask = EncloseInQLatin1CharAction - | EncloseInQLatin1StringAction | EncloseInQStringLiteralAction, - TranslateTrAction = 0x8, - TranslateQCoreApplicationAction = 0x10, - TranslateNoopAction = 0x20, - TranslationMask = TranslateTrAction - | TranslateQCoreApplicationAction | TranslateNoopAction, - RemoveObjectiveCAction = 0x40, - ConvertEscapeSequencesToCharAction = 0x100, - ConvertEscapeSequencesToStringAction = 0x200, - SingleQuoteAction = 0x400, - DoubleQuoteAction = 0x800 - }; - - enum Type { TypeString, TypeObjCString, TypeChar, TypeNone }; - void match(const CppQuickFixInterface &interface, QuickFixOperations &result) override; - - static QString replacement(unsigned actions); - static QByteArray stringToCharEscapeSequences(const QByteArray &content); - static QByteArray charToStringEscapeSequences(const QByteArray &content); - - static ExpressionAST *analyze(const QList &path, const CppRefactoringFilePtr &file, - Type *type, - QByteArray *enclosingFunction = 0, - CallAST **enclosingFunctionCall = 0); - -private: - static QString msgQtStringLiteralDescription(const QString &replacement, int qtVersion); - static QString msgQtStringLiteralDescription(const QString &replacement); }; /*! @@ -336,9 +300,6 @@ class SplitSimpleDeclaration: public CppQuickFixFactory { public: void match(const CppQuickFixInterface &interface, QuickFixOperations &result) override; - -private: - static bool checkDeclaration(SimpleDeclarationAST *declaration); }; /*!