From: Hans Wennborg Date: Fri, 27 Jul 2012 19:17:46 +0000 (+0000) Subject: Make -Wformat walk the typedef chain when looking for size_t, etc. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4684778993c667246039b4664acbce59dc99440c;p=clang Make -Wformat walk the typedef chain when looking for size_t, etc. 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::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 --- diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index f99b97a189..1fb05d7486 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -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 diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp index caceeac113..a68b9bb324 100644 --- a/lib/Analysis/FormatString.cpp +++ b/lib/Analysis/FormatString.cpp @@ -681,3 +681,37 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const { } return true; } + +bool FormatSpecifier::namedTypeToLengthModifier(QualType QT, + LengthModifier &LM) { + assert(isa(QT) && "Expected a TypedefType"); + const TypedefNameDecl *Typedef = cast(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(T)) + break; + + Typedef = cast(T)->getDecl(); + } + return false; +} diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index aa6d7424c0..2a9644a353 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -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(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(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); diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp index 066d5d6fa1..5c7e6ef8f2 100644 --- a/lib/Analysis/ScanfFormatString.cpp +++ b/lib/Analysis/ScanfFormatString.cpp @@ -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(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(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); diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c index 800691ecc8..15ac713428 100644 --- a/test/Sema/format-strings-fixit.c +++ b/test/Sema/format-strings-fixit.c @@ -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);