diff options
| author | Christian Kamm <[email protected]> | 2010-01-08 15:19:54 +0100 |
|---|---|---|
| committer | Christian Kamm <[email protected]> | 2010-01-08 15:24:23 +0100 |
| commit | a298759defb66a2a81dcb12efa96418b0ba374b6 (patch) | |
| tree | db286922dd6fe0c3a39b694b9208d0bdd445c5dd | |
| parent | bcfb9d2385b1d2aadc6490149603ae1f46f8625d (diff) | |
Quickfix: Add one that replaces + with % for strings.
Reviewed-by: Roberto Raggi <[email protected]>
| -rw-r--r-- | src/plugins/cppeditor/cppquickfix.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/src/plugins/cppeditor/cppquickfix.cpp b/src/plugins/cppeditor/cppquickfix.cpp index 82c122033a0..4be8afe773c 100644 --- a/src/plugins/cppeditor/cppquickfix.cpp +++ b/src/plugins/cppeditor/cppquickfix.cpp @@ -39,6 +39,12 @@ #include <ASTPatternBuilder.h> #include <ASTMatcher.h> #include <Token.h> +#include <Type.h> +#include <CoreTypes.h> +#include <Symbol.h> +#include <Symbols.h> +#include <Name.h> +#include <Literals.h> #include <cpptools/cppmodelmanagerinterface.h> #include <QtDebug> @@ -899,6 +905,165 @@ private: PostfixExpressionAST *qlatin1Call; }; +/* + Replace + a + b + With + a % b + If a and b are of string type. +*/ +class UseFastStringConcatenation: public QuickFixOperation +{ +public: + UseFastStringConcatenation() + {} + + virtual QString description() const + { + return QLatin1String("Use fast string concatenation with %"); // ### tr? + } + + virtual int match(const QList<AST *> &path) + { + if (path.isEmpty()) + return -1; + + // need to search 'up' too + int index = path.size() - 1; + if (BinaryExpressionAST *binary = asPlusNode(path[index])) { + while (0 != (binary = asPlusNode(binary->left_expression))) + _binaryExpressions.prepend(binary); + } + + // search 'down' + for (index = path.size() - 1; index != -1; --index) { + AST *node = path.at(index); + if (BinaryExpressionAST *binary = asPlusNode(node)) { + _binaryExpressions.append(binary); + } else if (! _binaryExpressions.isEmpty()) { + break; + } + } + + if (_binaryExpressions.isEmpty()) + return -1; + + // verify types of arguments + BinaryExpressionAST *prevBinary = 0; + foreach (BinaryExpressionAST *binary, _binaryExpressions) { + if (binary->left_expression != prevBinary) { + if (!hasCorrectType(binary->left_expression)) + return -1; + } + if (binary->right_expression != prevBinary) { + if (!hasCorrectType(binary->right_expression)) + return -1; + } + prevBinary = binary; + } + + return index + _binaryExpressions.size(); + } + + virtual void createChangeSet() + { + // replace + -> % + foreach (BinaryExpressionAST *binary, _binaryExpressions) + replace(binary->binary_op_token, "%"); + + // wrap literals in QLatin1Literal + foreach (StringLiteralAST *literal, _stringLiterals) { + insert(startOf(literal), "QLatin1Literal("); + insert(endOf(literal), ")"); + } + + // replace QLatin1String/QString/QByteArray(literal) -> QLatin1Literal(literal) + foreach (PostfixExpressionAST *postfix, _incorrectlyWrappedLiterals) { + replace(postfix->base_expression, "QLatin1Literal"); + } + } + + BinaryExpressionAST *asPlusNode(AST *ast) + { + BinaryExpressionAST *binary = ast->asBinaryExpression(); + if (binary && tokenAt(binary->binary_op_token).kind() == T_PLUS) + return binary; + return 0; + } + + bool hasCorrectType(ExpressionAST *ast) + { + if (StringLiteralAST *literal = ast->asStringLiteral()) { + _stringLiterals += literal; + return true; + } + + if (PostfixExpressionAST *postfix = ast->asPostfixExpression()) { + if (postfix->base_expression && postfix->postfix_expression_list + && postfix->postfix_expression_list->value + && !postfix->postfix_expression_list->next) + { + NameAST *name = postfix->base_expression->asName(); + CallAST *call = postfix->postfix_expression_list->value->asCall(); + if (name && call) { + QByteArray nameStr(name->name->identifier()->chars()); + if ((nameStr == "QLatin1String" + || nameStr == "QString" + || nameStr == "QByteArray") + && call->expression_list + && call->expression_list->value + && call->expression_list->value->asStringLiteral() + && !call->expression_list->next) + { + _incorrectlyWrappedLiterals += postfix; + return true; + } + } + } + } + + const QList<LookupItem> &lookup = typeOf(ast); + if (lookup.isEmpty()) + return false; + return isQtStringType(lookup[0].type()); + } + + bool isBuiltinStringType(FullySpecifiedType type) + { + // char* + if (PointerType *ptrTy = type->asPointerType()) + if (IntegerType *intTy = ptrTy->elementType()->asIntegerType()) + if (intTy->kind() == IntegerType::Char) + return true; + return false; + } + + bool isQtStringType(FullySpecifiedType type) + { + if (NamedType *nameTy = type->asNamedType()) { + if (!nameTy->name() || !nameTy->name()->identifier()) + return false; + + QByteArray name(nameTy->name()->identifier()->chars()); + if (name == "QString" + || name == "QByteArray" + || name == "QLatin1String" + || name == "QLatin1Literal" + || name == "QStringRef" + || name == "QChar" + ) + return true; + } + + return false; + } + +private: + QList<BinaryExpressionAST *> _binaryExpressions; + QList<StringLiteralAST *> _stringLiterals; + QList<PostfixExpressionAST *> _incorrectlyWrappedLiterals; +}; + } // end of anonymous namespace @@ -1211,6 +1376,7 @@ int CPPQuickFixCollector::startCompletion(TextEditor::ITextEditable *editable) QSharedPointer<FlipBinaryOp> flipBinaryOp(new FlipBinaryOp()); QSharedPointer<WrapStringLiteral> wrapStringLiteral(new WrapStringLiteral()); QSharedPointer<CStringToNSString> wrapCString(new CStringToNSString()); + QSharedPointer<UseFastStringConcatenation> useFastStringConcat(new UseFastStringConcatenation()); QList<QuickFixOperationPtr> candidates; candidates.append(rewriteLogicalAndOp); @@ -1223,6 +1389,7 @@ int CPPQuickFixCollector::startCompletion(TextEditor::ITextEditable *editable) candidates.append(flipBinaryOp); candidates.append(wrapStringLiteral); candidates.append(wrapCString); + candidates.append(useFastStringConcat); QMap<int, QList<QuickFixOperationPtr> > matchedOps; |
