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 }