]> granicus.if.org Git - clang/commitdiff
Added initial support for supporting __NSString__ in attribute "format".
authorTed Kremenek <kremenek@apple.com>
Thu, 8 May 2008 19:43:35 +0000 (19:43 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 8 May 2008 19:43:35 +0000 (19:43 +0000)
Still need to iron out some of the semantics (fixmes are present).
This addresses <rdar://problem/5916348>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50866 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticKinds.def
lib/Sema/SemaDecl.cpp

index 3839d7f76b29535e964048a6b849acb440f706ba..38322cbbc761b923653928bc0af21f469dba1249 100644 (file)
@@ -600,6 +600,8 @@ DIAG(err_format_attribute_requires_variadic, ERROR,
      "format attribute requires variadic function")
 DIAG(err_format_attribute_not_string, ERROR,
      "format argument not a string type")
+DIAG(err_format_attribute_not_NSString, ERROR,
+    "format argument is not an NSString")
 DIAG(err_attribute_invalid_size, ERROR,
      "vector size not an integral multiple of component size")
 DIAG(err_attribute_zero_size, ERROR,
index 9e9509adaa8a37461277ccb281b33965277e8b5e..373727a5d8e79a75559169b215cb6a75fda39b10 100644 (file)
@@ -2350,6 +2350,22 @@ static const FunctionTypeProto *getFunctionProto(Decl *d) {
   return 0;
 }
 
+static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
+  if (!T->isPointerType())
+    return false;
+  
+  T = T->getAsPointerType()->getPointeeType().getCanonicalType();
+  ObjCInterfaceType* ClsT = dyn_cast<ObjCInterfaceType>(T.getTypePtr());
+  
+  if (!ClsT)
+    return false;
+  
+  IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier();
+  
+  // FIXME: Should we walk the chain of classes?
+  return ClsName == &Ctx.Idents.get("NSString") ||
+         ClsName == &Ctx.Idents.get("NSMutableString");
+}
 
 /// Handle __attribute__((format(type,idx,firstarg))) attributes
 /// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
@@ -2393,10 +2409,28 @@ void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) {
     FormatLen -= 4;
   }
 
-  if (!((FormatLen == 5 && !memcmp(Format, "scanf", 5))
-     || (FormatLen == 6 && !memcmp(Format, "printf", 6))
-     || (FormatLen == 7 && !memcmp(Format, "strfmon", 7))
-     || (FormatLen == 8 && !memcmp(Format, "strftime", 8)))) {
+  bool Supported = false;
+  bool is_NSString = false;
+  bool is_strftime = false;
+  
+  switch (FormatLen) {
+    default: break;
+    case 5:
+      Supported = !memcmp(Format, "scanf", 5);
+      break;
+    case 6:
+      Supported = !memcmp(Format, "printf", 6);
+      break;
+    case 7:
+      Supported = !memcmp(Format, "strfmon", 7);
+      break;
+    case 8:
+      Supported = (is_strftime = !memcmp(Format, "strftime", 8)) || 
+                  (is_NSString = !memcmp(Format, "NSString", 8));
+      break;
+  }
+      
+  if (!Supported) {
     Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported,
            "format", rawAttr->getParameterName()->getName());
     return;
@@ -2417,16 +2451,32 @@ void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) {
     return;
   }
 
+  // FIXME: Do we need to bounds check?
+  unsigned ArgIdx = Idx.getZExtValue() - 1;
+  
   // make sure the format string is really a string
-  QualType Ty = proto->getArgType(Idx.getZExtValue()-1);
-  if (!Ty->isPointerType() ||
+  QualType Ty = proto->getArgType(ArgIdx);
+
+  if (is_NSString) {
+    // FIXME: do we need to check if the type is NSString*?  What are
+    //  the semantics?
+    if (!isNSStringType(Ty, Context)) {
+      // FIXME: Should highlight the actual expression that has the
+      // wrong type.
+      Diag(rawAttr->getLoc(), diag::err_format_attribute_not_NSString,
+           IdxExpr->getSourceRange());
+      return;
+    }    
+  }
+  else if (!Ty->isPointerType() ||
       !Ty->getAsPointerType()->getPointeeType()->isCharType()) {
+    // FIXME: Should highlight the actual expression that has the
+    // wrong type.
     Diag(rawAttr->getLoc(), diag::err_format_attribute_not_string,
          IdxExpr->getSourceRange());
     return;
   }
 
-
   // check the 3rd argument
   Expr *FirstArgExpr = static_cast<Expr *>(rawAttr->getArg(1));
   llvm::APSInt FirstArg(Context.getTypeSize(FirstArgExpr->getType()));
@@ -2448,7 +2498,7 @@ void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) {
 
   // strftime requires FirstArg to be 0 because it doesn't read from any variable
   // the input is just the current time + the format string
-  if (FormatLen == 8 && !memcmp(Format, "strftime", 8)) {
+  if (is_strftime) {
     if (FirstArg != 0) {
       Diag(rawAttr->getLoc(), diag::err_format_strftime_third_parameter,
              FirstArgExpr->getSourceRange());