From 33567d2feb3e52fac6e0b46d5b3d137fc8467fb0 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Fri, 29 Jan 2010 22:59:32 +0000 Subject: [PATCH] Per a suggestion from Cristian Draghici, add a method to FormatSpecifier that returns the expected type of the matching data argument. It isn't complete, but should handle several of the important cases. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94851 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Analysis/Analyses/PrintfFormatString.h | 49 +++++++++++++---- lib/Analysis/PrintfFormatString.cpp | 53 +++++++++++++++++++ 2 files changed, 93 insertions(+), 9 deletions(-) diff --git a/include/clang/Analysis/Analyses/PrintfFormatString.h b/include/clang/Analysis/Analyses/PrintfFormatString.h index c0863f25a8..f8f13a451b 100644 --- a/include/clang/Analysis/Analyses/PrintfFormatString.h +++ b/include/clang/Analysis/Analyses/PrintfFormatString.h @@ -15,9 +15,12 @@ #ifndef LLVM_CLANG_FPRINTF_FORMAT_H #define LLVM_CLANG_FPRINTF_FORMAT_H -#include +#include "clang/AST/CanonicalType.h" namespace clang { + +class ASTContext; + namespace analyze_printf { class ConversionSpecifier { @@ -147,24 +150,45 @@ private: HowSpecified hs; unsigned amt; }; + +class ArgTypeResult { + enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy }; + const Kind K; + QualType T; + ArgTypeResult(bool) : K(InvalidTy) {} +public: + ArgTypeResult() : K(UnknownTy) {} + ArgTypeResult(QualType t) : K(SpecificTy), T(t) {} + ArgTypeResult(CanQualType t) : K(SpecificTy), T(t) {} + + static ArgTypeResult Invalid() { return ArgTypeResult(true); } + + bool isValid() const { return K != InvalidTy; } + + const QualType *getSpecificType() const { + return K == SpecificTy ? &T : 0; + } + + bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }; +}; class FormatSpecifier { - unsigned lengthModifier : 5; + LengthModifier LM; unsigned flags : 5; - ConversionSpecifier conversionSpecifier; + ConversionSpecifier CS; OptionalAmount FieldWidth; OptionalAmount Precision; public: - FormatSpecifier() : lengthModifier(0), flags(0) {} + FormatSpecifier() : LM(None), flags(0) {} static FormatSpecifier Parse(const char *beg, const char *end); // Methods for incrementally constructing the FormatSpecifier. - void setConversionSpecifier(const ConversionSpecifier &CS) { - conversionSpecifier = CS; + void setConversionSpecifier(const ConversionSpecifier &cs) { + CS = cs; } void setLengthModifier(LengthModifier lm) { - lengthModifier = (unsigned) lm; + LM = lm; } void setIsLeftJustified() { flags |= LeftJustified; } void setHasPlusPrefix() { flags |= PlusPrefix; } @@ -175,11 +199,11 @@ public: // Methods for querying the format specifier. const ConversionSpecifier &getConversionSpecifier() const { - return conversionSpecifier; + return CS; } LengthModifier getLengthModifier() const { - return (LengthModifier) lengthModifier; + return LM; } const OptionalAmount &getFieldWidth() const { @@ -197,6 +221,13 @@ public: const OptionalAmount &getPrecision() const { return Precision; } + + /// \brief Returns the builtin type that a data argument + /// paired with this format specifier should have. This method + /// will return null if the format specifier does not have + /// a matching data argument or the matching argument matches + /// more than one type. + ArgTypeResult getArgType(ASTContext &Ctx) const; bool isLeftJustified() const { return flags & LeftJustified; } bool hasPlusPrefix() const { return flags & PlusPrefix; } diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index bb9ac8480a..6192c29e41 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -13,9 +13,11 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/PrintfFormatString.h" +#include "clang/AST/ASTContext.h" using clang::analyze_printf::FormatSpecifier; using clang::analyze_printf::OptionalAmount; +using clang::analyze_printf::ArgTypeResult; using namespace clang; namespace { @@ -261,3 +263,54 @@ bool clang::ParseFormatString(FormatStringHandler &H, } FormatStringHandler::~FormatStringHandler() {} + +//===----------------------------------------------------------------------===// +// Methods on FormatSpecifier. +//===----------------------------------------------------------------------===// + +ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const { + if (!CS.consumesDataArgument()) + return ArgTypeResult::Invalid(); + + if (CS.isIntArg()) + switch (LM) { + case AsLongDouble: + return ArgTypeResult::Invalid(); + case None: return Ctx.IntTy; + case AsChar: return Ctx.SignedCharTy; + case AsShort: return Ctx.ShortTy; + case AsLong: return Ctx.LongTy; + case AsLongLong: return Ctx.LongLongTy; + case AsIntMax: + // FIXME: Return unknown for now. + return ArgTypeResult(); + case AsSizeT: return Ctx.getSizeType(); + case AsPtrDiff: return Ctx.getPointerDiffType(); + } + + if (CS.isUIntArg()) + switch (LM) { + case AsLongDouble: + return ArgTypeResult::Invalid(); + case None: return Ctx.UnsignedIntTy; + case AsChar: return Ctx.UnsignedCharTy; + case AsShort: return Ctx.UnsignedShortTy; + case AsLong: return Ctx.UnsignedLongTy; + case AsLongLong: return Ctx.UnsignedLongLongTy; + case AsIntMax: + // FIXME: Return unknown for now. + return ArgTypeResult(); + case AsSizeT: + // FIXME: How to get the corresponding unsigned + // version of size_t? + return ArgTypeResult(); + case AsPtrDiff: + // FIXME: How to get the corresponding unsigned + // version of ptrdiff_t? + return ArgTypeResult(); + } + + // FIXME: Handle other cases. + return ArgTypeResult(); +} + -- 2.40.0