]> granicus.if.org Git - clang/commitdiff
Suggest %zu for size_t args to printf.
authorHans Wennborg <hans@hanshq.net>
Tue, 18 Oct 2011 08:10:06 +0000 (08:10 +0000)
committerHans Wennborg <hans@hanshq.net>
Tue, 18 Oct 2011 08:10:06 +0000 (08:10 +0000)
For PR11152. Make PrintSpecifier::fixType() suggest "%zu" for size_t, etc.
rather than looking at the underlying type and suggesting "%llu" or other
platform-specific length modifiers. Applies to C99 and C++11.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142342 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Analysis/Analyses/FormatString.h
lib/Analysis/PrintfFormatString.cpp
lib/Sema/SemaChecking.cpp
test/Sema/format-strings-fixit.c

index 61f416447204c9e2a7a000f1d46cf42ca280ca61..a2bd19c22833fa00aa6141ccab97d4e3766a1990 100644 (file)
@@ -463,7 +463,7 @@ public:
     /// Changes the specifier and length according to a QualType, retaining any
     /// flags or options. Returns true on success, or false when a conversion
     /// was not successful.
-  bool fixType(QualType QT);
+  bool fixType(QualType QT, const LangOptions &LangOpt);
 
   void toString(raw_ostream &os) const;
 
index 0c0e343331474b1af7fba1cfcb8465f581a61f8b..4e3e391fd065f1b23a92755655e632b72c41b023 100644 (file)
@@ -355,7 +355,7 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
   return ArgTypeResult();
 }
 
-bool PrintfSpecifier::fixType(QualType QT) {
+bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt) {
   // Handle strings first (char *, wchar_t *)
   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
     CS.setKind(ConversionSpecifier::sArg);
@@ -438,6 +438,23 @@ bool PrintfSpecifier::fixType(QualType QT) {
     break;
   }
 
+  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
+  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x)) {
+    const IdentifierInfo *Identifier = QT.getBaseTypeIdentifier();
+    if (Identifier->getName() == "size_t") {
+      LM.setKind(LengthModifier::AsSizeT);
+    } else if (Identifier->getName() == "ssize_t") {
+      // Not C99, but common in Unix.
+      LM.setKind(LengthModifier::AsSizeT);
+    } else if (Identifier->getName() == "intmax_t") {
+      LM.setKind(LengthModifier::AsIntMax);
+    } else if (Identifier->getName() == "uintmax_t") {
+      LM.setKind(LengthModifier::AsIntMax);
+    } else if (Identifier->getName() == "ptrdiff_t") {
+      LM.setKind(LengthModifier::AsPtrDiff);
+    }
+  }
+
   // Set conversion specifier and disable any flags which do not apply to it.
   // Let typedefs to char fall through to int, as %c is silly for uint8_t.
   if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) {
index 329adf89e8ad88ad13228e1dad9bfb98a5f44a45..fd99528bd682f79d4c999d91bd44c69035ff4cbf 100644 (file)
@@ -1966,7 +1966,7 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
 
     // We may be able to offer a FixItHint if it is a supported type.
     PrintfSpecifier fixedFS = FS;
-    bool success = fixedFS.fixType(Ex->getType());
+    bool success = fixedFS.fixType(Ex->getType(), S.getLangOptions());
 
     if (success) {
       // Get the fix string from the fixed format specifier
index d03cccb601f32ec14fa03b703655bc131dbcbc5e..5b2f54a59fae73a9ed430fead9dd9dc207330b09 100644 (file)
@@ -46,6 +46,19 @@ void test() {
   // Perserve the original formatting for unsigned integers.
   unsigned long val = 42;
   printf("%X", val);
+
+  typedef __SIZE_TYPE__ size_t;
+  typedef signed long int ssize_t;
+  typedef __INTMAX_TYPE__ intmax_t;
+  typedef __UINTMAX_TYPE__ uintmax_t;
+  typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+  // size_t, etc.
+  printf("%c", (size_t) 42);
+  printf("%c", (ssize_t) 42);
+  printf("%c", (intmax_t) 42);
+  printf("%c", (uintmax_t) 42);
+  printf("%c", (ptrdiff_t) 42);
 }
 
 // Validate the fixes...
@@ -68,3 +81,8 @@ void test() {
 // CHECK: printf("%s", "foo");
 // CHECK: printf("%1$p", (void *)0);
 // CHECK: printf("%lX", val);
+// CHECK: printf("%zu", (size_t) 42);
+// CHECK: printf("%zd", (ssize_t) 42);
+// CHECK: printf("%jd", (intmax_t) 42);
+// CHECK: printf("%ju", (uintmax_t) 42);
+// CHECK: printf("%td", (ptrdiff_t) 42);