File indexing completed on 2024-05-12 05:41:03
0001 /* 0002 SPDX-FileCopyrightText: 2015 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.com 0003 SPDX-FileContributor: Sérgio Martins <sergio.martins@kdab.com> 0004 0005 SPDX-FileCopyrightText: 2015 Sergio Martins <smartins@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "qvariant-template-instantiation.h" 0011 #include "StringUtils.h" 0012 #include "TemplateUtils.h" 0013 #include "clazy_stl.h" 0014 0015 #include <clang/AST/DeclCXX.h> 0016 #include <clang/AST/ExprCXX.h> 0017 #include <clang/AST/Stmt.h> 0018 #include <clang/AST/Type.h> 0019 #include <clang/Basic/LLVM.h> 0020 #include <llvm/ADT/StringRef.h> 0021 #include <llvm/Support/Casting.h> 0022 0023 #include <ctype.h> 0024 #include <vector> 0025 0026 class ClazyContext; 0027 0028 using namespace clang; 0029 0030 QVariantTemplateInstantiation::QVariantTemplateInstantiation(const std::string &name, ClazyContext *context) 0031 : CheckBase(name, context, Option_CanIgnoreIncludes) 0032 { 0033 } 0034 0035 static bool isMatchingClass(StringRef name) 0036 { 0037 static const std::vector<StringRef> classes = {"QBitArray", "QByteArray", "QChar", "QDate", "QDateTime", "QEasingCurve", "QJsonArray", 0038 "QJsonDocument", "QJsonObject", "QJsonValue", "QLocale", "QModelIndex", "QPoint", "QPointF", 0039 "QRect", "QRectF", "QRegExp", "QString", "QRegularExpression", "QSize", "QSizeF", 0040 "QStringList", "QTime", "QUrl", "QUuid"}; 0041 0042 return clazy::contains(classes, name); 0043 } 0044 0045 void QVariantTemplateInstantiation::VisitStmt(clang::Stmt *stm) 0046 { 0047 auto *callExpr = dyn_cast<CXXMemberCallExpr>(stm); 0048 if (!callExpr) { 0049 return; 0050 } 0051 0052 CXXMethodDecl *methodDecl = callExpr->getMethodDecl(); 0053 if (!methodDecl || clazy::name(methodDecl) != "value") { 0054 return; 0055 } 0056 0057 const auto *memberExpr = dyn_cast<MemberExpr>(callExpr->getCallee()); 0058 if (!memberExpr) { 0059 return; 0060 } 0061 0062 const auto *decl = dyn_cast<CXXRecordDecl>(memberExpr->getBase()->getType()->getAsCXXRecordDecl()); 0063 if (!decl || !decl->getDefinition() 0064 || !(decl->getNameAsString() == "QVariant" || decl->getNameAsString() == "QHash" || decl->getNameAsString() == "QMap")) { 0065 return; 0066 } 0067 0068 if (const auto *specDecl = dyn_cast<ClassTemplateSpecializationDecl>(decl)) { 0069 if (const auto *templateDecl = specDecl->getSpecializedTemplate()) { 0070 if (templateDecl->getNameAsString() == "QHash" || templateDecl->getNameAsString() == "QMap") { 0071 const TemplateArgumentList &templateArgs = specDecl->getTemplateArgs(); 0072 if (!(templateArgs.size() == 2) || !(templateArgs.get(1).getAsType().getAsString() == "QVariant")) { 0073 return; 0074 } 0075 } else if (templateDecl->getNameAsString() == "QList") { 0076 const TemplateArgumentList &templateArgs = specDecl->getTemplateArgs(); 0077 if (!(templateArgs.size() == 1) || !(templateArgs.get(0).getAsType().getAsString() == "QVariant")) { 0078 return; 0079 } 0080 } 0081 } 0082 } 0083 0084 std::vector<QualType> typeList = clazy::getTemplateArgumentsTypes(methodDecl); 0085 const Type *t = typeList.empty() ? nullptr : typeList[0].getTypePtrOrNull(); 0086 if (!t) { 0087 return; 0088 } 0089 0090 bool matches = false; 0091 if (t->isBooleanType() || t->isFloatingType() || (t->isIntegerType() && !t->isEnumeralType())) { 0092 matches = true; 0093 } else { 0094 CXXRecordDecl *recordDecl = t->getAsCXXRecordDecl(); 0095 matches = recordDecl && t->isClassType() && isMatchingClass(clazy::name(recordDecl)); 0096 } 0097 0098 if (matches) { 0099 std::string typeName = clazy::simpleTypeName(typeList[0], lo()); 0100 0101 std::string typeName2 = typeName; 0102 typeName2[0] = toupper(typeName2[0]); 0103 0104 if (typeName[0] == 'Q') { 0105 typeName2.erase(0, 1); // Remove first letter 0106 } 0107 std::string error = std::string("Use QVariant::to" + typeName2 + "() instead of QVariant::value<" + typeName + ">()"); 0108 emitWarning(stm->getBeginLoc(), error); 0109 } 0110 }