Objective-C. Under a special flag, -Wcstring-format-directive,
off by default, issue a warning if %s directive is used
in formart argument of a function/method declared as
__attribute__((format(CF/NSString, ...)))
To complete rdar://18182443

llvm-svn: 217619
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 0c3a3df..ac5b68f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -767,6 +767,15 @@
     S.Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
 }
 
+bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) {
+  FormatStringInfo FSI;
+  if ((GetFormatStringType(Format) == FST_NSString) &&
+      getFormatStringInfo(Format, false, &FSI)) {
+    Idx = FSI.FormatIdx;
+    return true;
+  }
+  return false;
+}
 /// \brief Diagnose use of %s directive in an NSString which is being passed
 /// as formatting string to formatting method.
 static void
@@ -774,27 +783,38 @@
                                         const NamedDecl *FDecl,
                                         Expr **Args,
                                         unsigned NumArgs) {
-  if (NumArgs < 3)
-    return;
+  unsigned Idx = 0;
+  bool Format = false;
   ObjCStringFormatFamily SFFamily = FDecl->getObjCFStringFormattingFamily();
   if (SFFamily == ObjCStringFormatFamily::SFF_CFString) {
-    const Expr *FormatExpr = Args[2];
-    if (const CStyleCastExpr *CSCE = dyn_cast<CStyleCastExpr>(FormatExpr))
-      FormatExpr = CSCE->getSubExpr();
-    const StringLiteral *FormatString;
-    if (const ObjCStringLiteral *OSL =
-        dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts()))
-      FormatString = OSL->getString();
-    else
-      FormatString = dyn_cast<StringLiteral>(FormatExpr->IgnoreParenImpCasts());
-    if (!FormatString)
-      return;
-    if (S.FormatStringHasSArg(FormatString)) {
-      S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
-        << "%s" << 1 << 1;
-        S.Diag(FDecl->getLocation(), diag::note_entity_declared_at)
-          << FDecl->getDeclName();
+    Idx = 2;
+    Format = true;
+  }
+  else
+    for (const auto *I : FDecl->specific_attrs<FormatAttr>()) {
+      if (S.GetFormatNSStringIdx(I, Idx)) {
+        Format = true;
+        break;
+      }
     }
+  if (!Format || NumArgs <= Idx)
+    return;
+  const Expr *FormatExpr = Args[Idx];
+  if (const CStyleCastExpr *CSCE = dyn_cast<CStyleCastExpr>(FormatExpr))
+    FormatExpr = CSCE->getSubExpr();
+  const StringLiteral *FormatString;
+  if (const ObjCStringLiteral *OSL =
+      dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts()))
+    FormatString = OSL->getString();
+  else
+    FormatString = dyn_cast<StringLiteral>(FormatExpr->IgnoreParenImpCasts());
+  if (!FormatString)
+    return;
+  if (S.FormatStringHasSArg(FormatString)) {
+    S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
+      << "%s" << 1 << 1;
+    S.Diag(FDecl->getLocation(), diag::note_entity_declared_at)
+      << FDecl->getDeclName();
   }
 }
 
@@ -930,8 +950,8 @@
     return false;
 
   CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo);
-  
-  DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs);
+  if (getLangOpts().ObjC1)
+    DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs);
 
   unsigned CMId = FDecl->getMemoryFunctionKind();
   if (CMId == 0)
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index d1c7aa6..ac28d83 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -2121,23 +2121,36 @@
                                         ObjCMethodDecl *Method,
                                         Selector Sel,
                                         Expr **Args, unsigned NumArgs) {
-  if (NumArgs == 0)
-    return;
+  unsigned Idx = 0;
+  bool Format = false;
   ObjCStringFormatFamily SFFamily = Sel.getStringFormatFamily();
   if (SFFamily == ObjCStringFormatFamily::SFF_NSString) {
-    Expr *FormatExpr = Args[0];
-    if (ObjCStringLiteral *OSL =
-        dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) {
-      StringLiteral *FormatString = OSL->getString();
-      if (S.FormatStringHasSArg(FormatString)) {
-        S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
-        << "%s" << 0 << 0;
-        if (Method)
-          S.Diag(Method->getLocation(), diag::note_method_declared_at)
-          << Method->getDeclName();
+    Idx = 0;
+    Format = true;
+  }
+  else if (Method) {
+    for (const auto *I : Method->specific_attrs<FormatAttr>()) {
+      if (S.GetFormatNSStringIdx(I, Idx)) {
+        Format = true;
+        break;
       }
     }
   }
+  if (!Format || NumArgs <= Idx)
+    return;
+  
+  Expr *FormatExpr = Args[Idx];
+  if (ObjCStringLiteral *OSL =
+      dyn_cast<ObjCStringLiteral>(FormatExpr->IgnoreParenImpCasts())) {
+    StringLiteral *FormatString = OSL->getString();
+    if (S.FormatStringHasSArg(FormatString)) {
+      S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string)
+        << "%s" << 0 << 0;
+      if (Method)
+        S.Diag(Method->getLocation(), diag::note_method_declared_at)
+          << Method->getDeclName();
+    }
+  }
 }
 
 /// \brief Build an Objective-C class message expression.