diff options
-rw-r--r-- | include/clang/Analysis/Analyses/FormatString.h | 2 | ||||
-rw-r--r-- | lib/Analysis/PrintfFormatString.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 2 | ||||
-rw-r--r-- | test/Sema/format-strings-fixit.c | 18 |
4 files changed, 38 insertions, 3 deletions
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index 61f4164472..a2bd19c228 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -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; diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 0c0e343331..4e3e391fd0 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -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()) { diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 329adf89e8..fd99528bd6 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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 diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c index d03cccb601..5b2f54a59f 100644 --- a/test/Sema/format-strings-fixit.c +++ b/test/Sema/format-strings-fixit.c @@ -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); |