Index: include/clang/Analysis/Analyses/ThreadSafetyCommon.h =================================================================== --- include/clang/Analysis/Analyses/ThreadSafetyCommon.h +++ include/clang/Analysis/Analyses/ThreadSafetyCommon.h @@ -397,6 +397,8 @@ CallingContext *Ctx) ; til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx); til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx); + til::SExpr *translateObjCIVarRefExpr(const ObjCIvarRefExpr *IVRE, + CallingContext *Ctx); til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx, const Expr *SelfE = nullptr); til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME, Index: lib/Analysis/ThreadSafetyCommon.cpp =================================================================== --- lib/Analysis/ThreadSafetyCommon.cpp +++ lib/Analysis/ThreadSafetyCommon.cpp @@ -211,6 +211,8 @@ return translateCXXThisExpr(cast(S), Ctx); case Stmt::MemberExprClass: return translateMemberExpr(cast(S), Ctx); + case Stmt::ObjCIvarRefExprClass: + return translateObjCIVarRefExpr(cast(S), Ctx); case Stmt::CallExprClass: return translateCallExpr(cast(S), Ctx); case Stmt::CXXMemberCallExprClass: @@ -311,9 +313,9 @@ return nullptr; } -static bool hasCppPointerType(const til::SExpr *E) { +static bool hasAnyPointerType(const til::SExpr *E) { auto *VD = getValueDeclFromSExpr(E); - if (VD && VD->getType()->isPointerType()) + if (VD && VD->getType()->isAnyPointerType()) return true; if (const auto *C = dyn_cast(E)) return C->castOpcode() == til::CAST_objToPtr; @@ -344,7 +346,20 @@ D = getFirstVirtualDecl(VD); til::Project *P = new (Arena) til::Project(E, D); - if (hasCppPointerType(BE)) + if (hasAnyPointerType(BE)) + P->setArrow(true); + return P; +} + +til::SExpr *SExprBuilder::translateObjCIVarRefExpr(const ObjCIvarRefExpr *IVRE, + CallingContext *Ctx) { + til::SExpr *BE = translate(IVRE->getBase(), Ctx); + til::SExpr *E = new (Arena) til::SApply(BE); + + const auto *D = cast(IVRE->getDecl()->getCanonicalDecl()); + + til::Project *P = new (Arena) til::Project(E, D); + if (hasAnyPointerType(BE)) P->setArrow(true); return P; } Index: test/SemaObjCXX/warn-thread-safety-analysis.mm =================================================================== --- test/SemaObjCXX/warn-thread-safety-analysis.mm +++ test/SemaObjCXX/warn-thread-safety-analysis.mm @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -Wthread-safety-beta -Wno-objc-root-class %s + +class __attribute__((lockable)) Lock { +public: + void Acquire() __attribute__((exclusive_lock_function())) {} + void Release() __attribute__((unlock_function())) {} +}; + +class __attribute__((scoped_lockable)) AutoLock { +public: + AutoLock(Lock &lock) __attribute__((exclusive_lock_function(lock))) + : lock_(lock) { + lock.Acquire(); + } + ~AutoLock() __attribute__((unlock_function())) { lock_.Release(); } + +private: + Lock &lock_; +}; + +@interface MyInterface { +@private + Lock lock_; + int value_; +} + +- (void)incrementValue; +- (void)decrementValue; + +@end + +@implementation MyInterface + +- (void)incrementValue { + AutoLock lock(lock_); + value_ += 1; +} + +- (void)decrementValue { + lock_.Acquire(); // expected-note{{mutex acquired here}} + value_ -= 1; +} // expected-warning{{mutex 'self->lock_' is still held at the end of function}} + +@end