fcloutier created this revision. fcloutier added reviewers: doug.gregor, dcoughlin, rsmith, NoQ, ahatanak. fcloutier added a project: clang. Herald added a reviewer: aaron.ballman. fcloutier requested review of this revision. Herald added a subscriber: cfe-commits.
It has come to my attention that _inside the interface of `NSString_`, using `__attribute__((format_arg(__NSString__, N)))` does not work for a method that returns `instancetype`. This is a pretty specific problem because not a lot of people define `NSString`. Thankfully, the fix isn't very difficult: if checking an Objective-C method definition, and it returns `instancetype`, we also check if the class being defined is `NSString`. rdar://84729746 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D112670 Files: clang/lib/Sema/SemaDeclAttr.cpp clang/test/SemaObjC/format-arg-attribute.m Index: clang/test/SemaObjC/format-arg-attribute.m =================================================================== --- clang/test/SemaObjC/format-arg-attribute.m +++ clang/test/SemaObjC/format-arg-attribute.m @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -verify -fsyntax-only %s -@class NSString; +@interface NSString ++(instancetype)stringWithCString:(const char *)cstr __attribute__((format_arg(1))); +@end + @class NSAttributedString; extern NSString *fa2 (const NSString *) __attribute__((format_arg(1))); Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -156,26 +156,39 @@ return false; } -static inline bool isNSStringType(QualType T, ASTContext &Ctx, - bool AllowNSAttributedString = false) { - const auto *PT = T->getAs<ObjCObjectPointerType>(); - if (!PT) - return false; - - ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); +static inline bool isNSStringInterface(ASTContext &Ctx, ObjCInterfaceDecl *Cls, bool AllowNSAttributedString = false) { if (!Cls) return false; - IdentifierInfo* ClsName = Cls->getIdentifier(); + IdentifierInfo *ClsName = Cls->getIdentifier(); - if (AllowNSAttributedString && - ClsName == &Ctx.Idents.get("NSAttributedString")) - return true; + if (ClsName == &Ctx.Idents.get("NSAttributedString")) + return AllowNSAttributedString; // FIXME: Should we walk the chain of classes? return ClsName == &Ctx.Idents.get("NSString") || ClsName == &Ctx.Idents.get("NSMutableString"); } +static inline bool isNSStringType(QualType T, ASTContext &Ctx, + bool AllowNSAttributedString = false) { + const auto *PT = T->getAs<ObjCObjectPointerType>(); + if (!PT) + return false; + + return isNSStringInterface(Ctx, PT->getObjectType()->getInterface(), AllowNSAttributedString); +} + +static inline bool isInstancetypeNSStringType(ASTContext &Ctx, QualType T, Decl *D, bool AllowNSAttributedString = false) { + if (T.getTypePtr() != Ctx.getObjCInstanceTypeDecl()->getTypeForDecl()) + return false; + + auto *OMD = dyn_cast<ObjCMethodDecl>(D); + if (!OMD) + return false; + + return isNSStringInterface(Ctx, OMD->getClassInterface(), AllowNSAttributedString); +} + static inline bool isCFStringType(QualType T, ASTContext &Ctx) { const auto *PT = T->getAs<PointerType>(); if (!PT) @@ -3390,6 +3403,7 @@ Ty = getFunctionOrMethodResultType(D); if (!isNSStringType(Ty, S.Context, /*AllowNSAttributedString=*/true) && !isCFStringType(Ty, S.Context) && + !isInstancetypeNSStringType(S.Context, Ty, D) && (!Ty->isPointerType() || !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_result_not)
Index: clang/test/SemaObjC/format-arg-attribute.m =================================================================== --- clang/test/SemaObjC/format-arg-attribute.m +++ clang/test/SemaObjC/format-arg-attribute.m @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -verify -fsyntax-only %s -@class NSString; +@interface NSString ++(instancetype)stringWithCString:(const char *)cstr __attribute__((format_arg(1))); +@end + @class NSAttributedString; extern NSString *fa2 (const NSString *) __attribute__((format_arg(1))); Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -156,26 +156,39 @@ return false; } -static inline bool isNSStringType(QualType T, ASTContext &Ctx, - bool AllowNSAttributedString = false) { - const auto *PT = T->getAs<ObjCObjectPointerType>(); - if (!PT) - return false; - - ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface(); +static inline bool isNSStringInterface(ASTContext &Ctx, ObjCInterfaceDecl *Cls, bool AllowNSAttributedString = false) { if (!Cls) return false; - IdentifierInfo* ClsName = Cls->getIdentifier(); + IdentifierInfo *ClsName = Cls->getIdentifier(); - if (AllowNSAttributedString && - ClsName == &Ctx.Idents.get("NSAttributedString")) - return true; + if (ClsName == &Ctx.Idents.get("NSAttributedString")) + return AllowNSAttributedString; // FIXME: Should we walk the chain of classes? return ClsName == &Ctx.Idents.get("NSString") || ClsName == &Ctx.Idents.get("NSMutableString"); } +static inline bool isNSStringType(QualType T, ASTContext &Ctx, + bool AllowNSAttributedString = false) { + const auto *PT = T->getAs<ObjCObjectPointerType>(); + if (!PT) + return false; + + return isNSStringInterface(Ctx, PT->getObjectType()->getInterface(), AllowNSAttributedString); +} + +static inline bool isInstancetypeNSStringType(ASTContext &Ctx, QualType T, Decl *D, bool AllowNSAttributedString = false) { + if (T.getTypePtr() != Ctx.getObjCInstanceTypeDecl()->getTypeForDecl()) + return false; + + auto *OMD = dyn_cast<ObjCMethodDecl>(D); + if (!OMD) + return false; + + return isNSStringInterface(Ctx, OMD->getClassInterface(), AllowNSAttributedString); +} + static inline bool isCFStringType(QualType T, ASTContext &Ctx) { const auto *PT = T->getAs<PointerType>(); if (!PT) @@ -3390,6 +3403,7 @@ Ty = getFunctionOrMethodResultType(D); if (!isNSStringType(Ty, S.Context, /*AllowNSAttributedString=*/true) && !isCFStringType(Ty, S.Context) && + !isInstancetypeNSStringType(S.Context, Ty, D) && (!Ty->isPointerType() || !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_result_not)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits