]> granicus.if.org Git - clang/commitdiff
Make -Wformat walk the typedef chain when looking for size_t, etc.
authorHans Wennborg <hans@hanshq.net>
Fri, 27 Jul 2012 19:17:46 +0000 (19:17 +0000)
committerHans Wennborg <hans@hanshq.net>
Fri, 27 Jul 2012 19:17:46 +0000 (19:17 +0000)
Clang's -Wformat fix-its currently suggest using "%zu" for values of
type size_t (in C99 or C++11 mode). However, for a type such as
std::vector<T>::size_type, it does not notice that type is actually
typedeffed to size_t, and instead suggests a format for the underlying
type, such as "%lu" or "%u".

This commit makes the format string fix mechanism walk the typedef chain
so that it notices if the type is size_t, even if that isn't "at the
top".

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

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

index f99b97a1898a0511e18b48502a86ab4805b0f019..1fb05d7486c2c0525132c87c75c772ff720ca14e 100644 (file)
@@ -355,6 +355,10 @@ public:
   bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
 
   bool hasStandardLengthConversionCombination() const;
+
+  /// For a TypedefType QT, if it is a named integer type such as size_t,
+  /// assign the appropriate value to LM and return true.
+  static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);
 };
 
 } // end analyze_format_string namespace
index caceeac113bf7ece4682d02f1c1d372046c5f9cd..a68b9bb3240f21889c37c8014af665edbf21bfa8 100644 (file)
@@ -681,3 +681,37 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
   }
   return true;
 }
+
+bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
+                                                LengthModifier &LM) {
+  assert(isa<TypedefType>(QT) && "Expected a TypedefType");
+  const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
+
+  for (;;) {
+    const IdentifierInfo *Identifier = Typedef->getIdentifier();
+    if (Identifier->getName() == "size_t") {
+      LM.setKind(LengthModifier::AsSizeT);
+      return true;
+    } else if (Identifier->getName() == "ssize_t") {
+      // Not C99, but common in Unix.
+      LM.setKind(LengthModifier::AsSizeT);
+      return true;
+    } else if (Identifier->getName() == "intmax_t") {
+      LM.setKind(LengthModifier::AsIntMax);
+      return true;
+    } else if (Identifier->getName() == "uintmax_t") {
+      LM.setKind(LengthModifier::AsIntMax);
+      return true;
+    } else if (Identifier->getName() == "ptrdiff_t") {
+      LM.setKind(LengthModifier::AsPtrDiff);
+      return true;
+    }
+
+    QualType T = Typedef->getUnderlyingType();
+    if (!isa<TypedefType>(T))
+      break;
+
+    Typedef = cast<TypedefType>(T)->getDecl();
+  }
+  return false;
+}
index aa6d7424c0a56bf20beebfe9653a8cb21f95c3ff..2a9644a35307a510f5ad48635f3d333874cb6947 100644 (file)
@@ -447,21 +447,8 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
   }
 
   // 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);
-    }
-  }
+  if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+    namedTypeToLengthModifier(QT, LM);
 
   // If fixing the length modifier was enough, we are done.
   const analyze_printf::ArgTypeResult &ATR = getArgType(Ctx, IsObjCLiteral);
index 066d5d6fa13e62dd158cf68c62b0ab3b61973837..5c7e6ef8f27eba1168398fb78a89169207e323fb 100644 (file)
@@ -382,21 +382,8 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
   }
 
   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
-  if (isa<TypedefType>(PT) && (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);
-    }
-  }
+  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+    namedTypeToLengthModifier(PT, LM);
 
   // If fixing the length modifier was enough, we are done.
   const analyze_scanf::ScanfArgTypeResult &ATR = getArgType(Ctx);
index 800691ecc8cd374e7fc956dcff5f379c0ee49414..15ac71342876446d981821587bfe1db3c1265be2 100644 (file)
@@ -64,6 +64,18 @@ void test() {
   printf("%f", (uintmax_t) 42);
   printf("%f", (ptrdiff_t) 42);
 
+  // Look beyond the first typedef.
+  typedef size_t my_size_type;
+  typedef intmax_t my_intmax_type;
+  typedef uintmax_t my_uintmax_type;
+  typedef ptrdiff_t my_ptrdiff_type;
+  typedef int my_int_type;
+  printf("%f", (my_size_type) 42);
+  printf("%f", (my_intmax_type) 42);
+  printf("%f", (my_uintmax_type) 42);
+  printf("%f", (my_ptrdiff_type) 42);
+  printf("%f", (my_int_type) 42);
+
   // string
   printf("%ld", "foo");
 
@@ -122,6 +134,18 @@ void test2() {
   scanf("%f", &uIntmaxVar);
   scanf("%f", &ptrdiffVar);
 
+  // Look beyond the first typedef for named integer types.
+  typedef size_t my_size_type;
+  typedef intmax_t my_intmax_type;
+  typedef uintmax_t my_uintmax_type;
+  typedef ptrdiff_t my_ptrdiff_type;
+  typedef int my_int_type;
+  scanf("%f", (my_size_type*)&sizeVar);
+  scanf("%f", (my_intmax_type*)&intmaxVar);
+  scanf("%f", (my_uintmax_type*)&uIntmaxVar);
+  scanf("%f", (my_ptrdiff_type*)&ptrdiffVar);
+  scanf("%f", (my_int_type*)&intVar);
+
   // Preserve the original formatting.
   scanf("%o", &longVar);
   scanf("%u", &longVar);
@@ -162,6 +186,11 @@ void test2() {
 // CHECK: printf("%jd", (intmax_t) 42);
 // CHECK: printf("%ju", (uintmax_t) 42);
 // CHECK: printf("%td", (ptrdiff_t) 42);
+// CHECK: printf("%zu", (my_size_type) 42);
+// CHECK: printf("%jd", (my_intmax_type) 42);
+// CHECK: printf("%ju", (my_uintmax_type) 42);
+// CHECK: printf("%td", (my_ptrdiff_type) 42);
+// CHECK: printf("%d", (my_int_type) 42);
 // CHECK: printf("%s", "foo");
 // CHECK: printf("%lo", (long) 42);
 // CHECK: printf("%lu", (long) 42);
@@ -193,6 +222,11 @@ void test2() {
 // CHECK: scanf("%jd", &intmaxVar);
 // CHECK: scanf("%ju", &uIntmaxVar);
 // CHECK: scanf("%td", &ptrdiffVar);
+// CHECK: scanf("%zu", (my_size_type*)&sizeVar);
+// CHECK: scanf("%jd", (my_intmax_type*)&intmaxVar);
+// CHECK: scanf("%ju", (my_uintmax_type*)&uIntmaxVar);
+// CHECK: scanf("%td", (my_ptrdiff_type*)&ptrdiffVar);
+// CHECK: scanf("%d", (my_int_type*)&intVar);
 // CHECK: scanf("%lo", &longVar);
 // CHECK: scanf("%lu", &longVar);
 // CHECK: scanf("%lx", &longVar);