diff options
Diffstat (limited to 'src/checks/level1/connect-3arg-lambda.cpp')
-rw-r--r-- | src/checks/level1/connect-3arg-lambda.cpp | 78 |
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"); + } + } +} |