diff options
-rw-r--r-- | include/clang/Analysis/Analyses/PrintfFormatString.h | 9 | ||||
-rw-r--r-- | lib/Analysis/PrintfFormatString.cpp | 57 | ||||
-rw-r--r-- | test/Sema/format-strings.c | 15 |
3 files changed, 56 insertions, 25 deletions
diff --git a/include/clang/Analysis/Analyses/PrintfFormatString.h b/include/clang/Analysis/Analyses/PrintfFormatString.h index a4ad0b7037..f1e8220908 100644 --- a/include/clang/Analysis/Analyses/PrintfFormatString.h +++ b/include/clang/Analysis/Analyses/PrintfFormatString.h @@ -75,11 +75,14 @@ public: VoidPtrArg, // 'p' OutIntPtrArg, // 'n' PercentArg, // '%' - // Objective-C specific specifiers. + // MacOS X unicode extensions. + CArg, // 'C' + UnicodeStrArg, // 'S' + // Objective-C specific specifiers. ObjCObjArg, // '@' - // GlibC specific specifiers. + // GlibC specific specifiers. PrintErrno, // 'm' - // Specifier ranges. + // Specifier ranges. IntArgBeg = dArg, IntArgEnd = iArg, UIntArgBeg = oArg, diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 55abd10771..3aee57cb81 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -214,25 +214,28 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, default: break; // C99: 7.19.6.1 (section 8). - case 'd': k = ConversionSpecifier::dArg; break; - case 'i': k = ConversionSpecifier::iArg; break; - case 'o': k = ConversionSpecifier::oArg; break; - case 'u': k = ConversionSpecifier::uArg; break; - case 'x': k = ConversionSpecifier::xArg; break; - case 'X': k = ConversionSpecifier::XArg; break; - case 'f': k = ConversionSpecifier::fArg; break; - case 'F': k = ConversionSpecifier::FArg; break; - case 'e': k = ConversionSpecifier::eArg; break; + case '%': k = ConversionSpecifier::PercentArg; break; + case 'A': k = ConversionSpecifier::AArg; break; case 'E': k = ConversionSpecifier::EArg; break; - case 'g': k = ConversionSpecifier::gArg; break; + case 'F': k = ConversionSpecifier::FArg; break; case 'G': k = ConversionSpecifier::GArg; break; + case 'X': k = ConversionSpecifier::XArg; break; case 'a': k = ConversionSpecifier::aArg; break; - case 'A': k = ConversionSpecifier::AArg; break; case 'c': k = ConversionSpecifier::IntAsCharArg; break; - case 's': k = ConversionSpecifier::CStrArg; break; - case 'p': k = ConversionSpecifier::VoidPtrArg; break; + case 'd': k = ConversionSpecifier::dArg; break; + case 'e': k = ConversionSpecifier::eArg; break; + case 'f': k = ConversionSpecifier::fArg; break; + case 'g': k = ConversionSpecifier::gArg; break; + case 'i': k = ConversionSpecifier::iArg; break; case 'n': k = ConversionSpecifier::OutIntPtrArg; break; - case '%': k = ConversionSpecifier::PercentArg; break; + case 'o': k = ConversionSpecifier::oArg; break; + case 'p': k = ConversionSpecifier::VoidPtrArg; break; + case 's': k = ConversionSpecifier::CStrArg; break; + case 'u': k = ConversionSpecifier::uArg; break; + case 'x': k = ConversionSpecifier::xArg; break; + // Mac OS X (unicode) specific + case 'C': k = ConversionSpecifier::CArg; break; + case 'S': k = ConversionSpecifier::UnicodeStrArg; break; // Objective-C. case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. @@ -345,8 +348,10 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { if (!PT) return false; - QualType pointeeTy = PT->getPointeeType(); - return pointeeTy == C.WCharTy; + QualType pointeeTy = + C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); + + return pointeeTy == C.getWCharType(); } return false; @@ -359,7 +364,7 @@ QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { if (K == CStrTy) return C.getPointerType(C.CharTy); if (K == WCStrTy) - return C.getPointerType(C.WCharTy); + return C.getPointerType(C.getWCharType()); if (K == ObjCPointerTy) return C.ObjCBuiltinIdTy; @@ -425,11 +430,19 @@ ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const { return Ctx.LongDoubleTy; return Ctx.DoubleTy; } - - if (CS.getKind() == ConversionSpecifier::CStrArg) - return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy - : ArgTypeResult::CStrTy); - + + switch (CS.getKind()) { + case ConversionSpecifier::CStrArg: + return ArgTypeResult(LM == AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy); + case ConversionSpecifier::UnicodeStrArg: + // FIXME: This appears to be Mac OS X specific. + return ArgTypeResult::WCStrTy; + case ConversionSpecifier::CArg: + return Ctx.WCharTy; + default: + break; + } + // FIXME: Handle other cases. return ArgTypeResult(); } diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c index f1fa6580e3..4cd4db26eb 100644 --- a/test/Sema/format-strings.c +++ b/test/Sema/format-strings.c @@ -204,3 +204,18 @@ void test_asl(aslclient asl) { // <rdar://problem/7595366> typedef enum { A } int_t; void f0(int_t x) { printf("%d\n", x); } + +// Unicode test cases. These are possibly specific to Mac OS X. If so, they should +// eventually be moved into a separate test. +typedef __WCHAR_TYPE__ wchar_t; + +void test_unicode_conversions(wchar_t *s) { + printf("%S", s); // no-warning + printf("%s", s); // expected-warning{{conversion specifies type 'char *' but the argument has type 'wchar_t *'}} + printf("%C", s[0]); // no-warning + printf("%c", s[0]); + printf("%C", 10); + // FIXME: we report the expected type as 'int*' instead of 'wchar_t*' + printf("%S", "hello"); // expected-warning{{but the argument has type 'char *'}} +} + |