37#include "llvm/Support/Debug.h"
41using namespace ast_matchers;
46const char *WarnAtNode =
"waitcall";
48class GCDAntipatternChecker :
public Checker<check::ASTCodeBody> {
50 void checkASTCodeBody(
const Decl *
D,
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();
216 auto GroupMatcherM = findGCDAntiPatternWithGroup();
228bool ento::shouldRegisterGCDAntipattern(
const CheckerManager &mgr) {
BoundNodesTreeBuilder Nodes
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.
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 CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=std::nullopt, ArrayRef< FixItHint > Fixits=std::nullopt)
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
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 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 AstTypeMatcher< BlockPointerType > blockPointerType
Matches block pointer types, i.e.
const internal::VariadicDynCastAllOfMatcher< Stmt, BinaryOperator > binaryOperator
Matches binary operator expressions.
internal::PolymorphicMatcher< internal::ValueEqualsMatcher, void(internal::AllNodeBaseTypes), ValueT > equals(const ValueT &Value)
Matches literals that are equal to the given value of type ValueT.
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.
The JSON file list parser is used to communicate input to InstallAPI.