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

Reply via email to