forked from qt-creator/qt-creator
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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user