diff options
author | hjk <hjk@qt.io> | 2017-12-18 16:56:50 +0100 |
---|---|---|
committer | hjk <hjk@qt.io> | 2018-01-03 07:36:11 +0000 |
commit | 0e687d6a4f8ccbacdeefc43c7ecdbbc3d7814a82 (patch) | |
tree | efb8116e3f9e3e783bb91471a0025a8749c9d63b /src/plugins/cppeditor/cppquickfixes.cpp | |
parent | 915d5cf259fd8e03a30af5f72e92ddfed58930ea (diff) |
CppEditor: Normalize WrapStringLiteral and RewriteLogicalAnd interface
Slims down publicly visible interface and could be one step towards
replacing the CppQuickFixFactory derived classes by plain
stand-alone functions.
Change-Id: I9c6a8bcbd8481e14fb21dd41b11a1e6153a35e4b
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@qt.io>
Diffstat (limited to 'src/plugins/cppeditor/cppquickfixes.cpp')
-rw-r--r-- | src/plugins/cppeditor/cppquickfixes.cpp | 191 |
1 files changed, 106 insertions, 85 deletions
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<RewriteLogicalAndOp> 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<AST *> &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<AST *> &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<AST *> &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<AST *> &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<AST *> &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<LookupItem> &results, const LookupContext &ctxt) +static Enum *findEnum(const QList<LookupItem> &results, const LookupContext &ctxt) { foreach (const LookupItem &result, results) { const FullySpecifiedType fst = result.type(); |