ProgramStateRef setRefBinding(ProgramStateRef State, SymbolRef Sym,
RefVal Val) {
+ assert(Sym != nullptr);
return State->set<RefBindings>(Sym, Val);
}
}
// Consult the summary for the return value.
- SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol();
RetEffect RE = Summ.getRetEffect();
- if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
- if (Optional<RefVal> updatedRefVal =
- refValFromRetEffect(RE, MCall->getResultType())) {
- state = setRefBinding(state, Sym, *updatedRefVal);
+
+ if (SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol()) {
+ if (const auto *MCall = dyn_cast<CXXMemberCall>(&CallOrMsg)) {
+ if (Optional<RefVal> updatedRefVal =
+ refValFromRetEffect(RE, MCall->getResultType())) {
+ state = setRefBinding(state, Sym, *updatedRefVal);
+ }
}
- }
- if (RE.getKind() == RetEffect::NoRetHard && Sym)
- state = removeRefBinding(state, Sym);
+ if (RE.getKind() == RetEffect::NoRetHard)
+ state = removeRefBinding(state, Sym);
+ }
C.addTransition(state);
}
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang;
using namespace ento;
return Summ;
}
-static bool isOSObjectSubclass(QualType T);
-
-static bool isOSObjectSubclass(const CXXRecordDecl *RD) {
- if (RD->getDeclName().getAsString() == "OSObject")
- return true;
-
- const CXXRecordDecl *RDD = RD->getDefinition();
- if (!RDD)
- return false;
+static bool isSubclass(const Decl *D,
+ StringRef ClassName) {
+ using namespace ast_matchers;
+ DeclarationMatcher SubclassM = cxxRecordDecl(isSameOrDerivedFrom(ClassName));
+ return !(match(SubclassM, *D, D->getASTContext()).empty());
+}
- for (const CXXBaseSpecifier Spec : RDD->bases()) {
- if (isOSObjectSubclass(Spec.getType()))
- return true;
- }
- return false;
+static bool isOSObjectSubclass(const Decl *D) {
+ return isSubclass(D, "OSObject");
}
-/// \return Whether type represents an OSObject successor.
-static bool isOSObjectSubclass(QualType T) {
- if (const auto *RD = T->getAsCXXRecordDecl()) {
- return isOSObjectSubclass(RD);
- }
- return false;
+static bool isOSIteratorSubclass(const Decl *D) {
+ return isSubclass(D, "OSIterator");
}
static bool hasRCAnnotation(const Decl *D, StringRef rcAnnotation) {
}
if (RetTy->isPointerType()) {
- if (TrackOSObjects && isOSObjectSubclass(RetTy->getPointeeType())) {
+
+ const CXXRecordDecl *PD = RetTy->getPointeeType()->getAsCXXRecordDecl();
+ if (TrackOSObjects && PD && isOSObjectSubclass(PD)) {
if (const IdentifierInfo *II = FD->getIdentifier()) {
- StringRef FuncName = II->getName();
- if (FuncName.contains_lower("with")
- || FuncName.contains_lower("create")
- || FuncName.contains_lower("copy"))
+
+ // All objects returned with functions starting with "get" are getters.
+ if (II->getName().startswith("get")) {
+
+ // ...except for iterators.
+ if (isOSIteratorSubclass(PD))
+ return getOSSummaryCreateRule(FD);
+ return getOSSummaryGetRule(FD);
+ } else {
return getOSSummaryCreateRule(FD);
+ }
}
- return getOSSummaryGetRule(FD);
}
// For CoreFoundation ('CF') types.
if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) {
const CXXRecordDecl *Parent = MD->getParent();
- if (TrackOSObjects && isOSObjectSubclass(Parent)) {
- if (isRelease(FD, FName))
+ if (TrackOSObjects && Parent && isOSObjectSubclass(Parent)) {
+ if (FName == "release")
return getOSSummaryReleaseRule(FD);
- if (isRetain(FD, FName))
+ if (FName == "retain")
return getOSSummaryRetainRule(FD);
}
}