Commit 425483b0 authored by Lucie Gerard's avatar Lucie Gerard Committed by Sergio Martins

WIP: Add qt6-qlatin1string-to-u check

Replaces QLatin1Char() calls with u""
Only for Qt6
parent 11f03c11
......@@ -15,6 +15,7 @@ set(CLAZY_CHECKS_SRCS ${CLAZY_CHECKS_SRCS}
${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/qt4-qstring-from-array.cpp
${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/qt6-qhash-signature.cpp
${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/qt6-qlatin1string-to-u.cpp
${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/qt6-qlatin1char-to-u.cpp
${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/qvariant-template-instantiation.cpp
${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/raw-environment-function.cpp
${CMAKE_CURRENT_LIST_DIR}/src/checks/manuallevel/reserve-candidates.cpp
......
......@@ -230,6 +230,7 @@ clazy runs all checks from level1 by default.
- [qt4-qstring-from-array](docs/checks/README-qt4-qstring-from-array.md) (fix-qt4-qstring-from-array)
- [qt6-qhash-signature](docs/checks/README-qt6-qhash-signature.md) (fix-qt6-qhash-signature)
- [qt6-qlatin1string-to-u](docs/checks/README-qt6-qlatin1string-to-u.md) (fix-qt6-qlatin1string-to-u)
- [qt6-qlatin1char-to-u](docs/checks/README-qt6-qlatin1char-to-u.md) (fix-qt6-qlatin1char-to-u)
- [qvariant-template-instantiation](docs/checks/README-qvariant-template-instantiation.md)
- [raw-environment-function](docs/checks/README-raw-environment-function.md)
- [reserve-candidates](docs/checks/README-reserve-candidates.md)
......
......@@ -77,6 +77,18 @@
],
"visits_stmts" : true
},
{
"name" : "qt6-qlatin1char-to-u",
"class_name" : "Qt6QLatin1CharToU",
"level" : -1,
"categories" : ["qt6", "containers"],
"fixits" : [
{
"name" : "qt6-qlatin1char-to-u"
}
],
"visits_stmts" : true
},
{
"name" : "qt6-qhash-signature",
"class_name" : "Qt6QHashSignature",
......
# qt6-qlatin1char-to-u
Warns when using `QLatin1Char` and replaces it with `u`.
......@@ -15,6 +15,7 @@ SET(README_manuallevel_FILES
${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-qt4-qstring-from-array.md
${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-qt6-qhash-signature.md
${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-qt6-qlatin1string-to-u.md
${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-qt6-qlatin1char-to-u.md
${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-qvariant-template-instantiation.md
${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-raw-environment-function.md
${CMAKE_CURRENT_LIST_DIR}/docs/checks/README-reserve-candidates.md
......
......@@ -43,6 +43,7 @@
#include "checks/manuallevel/qt4-qstring-from-array.h"
#include "checks/manuallevel/qt6-qhash-signature.h"
#include "checks/manuallevel/qt6-qlatin1string-to-u.h"
#include "checks/manuallevel/qt6-qlatin1char-to-u.h"
#include "checks/manuallevel/qvariant-template-instantiation.h"
#include "checks/manuallevel/raw-environment-function.h"
#include "checks/manuallevel/reserve-candidates.h"
......@@ -145,6 +146,8 @@ void CheckManager::registerChecks()
registerFixIt(1, "fix-qt6-qhash-signature", "qt6-qhash-signature");
registerCheck(check<Qt6QLatin1StringToU>("qt6-qlatin1string-to-u", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts));
registerFixIt(1, "fix-qt6-qlatin1string-to-u", "qt6-qlatin1string-to-u");
registerCheck(check<Qt6QLatin1CharToU>("qt6-qlatin1char-to-u", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts));
registerFixIt(1, "fix-qt6-qlatin1char-to-u", "qt6-qlatin1char-to-u");
registerCheck(check<QVariantTemplateInstantiation>("qvariant-template-instantiation", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts));
registerCheck(check<RawEnvironmentFunction>("raw-environment-function", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts));
registerCheck(check<ReserveCandidates>("reserve-candidates", ManualCheckLevel, RegisteredCheck::Option_VisitsStmts));
......
/*
This file is part of the clazy static checker.
Copyright (C) 2020 The Qt Company Ltd.
Copyright (C) 2020 Lucie Gerard <lucie.gerard@qt.io>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "qt6-qlatin1char-to-u.h"
#include "ClazyContext.h"
#include "Utils.h"
#include "StringUtils.h"
#include "FixItUtils.h"
#include "HierarchyUtils.h"
#include "SourceCompatibilityHelpers.h"
#include "clazy_stl.h"
#include <clang/Lex/Lexer.h>
#include <clang/AST/Decl.h>
#include <clang/AST/DeclCXX.h>
#include <clang/AST/Expr.h>
#include <clang/AST/ExprCXX.h>
#include <clang/AST/Stmt.h>
#include <clang/AST/Type.h>
#include <clang/Basic/Diagnostic.h>
#include <clang/Basic/LLVM.h>
#include <clang/Basic/SourceLocation.h>
#include <llvm/ADT/ArrayRef.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/Casting.h>
using namespace clang;
using namespace std;
Qt6QLatin1CharToU::Qt6QLatin1CharToU(const std::string &name, ClazyContext *context)
: CheckBase(name, context, Option_CanIgnoreIncludes)
{
enablePreProcessorCallbacks();
}
static bool isInterestingCtorCall(CXXConstructorDecl *ctor)
{
if (!ctor || !clazy::isOfClass(ctor, "QLatin1Char"))
return false;
for (auto param : Utils::functionParameters(ctor)) {
return param->getType().getTypePtr()->isCharType();
}
return false;
}
void Qt6QLatin1CharToU::VisitStmt(clang::Stmt *stmt)
{
auto ctorExpr = dyn_cast<CXXConstructExpr>(stmt);
if (!ctorExpr)
return;
vector<FixItHint> fixits;
string message;
if (ctorExpr) {
CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor();
if (!isInterestingCtorCall(ctorDecl))
return;
message = "QLatin1Char(char) ctor being called";
for (auto macro_pos : m_listingMacroExpand) {
if (m_sm.isPointWithin(macro_pos, clazy::getLocStart(stmt), clazy::getLocEnd(stmt))) {
emitWarning(clazy::getLocStart(stmt), message, fixits);
return;
}
}
fixits = fixitReplace(stmt);
} else {
return;
}
emitWarning(clazy::getLocStart(stmt), message, fixits);
}
std::vector<FixItHint> Qt6QLatin1CharToU::fixitReplace(clang::Stmt *stmt)
{
string replacement = "";
// Iterating over the stmt's children to build the replacement
int i = 0;
Stmt *current_stm = stmt;
for (auto it = current_stm->child_begin() ; it !=current_stm->child_end() ; it++) {
Stmt *child = clazy::childAt(current_stm, i);
if (!child)
break;
ConditionalOperator *parent_condOp = dyn_cast<ConditionalOperator>(current_stm);
ImplicitCastExpr *child_dynCastExp = dyn_cast<ImplicitCastExpr>(child);
CharacterLiteral *child_charliteral = dyn_cast<CharacterLiteral>(child);
ConditionalOperator *child_condOp = dyn_cast<ConditionalOperator>(child);
CXXBoolLiteralExpr *child_boolLitExp = dyn_cast<CXXBoolLiteralExpr>(child);
DeclRefExpr *child_declRefExp = dyn_cast<DeclRefExpr>(child);
if (child_dynCastExp || child_condOp) {// skipping those.
current_stm = child;
i = 0;
} else if (child_charliteral) {
replacement += "u\'";
if (child_charliteral->getValue() == 92 || child_charliteral->getValue() == 39)
replacement += "\\";
replacement += child_charliteral->getValue();
replacement += "\'";
if (parent_condOp && i == 1) // the first string is the second child of the ConditionalOperator.
replacement += " : ";
i++;
} else if (child_boolLitExp) {
replacement = child_boolLitExp->getValue() ? "true" : "false";
if (parent_condOp)
replacement += " ? ";
i++;
} else if (child_declRefExp) { // not replacing those cases.
// would have to check that the ancestor is a QChar, and that the type is something accepted by
// the QChar constructor.
// The NameInfo would then be the replacement.
return {};
} else {
if (it == current_stm->child_end()) {
current_stm = child;
i = 0;
} else {
i++;
}
}
}
if (replacement.size() < 3)
return {};
vector<FixItHint> fixits;
fixits.push_back(FixItHint::CreateReplacement(stmt->getSourceRange(), replacement));
return fixits;
}
void Qt6QLatin1CharToU::VisitMacroExpands(const clang::Token &MacroNameTok, const clang::SourceRange &range, const MacroInfo *)
{
m_listingMacroExpand.push_back(range.getBegin());
return;
}
/*
This file is part of the clazy static checker.
Copyright (C) 2020 The Qt Company Ltd.
Copyright (C) 2020 Lucie Gerard <lucie.gerard@qt.io>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef CLAZY_QT6_QLATINCHAR_TO_U_H
#define CLAZY_QT6_QLATINCHAR_TO_U_H
#include "checkbase.h"
#include <vector>
#include <string>
class ClazyContext;
namespace clang {
class Stmt;
class FixItHint;
class CXXConstructExpr;
class CXXOperatorCallExpr;
class Expr;
class CXXMemberCallExpr;
class CXXFunctionalCastExpr;
}
/**
* Replaces QLatin1String(char*) calls with u(char*).
*
* Run only in Qt 6 code.
*/
class Qt6QLatin1CharToU
: public CheckBase
{
public:
explicit Qt6QLatin1CharToU(const std::string &name, ClazyContext *context);
void VisitStmt(clang::Stmt *stmt) override;
void VisitMacroExpands(const clang::Token &MacroNameTok,
const clang::SourceRange &range, const clang::MacroInfo *minfo = nullptr) override;
private:
std::vector<clang::SourceLocation> m_listingMacroExpand;
std::vector<clang::FixItHint> fixitReplace(clang::Stmt *stmt);
};
#endif
{
"tests" : [
{
"filename" : "main.cpp",
"qt_major_version": 6,
"has_fixits" : true
}
]
}
#include <QtCore/QLatin1Char>
#include <QtCore/QChar>
#include <QtCore/QString>
#include <QtCore/QDir>
void receivingQChar(QChar s1) {}
void receivingQLatin1Char(QLatin1Char s1) {}
#define PREFIX '*'
void test()
{
QChar c1 = QLatin1Char('*');
QChar c11 = u'*'; // remove the check
QString s = "aaa";
bool b = s.startsWith(QLatin1Char('/'));
s += QLatin1Char('.');
QString appPrefix = s + QLatin1Char('\\');
appPrefix = s + QLatin1Char('\'');
if (s.at(1) == QLatin1Char('*'))
b = true;
QChar quotes[] = { QLatin1Char('"'), QLatin1Char('"') };
QChar c2 = QLatin1Char(true ? '*' : '/');
int i = s.lastIndexOf(QLatin1Char('*'));
const QString sc = "sc";
QString s2 = QDir::cleanPath(sc + QLatin1Char('*'));
s2.insert(1, QLatin1Char('*'));
receivingQChar(QLatin1Char('/'));
receivingQLatin1Char(QLatin1Char('/'));
//error: no matching function for call to 'receivingQLatin1Char'
//receivingQLatin1Char(u'/'); // remove check
QLatin1Char toto = QLatin1Char('/');
//error: no viable conversion from 'char16_t' to 'QLatin1Char'
//QLatin1Char totoo = u'/'; // remove check
QChar char_with_macro = QLatin1Char(PREFIX); // should not be fixed
}
qt6-qlatin1char-to-u/main.cpp:12:16: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:16:27: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:18:10: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:20:29: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:21:21: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:23:20: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:26:24: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:26:42: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:26:24: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:26:42: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:27:16: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:29:27: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:32:39: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:34:18: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:37:20: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:39:26: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:43:24: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
qt6-qlatin1char-to-u/main.cpp:47:29: warning: QLatin1Char(char) ctor being called [-Wclazy-qt6-qlatin1char-to-u]
#include <QtCore/QLatin1Char>
#include <QtCore/QChar>
#include <QtCore/QString>
#include <QtCore/QDir>
void receivingQChar(QChar s1) {}
void receivingQLatin1Char(QLatin1Char s1) {}
#define PREFIX '*'
void test()
{
QChar c1 = u'*';
QChar c11 = u'*'; // remove the check
QString s = "aaa";
bool b = s.startsWith(u'/');
s += u'.';
QString appPrefix = s + u'\\';
appPrefix = s + u'\'';
if (s.at(1) == u'*')
b = true;
QChar quotes[] = { u'"', u'"' };
QChar c2 = true ? u'*' : u'/';
int i = s.lastIndexOf(u'*');
const QString sc = "sc";
QString s2 = QDir::cleanPath(sc + u'*');
s2.insert(1, u'*');
receivingQChar(u'/');
receivingQLatin1Char(u'/');
//error: no matching function for call to 'receivingQLatin1Char'
//receivingQLatin1Char(u'/'); // remove check
QLatin1Char toto = u'/';
//error: no viable conversion from 'char16_t' to 'QLatin1Char'
//QLatin1Char totoo = u'/'; // remove check
QChar char_with_macro = QLatin1Char(PREFIX); // should not be fixed
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment