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>
This commit is contained in:
hjk
2017-12-18 16:56:50 +01:00
parent 915d5cf259
commit 0e687d6a4f
2 changed files with 106 additions and 124 deletions

View File

@@ -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,
ExpressionAST *literal = analyzeStringLiteral(path, file, &type, &enclosingFunction,
&qlatin1Call);
if (!literal || type != WrapStringLiteral::TypeString)
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();

View File

@@ -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<AST *> &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);
};
/*!