aboutsummaryrefslogtreecommitdiffstats
path: root/src/checks/level1/connect-3arg-lambda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checks/level1/connect-3arg-lambda.cpp')
-rw-r--r--src/checks/level1/connect-3arg-lambda.cpp78
1 files changed, 63 insertions, 15 deletions
diff --git a/src/checks/level1/connect-3arg-lambda.cpp b/src/checks/level1/connect-3arg-lambda.cpp
index 12148907..8463b90f 100644
--- a/src/checks/level1/connect-3arg-lambda.cpp
+++ b/src/checks/level1/connect-3arg-lambda.cpp
@@ -24,31 +24,48 @@
#include "HierarchyUtils.h"
#include "QtUtils.h"
#include "TypeUtils.h"
-#include "checkmanager.h"
#include <clang/AST/AST.h>
using namespace clang;
using namespace std;
+using uint = unsigned;
-Connect3argLambda::Connect3argLambda(const std::string &name, ClazyContext *context)
- : CheckBase(name, context)
+Connect3ArgLambda::Connect3ArgLambda(const std::string &name, ClazyContext *context)
+ : CheckBase(name, context, Option_CanIgnoreIncludes)
{
}
-
-void Connect3argLambda::VisitStmt(clang::Stmt *stmt)
+void Connect3ArgLambda::VisitStmt(clang::Stmt *stmt)
{
auto callExpr = dyn_cast<CallExpr>(stmt);
if (!callExpr)
return;
FunctionDecl *fdecl = callExpr->getDirectCallee();
- if (!QtUtils::isConnect(fdecl) || fdecl->getNumParams() != 3)
+ if (!fdecl)
+ return;
+
+ const uint numParams = fdecl->getNumParams();
+ if (numParams != 2 && numParams != 3)
+ return;
+
+ string qualifiedName = fdecl->getQualifiedNameAsString();
+ if (qualifiedName == "QTimer::singleShot") {
+ processQTimer(fdecl, stmt);
return;
+ }
- auto lambda = HierarchyUtils::getFirstChildOfType2<LambdaExpr>(callExpr->getArg(2));
+ if (qualifiedName == "QMenu::addAction") {
+ processQMenu(fdecl, stmt);
+ return;
+ }
+
+ if (numParams != 3 || !clazy::isConnect(fdecl))
+ return;
+
+ auto lambda = clazy::getFirstChildOfType2<LambdaExpr>(callExpr->getArg(2));
if (!lambda)
return;
@@ -63,15 +80,14 @@ void Connect3argLambda::VisitStmt(clang::Stmt *stmt)
if ((senderMemberExpr = dyn_cast<MemberExpr>(s)))
break;
- s = HierarchyUtils::getFirstChild(s);
+ s = clazy::getFirstChild(s);
}
-
// The sender can be: this
- CXXThisExpr* senderThis = HierarchyUtils::unpeal<CXXThisExpr>(callExpr->getArg(0), HierarchyUtils::IgnoreImplicitCasts);
+ auto senderThis = clazy::unpeal<CXXThisExpr>(callExpr->getArg(0), clazy::IgnoreImplicitCasts);
// The variables used inside the lambda
- auto declrefs = HierarchyUtils::getStatements<DeclRefExpr>(lambda->getBody());
+ auto declrefs = clazy::getStatements<DeclRefExpr>(lambda->getBody());
ValueDecl *senderDecl = senderDeclRef ? senderDeclRef->getDecl() : nullptr;
@@ -82,21 +98,53 @@ void Connect3argLambda::VisitStmt(clang::Stmt *stmt)
if (decl == senderDecl)
continue; // It's the sender, continue.
- if (QtUtils::isQObject(decl->getType())) {
+ if (clazy::isQObject(decl->getType())) {
found = true;
break;
}
}
if (!found) {
- auto thisexprs = HierarchyUtils::getStatements<CXXThisExpr>(lambda->getBody());
+ auto thisexprs = clazy::getStatements<CXXThisExpr>(lambda->getBody());
if (!thisexprs.empty() && !senderThis)
found = true;
}
if (found)
- emitWarning(stmt->getLocStart(), "Pass a context object as 3rd connect parameter");
+ emitWarning(stmt, "Pass a context object as 3rd connect parameter");
}
+void Connect3ArgLambda::processQTimer(FunctionDecl *func, Stmt *stmt)
+{
+ // Signatures to catch:
+ // QTimer::singleShot(int msec, Functor functor)
+ // QTimer::singleShot(int msec, Qt::TimerType timerType, Functor functor)
+
+ const uint numParams = func->getNumParams();
+ if (numParams == 2) {
+ if (func->getParamDecl(0)->getNameAsString() == "interval" &&
+ func->getParamDecl(1)->getNameAsString() == "slot") {
+ emitWarning(stmt, "Pass a context object as 2nd singleShot parameter");
+ }
+ } else if (numParams == 3) {
+ if (func->getParamDecl(0)->getNameAsString() == "interval" &&
+ func->getParamDecl(1)->getNameAsString() == "timerType" &&
+ func->getParamDecl(2)->getNameAsString() == "slot") {
+ emitWarning(stmt, "Pass a context object as 3rd singleShot parameter");
+ }
+ }
+}
-REGISTER_CHECK("connect-3arg-lambda", Connect3argLambda, CheckLevel1)
+void Connect3ArgLambda::processQMenu(FunctionDecl *func, Stmt *stmt)
+{
+ // Signatures to catch:
+ // QMenu::addAction(const QString &text, Func1 slot, const QKeySequence &shortcut = 0)
+ const uint numParams = func->getNumParams();
+ if (numParams == 3) {
+ if (func->getParamDecl(0)->getNameAsString() == "text" &&
+ func->getParamDecl(1)->getNameAsString() == "slot" &&
+ func->getParamDecl(2)->getNameAsString() == "shortcut") {
+ emitWarning(stmt, "Pass a context object as 2nd singleShot parameter");
+ }
+ }
+}