diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -742,8 +742,9 @@ static Stmt *createObjCPropertyGetter(ASTContext &Ctx, const ObjCMethodDecl *MD) { - // First, find the backing ivar. + // First, find the backing ivar. const ObjCIvarDecl *IVar = nullptr; + const ObjCPropertyDecl *Prop = nullptr; // Property accessor stubs sometimes do not correspond to any property decl // in the current interface (but in a superclass). They still have a @@ -751,54 +752,56 @@ if (MD->isSynthesizedAccessorStub()) { const ObjCInterfaceDecl *IntD = MD->getClassInterface(); const ObjCImplementationDecl *ImpD = IntD->getImplementation(); - for (const auto *PI: ImpD->property_impls()) { - if (const ObjCPropertyDecl *P = PI->getPropertyDecl()) { - if (P->getGetterName() == MD->getSelector()) - IVar = P->getPropertyIvarDecl(); + for (const auto *PI : ImpD->property_impls()) { + if (PI->getPropertyDecl()) { + Prop = PI->getPropertyDecl(); + if (Prop->getGetterName() == MD->getSelector()) + IVar = Prop->getPropertyIvarDecl(); } } } if (!IVar) { - const ObjCPropertyDecl *Prop = MD->findPropertyDecl(); + Prop = MD->findPropertyDecl(); IVar = findBackingIvar(Prop); - if (!IVar) - return nullptr; + } - // Ignore weak variables, which have special behavior. - if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak) - return nullptr; + if (!IVar || !Prop) + return nullptr; - // Look to see if Sema has synthesized a body for us. This happens in - // Objective-C++ because the return value may be a C++ class type with a - // non-trivial copy constructor. We can only do this if we can find the - // @synthesize for this property, though (or if we know it's been auto- - // synthesized). - const ObjCImplementationDecl *ImplDecl = + // Ignore weak variables, which have special behavior. + if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak) + return nullptr; + + // Look to see if Sema has synthesized a body for us. This happens in + // Objective-C++ because the return value may be a C++ class type with a + // non-trivial copy constructor. We can only do this if we can find the + // @synthesize for this property, though (or if we know it's been auto- + // synthesized). + const ObjCImplementationDecl *ImplDecl = IVar->getContainingInterface()->getImplementation(); - if (ImplDecl) { - for (const auto *I : ImplDecl->property_impls()) { - if (I->getPropertyDecl() != Prop) - continue; - - if (I->getGetterCXXConstructor()) { - ASTMaker M(Ctx); - return M.makeReturn(I->getGetterCXXConstructor()); - } + if (ImplDecl) { + for (const auto *I : ImplDecl->property_impls()) { + if (I->getPropertyDecl() != Prop) + continue; + + if (I->getGetterCXXConstructor()) { + ASTMaker M(Ctx); + return M.makeReturn(I->getGetterCXXConstructor()); } } - - // Sanity check that the property is the same type as the ivar, or a - // reference to it, and that it is either an object pointer or trivially - // copyable. - if (!Ctx.hasSameUnqualifiedType(IVar->getType(), - Prop->getType().getNonReferenceType())) - return nullptr; - if (!IVar->getType()->isObjCLifetimeType() && - !IVar->getType().isTriviallyCopyableType(Ctx)) - return nullptr; } + // Sanity check that the property is the same type as the ivar, or a + // reference to it, and that it is either an object pointer or trivially + // copyable. + if (!Ctx.hasSameUnqualifiedType(IVar->getType(), + Prop->getType().getNonReferenceType())) + return nullptr; + if (!IVar->getType()->isObjCLifetimeType() && + !IVar->getType().isTriviallyCopyableType(Ctx)) + return nullptr; + // Generate our body: // return self->_ivar; ASTMaker M(Ctx); @@ -807,11 +810,8 @@ if (!selfVar) return nullptr; - Expr *loadedIVar = - M.makeObjCIvarRef( - M.makeLvalueToRvalue( - M.makeDeclRefExpr(selfVar), - selfVar->getType()), + Expr *loadedIVar = M.makeObjCIvarRef( + M.makeLvalueToRvalue(M.makeDeclRefExpr(selfVar), selfVar->getType()), IVar); if (!MD->getReturnType()->isReferenceType()) diff --git a/clang/test/Analysis/properties.mm b/clang/test/Analysis/properties.mm --- a/clang/test/Analysis/properties.mm +++ b/clang/test/Analysis/properties.mm @@ -77,3 +77,23 @@ clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}} } + +@protocol NoDirectPropertyDecl +@property IntWrapperStruct inner; +@end +@interface NoDirectPropertyDecl +@end +@implementation NoDirectPropertyDecl +@synthesize inner; +@end + +// rdar://67416721 +void testNoDirectPropertyDecl(NoDirectPropertyDecl *w) { + clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}} + + int origValue = w.inner.value; + if (origValue != 42) + return; + + clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}} +}