File indexing completed on 2024-05-12 05:40:55
0001 /* 0002 SPDX-FileCopyrightText: 2018 Sergio Martins <smartins@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "empty-qstringliteral.h" 0008 #include "ClazyContext.h" 0009 #include "HierarchyUtils.h" 0010 #include "PreProcessorVisitor.h" 0011 #include "QtUtils.h" 0012 0013 #include <clang/AST/Decl.h> 0014 #include <clang/AST/Expr.h> 0015 #include <clang/AST/Stmt.h> 0016 #include <clang/Basic/LLVM.h> 0017 #include <clang/Basic/SourceLocation.h> 0018 #include <llvm/ADT/StringRef.h> 0019 #include <llvm/Support/Casting.h> 0020 0021 using namespace clang; 0022 0023 EmptyQStringliteral::EmptyQStringliteral(const std::string &name, ClazyContext *context) 0024 : CheckBase(name, context) 0025 { 0026 context->enablePreprocessorVisitor(); 0027 } 0028 0029 void EmptyQStringliteral::VisitStmt(clang::Stmt *stmt) 0030 { 0031 if (!stmt->getBeginLoc().isMacroID()) { 0032 return; 0033 } 0034 0035 const std::string filepath = static_cast<std::string>(sm().getFilename(sm().getExpansionLoc(stmt->getBeginLoc()))); 0036 if (clazy::contains(filepath, ".rcc/qmlcache/")) { 0037 return; // This is an autogenerated file 0038 } 0039 if (auto splitted = clazy::splitString(filepath, '/'); !splitted.empty()) { 0040 if (std::string filename = splitted[splitted.size() - 1]; clazy::startsWith(filename, "ui_") && clazy::endsWith(filename, ".h")) { 0041 return; // Also ignore all ui files 0042 } 0043 } 0044 0045 if (m_context->preprocessorVisitor && m_context->preprocessorVisitor->qtVersion() >= 60000) { // The AST looks very different in Qt6 0046 handleQt6StringLiteral(stmt); 0047 } else { 0048 handleQt5StringLiteral(stmt); 0049 } 0050 } 0051 0052 void EmptyQStringliteral::handleQt6StringLiteral(clang::Stmt *stmt) 0053 { 0054 if (auto c = dyn_cast<CallExpr>(stmt)) { 0055 if (clazy::qualifiedMethodName(c->getDirectCallee()) == "QtPrivate::qMakeStringPrivate") { 0056 if (auto lt = clazy::getFirstChildOfType<StringLiteral>(c); lt && lt->getByteLength() == 0) { 0057 emitWarning(stmt, "Use QLatin1String(\"\") or QString() instead of an empty QStringLiteral"); 0058 } 0059 } 0060 } 0061 } 0062 0063 void EmptyQStringliteral::handleQt5StringLiteral(clang::Stmt *stmt) 0064 { 0065 auto *declstm = dyn_cast<DeclStmt>(stmt); 0066 if (!declstm || !declstm->isSingleDecl()) { 0067 return; 0068 } 0069 0070 auto *vd = dyn_cast<VarDecl>(declstm->getSingleDecl()); 0071 if (!vd || clazy::name(vd) != "qstring_literal") { 0072 return; 0073 } 0074 0075 Expr *expr = vd->getInit(); 0076 auto *initListExpr = expr ? dyn_cast<InitListExpr>(expr) : nullptr; 0077 if (!initListExpr || initListExpr->getNumInits() != 2) { 0078 return; 0079 } 0080 0081 Expr *init = initListExpr->getInit(1); 0082 auto *literal = init ? dyn_cast<StringLiteral>(init) : nullptr; 0083 if (!literal || literal->getByteLength() != 0) { 0084 return; 0085 } 0086 0087 emitWarning(stmt, "Use QLatin1String(\"\") or QString() instead of an empty QStringLiteral"); 0088 }