37#include "llvm/Support/Debug.h"
46const char *WarnAtNode =
"waitcall";
48class GCDAntipatternChecker :
public Checker<check::ASTCodeBody> {
50 void checkASTCodeBody(
const Decl *D,
52 BugReporter &BR)
const;
55decltype(
auto) callsName(
const char *FunctionName) {
59decltype(
auto) equalsBoundArgDecl(
int ArgIdx,
const char *DeclName) {
60 return hasArgument(ArgIdx, ignoringParenCasts(
declRefExpr(
61 to(
varDecl(equalsBoundNode(DeclName))))));
64decltype(
auto) bindAssignmentToDecl(
const char *DeclName) {
65 return hasLHS(ignoringParenImpCasts(
73static bool isTest(
const Decl *D) {
74 if (
const auto* ND = dyn_cast<NamedDecl>(D)) {
75 std::string DeclName = ND->getNameAsString();
76 if (StringRef(DeclName).starts_with(
"test"))
79 if (
const auto *OD = dyn_cast<ObjCMethodDecl>(D)) {
80 if (
const auto *CD = dyn_cast<ObjCContainerDecl>(OD->getParent())) {
81 std::string ContainerName = CD->getNameAsString();
82 StringRef CN(ContainerName);
83 if (CN.contains_insensitive(
"test") || CN.contains_insensitive(
"mock"))
90static 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);
134static 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) {
187 std::string Diagnostics;
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());
203void GCDAntipatternChecker::checkASTCodeBody(
const Decl *D,
211 auto SemaphoreMatcherM = findGCDAntiPatternWithSemaphore();
213 for (BoundNodes
Match : Matches)
216 auto GroupMatcherM = findGCDAntiPatternWithGroup();
218 for (BoundNodes
Match : Matches)
224void ento::registerGCDAntipattern(CheckerManager &Mgr) {
228bool ento::shouldRegisterGCDAntipattern(
const CheckerManager &mgr) {
static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)
AnalysisDeclContext contains the context data for the function, method or block under analysis.
const Decl * getDecl() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Decl - This represents one declaration (or definition), e.g.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
The base class of the type hierarchy.
Maps string IDs to AST nodes matched by parts of a matcher.
const T * getNodeAs(StringRef ID) const
Returns the AST node bound to ID.
ASTContext & getASTContext() override
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerFrontend *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges={}, ArrayRef< FixItHint > Fixits={})
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
internal::Matcher< NamedDecl > hasName(StringRef Name)
Matches NamedDecl nodes that have the specified name.
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, CompoundStmt > compoundStmt
Matches compound statements.
const AstTypeMatcher< BlockPointerType > blockPointerType
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCMessageExpr > objcMessageExpr
Matches ObjectiveC Message invocation expressions.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> allOf
Matches if all given matchers match.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, IntegerLiteral > integerLiteral
Matches integer literals of all sizes / encodings, e.g.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits< unsigned >::max()> anyOf
Matches if any of the given matchers matches.
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
bool equals(const til::SExpr *E1, const til::SExpr *E2)
The JSON file list parser is used to communicate input to InstallAPI.
@ Match
This is not an overload because the signature exactly matches an existing declaration.