Check that arguments to a scanf call match the format specifier,
and offer fixits when there is a mismatch.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146326 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/taint-generic.c b/test/Analysis/taint-generic.c
index eeec886..9c99f90 100644
--- a/test/Analysis/taint-generic.c
+++ b/test/Analysis/taint-generic.c
@@ -39,7 +39,8 @@
 
 void scanfArg() {
   int t;
-  scanf("%d", t); // expected-warning {{Pointer argument is expected}}
+  scanf("%d", t); // expected-warning {{Pointer argument is expected}} \
+                  // expected-warning {{conversion specifies type 'int *' but the argument has type 'int'}}
 }
 
 void bufferGetchar(int x) {
diff --git a/test/Analysis/taint-tester.c b/test/Analysis/taint-tester.c
index 8a82cd3..da1ff02 100644
--- a/test/Analysis/taint-tester.c
+++ b/test/Analysis/taint-tester.c
@@ -49,8 +49,8 @@
 
   // Taint on fields of a struct.
   struct XYStruct xy = {2, 3, 11};
-  scanf("%f", &xy.y);
-  scanf("%f", &xy.x);
+  scanf("%d", &xy.y);
+  scanf("%d", &xy.x);
   int tx = xy.x; // expected-warning {{tainted}}
   int ty = xy.y; // FIXME: This should be tainted as well.
   char ntz = xy.z;// no warning
diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c
index bfb5432..4fb6d75 100644
--- a/test/Sema/format-strings-fixit.c
+++ b/test/Sema/format-strings-fixit.c
@@ -10,6 +10,11 @@
 
 int printf(char const *, ...);
 
+typedef __SIZE_TYPE__ size_t;
+typedef __INTMAX_TYPE__ intmax_t;
+typedef __UINTMAX_TYPE__ uintmax_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
 void test() {
   // Basic types
   printf("%s", (int) 123);
@@ -47,11 +52,6 @@
   unsigned long val = 42;
   printf("%X", val);
 
-  typedef __SIZE_TYPE__ size_t;
-  typedef __INTMAX_TYPE__ intmax_t;
-  typedef __UINTMAX_TYPE__ uintmax_t;
-  typedef __PTRDIFF_TYPE__ ptrdiff_t;
-
   // size_t, etc.
   printf("%f", (size_t) 42);
   printf("%f", (intmax_t) 42);
@@ -62,6 +62,51 @@
   printf("%ld", "foo");
 }
 
+int scanf(char const *, ...);
+
+void test2() {
+  char str[100];
+  short shortVar;
+  unsigned short uShortVar;
+  int intVar;
+  unsigned uIntVar;
+  float floatVar;
+  double doubleVar;
+  long double longDoubleVar;
+  long longVar;
+  unsigned long uLongVar;
+  long long longLongVar;
+  unsigned long long uLongLongVar;
+  size_t sizeVar;
+  intmax_t intmaxVar;
+  uintmax_t uIntmaxVar;
+  ptrdiff_t ptrdiffVar;
+
+  scanf("%lf", str);
+  scanf("%f", &shortVar);
+  scanf("%f", &uShortVar);
+  scanf("%p", &intVar);
+  scanf("%Lf", &uIntVar);
+  scanf("%ld", &floatVar);
+  scanf("%f", &doubleVar);
+  scanf("%d", &longDoubleVar);
+  scanf("%f", &longVar);
+  scanf("%f", &uLongVar);
+  scanf("%f", &longLongVar);
+  scanf("%f", &uLongLongVar);
+
+  // Some named ints.
+  scanf("%f", &sizeVar);
+  scanf("%f", &intmaxVar);
+  scanf("%f", &uIntmaxVar);
+  scanf("%f", &ptrdiffVar);
+
+  // Perserve the original formatting for unsigned integers.
+  scanf("%o", &uLongVar);
+  scanf("%x", &uLongVar);
+  scanf("%X", &uLongVar);
+}
+
 // Validate the fixes...
 // CHECK: printf("%d", (int) 123);
 // CHECK: printf("abc%s", "testing testing 123");
@@ -87,3 +132,23 @@
 // CHECK: printf("%ju", (uintmax_t) 42);
 // CHECK: printf("%td", (ptrdiff_t) 42);
 // CHECK: printf("%s", "foo");
+
+// CHECK: scanf("%s", str);
+// CHECK: scanf("%hd", &shortVar);
+// CHECK: scanf("%hu", &uShortVar);
+// CHECK: scanf("%d", &intVar);
+// CHECK: scanf("%u", &uIntVar);
+// CHECK: scanf("%f", &floatVar);
+// CHECK: scanf("%lf", &doubleVar);
+// CHECK: scanf("%Lf", &longDoubleVar);
+// CHECK: scanf("%ld", &longVar);
+// CHECK: scanf("%lu", &uLongVar);
+// CHECK: scanf("%lld", &longLongVar);
+// CHECK: scanf("%llu", &uLongLongVar);
+// CHECK: scanf("%zu", &sizeVar);
+// CHECK: scanf("%jd", &intmaxVar);
+// CHECK: scanf("%ju", &uIntmaxVar);
+// CHECK: scanf("%td", &ptrdiffVar);
+// CHECK: scanf("%lo", &uLongVar);
+// CHECK: scanf("%lx", &uLongVar);
+// CHECK: scanf("%lX", &uLongVar);
diff --git a/test/Sema/format-strings-int-typedefs.c b/test/Sema/format-strings-int-typedefs.c
index 2568b8d..8d5dff1 100644
--- a/test/Sema/format-strings-int-typedefs.c
+++ b/test/Sema/format-strings-int-typedefs.c
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
 
 int printf(char const *, ...);
+int scanf(char const *, ...);
 
 void test(void) {
   printf("%jd", 42.0); // expected-warning {{conversion specifies type 'intmax_t' (aka 'long long')}}
@@ -12,6 +13,15 @@
   printf("%S", 42.0);  // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
   printf("%C", 42.0);  // expected-warning {{conversion specifies type 'wchar_t' (aka 'int')}}
 
+  scanf("%jd", 0); // expected-warning {{conversion specifies type 'intmax_t *' (aka 'long long *')}}
+  scanf("%ju", 0); // expected-warning {{conversion specifies type 'uintmax_t *' (aka 'unsigned long long *')}}
+  scanf("%zu", 0); // expected-warning {{conversion specifies type 'size_t *' (aka 'unsigned long *')}}
+  scanf("%td", 0); // expected-warning {{conversion specifies type 'ptrdiff_t *' (aka 'int *')}}
+  scanf("%lc", 0); // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
+  scanf("%ls", 0); // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
+  scanf("%S",  0);  // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
+  scanf("%C",  0);  // expected-warning {{conversion specifies type 'wchar_t *' (aka 'int *')}}
+
 
   // typedef size_t et al. to something crazy.
   typedef void *size_t;
diff --git a/test/Sema/format-strings-scanf.c b/test/Sema/format-strings-scanf.c
index ee559da..4675862 100644
--- a/test/Sema/format-strings-scanf.c
+++ b/test/Sema/format-strings-scanf.c
@@ -28,7 +28,7 @@
 
 void bad_length_modifiers(char *s, void *p, wchar_t *ws, long double *ld) {
   scanf("%hhs", "foo"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
-  scanf("%1$zp", p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}
+  scanf("%1$zp", &p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}
   scanf("%ls", ws); // no-warning
   scanf("%#.2Lf", ld); // expected-warning{{invalid conversion specifier '#'}}
 }
@@ -37,10 +37,11 @@
 // format string is somewhere else, point to it in a note.
 void pr9751() {
   int *i;
+  char str[100];
   const char kFormat1[] = "%00d"; // expected-note{{format string is defined here}}}
   scanf(kFormat1, i); // expected-warning{{zero field width in scanf format string is unused}}
   scanf("%00d", i); // expected-warning{{zero field width in scanf format string is unused}}
   const char kFormat2[] = "%["; // expected-note{{format string is defined here}}}
-  scanf(kFormat2, &i); // expected-warning{{no closing ']' for '%[' in scanf format string}}
-  scanf("%[", &i); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+  scanf(kFormat2, str); // expected-warning{{no closing ']' for '%[' in scanf format string}}
+  scanf("%[", str); // expected-warning{{no closing ']' for '%[' in scanf format string}}
 }