From: Ted Kremenek Date: Thu, 8 May 2008 19:43:35 +0000 (+0000) Subject: Added initial support for supporting __NSString__ in attribute "format". X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c5f551f06c3ac27826e3e5a7a29851fc5182f912;p=clang Added initial support for supporting __NSString__ in attribute "format". Still need to iron out some of the semantics (fixmes are present). This addresses git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50866 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 3839d7f76b..38322cbbc7 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -600,6 +600,8 @@ 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_attribute_invalid_size, ERROR, "vector size not an integral multiple of component size") DIAG(err_attribute_zero_size, ERROR, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9e9509adaa..373727a5d8 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2350,6 +2350,22 @@ static const FunctionTypeProto *getFunctionProto(Decl *d) { return 0; } +static inline bool isNSStringType(QualType T, ASTContext &Ctx) { + if (!T->isPointerType()) + return false; + + T = T->getAsPointerType()->getPointeeType().getCanonicalType(); + ObjCInterfaceType* ClsT = dyn_cast(T.getTypePtr()); + + if (!ClsT) + return false; + + IdentifierInfo* ClsName = ClsT->getDecl()->getIdentifier(); + + // FIXME: Should we walk the chain of classes? + return ClsName == &Ctx.Idents.get("NSString") || + ClsName == &Ctx.Idents.get("NSMutableString"); +} /// Handle __attribute__((format(type,idx,firstarg))) attributes /// based on http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html @@ -2393,10 +2409,28 @@ void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) { FormatLen -= 4; } - if (!((FormatLen == 5 && !memcmp(Format, "scanf", 5)) - || (FormatLen == 6 && !memcmp(Format, "printf", 6)) - || (FormatLen == 7 && !memcmp(Format, "strfmon", 7)) - || (FormatLen == 8 && !memcmp(Format, "strftime", 8)))) { + bool Supported = false; + bool is_NSString = false; + bool is_strftime = false; + + switch (FormatLen) { + default: break; + case 5: + Supported = !memcmp(Format, "scanf", 5); + break; + 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)); + break; + } + + if (!Supported) { Diag(rawAttr->getLoc(), diag::warn_attribute_type_not_supported, "format", rawAttr->getParameterName()->getName()); return; @@ -2417,16 +2451,32 @@ void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) { return; } + // FIXME: Do we need to bounds check? + unsigned ArgIdx = Idx.getZExtValue() - 1; + // make sure the format string is really a string - QualType Ty = proto->getArgType(Idx.getZExtValue()-1); - if (!Ty->isPointerType() || + QualType Ty = proto->getArgType(ArgIdx); + + if (is_NSString) { + // FIXME: do we need to check if the type is NSString*? What are + // the semantics? + if (!isNSStringType(Ty, Context)) { + // FIXME: Should highlight the actual expression that has the + // wrong type. + Diag(rawAttr->getLoc(), diag::err_format_attribute_not_NSString, + IdxExpr->getSourceRange()); + return; + } + } + else if (!Ty->isPointerType() || !Ty->getAsPointerType()->getPointeeType()->isCharType()) { + // FIXME: Should highlight the actual expression that has the + // wrong type. Diag(rawAttr->getLoc(), diag::err_format_attribute_not_string, IdxExpr->getSourceRange()); return; } - // check the 3rd argument Expr *FirstArgExpr = static_cast(rawAttr->getArg(1)); llvm::APSInt FirstArg(Context.getTypeSize(FirstArgExpr->getType())); @@ -2448,7 +2498,7 @@ void Sema::HandleFormatAttribute(Decl *d, AttributeList *rawAttr) { // strftime requires FirstArg to be 0 because it doesn't read from any variable // the input is just the current time + the format string - if (FormatLen == 8 && !memcmp(Format, "strftime", 8)) { + if (is_strftime) { if (FirstArg != 0) { Diag(rawAttr->getLoc(), diag::err_format_strftime_third_parameter, FirstArgExpr->getSourceRange());