Objective-C. Under a special flag, -Wcstring-format-directive,
off by default, issue a warning if %s directive is used in
certain CF/NS formatting APIs, to assist user in deprecating
use of such %s in these APIs. rdar://18182443

llvm-svn: 217467
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 435b951..0c3a3df 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -767,6 +767,37 @@
     S.Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
 }
 
+/// \brief Diagnose use of %s directive in an NSString which is being passed
+/// as formatting string to formatting method.
+static void
+DiagnoseCStringFormatDirectiveInCFAPI(Sema &S,
+                                        const NamedDecl *FDecl,
+                                        Expr **Args,
+                                        unsigned NumArgs) {
+  if (NumArgs < 3)
+    return;
+  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();
+    }
+  }
+}
+
 static void CheckNonNullArguments(Sema &S,
                                   const NamedDecl *FDecl,
                                   ArrayRef<const Expr *> Args,
@@ -899,6 +930,8 @@
     return false;
 
   CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo);
+  
+  DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs);
 
   unsigned CMId = FDecl->getMemoryFunctionKind();
   if (CMId == 0)
@@ -3744,6 +3777,20 @@
   } // TODO: handle other formats
 }
 
+bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) {
+  // Str - The format string.  NOTE: this is NOT null-terminated!
+  StringRef StrRef = FExpr->getString();
+  const char *Str = StrRef.data();
+  // Account for cases where the string literal is truncated in a declaration.
+  const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType());
+  assert(T && "String literal not of constant array type!");
+  size_t TypeSize = T->getSize().getZExtValue();
+  size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
+  return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen,
+                                                         getLangOpts(),
+                                                         Context.getTargetInfo());
+}
+
 //===--- CHECK: Warn on use of wrong absolute value function. -------------===//
 
 // Returns the related absolute value function that is larger, of 0 if one