File indexing completed on 2024-05-12 05:40:56

0001 /*
0002     SPDX-FileCopyrightText: 2016-2017 Sergio Martins <smartins@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "lambda-in-connect.h"
0008 #include "ClazyContext.h"
0009 #include "ContextUtils.h"
0010 #include "HierarchyUtils.h"
0011 #include "QtUtils.h"
0012 #include "StringUtils.h"
0013 
0014 #include <clang/AST/Decl.h>
0015 #include <clang/AST/Expr.h>
0016 #include <clang/AST/ExprCXX.h>
0017 #include <clang/AST/LambdaCapture.h>
0018 #include <clang/AST/Stmt.h>
0019 #include <clang/AST/Type.h>
0020 #include <clang/Basic/LLVM.h>
0021 #include <clang/Basic/Lambda.h>
0022 #include <llvm/ADT/iterator_range.h>
0023 #include <llvm/Support/Casting.h>
0024 
0025 using namespace clang;
0026 
0027 LambdaInConnect::LambdaInConnect(const std::string &name, ClazyContext *context)
0028     : CheckBase(name, context, Option_CanIgnoreIncludes)
0029 {
0030 }
0031 
0032 void LambdaInConnect::VisitStmt(clang::Stmt *stmt)
0033 {
0034     auto *lambda = dyn_cast<LambdaExpr>(stmt);
0035     if (!lambda) {
0036         return;
0037     }
0038 
0039     auto captures = lambda->captures();
0040     if (captures.begin() == captures.end()) {
0041         return;
0042     }
0043 
0044     auto *callExpr = clazy::getFirstParentOfType<CallExpr>(m_context->parentMap, lambda);
0045     if (clazy::qualifiedMethodName(callExpr) != "QObject::connect") {
0046         return;
0047     }
0048 
0049     ValueDecl *senderDecl = clazy::signalSenderForConnect(callExpr);
0050     if (senderDecl) {
0051         const Type *t = senderDecl->getType().getTypePtrOrNull();
0052         if (t && !t->isPointerType()) {
0053             return;
0054         }
0055     }
0056 
0057     ValueDecl *receiverDecl = clazy::signalReceiverForConnect(callExpr);
0058 
0059     for (auto capture : captures) {
0060         if (capture.getCaptureKind() == clang::LCK_ByRef) {
0061             auto *declForCapture = capture.getCapturedVar();
0062             if (declForCapture && declForCapture != receiverDecl && clazy::isValueDeclInFunctionContext(declForCapture)) {
0063                 emitWarning(capture.getLocation(), "captured local variable by reference might go out of scope before lambda is called");
0064             }
0065         }
0066     }
0067 }