37 #include "llvm/Support/Debug.h" 39 using namespace clang;
46 const char *WarnAtNode =
"waitcall";
48 class GCDAntipatternChecker :
public Checker<check::ASTCodeBody> {
50 void checkASTCodeBody(
const Decl *D,
52 BugReporter &BR)
const;
55 auto callsName(
const char *FunctionName)
60 auto equalsBoundArgDecl(
int ArgIdx,
const char *DeclName)
61 -> decltype(hasArgument(0,
expr())) {
62 return hasArgument(ArgIdx, ignoringParenCasts(
declRefExpr(
63 to(
varDecl(equalsBoundNode(DeclName))))));
66 auto bindAssignmentToDecl(
const char *DeclName) -> decltype(hasLHS(
expr())) {
67 return hasLHS(ignoringParenImpCasts(
75 static bool isTest(
const Decl *D) {
76 if (
const auto* ND = dyn_cast<NamedDecl>(D)) {
77 std::string DeclName = ND->getNameAsString();
78 if (StringRef(DeclName).startswith(
"test"))
81 if (
const auto *OD = dyn_cast<ObjCMethodDecl>(D)) {
82 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(OD->getParent())) {
83 std::string ContainerName = CD->getNameAsString();
84 StringRef CN(ContainerName);
85 if (CN.contains_lower(
"test") || CN.contains_lower(
"mock"))
92 static auto findGCDAntiPatternWithSemaphore() -> decltype(
compoundStmt()) {
94 const char *SemaphoreBinding =
"semaphore_name";
96 callsName(
"dispatch_semaphore_create"),
99 auto SemaphoreBindingM =
anyOf(
103 hasRHS(SemaphoreCreateM))));
105 auto HasBlockArgumentM = hasAnyArgument(hasType(
111 callsName(
"dispatch_semaphore_signal"),
112 equalsBoundArgDecl(0, SemaphoreBinding)
115 auto HasBlockAndCallsSignalM =
allOf(HasBlockArgumentM, ArgCallsSignalM);
117 auto HasBlockCallingSignalM =
127 callsName(
"dispatch_semaphore_wait"),
128 equalsBoundArgDecl(0, SemaphoreBinding)
133 SemaphoreBindingM, HasBlockCallingSignalM, SemaphoreWaitM);
136 static auto findGCDAntiPatternWithGroup() -> decltype(
compoundStmt()) {
138 const char *GroupBinding =
"group_name";
139 auto DispatchGroupCreateM =
callExpr(callsName(
"dispatch_group_create"));
141 auto GroupBindingM =
anyOf(
145 hasRHS(DispatchGroupCreateM))));
149 equalsBoundArgDecl(0, GroupBinding)))));
151 auto HasBlockArgumentM = hasAnyArgument(hasType(
157 callsName(
"dispatch_group_leave"),
158 equalsBoundArgDecl(0, GroupBinding)
161 auto HasBlockAndCallsLeaveM =
allOf(HasBlockArgumentM, ArgCallsSignalM);
173 callsName(
"dispatch_group_wait"),
174 equalsBoundArgDecl(0, GroupBinding)
178 return compoundStmt(GroupBindingM, GroupEnterM, AcceptsBlockM, GroupWaitM);
185 const GCDAntipatternChecker *Checker) {
189 std::string Diagnostics;
190 llvm::raw_string_ostream
OS(Diagnostics);
191 OS <<
"Waiting on a callback using a " << Type <<
" creates useless threads " 192 <<
"and is subject to priority inversion; consider " 193 <<
"using a synchronous API or changing the caller to be asynchronous";
198 "GCD performance anti-pattern",
202 SW->getSourceRange());
205 void GCDAntipatternChecker::checkASTCodeBody(
const Decl *D,
207 BugReporter &BR)
const {
213 auto SemaphoreMatcherM = findGCDAntiPatternWithSemaphore();
214 auto Matches =
match(SemaphoreMatcherM, *D->
getBody(), AM.getASTContext());
218 auto GroupMatcherM = findGCDAntiPatternWithGroup();
219 Matches =
match(GroupMatcherM, *D->
getBody(), AM.getASTContext());
226 void ento::registerGCDAntipattern(CheckerManager &Mgr) {
227 Mgr.registerChecker<GCDAntipatternChecker>();
230 bool ento::shouldRegisterGCDAntipattern(
const LangOptions &LO) {
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.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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.