37 #include "llvm/Support/Debug.h"
39 using namespace clang;
41 using namespace ast_matchers;
46 const char *WarnAtNode =
"waitcall";
48 class GCDAntipatternChecker :
public Checker<check::ASTCodeBody> {
50 void checkASTCodeBody(
const Decl *D,
52 BugReporter &BR)
const;
55 decltype(
auto) callsName(const
char *FunctionName) {
59 decltype(
auto) equalsBoundArgDecl(
int ArgIdx, const
char *DeclName) {
60 return hasArgument(ArgIdx, ignoringParenCasts(
declRefExpr(
61 to(
varDecl(equalsBoundNode(DeclName))))));
64 decltype(
auto) bindAssignmentToDecl(const
char *DeclName) {
65 return hasLHS(ignoringParenImpCasts(
73 static bool isTest(
const Decl *D) {
74 if (
const auto* ND = dyn_cast<NamedDecl>(D)) {
76 if (StringRef(DeclName).startswith(
"test"))
79 if (
const auto *OD = dyn_cast<ObjCMethodDecl>(D)) {
80 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(OD->getParent())) {
82 StringRef CN(ContainerName);
83 if (CN.contains_insensitive(
"test") || CN.contains_insensitive(
"mock"))
90 static auto findGCDAntiPatternWithSemaphore() -> decltype(
compoundStmt()) {
92 const char *SemaphoreBinding =
"semaphore_name";
94 callsName(
"dispatch_semaphore_create"),
97 auto SemaphoreBindingM =
anyOf(
101 hasRHS(SemaphoreCreateM))));
103 auto HasBlockArgumentM = hasAnyArgument(hasType(
109 callsName(
"dispatch_semaphore_signal"),
110 equalsBoundArgDecl(0, SemaphoreBinding)
113 auto HasBlockAndCallsSignalM =
allOf(HasBlockArgumentM, ArgCallsSignalM);
115 auto HasBlockCallingSignalM =
125 callsName(
"dispatch_semaphore_wait"),
126 equalsBoundArgDecl(0, SemaphoreBinding)
131 SemaphoreBindingM, HasBlockCallingSignalM, SemaphoreWaitM);
134 static auto findGCDAntiPatternWithGroup() -> decltype(
compoundStmt()) {
136 const char *GroupBinding =
"group_name";
137 auto DispatchGroupCreateM =
callExpr(callsName(
"dispatch_group_create"));
139 auto GroupBindingM =
anyOf(
143 hasRHS(DispatchGroupCreateM))));
147 equalsBoundArgDecl(0, GroupBinding)))));
149 auto HasBlockArgumentM = hasAnyArgument(hasType(
155 callsName(
"dispatch_group_leave"),
156 equalsBoundArgDecl(0, GroupBinding)
159 auto HasBlockAndCallsLeaveM =
allOf(HasBlockArgumentM, ArgCallsSignalM);
171 callsName(
"dispatch_group_wait"),
172 equalsBoundArgDecl(0, GroupBinding)
176 return compoundStmt(GroupBindingM, GroupEnterM, AcceptsBlockM, GroupWaitM);
183 const GCDAntipatternChecker *Checker) {
188 llvm::raw_string_ostream
OS(Diagnostics);
189 OS <<
"Waiting on a callback using a " <<
Type <<
" creates useless threads "
190 <<
"and is subject to priority inversion; consider "
191 <<
"using a synchronous API or changing the caller to be asynchronous";
196 "GCD performance anti-pattern",
200 SW->getSourceRange());
203 void GCDAntipatternChecker::checkASTCodeBody(
const Decl *D,
205 BugReporter &BR)
const {
211 auto SemaphoreMatcherM = findGCDAntiPatternWithSemaphore();
212 auto Matches =
match(SemaphoreMatcherM, *D->
getBody(), AM.getASTContext());
216 auto GroupMatcherM = findGCDAntiPatternWithGroup();
217 Matches =
match(GroupMatcherM, *D->
getBody(), AM.getASTContext());
224 void ento::registerGCDAntipattern(CheckerManager &Mgr) {
225 Mgr.registerChecker<GCDAntipatternChecker>();
228 bool ento::shouldRegisterGCDAntipattern(
const CheckerManager &mgr) {