38 #include "llvm/Support/Debug.h" 40 using namespace clang;
47 const char *WarnAtNode =
"waitcall";
49 class GCDAntipatternChecker :
public Checker<check::ASTCodeBody> {
51 void checkASTCodeBody(
const Decl *D,
53 BugReporter &BR)
const;
56 auto callsName(
const char *FunctionName)
61 auto equalsBoundArgDecl(
int ArgIdx,
const char *DeclName)
62 -> decltype(hasArgument(0,
expr())) {
63 return hasArgument(ArgIdx, ignoringParenCasts(
declRefExpr(
64 to(
varDecl(equalsBoundNode(DeclName))))));
67 auto bindAssignmentToDecl(
const char *DeclName) -> decltype(hasLHS(
expr())) {
68 return hasLHS(ignoringParenImpCasts(
76 static bool isTest(
const Decl *D) {
77 if (
const auto* ND = dyn_cast<NamedDecl>(D)) {
78 std::string DeclName = ND->getNameAsString();
79 if (StringRef(DeclName).startswith(
"test"))
82 if (
const auto *OD = dyn_cast<ObjCMethodDecl>(D)) {
83 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(OD->getParent())) {
84 std::string ContainerName = CD->getNameAsString();
85 StringRef CN(ContainerName);
86 if (CN.contains_lower(
"test") || CN.contains_lower(
"mock"))
93 static auto findGCDAntiPatternWithSemaphore() -> decltype(
compoundStmt()) {
95 const char *SemaphoreBinding =
"semaphore_name";
97 callsName(
"dispatch_semaphore_create"),
100 auto SemaphoreBindingM =
anyOf(
104 hasRHS(SemaphoreCreateM))));
106 auto HasBlockArgumentM = hasAnyArgument(hasType(
112 callsName(
"dispatch_semaphore_signal"),
113 equalsBoundArgDecl(0, SemaphoreBinding)
116 auto HasBlockAndCallsSignalM =
allOf(HasBlockArgumentM, ArgCallsSignalM);
118 auto HasBlockCallingSignalM =
128 callsName(
"dispatch_semaphore_wait"),
129 equalsBoundArgDecl(0, SemaphoreBinding)
134 SemaphoreBindingM, HasBlockCallingSignalM, SemaphoreWaitM);
137 static auto findGCDAntiPatternWithGroup() -> decltype(
compoundStmt()) {
139 const char *GroupBinding =
"group_name";
140 auto DispatchGroupCreateM =
callExpr(callsName(
"dispatch_group_create"));
142 auto GroupBindingM =
anyOf(
146 hasRHS(DispatchGroupCreateM))));
150 equalsBoundArgDecl(0, GroupBinding)))));
152 auto HasBlockArgumentM = hasAnyArgument(hasType(
158 callsName(
"dispatch_group_leave"),
159 equalsBoundArgDecl(0, GroupBinding)
162 auto HasBlockAndCallsLeaveM =
allOf(HasBlockArgumentM, ArgCallsSignalM);
174 callsName(
"dispatch_group_wait"),
175 equalsBoundArgDecl(0, GroupBinding)
179 return compoundStmt(GroupBindingM, GroupEnterM, AcceptsBlockM, GroupWaitM);
186 const GCDAntipatternChecker *Checker) {
190 std::string Diagnostics;
191 llvm::raw_string_ostream
OS(Diagnostics);
192 OS <<
"Waiting on a callback using a " << Type <<
" creates useless threads " 193 <<
"and is subject to priority inversion; consider " 194 <<
"using a synchronous API or changing the caller to be asynchronous";
199 "GCD performance anti-pattern",
203 SW->getSourceRange());
206 void GCDAntipatternChecker::checkASTCodeBody(
const Decl *D,
208 BugReporter &BR)
const {
214 auto SemaphoreMatcherM = findGCDAntiPatternWithSemaphore();
215 auto Matches =
match(SemaphoreMatcherM, *D->
getBody(), AM.getASTContext());
219 auto GroupMatcherM = findGCDAntiPatternWithGroup();
220 Matches =
match(GroupMatcherM, *D->
getBody(), AM.getASTContext());
227 void ento::registerGCDAntipattern(CheckerManager &Mgr) {
228 Mgr.registerChecker<GCDAntipatternChecker>();
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
Decl - This represents one declaration (or definition), e.g.
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher. ...
The base class of the type hierarchy.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
BoundNodesTreeBuilder Nodes
AnalysisDeclContext contains the context data for the function or method under analysis.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
const T * getNodeAs(StringRef ID) const
Returns the AST node bound to ID.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher. ...
bool equals(const til::SExpr *E1, const til::SExpr *E2)
Maps string IDs to AST nodes matched by parts of a matcher.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
const internal::VariadicDynCastAllOfMatcher< Stmt, IntegerLiteral > integerLiteral
Matches integer literals of all sizes / encodings, e.g.
const Decl * getDecl() const
static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)
Dataflow Directional Tag Classes.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
internal::Matcher< NamedDecl > hasName(const std::string &Name)
Matches NamedDecl nodes that have the specified name.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
const internal::VariadicDynCastAllOfMatcher< Stmt, CompoundStmt > compoundStmt
Matches compound statements.
const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCMessageExpr > objcMessageExpr
Matches ObjectiveC Message invocation expressions.
const AstTypeMatcher< BlockPointerType > blockPointerType
Matches block pointer types, i.e.