r217467 - Objective-C. Under a special flag, -Wcstring-format-directive,
Fariborz Jahanian
fjahanian at apple.com
Tue Sep 9 16:10:55 PDT 2014
Author: fjahanian
Date: Tue Sep 9 18:10:54 2014
New Revision: 217467
URL: http://llvm.org/viewvc/llvm-project?rev=217467&view=rev
Log:
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
Added:
cfe/trunk/test/SemaObjC/format-cstrings-warning.m
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/IdentifierTable.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/Analysis/PrintfFormatString.cpp
cfe/trunk/lib/Basic/IdentifierTable.cpp
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/lib/Sema/SemaExprObjC.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Sep 9 18:10:54 2014
@@ -289,6 +289,8 @@ public:
return const_cast<NamedDecl*>(this)->getMostRecentDecl();
}
+ ObjCStringFormatFamily getObjCFStringFormattingFamily() const;
+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; }
};
Modified: cfe/trunk/include/clang/Analysis/Analyses/FormatString.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/FormatString.h?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)
+++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h Tue Sep 9 18:10:54 2014
@@ -647,6 +647,9 @@ public:
bool ParsePrintfString(FormatStringHandler &H,
const char *beg, const char *end, const LangOptions &LO,
const TargetInfo &Target);
+
+bool ParseFormatStringHasSArg(const char *beg, const char *end, const LangOptions &LO,
+ const TargetInfo &Target);
bool ParseScanfString(FormatStringHandler &H,
const char *beg, const char *end, const LangOptions &LO,
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Tue Sep 9 18:10:54 2014
@@ -350,6 +350,7 @@ def InvalidOffsetof : DiagGroup<"invalid
def : DiagGroup<"strict-prototypes">;
def StrictSelector : DiagGroup<"strict-selector-match">;
def MethodDuplicate : DiagGroup<"duplicate-method-match">;
+def ObjCCStringFormat : DiagGroup<"cstring-format-directive">;
def CoveredSwitchDefault : DiagGroup<"covered-switch-default">;
def SwitchBool : DiagGroup<"switch-bool">;
def SwitchEnum : DiagGroup<"switch-enum">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Sep 9 18:10:54 2014
@@ -719,6 +719,11 @@ def err_duplicate_method_decl : Error<"d
def warn_duplicate_method_decl :
Warning<"multiple declarations of method %0 found and ignored">,
InGroup<MethodDuplicate>, DefaultIgnore;
+def warn_objc_cdirective_format_string :
+ Warning<"using %0 directive in %select{NSString|CFString}1 "
+ "which is being passed as a formatting argument to the formatting "
+ "%select{method|CFfunction}2">,
+ InGroup<ObjCCStringFormat>, DefaultIgnore;
def err_objc_var_decl_inclass :
Error<"cannot declare variable inside @interface or @protocol">;
def error_missing_method_context : Error<
Modified: cfe/trunk/include/clang/Basic/IdentifierTable.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/IdentifierTable.h?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/IdentifierTable.h (original)
+++ cfe/trunk/include/clang/Basic/IdentifierTable.h Tue Sep 9 18:10:54 2014
@@ -589,6 +589,12 @@ enum ObjCInstanceTypeFamily {
OIT_ReturnsSelf
};
+enum ObjCStringFormatFamily {
+ SFF_None,
+ SFF_NSString,
+ SFF_CFString
+};
+
/// \brief Smart pointer class that efficiently represents Objective-C method
/// names.
///
@@ -634,6 +640,8 @@ class Selector {
}
static ObjCMethodFamily getMethodFamilyImpl(Selector sel);
+
+ static ObjCStringFormatFamily getStringFormatFamilyImpl(Selector sel);
public:
friend class SelectorTable; // only the SelectorTable can create these
@@ -704,7 +712,11 @@ public:
ObjCMethodFamily getMethodFamily() const {
return getMethodFamilyImpl(*this);
}
-
+
+ ObjCStringFormatFamily getStringFormatFamily() const {
+ return getStringFormatFamilyImpl(*this);
+ }
+
static Selector getEmptyMarker() {
return Selector(uintptr_t(-1));
}
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Sep 9 18:10:54 2014
@@ -8403,6 +8403,8 @@ public:
FormatStringType Type, bool inFunctionCall,
VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs);
+
+ bool FormatStringHasSArg(const StringLiteral *FExpr);
private:
bool CheckFormatArguments(const FormatAttr *Format,
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Tue Sep 9 18:10:54 2014
@@ -1001,6 +1001,19 @@ bool NamedDecl::isLinkageValid() const {
getCachedLinkage();
}
+ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const {
+ StringRef name = getName();
+ if (name.empty()) return SFF_None;
+
+ if (name.front() == 'C')
+ if (name == "CFStringCreateWithFormat" ||
+ name == "CFStringCreateWithFormatAndArguments" ||
+ name == "CFStringAppendFormat" ||
+ name == "CFStringAppendFormatAndArguments")
+ return SFF_CFString;
+ return SFF_None;
+}
+
Linkage NamedDecl::getLinkageInternal() const {
// We don't care about visibility here, so ask for the cheapest
// possible visibility analysis.
Modified: cfe/trunk/lib/Analysis/PrintfFormatString.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)
+++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp Tue Sep 9 18:10:54 2014
@@ -54,7 +54,8 @@ static PrintfSpecifierResult ParsePrintf
const char *E,
unsigned &argIndex,
const LangOptions &LO,
- const TargetInfo &Target) {
+ const TargetInfo &Target,
+ bool Warn) {
using namespace clang::analyze_format_string;
using namespace clang::analyze_printf;
@@ -83,7 +84,8 @@ static PrintfSpecifierResult ParsePrintf
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -93,7 +95,8 @@ static PrintfSpecifierResult ParsePrintf
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -118,7 +121,8 @@ static PrintfSpecifierResult ParsePrintf
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -129,7 +133,8 @@ static PrintfSpecifierResult ParsePrintf
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -137,7 +142,8 @@ static PrintfSpecifierResult ParsePrintf
if (*I == '.') {
++I;
if (I == E) {
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -147,7 +153,8 @@ static PrintfSpecifierResult ParsePrintf
if (I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
}
@@ -155,7 +162,8 @@ static PrintfSpecifierResult ParsePrintf
// Look for the length modifier.
if (ParseLengthModifier(FS, I, E, LO) && I == E) {
// No more characters left?
- H.HandleIncompleteSpecifier(Start, E - Start);
+ if (Warn)
+ H.HandleIncompleteSpecifier(Start, E - Start);
return true;
}
@@ -239,7 +247,7 @@ bool clang::analyze_format_string::Parse
// Keep looking for a format specifier until we have exhausted the string.
while (I != E) {
const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
- LO, Target);
+ LO, Target, true);
// Did a fail-stop error of any kind occur when parsing the specifier?
// If so, don't do any more processing.
if (FSR.shouldStop())
@@ -257,6 +265,34 @@ bool clang::analyze_format_string::Parse
return false;
}
+bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
+ const char *E,
+ const LangOptions &LO,
+ const TargetInfo &Target) {
+
+ unsigned argIndex = 0;
+
+ // Keep looking for a %s format specifier until we have exhausted the string.
+ FormatStringHandler H;
+ while (I != E) {
+ const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
+ LO, Target, false);
+ // Did a fail-stop error of any kind occur when parsing the specifier?
+ // If so, don't do any more processing.
+ if (FSR.shouldStop())
+ return false;
+ // Did we exhaust the string or encounter an error that
+ // we can recover from?
+ if (!FSR.hasValue())
+ continue;
+ const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
+ // Return true if this a %s format specifier.
+ if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
+ return true;
+ }
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Methods on PrintfSpecifier.
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Tue Sep 9 18:10:54 2014
@@ -487,6 +487,33 @@ ObjCInstanceTypeFamily Selector::getInst
return OIT_None;
}
+ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) {
+ IdentifierInfo *first = sel.getIdentifierInfoForSlot(0);
+ if (!first) return SFF_None;
+
+ StringRef name = first->getName();
+
+ switch (name.front()) {
+ case 'a':
+ if (name == "appendFormat") return SFF_NSString;
+ break;
+
+ case 'i':
+ if (name == "initWithFormat") return SFF_NSString;
+ break;
+
+ case 'l':
+ if (name == "localizedStringWithFormat") return SFF_NSString;
+ break;
+
+ case 's':
+ if (name == "stringByAppendingFormat" ||
+ name == "stringWithFormat") return SFF_NSString;
+ break;
+ }
+ return SFF_None;
+}
+
namespace {
struct SelectorTableImpl {
llvm::FoldingSet<MultiKeywordSelector> Table;
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Sep 9 18:10:54 2014
@@ -767,6 +767,37 @@ static void CheckNonNullArgument(Sema &S
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 @@ bool Sema::CheckFunctionCall(FunctionDec
return false;
CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo);
+
+ DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs);
unsigned CMId = FDecl->getMemoryFunctionKind();
if (CMId == 0)
@@ -3744,6 +3777,20 @@ void Sema::CheckFormatString(const Strin
} // 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
Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=217467&r1=217466&r2=217467&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Tue Sep 9 18:10:54 2014
@@ -2114,6 +2114,32 @@ static void checkCocoaAPI(Sema &S, const
edit::rewriteObjCRedundantCallWithLiteral);
}
+/// \brief Diagnose use of %s directive in an NSString which is being passed
+/// as formatting string to formatting method.
+static void
+DiagnoseCStringFormatDirectiveInObjCAPI(Sema &S,
+ ObjCMethodDecl *Method,
+ Selector Sel,
+ Expr **Args, unsigned NumArgs) {
+ if (NumArgs == 0)
+ return;
+ 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();
+ }
+ }
+ }
+}
+
/// \brief Build an Objective-C class message expression.
///
/// This routine takes care of both normal class messages and
@@ -2258,7 +2284,9 @@ ExprResult Sema::BuildClassMessage(TypeS
}
}
}
-
+
+ DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs);
+
// Construct the appropriate ObjCMessageExpr.
ObjCMessageExpr *Result;
if (SuperLoc.isValid())
@@ -2743,6 +2771,8 @@ ExprResult Sema::BuildInstanceMessage(Ex
}
}
+ DiagnoseCStringFormatDirectiveInObjCAPI(*this, Method, Sel, Args, NumArgs);
+
// Construct the appropriate ObjCMessageExpr instance.
ObjCMessageExpr *Result;
if (SuperLoc.isValid())
Added: cfe/trunk/test/SemaObjC/format-cstrings-warning.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/format-cstrings-warning.m?rev=217467&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/format-cstrings-warning.m (added)
+++ cfe/trunk/test/SemaObjC/format-cstrings-warning.m Tue Sep 9 18:10:54 2014
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -Wcstring-format-directive -verify -fsyntax-only %s
+// rdar://18182443
+
+typedef __builtin_va_list __darwin_va_list;
+typedef __builtin_va_list va_list;
+
+ at interface NSString @end
+
+ at 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 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)));
+ at end
+
+ at interface NSMutableString : NSString
+ at end
+
+ at interface NSMutableString (NSMutableStringExtensionMethods)
+
+- (void)appendFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2)));
+
+ at end
+
+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}}
+ 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}}
+}
+
+
+typedef const struct __CFString * CFStringRef;
+typedef struct __CFString * CFMutableStringRef;
+typedef const struct __CFAllocator * CFAllocatorRef;
+
+
+typedef const struct __CFDictionary * CFDictionaryRef;
+
+
+extern
+CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, ...) __attribute__((format(CFString, 3, 4)));
+
+extern
+CFStringRef CFStringCreateWithFormatAndArguments(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, va_list arguments) __attribute__((format(CFString, 3, 0))); // expected-note {{'CFStringCreateWithFormatAndArguments' declared here}}
+
+extern
+void CFStringAppendFormat(CFMutableStringRef theString, CFDictionaryRef formatOptions, CFStringRef format, ...) __attribute__((format(CFString, 3, 4)));
+
+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) {
+ 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);
+}
More information about the cfe-commits
mailing list