35 #include "llvm/ADT/Twine.h" 37 using namespace clang;
43 const char *ProblematicWriteBind =
"problematicwrite";
44 const char *CapturedBind =
"capturedbind";
45 const char *ParamBind =
"parambind";
46 const char *IsMethodBind =
"ismethodbind";
48 class ObjCAutoreleaseWriteChecker :
public Checker<check::ASTCodeBody> {
50 void checkASTCodeBody(
const Decl *D,
52 BugReporter &BR)
const;
54 std::vector<std::string> SelectorsWithAutoreleasingPool = {
56 "enumerateObjectsUsingBlock:",
57 "enumerateObjectsWithOptions:usingBlock:",
60 "enumerateObjectsAtIndexes:options:usingBlock:",
61 "indexOfObjectAtIndexes:options:passingTest:",
62 "indexesOfObjectsAtIndexes:options:passingTest:",
63 "indexOfObjectPassingTest:",
64 "indexOfObjectWithOptions:passingTest:",
65 "indexesOfObjectsPassingTest:",
66 "indexesOfObjectsWithOptions:passingTest:",
69 "enumerateKeysAndObjectsUsingBlock:",
70 "enumerateKeysAndObjectsWithOptions:usingBlock:",
71 "keysOfEntriesPassingTest:",
72 "keysOfEntriesWithOptions:passingTest:",
75 "objectsPassingTest:",
76 "objectsWithOptions:passingTest:",
77 "enumerateIndexPathsWithOptions:usingBlock:",
80 "enumerateIndexesWithOptions:usingBlock:",
81 "enumerateIndexesUsingBlock:",
82 "enumerateIndexesInRange:options:usingBlock:",
83 "enumerateRangesUsingBlock:",
84 "enumerateRangesWithOptions:usingBlock:",
85 "enumerateRangesInRange:options:usingBlock:",
87 "indexesPassingTest:",
88 "indexWithOptions:passingTest:",
89 "indexesWithOptions:passingTest:",
90 "indexInRange:options:passingTest:",
91 "indexesInRange:options:passingTest:" 94 std::vector<std::string> FunctionsWithAutoreleasingPool = {
95 "dispatch_async",
"dispatch_group_async",
"dispatch_barrier_async"};
99 static inline std::vector<llvm::StringRef>
toRefs(std::vector<std::string>
V) {
100 return std::vector<llvm::StringRef>(V.begin(), V.end());
103 static auto callsNames(std::vector<std::string> FunctionNames)
110 const ObjCAutoreleaseWriteChecker *Checker) {
117 const char *ActionMsg =
"Write to";
118 const auto *MarkedStmt = Match.
getNodeAs<
Expr>(ProblematicWriteBind);
119 bool IsCapture =
false;
125 ActionMsg =
"Capture of";
131 MarkedStmt, BR.getSourceManager(), ADC);
133 const char *Name = IsMethod ?
"method" :
"function";
137 (llvm::Twine(ActionMsg)
138 +
" autoreleasing out parameter inside autorelease pool").str(),
140 (llvm::Twine(ActionMsg) +
" autoreleasing out parameter " +
141 (IsCapture ?
"'" + PVD->getName() +
"'" +
" " :
"") +
"inside " +
142 "autorelease pool that may exit before " + Name +
" returns; consider " 143 "writing first to a strong local variable declared outside of the block")
149 void ObjCAutoreleaseWriteChecker::checkASTCodeBody(
const Decl *D,
151 BugReporter &BR)
const {
153 auto DoublePointerParamM =
158 auto ReferencedParamM =
164 hasOperatorName(
"*"),
166 ignoringParenImpCasts(ReferencedParamM))
169 ).bind(ProblematicWriteBind);
171 auto ArgumentCaptureM = hasAnyArgument(
172 ignoringParenImpCasts(ReferencedParamM));
178 auto WritesOrCapturesInBlockM = hasAnyArgument(
allOf(
181 stmt(
anyOf(WritesIntoM, CapturedInParamM))
184 auto BlockPassedToMarkedFuncM =
stmt(
anyOf(
186 callsNames(FunctionsWithAutoreleasingPool), WritesOrCapturesInBlockM)),
189 WritesOrCapturesInBlockM))
192 auto HasParamAndWritesInMarkedFuncM =
allOf(
193 hasAnyParameter(DoublePointerParamM),
197 objcMethodDecl(HasParamAndWritesInMarkedFuncM).bind(IsMethodBind),
199 blockDecl(HasParamAndWritesInMarkedFuncM)));
206 void ento::registerAutoreleaseWriteChecker(CheckerManager &Mgr) {
207 Mgr.registerChecker<ObjCAutoreleaseWriteChecker>();
210 bool ento::shouldRegisterAutoreleaseWriteChecker(
const LangOptions &LO) {
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.
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.
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.