зеркало из https://github.com/microsoft/clang.git
Add support for CFString in format attribute.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@56639 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
248e1c01d3
Коммит
085e8f7da3
|
@ -658,10 +658,8 @@ DIAG(err_format_strftime_third_parameter, ERROR,
|
|||
"strftime format attribute requires 3rd parameter to be 0")
|
||||
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_format_attribute_not, ERROR,
|
||||
"format argument not %0")
|
||||
DIAG(err_attribute_invalid_size, ERROR,
|
||||
"vector size not an integral multiple of component size")
|
||||
DIAG(err_attribute_zero_size, ERROR,
|
||||
|
|
|
@ -61,6 +61,22 @@ static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
|
|||
ClsName == &Ctx.Idents.get("NSMutableString");
|
||||
}
|
||||
|
||||
static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
|
||||
const PointerType *PT = T->getAsPointerType();
|
||||
if (!PT)
|
||||
return false;
|
||||
|
||||
const RecordType *RT = PT->getPointeeType()->getAsRecordType();
|
||||
if (!RT)
|
||||
return false;
|
||||
|
||||
const RecordDecl *RD = RT->getDecl();
|
||||
if (RD->getTagKind() != TagDecl::TK_struct)
|
||||
return false;
|
||||
|
||||
return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Attribute Implementations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -648,6 +664,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|||
bool Supported = false;
|
||||
bool is_NSString = false;
|
||||
bool is_strftime = false;
|
||||
bool is_CFString = false;
|
||||
|
||||
switch (FormatLen) {
|
||||
default: break;
|
||||
|
@ -655,8 +672,9 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|||
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));
|
||||
Supported = (is_strftime = !memcmp(Format, "strftime", 8)) ||
|
||||
(is_NSString = !memcmp(Format, "NSString", 8)) ||
|
||||
(is_CFString = !memcmp(Format, "CFString", 8));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -687,22 +705,28 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
|||
// make sure the format string is really a string
|
||||
QualType Ty = proto->getArgType(ArgIdx);
|
||||
|
||||
if (is_NSString) {
|
||||
if (is_CFString) {
|
||||
if (!isCFStringType(Ty, S.Context)) {
|
||||
S.Diag(Attr.getLoc(), diag::err_format_attribute_not,
|
||||
"a CFString", IdxExpr->getSourceRange());
|
||||
return;
|
||||
}
|
||||
} else if (is_NSString) {
|
||||
// FIXME: do we need to check if the type is NSString*? What are
|
||||
// the semantics?
|
||||
if (!isNSStringType(Ty, S.Context)) {
|
||||
// FIXME: Should highlight the actual expression that has the
|
||||
// wrong type.
|
||||
S.Diag(Attr.getLoc(), diag::err_format_attribute_not_NSString,
|
||||
IdxExpr->getSourceRange());
|
||||
S.Diag(Attr.getLoc(), diag::err_format_attribute_not,
|
||||
"an NSString", IdxExpr->getSourceRange());
|
||||
return;
|
||||
}
|
||||
} else if (!Ty->isPointerType() ||
|
||||
!Ty->getAsPointerType()->getPointeeType()->isCharType()) {
|
||||
// FIXME: Should highlight the actual expression that has the
|
||||
// wrong type.
|
||||
S.Diag(Attr.getLoc(), diag::err_format_attribute_not_string,
|
||||
IdxExpr->getSourceRange());
|
||||
S.Diag(Attr.getLoc(), diag::err_format_attribute_not,
|
||||
"a string type", IdxExpr->getSourceRange());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,9 @@ typedef float CGFloat;
|
|||
@interface NSConstantString : NSSimpleCString @end
|
||||
extern void *_NSConstantStringClassReference;
|
||||
|
||||
typedef const struct __CFString * CFStringRef;
|
||||
extern void CFStringCreateWithFormat(CFStringRef format, ...) __attribute__((format(CFString, 1, 2)));
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Test cases.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -34,3 +37,7 @@ void check_nslog(unsigned k) {
|
|||
NSLog(@"%d%%", k); // no-warning
|
||||
NSLog(@"%s%lb%d", "unix", 10,20); // expected-warning {{lid conversion '%lb'}}
|
||||
}
|
||||
|
||||
// Check type validation
|
||||
extern void NSLog2(int format, ...) __attribute__((format(__NSString__, 1, 2))); // expected-error {{format argument not an NSString}}
|
||||
extern void CFStringCreateWithFormat2(int *format, ...) __attribute__((format(CFString, 1, 2))); // expected-error {{format argument not a CFString}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче