src/checks/level0/lambda-in-connect.cpp (58 lines of code) (raw):

/* SPDX-FileCopyrightText: 2016-2017 Sergio Martins <smartins@kde.org> SPDX-License-Identifier: LGPL-2.0-or-later */ #include "lambda-in-connect.h" #include "ClazyContext.h" #include "ContextUtils.h" #include "HierarchyUtils.h" #include "QtUtils.h" #include "StringUtils.h" #include <clang/AST/Decl.h> #include <clang/AST/Expr.h> #include <clang/AST/ExprCXX.h> #include <clang/AST/LambdaCapture.h> #include <clang/AST/Stmt.h> #include <clang/AST/Type.h> #include <clang/Basic/LLVM.h> #include <clang/Basic/Lambda.h> #include <llvm/ADT/iterator_range.h> #include <llvm/Support/Casting.h> using namespace clang; LambdaInConnect::LambdaInConnect(const std::string &name, ClazyContext *context) : CheckBase(name, context, Option_CanIgnoreIncludes) { } void LambdaInConnect::VisitStmt(clang::Stmt *stmt) { auto *lambda = dyn_cast<LambdaExpr>(stmt); if (!lambda) { return; } auto captures = lambda->captures(); if (captures.begin() == captures.end()) { return; } auto *callExpr = clazy::getFirstParentOfType<CallExpr>(m_context->parentMap, lambda); if (clazy::qualifiedMethodName(callExpr) != "QObject::connect") { return; } ValueDecl *senderDecl = clazy::signalSenderForConnect(callExpr); if (senderDecl) { const Type *t = senderDecl->getType().getTypePtrOrNull(); if (t && !t->isPointerType()) { return; } } ValueDecl *receiverDecl = clazy::signalReceiverForConnect(callExpr); if (receiverDecl) { const Type *t = receiverDecl->getType().getTypePtrOrNull(); if (t && !t->isPointerType()) { return; } } for (auto capture : captures) { if (capture.getCaptureKind() == clang::LCK_ByRef) { auto *declForCapture = capture.getCapturedVar(); if (declForCapture && declForCapture != receiverDecl && clazy::isValueDeclInFunctionContext(declForCapture)) { emitWarning(capture.getLocation(), "captured local variable by reference might go out of scope before lambda is called"); } } } }