From: Fariborz Jahanian Date: Wed, 11 Jun 2014 16:52:44 +0000 (+0000) Subject: Objective-C. Patch to handle bridge attribute warnings X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ceaaaef14c5c467c0d5edd4321342e4e98d91c36;p=clang Objective-C. Patch to handle bridge attribute warnings correctly when both NSAttributedString and NSMutableAttributedString are specified on the same CFStruct via different typedefs. // rdar://17238954 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@210660 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index ced1555588..03482d33c3 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -3280,12 +3280,15 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, } template -static void CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) { +static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, + bool &HadTheAttribute, bool warn) { QualType T = castExpr->getType(); + HadTheAttribute = false; while (const TypedefType *TD = dyn_cast(T.getTypePtr())) { TypedefNameDecl *TDNDecl = TD->getDecl(); if (TB *ObjCBAttr = getObjCBridgeAttr(TD)) { if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { + HadTheAttribute = true; NamedDecl *Target = nullptr; // Check for an existing type with this name. LookupResult R(S, DeclarationName(Parm), SourceLocation(), @@ -3300,23 +3303,26 @@ static void CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) { = InterfacePointerType->getObjectType()->getInterface(); if ((CastClass == ExprClass) || (CastClass && ExprClass->isSuperClassOf(CastClass))) - return; - S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge) - << T << Target->getName() << castType->getPointeeType(); - return; + return true; + if (warn) + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge) + << T << Target->getName() << castType->getPointeeType(); + return false; } else if (castType->isObjCIdType() || (S.Context.ObjCObjectAdoptsQTypeProtocols( castType, ExprClass))) // ok to cast to 'id'. // casting to id is ok if bridge type adopts all of // p-list protocols. - return; + return true; else { - S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge) - << T << Target->getName() << castType; - S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); - S.Diag(Target->getLocStart(), diag::note_declared_at); - return; + if (warn) { + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge) + << T << Target->getName() << castType; + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + S.Diag(Target->getLocStart(), diag::note_declared_at); + } + return false; } } } @@ -3325,20 +3331,25 @@ static void CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) { S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); if (Target) S.Diag(Target->getLocStart(), diag::note_declared_at); + return true; } - return; + return false; } T = TDNDecl->getUnderlyingType(); } + return true; } template -static void CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) { +static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr, + bool &HadTheAttribute, bool warn) { QualType T = castType; + HadTheAttribute = false; while (const TypedefType *TD = dyn_cast(T.getTypePtr())) { TypedefNameDecl *TDNDecl = TD->getDecl(); if (TB *ObjCBAttr = getObjCBridgeAttr(TD)) { if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { + HadTheAttribute = true; NamedDecl *Target = nullptr; // Check for an existing type with this name. LookupResult R(S, DeclarationName(Parm), SourceLocation(), @@ -3353,24 +3364,28 @@ static void CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) { = InterfacePointerType->getObjectType()->getInterface(); if ((CastClass == ExprClass) || (ExprClass && CastClass->isSuperClassOf(ExprClass))) - return; - S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf) - << castExpr->getType()->getPointeeType() << T; - S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); - return; + return true; + if (warn) { + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf) + << castExpr->getType()->getPointeeType() << T; + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + } + return false; } else if (castExpr->getType()->isObjCIdType() || (S.Context.QIdProtocolsAdoptObjCObjectProtocols( castExpr->getType(), CastClass))) // ok to cast an 'id' expression to a CFtype. // ok to cast an 'id' expression to CFtype provided plist // adopts all of CFtype's ObjetiveC's class plist. - return; + return true; else { - S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf) - << castExpr->getType() << castType; - S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); - S.Diag(Target->getLocStart(), diag::note_declared_at); - return; + if (warn) { + S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge_to_cf) + << castExpr->getType() << castType; + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + S.Diag(Target->getLocStart(), diag::note_declared_at); + } + return false; } } } @@ -3379,11 +3394,13 @@ static void CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr) { S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); if (Target) S.Diag(Target->getLocStart(), diag::note_declared_at); + return true; } - return; + return false; } T = TDNDecl->getUnderlyingType(); } + return true; } void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) { @@ -3393,12 +3410,46 @@ void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) { ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExpr->getType()); ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType); if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) { - CheckObjCBridgeNSCast(*this, castType, castExpr); - CheckObjCBridgeNSCast(*this, castType, castExpr); + bool HasObjCBridgeAttr; + bool ObjCBridgeAttrWillNotWarn = + CheckObjCBridgeNSCast(*this, castType, castExpr, HasObjCBridgeAttr, + false); + if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr) + return; + bool HasObjCBridgeMutableAttr; + bool ObjCBridgeMutableAttrWillNotWarn = + CheckObjCBridgeNSCast(*this, castType, castExpr, + HasObjCBridgeMutableAttr, false); + if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr) + return; + + if (HasObjCBridgeAttr) + CheckObjCBridgeNSCast(*this, castType, castExpr, HasObjCBridgeAttr, + true); + else if (HasObjCBridgeMutableAttr) + CheckObjCBridgeNSCast(*this, castType, castExpr, + HasObjCBridgeMutableAttr, true); } else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable) { - CheckObjCBridgeCFCast(*this, castType, castExpr); - CheckObjCBridgeCFCast(*this, castType, castExpr); + bool HasObjCBridgeAttr; + bool ObjCBridgeAttrWillNotWarn = + CheckObjCBridgeCFCast(*this, castType, castExpr, HasObjCBridgeAttr, + false); + if (ObjCBridgeAttrWillNotWarn && HasObjCBridgeAttr) + return; + bool HasObjCBridgeMutableAttr; + bool ObjCBridgeMutableAttrWillNotWarn = + CheckObjCBridgeCFCast(*this, castType, castExpr, + HasObjCBridgeMutableAttr, false); + if (ObjCBridgeMutableAttrWillNotWarn && HasObjCBridgeMutableAttr) + return; + + if (HasObjCBridgeAttr) + CheckObjCBridgeCFCast(*this, castType, castExpr, HasObjCBridgeAttr, + true); + else if (HasObjCBridgeMutableAttr) + CheckObjCBridgeCFCast(*this, castType, castExpr, + HasObjCBridgeMutableAttr, true); } } diff --git a/test/SemaObjC/objc-mixed-bridge-attribute.m b/test/SemaObjC/objc-mixed-bridge-attribute.m new file mode 100644 index 0000000000..5fa3473196 --- /dev/null +++ b/test/SemaObjC/objc-mixed-bridge-attribute.m @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s +// expected-no-diagnostics +// rdar://17238954 + +typedef const struct __attribute__((objc_bridge(NSAttributedString))) __CFAttributedString *CFAttributedStringRef; + +typedef struct __attribute__((objc_bridge_mutable(NSMutableAttributedString))) __CFAttributedString *CFMutableAttributedStringRef; + +@interface NSAttributedString +@end + +@interface NSMutableAttributedString +@end + +struct __CFAttributedString { +}; + +void Test1(CFAttributedStringRef attrStr) +{ + id x = (NSAttributedString *) attrStr; // no warning +} + +void Test2(NSAttributedString *attrStr) { + CFAttributedStringRef cfsr = (CFAttributedStringRef) attrStr; +} +