aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2013-01-17 18:47:16 +0000
committerJordan Rose <jordan_rose@apple.com>2013-01-17 18:47:16 +0000
commit242ae3d6805185fcb4fd45e96af5beba93e3532c (patch)
treeca28f50c979f0895ee2fa893654c8de51e32069f
parentc8145bbab03caba4b7ef5540727487529c7effeb (diff)
Format strings: correct signedness if already correcting width (%d,%u).
It is valid to do this: printf("%u", (int)x); But if we see this: printf("%lu", (int)x); ...our fixit should suggest %d, not %u. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172739 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Analysis/PrintfFormatString.cpp20
-rw-r--r--test/FixIt/format-darwin.m18
-rw-r--r--test/FixIt/format.m11
3 files changed, 48 insertions, 1 deletions
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index b52433a0a4..5d37de362a 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -499,8 +499,26 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
namedTypeToLengthModifier(QT, LM);
- // If fixing the length modifier was enough, we are done.
+ // If fixing the length modifier was enough, we might be done.
if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ // If we're going to offer a fix anyway, make sure the sign matches.
+ switch (CS.getKind()) {
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
+ if (QT->isSignedIntegerType())
+ CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
+ break;
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
+ case ConversionSpecifier::iArg:
+ if (QT->isUnsignedIntegerType())
+ CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
+ break;
+ default:
+ // Other specifiers do not have signed/unsigned variants.
+ break;
+ }
+
const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
if (ATR.isValid() && ATR.matchesType(Ctx, QT))
return true;
diff --git a/test/FixIt/format-darwin.m b/test/FixIt/format-darwin.m
index 46b6705f15..cfaac29e90 100644
--- a/test/FixIt/format-darwin.m
+++ b/test/FixIt/format-darwin.m
@@ -118,6 +118,16 @@ void testPreserveHex() {
// CHECK-64: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]:16}:"(unsigned long)"
}
+void testSignedness(NSInteger i, NSUInteger u) {
+ printf("%d", u); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+ printf("%i", u); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+ printf("%u", i); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
+
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%ld"
+}
+
void testNoWarn() {
printf("%ld", getNSInteger()); // no-warning
printf("%lu", getNSUInteger()); // no-warning
@@ -154,6 +164,14 @@ void testNoWarn() {
printf("%lu", getUInt32()); // no-warning
}
+void testSignedness(NSInteger i, NSUInteger u) {
+ // It is valid to use a specifier with the opposite signedness as long as
+ // the type is correct.
+ printf("%d", u); // no-warning
+ printf("%i", u); // no-warning
+ printf("%u", i); // no-warning
+}
+
#endif
diff --git a/test/FixIt/format.m b/test/FixIt/format.m
index 58c553a010..f8ca0e124d 100644
--- a/test/FixIt/format.m
+++ b/test/FixIt/format.m
@@ -213,3 +213,14 @@ void test_percent_C() {
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:22}:"(unichar)"
}
+
+
+void testSignedness(long i, unsigned long u) {
+ printf("%d", u); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned long'}}
+ printf("%i", u); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned long'}}
+ printf("%u", i); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'long'}}
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%ld"
+}