File indexing completed on 2024-05-12 05:40:57
0001 /* 0002 SPDX-FileCopyrightText: 2015 Sergio Martins <smartins@kde.org> 0003 SPDX-FileCopyrightText: 2024 Alexander Lohnau <alexander.lohnau@gmx.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "wrong-qglobalstatic.h" 0009 #include "MacroUtils.h" 0010 #include "StringUtils.h" 0011 #include "TemplateUtils.h" 0012 0013 #include <clang/AST/DeclCXX.h> 0014 #include <clang/AST/ExprCXX.h> 0015 #include <clang/AST/Stmt.h> 0016 #include <clang/AST/Type.h> 0017 #include <clang/Basic/LLVM.h> 0018 #include <clang/Basic/SourceLocation.h> 0019 #include <llvm/ADT/StringRef.h> 0020 #include <llvm/Support/Casting.h> 0021 0022 #include <vector> 0023 0024 class ClazyContext; 0025 0026 using namespace clang; 0027 0028 WrongQGlobalStatic::WrongQGlobalStatic(const std::string &name, ClazyContext *context) 0029 : CheckBase(name, context) 0030 { 0031 } 0032 0033 void WrongQGlobalStatic::VisitStmt(clang::Stmt *stmt) 0034 { 0035 auto *ctorExpr = dyn_cast<CXXConstructExpr>(stmt); 0036 if (!ctorExpr) { 0037 return; 0038 } 0039 0040 CXXConstructorDecl *ctorDecl = ctorExpr->getConstructor(); 0041 if (!ctorDecl) { 0042 return; 0043 } 0044 if (StringRef name = clazy::name(ctorDecl); name != "QGlobalStatic" && name != "QGlobalStaticCompoundStmt") { 0045 return; // Only consider relevant Qt5 and Qt6 ctors 0046 } 0047 0048 SourceLocation loc = stmt->getBeginLoc(); 0049 if (clazy::isInMacro(&m_astContext, loc, "Q_GLOBAL_STATIC_WITH_ARGS")) { 0050 return; 0051 } 0052 0053 CXXRecordDecl *record = ctorDecl->getParent(); 0054 std::vector<QualType> typeList = clazy::getTemplateArgumentsTypes(record); 0055 CXXRecordDecl *usersClass = nullptr; 0056 std::string underlyingTypeName; 0057 if (typeList.empty()) { 0058 return; 0059 } 0060 if (clazy::classNameFor(typeList[0]) == "Holder") { // In Qt6, we need to look into the Holder for the user-defined class/type name 0061 auto templateTypes = clazy::getTemplateArgumentsTypes(typeList[0]->getAsCXXRecordDecl()); 0062 if (templateTypes.empty()) { 0063 return; 0064 } 0065 QualType qgsType = templateTypes[0]; 0066 if (auto *typePtr = qgsType.getTypePtrOrNull(); typePtr && typePtr->isRecordType()) { 0067 for (auto *decl : typePtr->getAsCXXRecordDecl()->decls()) { 0068 if (auto *typedefDecl = dyn_cast<TypedefDecl>(decl); typedefDecl && typedefDecl->getNameAsString() == "QGS_Type") { 0069 usersClass = typedefDecl->getUnderlyingType()->getAsCXXRecordDecl(); 0070 underlyingTypeName = typedefDecl->getUnderlyingType().getAsString(); 0071 break; 0072 } 0073 } 0074 } 0075 } else if (auto *t = typeList[0].getTypePtrOrNull()) { 0076 usersClass = t->getAsCXXRecordDecl(); 0077 underlyingTypeName = typeList[0].getAsString(); 0078 } 0079 0080 if (usersClass) { 0081 if (usersClass->hasTrivialDefaultConstructor() && usersClass->hasTrivialDestructor()) { 0082 emitWarning(loc, "Don't use Q_GLOBAL_STATIC with trivial type (" + usersClass->getNameAsString() + ')'); 0083 } 0084 } else { 0085 // Not a class, why use Q_GLOBAL_STATIC ? 0086 emitWarning(loc, "Don't use Q_GLOBAL_STATIC with non-class type (" + underlyingTypeName + ')'); 0087 } 0088 }