diff options
author | Sergio Martins <iamsergio@gmail.com> | 2017-12-03 18:05:38 +0000 |
---|---|---|
committer | Sergio Martins <iamsergio@gmail.com> | 2017-12-03 18:10:19 +0000 |
commit | 49825f06fda23989961cfa41cd1576b58e2bcc5d (patch) | |
tree | 35edd71235740694335a2e522734bdb218cb1193 /src | |
parent | 41e79d655cd7133459706e17ab8cf794ce4e5251 (diff) |
Don't try to fix strings with escaped bytes
While QString::fromUtf8("ö") is equal to QString::fromUtf8("\xc3\xb6"),
QStringLiteral("ö") is not equal to QStringLiteral("\xc3\xb6") because the
escaped bytes won't be converted to utf-16 but instead used directly as is.
CCMAIL: faure@kde.org
CCMAIL: montel@kde.org
Diffstat (limited to 'src')
-rw-r--r-- | src/Utils.cpp | 22 | ||||
-rw-r--r-- | src/Utils.h | 5 | ||||
-rw-r--r-- | src/checks/level2/qstring-allocations.cpp | 10 |
3 files changed, 36 insertions, 1 deletions
diff --git a/src/Utils.cpp b/src/Utils.cpp index 8ceb6e95..5d0a1500 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -28,6 +28,7 @@ #include "ContextUtils.h" #include "StmtBodyRange.h" +#include <clang/AST/Expr.h> #include <clang/AST/StmtCXX.h> #include <clang/AST/ASTContext.h> #include <clang/AST/DeclCXX.h> @@ -885,3 +886,24 @@ SourceLocation Utils::locForNextToken(SourceLocation loc, const clang::SourceMan return loc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars); } + +bool Utils::literalContainsEscapedBytes(StringLiteral *lt, const SourceManager &sm, const LangOptions &lo) +{ + if (!lt) + return false; + + // The AST doesn't have the info, we need to ask the Lexer + SourceRange sr = lt->getSourceRange(); + CharSourceRange cr = Lexer::getAsCharRange(sr, sm, lo); + const StringRef str = Lexer::getSourceText(cr, sm, lo); + + for (int i = 0, size = str.size(); i < size - 1; ++i) { + if (str[i] == '\\') { + auto next = str[i+1]; + if (next == 'U' || next == 'u' || next == 'x' || std::isdigit(next)) + return true; + } + } + + return false; +} diff --git a/src/Utils.h b/src/Utils.h index 740d47c4..6aabee32 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -273,6 +273,11 @@ namespace Utils { CLAZYLIB_EXPORT clang::SourceLocation locForNextToken(clang::SourceLocation loc, const clang::SourceManager &sm, const clang::LangOptions &lo); + + /** + * Returns true if the string literal contains escaped bytes, such as \x12, \123, \u00F6. + */ + bool literalContainsEscapedBytes(clang::StringLiteral *lt, const clang::SourceManager &sm, const clang::LangOptions &lo); } #endif diff --git a/src/checks/level2/qstring-allocations.cpp b/src/checks/level2/qstring-allocations.cpp index dd0c0bef..298c8170 100644 --- a/src/checks/level2/qstring-allocations.cpp +++ b/src/checks/level2/qstring-allocations.cpp @@ -279,14 +279,17 @@ void QStringAllocations::VisitCtor(Stmt *stm) vector<FixItHint> QStringAllocations::fixItReplaceWordWithWord(clang::Stmt *begin, const string &replacement, const string &replacee, int fixitType) { + StringLiteral *lt = stringLiteralForCall(begin); if (replacee == "QLatin1String") { - StringLiteral *lt = stringLiteralForCall(begin); if (lt && !Utils::isAscii(lt)) { emitWarning(lt->getLocStart(), "Don't use QLatin1String with non-latin1 literals"); return {}; } } + if (Utils::literalContainsEscapedBytes(lt, sm(), lo())) + return {}; + vector<FixItHint> fixits; FixItHint fixit = FixItUtils::fixItReplaceWordWithWord(&m_astContext, begin, replacement, replacee); if (fixit.isNull()) { @@ -387,6 +390,8 @@ std::vector<FixItHint> QStringAllocations::fixItReplaceFromLatin1OrFromUtf8(Call StringLiteral *literal = stringLiteralForCall(callExpr); if (literal) { + if (Utils::literalContainsEscapedBytes(literal, sm(), lo())) + return {}; if (!Utils::isAscii(literal)) { // QString::fromLatin1() to QLatin1String() is fine // QString::fromUtf8() to QStringLiteral() is fine @@ -426,6 +431,9 @@ std::vector<FixItHint> QStringAllocations::fixItRawLiteral(clang::StringLiteral if (start.isMacroID()) { queueManualFixitWarning(start, CharPtrAllocations, "Can't use QStringLiteral in macro.."); } else { + if (Utils::literalContainsEscapedBytes(lt, sm(), lo())) + return {}; + string revisedReplacement = lt->getLength() == 0 ? "QLatin1String" : replacement; // QLatin1String("") is better than QStringLiteral("") if (revisedReplacement == "QStringLiteral" && lt->getLocStart().isMacroID()) { queueManualFixitWarning(lt->getLocStart(), CharPtrAllocations, "Can't use QStringLiteral in macro..."); |