36#include "llvm/ADT/Twine.h"
40using namespace ast_matchers;
44const char *ProblematicWriteBind =
"problematicwrite";
45const char *CapturedBind =
"capturedbind";
46const char *ParamBind =
"parambind";
47const char *IsMethodBind =
"ismethodbind";
48const char *IsARPBind =
"isautoreleasepoolbind";
50class ObjCAutoreleaseWriteChecker :
public Checker<check::ASTCodeBody> {
52 void checkASTCodeBody(
const Decl *
D,
56 std::vector<std::string> SelectorsWithAutoreleasingPool = {
58 "enumerateObjectsUsingBlock:",
59 "enumerateObjectsWithOptions:usingBlock:",
62 "enumerateObjectsAtIndexes:options:usingBlock:",
63 "indexOfObjectAtIndexes:options:passingTest:",
64 "indexesOfObjectsAtIndexes:options:passingTest:",
65 "indexOfObjectPassingTest:",
66 "indexOfObjectWithOptions:passingTest:",
67 "indexesOfObjectsPassingTest:",
68 "indexesOfObjectsWithOptions:passingTest:",
71 "enumerateKeysAndObjectsUsingBlock:",
72 "enumerateKeysAndObjectsWithOptions:usingBlock:",
73 "keysOfEntriesPassingTest:",
74 "keysOfEntriesWithOptions:passingTest:",
77 "objectsPassingTest:",
78 "objectsWithOptions:passingTest:",
79 "enumerateIndexPathsWithOptions:usingBlock:",
82 "enumerateIndexesWithOptions:usingBlock:",
83 "enumerateIndexesUsingBlock:",
84 "enumerateIndexesInRange:options:usingBlock:",
85 "enumerateRangesUsingBlock:",
86 "enumerateRangesWithOptions:usingBlock:",
87 "enumerateRangesInRange:options:usingBlock:",
89 "indexesPassingTest:",
90 "indexWithOptions:passingTest:",
91 "indexesWithOptions:passingTest:",
92 "indexInRange:options:passingTest:",
93 "indexesInRange:options:passingTest:"
96 std::vector<std::string> FunctionsWithAutoreleasingPool = {
97 "dispatch_async",
"dispatch_group_async",
"dispatch_barrier_async"};
101static inline std::vector<llvm::StringRef>
103 return std::vector<llvm::StringRef>(
V.begin(),
V.end());
113 const ObjCAutoreleaseWriteChecker *
Checker) {
120 const char *ActionMsg =
"Write to";
121 const auto *MarkedStmt = Match.
getNodeAs<
Expr>(ProblematicWriteBind);
122 bool IsCapture =
false;
128 ActionMsg =
"Capture of";
137 const char *FunctionDescription = IsMethod ?
"method" :
"function";
141 llvm::raw_svector_ostream BugName(BugNameBuf);
143 <<
" autoreleasing out parameter inside autorelease pool";
146 llvm::raw_svector_ostream BugMessage(BugMessageBuf);
147 BugMessage << ActionMsg <<
" autoreleasing out parameter ";
149 BugMessage <<
"'" + PVD->getName() +
"' ";
151 BugMessage <<
"inside ";
153 BugMessage <<
"locally-scoped autorelease pool;";
155 BugMessage <<
"autorelease pool that may exit before "
156 << FunctionDescription <<
" returns;";
158 BugMessage <<
" consider writing first to a strong local variable"
159 " declared outside ";
161 BugMessage <<
"of the autorelease pool";
163 BugMessage <<
"of the block";
170void ObjCAutoreleaseWriteChecker::checkASTCodeBody(
const Decl *
D,
174 auto DoublePointerParamM =
179 auto ReferencedParamM =
185 hasOperatorName(
"*"),
187 ignoringParenImpCasts(ReferencedParamM))
190 ).bind(ProblematicWriteBind);
192 auto ArgumentCaptureM = hasAnyArgument(
193 ignoringParenImpCasts(ReferencedParamM));