r217619 - Objective-C. Under a special flag, -Wcstring-format-directive,

Fariborz Jahanian fjahanian at apple.com
Thu Sep 11 12:13:23 PDT 2014


Author: fjahanian
Date: Thu Sep 11 14:13:23 2014
New Revision: 217619

URL: http://llvm.org/viewvc/llvm-project?rev=217619&view=rev
Log:
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

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/test/SemaObjC/format-cstrings-warning.m

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=217619&r1=217618&r2=217619&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Sep 11 14:13:23 2014
@@ -8405,6 +8405,8 @@ public:
                          llvm::SmallBitVector &CheckedVarArgs);
   
   bool FormatStringHasSArg(const StringLiteral *FExpr);
+  
+  bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx);
 
 private:
   bool CheckFormatArguments(const FormatAttr *Format,

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=217619&r1=217618&r2=217619&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Sep 11 14:13:23 2014
@@ -767,6 +767,15 @@ static void CheckNonNullArgument(Sema &S
     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 @@ DiagnoseCStringFormatDirectiveInCFAPI(Se
                                         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 @@ bool Sema::CheckFunctionCall(FunctionDec
     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)

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=217619&r1=217618&r2=217619&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Thu Sep 11 14:13:23 2014
@@ -2121,21 +2121,34 @@ DiagnoseCStringFormatDirectiveInObjCAPI(
                                         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)
+    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)
+      if (Method)
+        S.Diag(Method->getLocation(), diag::note_method_declared_at)
           << Method->getDeclName();
-      }
     }
   }
 }

Modified: cfe/trunk/test/SemaObjC/format-cstrings-warning.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/format-cstrings-warning.m?rev=217619&r1=217618&r2=217619&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/format-cstrings-warning.m (original)
+++ cfe/trunk/test/SemaObjC/format-cstrings-warning.m Thu Sep 11 14:13:23 2014
@@ -4,16 +4,20 @@
 typedef __builtin_va_list __darwin_va_list;
 typedef __builtin_va_list va_list;
 
- at interface NSString @end
+ at interface NSString 
+ at end
+
+va_list argList;
 
 @interface NSString (NSStringExtensionMethods)
 - (NSString *)stringByAppendingFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
-- (instancetype)initWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'initWithFormat:' declared here}}
+- (instancetype)initWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note 2 {{method 'initWithFormat:' declared here}}
 - (instancetype)initWithFormat:(NSString *)format arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0)));
 - (instancetype)initWithFormat:(NSString *)format locale:(id)locale, ... __attribute__((format(__NSString__, 1, 3)));
 - (instancetype)initWithFormat:(NSString *)format locale:(id)locale arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0)));
 + (instancetype)stringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'stringWithFormat:' declared here}}
-+ (instancetype)localizedStringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
++ (instancetype)localizedStringWithFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); // expected-note {{method 'localizedStringWithFormat:' declared here}}
+- (void)MyRandomMethod:(NSString *)format locale:(id)locale arguments:(va_list)argList __attribute__((format(__NSString__, 1, 0))); // expected-note {{method 'MyRandomMethod:locale:arguments:' declared here}}
 @end
 
 @interface NSMutableString : NSString
@@ -27,6 +31,9 @@ typedef __builtin_va_list va_list;
 
 NSString *ns(NSString *pns) {
   [pns initWithFormat: @"Number %d length %c name %s", 1, 'a', "something"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+  [NSString localizedStringWithFormat : @"Hello%s", " There"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+  [pns initWithFormat : @"Hello%s %d %d", "Hello", 1, 2]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
+  [pns MyRandomMethod : @"Hello%s %d %d" locale:0 arguments: argList];  // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
   return [NSString stringWithFormat : @"Hello%s", " There"]; // expected-warning {{using %s directive in NSString which is being passed as a formatting argument to the formatting method}}
 }
 
@@ -51,10 +58,22 @@ void CFStringAppendFormat(CFMutableStrin
 extern
 void CFStringAppendFormatAndArguments(CFMutableStringRef theString, CFDictionaryRef formatOptions, CFStringRef format, va_list arguments) __attribute__((format(CFString, 3, 0))); // expected-note {{'CFStringAppendFormatAndArguments' declared here}}
 
-void foo(va_list argList) {
+void Test1(va_list argList) {
   CFAllocatorRef alloc;
   CFStringCreateWithFormatAndArguments (alloc, 0, (CFStringRef)@"%s\n", argList); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
   CFStringAppendFormatAndArguments ((CFMutableStringRef)@"AAAA", 0, (CFStringRef)"Hello %s there %d\n", argList); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
   CFStringCreateWithFormatAndArguments (alloc, 0, (CFStringRef)@"%c\n", argList);
   CFStringAppendFormatAndArguments ((CFMutableStringRef)@"AAAA", 0, (CFStringRef)"%d\n", argList);
 }
+
+extern void MyNSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); // expected-note {{'MyNSLog' declared here}}
+extern void MyCFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(__CFString__, 1, 2))); // expected-note {{'MyCFStringCreateWithFormat' declared here}}
+extern void XMyNSLog(int, NSString *format, ...) __attribute__((format(__NSString__, 2, 3))); // expected-note {{'XMyNSLog' declared here}}
+
+void Test2() {
+  MyNSLog(@"%s\n", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+
+  MyCFStringCreateWithFormat((CFStringRef)@"%s", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+  XMyNSLog(4, @"%s\n", "Hello"); // expected-warning {{using %s directive in CFString which is being passed as a formatting argument to the formatting CFfunction}}
+}
+





More information about the cfe-commits mailing list