36 #include "llvm/ADT/Twine.h" 38 using namespace clang;
44 const char *ProblematicWriteBind =
"problematicwrite";
45 const char *CapturedBind =
"capturedbind";
46 const char *ParamBind =
"parambind";
47 const char *IsMethodBind =
"ismethodbind";
49 class ObjCAutoreleaseWriteChecker :
public Checker<check::ASTCodeBody> {
51 void checkASTCodeBody(
const Decl *D,
53 BugReporter &BR)
const;
55 std::vector<std::string> SelectorsWithAutoreleasingPool = {
57 "enumerateObjectsUsingBlock:",
58 "enumerateObjectsWithOptions:usingBlock:",
61 "enumerateObjectsAtIndexes:options:usingBlock:",
62 "indexOfObjectAtIndexes:options:passingTest:",
63 "indexesOfObjectsAtIndexes:options:passingTest:",
64 "indexOfObjectPassingTest:",
65 "indexOfObjectWithOptions:passingTest:",
66 "indexesOfObjectsPassingTest:",
67 "indexesOfObjectsWithOptions:passingTest:",
70 "enumerateKeysAndObjectsUsingBlock:",
71 "enumerateKeysAndObjectsWithOptions:usingBlock:",
72 "keysOfEntriesPassingTest:",
73 "keysOfEntriesWithOptions:passingTest:",
76 "objectsPassingTest:",
77 "objectsWithOptions:passingTest:",
78 "enumerateIndexPathsWithOptions:usingBlock:",
81 "enumerateIndexesWithOptions:usingBlock:",
82 "enumerateIndexesUsingBlock:",
83 "enumerateIndexesInRange:options:usingBlock:",
84 "enumerateRangesUsingBlock:",
85 "enumerateRangesWithOptions:usingBlock:",
86 "enumerateRangesInRange:options:usingBlock:",
88 "indexesPassingTest:",
89 "indexWithOptions:passingTest:",
90 "indexesWithOptions:passingTest:",
91 "indexInRange:options:passingTest:",
92 "indexesInRange:options:passingTest:" 95 std::vector<std::string> FunctionsWithAutoreleasingPool = {
96 "dispatch_async",
"dispatch_group_async",
"dispatch_barrier_async"};
100 static inline std::vector<llvm::StringRef>
toRefs(std::vector<std::string> V) {
101 return std::vector<llvm::StringRef>(V.begin(), V.end());
104 static auto callsNames(std::vector<std::string> FunctionNames)
111 const ObjCAutoreleaseWriteChecker *Checker) {
118 const char *ActionMsg =
"Write to";
119 const auto *MarkedStmt = Match.
getNodeAs<
Expr>(ProblematicWriteBind);
120 bool IsCapture =
false;
126 ActionMsg =
"Capture of";
132 MarkedStmt, BR.getSourceManager(), ADC);
134 const char *Name = IsMethod ?
"method" :
"function";
138 (llvm::Twine(ActionMsg)
139 +
" autoreleasing out parameter inside autorelease pool").
str(),
141 (llvm::Twine(ActionMsg) +
" autoreleasing out parameter " +
142 (IsCapture ?
"'" + PVD->getName() +
"'" +
" " :
"") +
"inside " +
143 "autorelease pool that may exit before " + Name +
" returns; consider " 144 "writing first to a strong local variable declared outside of the block")
150 void ObjCAutoreleaseWriteChecker::checkASTCodeBody(
const Decl *D,
152 BugReporter &BR)
const {
154 auto DoublePointerParamM =
159 auto ReferencedParamM =
165 hasOperatorName(
"*"),
167 ignoringParenImpCasts(ReferencedParamM))
170 ).bind(ProblematicWriteBind);
172 auto ArgumentCaptureM = hasAnyArgument(
173 ignoringParenImpCasts(ReferencedParamM));
179 auto WritesOrCapturesInBlockM = hasAnyArgument(
allOf(
182 stmt(
anyOf(WritesIntoM, CapturedInParamM))
185 auto BlockPassedToMarkedFuncM =
stmt(
anyOf(
187 callsNames(FunctionsWithAutoreleasingPool), WritesOrCapturesInBlockM)),
190 WritesOrCapturesInBlockM))
193 auto HasParamAndWritesInMarkedFuncM =
allOf(
194 hasAnyParameter(DoublePointerParamM),
198 objcMethodDecl(HasParamAndWritesInMarkedFuncM).bind(IsMethodBind),
200 blockDecl(HasParamAndWritesInMarkedFuncM)));
207 void ento::registerAutoreleaseWriteChecker(CheckerManager &Mgr) {
208 Mgr.registerChecker<ObjCAutoreleaseWriteChecker>();
const internal::VariadicDynCastAllOfMatcher< Stmt, CallExpr > callExpr
Matches call expressions.
A (possibly-)qualified type.
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
const internal::VariadicFunction< internal::Matcher< ObjCMessageExpr >, StringRef, internal::hasAnySelectorFunc > hasAnySelector
Matches when at least one of the supplied string equals to the Selector.getAsString() ...
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 AstTypeMatcher< PointerType > pointerType
Matches pointer types, but does not match Objective-C object pointer types.
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.
ObjCMethodDecl - Represents an instance or class method declaration.
const internal::VariadicDynCastAllOfMatcher< Decl, FunctionDecl > functionDecl
Matches function declarations.
Represents a parameter to a function.
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.
const internal::VariadicFunction< internal::Matcher< NamedDecl >, StringRef, internal::hasAnyNameFunc > hasAnyName
Matches NamedDecl nodes that have any of the specified names.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
static auto callsNames(std::vector< std::string > FunctionNames) -> decltype(callee(functionDecl()))
const internal::ArgumentAdaptingMatcherFunc< internal::ForEachDescendantMatcher > forEachDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher. ...
This represents one expression.
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
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< Decl, ParmVarDecl > parmVarDecl
Matches parameter variable declarations.
ASTContext & getASTContext() const LLVM_READONLY
const internal::VariadicDynCastAllOfMatcher< Decl, ObjCMethodDecl > objcMethodDecl
Matches Objective-C method declarations.
const Decl * getDecl() const
static void emitDiagnostics(BoundNodes &Match, const Decl *D, BugReporter &BR, AnalysisManager &AM, const ObjCAutoreleaseWriteChecker *Checker)
Assigning into this object requires a lifetime extension.
Dataflow Directional Tag Classes.
const internal::VariadicDynCastAllOfMatcher< Stmt, UnaryOperator > unaryOperator
Matches unary operator expressions.
static std::vector< llvm::StringRef > toRefs(std::vector< std::string > V)
const AstTypeMatcher< ObjCObjectPointerType > objcObjectPointerType
Matches an Objective-C object pointer type, which is different from a pointer type, despite being syntactically similar.
const internal::VariadicDynCastAllOfMatcher< Decl, BlockDecl > blockDecl
Matches block declarations.
A trivial tuple used to represent a source range.
const internal::VariadicDynCastAllOfMatcher< Stmt, ObjCMessageExpr > objcMessageExpr
Matches ObjectiveC Message invocation expressions.
const AstTypeMatcher< BlockPointerType > blockPointerType
Matches block pointer types, i.e.