From: Ted Kremenek Date: Tue, 20 Jul 2010 20:04:27 +0000 (+0000) Subject: Add 'ConversionSpecifier' root class in 'analyze_format_string' namespace and X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6ecb950c65329f8d6ce9ad0514632df35a5ab61f;p=clang Add 'ConversionSpecifier' root class in 'analyze_format_string' namespace and derived 'PrintfConversionSpecifier' from this class. We will do the same for 'ScanfConversionSpecifier'. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108903 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h index bd51bdf712..9c0db5b7e6 100644 --- a/include/clang/Analysis/Analyses/FormatString.h +++ b/include/clang/Analysis/Analyses/FormatString.h @@ -104,6 +104,82 @@ private: const char *Position; Kind kind; }; + +class ConversionSpecifier { +public: + enum Kind { + InvalidSpecifier = 0, + // C99 conversion specifiers. + cArg, + dArg, + iArg, + IntArgBeg = cArg, IntArgEnd = iArg, + + oArg, + uArg, + xArg, + XArg, + UIntArgBeg = oArg, UIntArgEnd = XArg, + + fArg, + FArg, + eArg, + EArg, + gArg, + GArg, + aArg, + AArg, + DoubleArgBeg = fArg, DoubleArgEnd = AArg, + + sArg, + pArg, + nArg, + PercentArg, + CArg, + SArg, + + // ** Printf-specific ** + + // Objective-C specific specifiers. + ObjCObjArg, // '@' + ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, + + // GlibC specific specifiers. + PrintErrno, // 'm' + + PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno + }; + + ConversionSpecifier(bool isPrintf) + : IsPrintf(isPrintf), Position(0), kind(InvalidSpecifier) {} + + ConversionSpecifier(bool isPrintf, const char *pos, Kind k) + : IsPrintf(isPrintf), Position(pos), kind(k) {} + + const char *getStart() const { + return Position; + } + + llvm::StringRef getCharacters() const { + return llvm::StringRef(getStart(), getLength()); + } + + Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } + unsigned getLength() const { + // Conversion specifiers currently only are represented by + // single characters, but we be flexible. + return 1; + } + const char *toString() const; + + bool isPrintfKind() const { return IsPrintf; } + +protected: + bool IsPrintf; + const char *Position; + Kind kind; +}; class ArgTypeResult { public: @@ -253,64 +329,14 @@ public: namespace analyze_printf { -class ConversionSpecifier { +class PrintfConversionSpecifier : + public analyze_format_string::ConversionSpecifier { public: - enum Kind { - InvalidSpecifier = 0, - // C99 conversion specifiers. - cArg, - dArg, - iArg, - IntArgBeg = cArg, IntArgEnd = iArg, - - oArg, - uArg, - xArg, - XArg, - UIntArgBeg = oArg, UIntArgEnd = XArg, - - fArg, - FArg, - eArg, - EArg, - gArg, - GArg, - aArg, - AArg, - DoubleArgBeg = fArg, DoubleArgEnd = AArg, - - sArg, - pArg, - nArg, - PercentArg, - CArg, - SArg, + PrintfConversionSpecifier() + : ConversionSpecifier(true, 0, InvalidSpecifier) {} - // ** Printf-specific ** - - // Objective-C specific specifiers. - ObjCObjArg, // '@' - ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, - - // GlibC specific specifiers. - PrintErrno, // 'm' - - PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno - }; - - ConversionSpecifier() - : Position(0), kind(InvalidSpecifier) {} - - ConversionSpecifier(const char *pos, Kind k) - : Position(pos), kind(k) {} - - const char *getStart() const { - return Position; - } - - llvm::StringRef getCharacters() const { - return llvm::StringRef(getStart(), getLength()); - } + PrintfConversionSpecifier(const char *pos, Kind k) + : ConversionSpecifier(true, pos, k) {} bool consumesDataArgument() const { switch (kind) { @@ -323,21 +349,19 @@ public: } bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } - bool isIntArg() const { return kind >= dArg && kind <= iArg; } - bool isUIntArg() const { return kind >= oArg && kind <= XArg; } - bool isDoubleArg() const { return kind >= fArg && kind <= AArg; } - Kind getKind() const { return kind; } - void setKind(Kind k) { kind = k; } + bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; } + bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } + bool isDoubleArg() const { return kind >= DoubleArgBeg && + kind <= DoubleArgBeg; } unsigned getLength() const { // Conversion specifiers currently only are represented by // single characters, but we be flexible. return 1; } - const char *toString() const; -private: - const char *Position; - Kind kind; + static bool classof(const analyze_format_string::ConversionSpecifier *CS) { + return CS->isPrintfKind(); + } }; using analyze_format_string::ArgTypeResult; @@ -351,17 +375,17 @@ class PrintfSpecifier : public analyze_format_string::FormatSpecifier { OptionalFlag HasSpacePrefix; // ' ' OptionalFlag HasAlternativeForm; // '#' OptionalFlag HasLeadingZeroes; // '0' - ConversionSpecifier CS; + analyze_format_string::ConversionSpecifier CS; OptionalAmount Precision; public: PrintfSpecifier() : - IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), - HasAlternativeForm("#"), HasLeadingZeroes("0") {} + IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "), + HasAlternativeForm("#"), HasLeadingZeroes("0"), CS(/* isPrintf = */ true) {} static PrintfSpecifier Parse(const char *beg, const char *end); // Methods for incrementally constructing the PrintfSpecifier. - void setConversionSpecifier(const ConversionSpecifier &cs) { + void setConversionSpecifier(const PrintfConversionSpecifier &cs) { CS = cs; } void setIsLeftJustified(const char *position) { @@ -388,8 +412,8 @@ public: // Methods for querying the format specifier. - const ConversionSpecifier &getConversionSpecifier() const { - return CS; + const PrintfConversionSpecifier &getConversionSpecifier() const { + return cast(CS); } void setPrecision(const OptionalAmount &Amt) { @@ -402,7 +426,7 @@ public: } bool consumesDataArgument() const { - return CS.consumesDataArgument(); + return getConversionSpecifier().consumesDataArgument(); } /// \brief Returns the builtin type that a data argument @@ -444,7 +468,7 @@ public: namespace analyze_scanf { -class ConversionSpecifier { +class ScanfConversionSpecifier { public: enum Kind { InvalidSpecifier = 0, @@ -481,10 +505,10 @@ public: DoubleArgEnd = AArg }; - ConversionSpecifier() + ScanfConversionSpecifier() : Position(0), EndScanList(0), kind(InvalidSpecifier) {} - ConversionSpecifier(const char *pos, Kind k) + ScanfConversionSpecifier(const char *pos, Kind k) : Position(pos), EndScanList(0), kind(k) {} const char *getStart() const { @@ -525,7 +549,7 @@ using analyze_format_string::OptionalFlag; class ScanfSpecifier : public analyze_format_string::FormatSpecifier { OptionalFlag SuppressAssignment; // '*' - ConversionSpecifier CS; + ScanfConversionSpecifier CS; public: ScanfSpecifier() : SuppressAssignment("*") {} @@ -538,11 +562,11 @@ public: return SuppressAssignment; } - void setConversionSpecifier(const ConversionSpecifier &cs) { + void setConversionSpecifier(const ScanfConversionSpecifier &cs) { CS = cs; } - const ConversionSpecifier &getConversionSpecifier() const { + const ScanfConversionSpecifier &getConversionSpecifier() const { return CS; } diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 59f865799b..2aeb53f52e 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -19,7 +19,7 @@ using clang::analyze_format_string::ArgTypeResult; using clang::analyze_format_string::FormatStringHandler; using clang::analyze_format_string::LengthModifier; using clang::analyze_format_string::OptionalAmount; -using clang::analyze_printf::ConversionSpecifier; +using clang::analyze_format_string::ConversionSpecifier; using clang::analyze_printf::PrintfSpecifier; using namespace clang; @@ -54,6 +54,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *E, unsigned &argIndex) { + using namespace clang::analyze_format_string; using namespace clang::analyze_printf; const char *I = Beg; @@ -192,7 +193,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; } - ConversionSpecifier CS(conversionPosition, k); + PrintfConversionSpecifier CS(conversionPosition, k); FS.setConversionSpecifier(CS); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); @@ -274,6 +275,8 @@ const char *ConversionSpecifier::toString() const { //===----------------------------------------------------------------------===// ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { + const PrintfConversionSpecifier &CS = getConversionSpecifier(); + if (!CS.consumesDataArgument()) return ArgTypeResult::Invalid(); diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp index fc2e77c0a9..493a3c8df2 100644 --- a/lib/Analysis/ScanfFormatString.cpp +++ b/lib/Analysis/ScanfFormatString.cpp @@ -19,14 +19,14 @@ using clang::analyze_format_string::ArgTypeResult; using clang::analyze_format_string::FormatStringHandler; using clang::analyze_format_string::LengthModifier; using clang::analyze_format_string::OptionalAmount; -using clang::analyze_scanf::ConversionSpecifier; +using clang::analyze_scanf::ScanfConversionSpecifier; using clang::analyze_scanf::ScanfSpecifier; typedef clang::analyze_format_string::SpecifierResult ScanfSpecifierResult; static bool ParseScanList(FormatStringHandler &H, - ConversionSpecifier &CS, + ScanfConversionSpecifier &CS, const char *&Beg, const char *E) { const char *I = Beg; const char *start = I - 1; @@ -142,34 +142,34 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, // Finally, look for the conversion specifier. const char *conversionPosition = I++; - ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; + ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier; switch (*conversionPosition) { default: break; - case '%': k = ConversionSpecifier::PercentArg; break; - case 'A': k = ConversionSpecifier::AArg; break; - case 'E': k = ConversionSpecifier::EArg; break; - case 'F': k = ConversionSpecifier::FArg; break; - case 'G': k = ConversionSpecifier::GArg; break; - case 'X': k = ConversionSpecifier::XArg; break; - case 'a': k = ConversionSpecifier::aArg; break; - case 'd': k = ConversionSpecifier::dArg; break; - case 'e': k = ConversionSpecifier::eArg; break; - case 'f': k = ConversionSpecifier::fArg; break; - case 'g': k = ConversionSpecifier::gArg; break; - case 'i': k = ConversionSpecifier::iArg; break; - case 'n': k = ConversionSpecifier::nArg; break; - case 'c': k = ConversionSpecifier::cArg; break; - case 'C': k = ConversionSpecifier::CArg; break; - case 'S': k = ConversionSpecifier::SArg; break; - case '[': k = ConversionSpecifier::ScanListArg; break; - case 'u': k = ConversionSpecifier::uArg; break; - case 'x': k = ConversionSpecifier::xArg; break; - case 'o': k = ConversionSpecifier::oArg; break; - case 's': k = ConversionSpecifier::sArg; break; + case '%': k = ScanfConversionSpecifier::PercentArg; break; + case 'A': k = ScanfConversionSpecifier::AArg; break; + case 'E': k = ScanfConversionSpecifier::EArg; break; + case 'F': k = ScanfConversionSpecifier::FArg; break; + case 'G': k = ScanfConversionSpecifier::GArg; break; + case 'X': k = ScanfConversionSpecifier::XArg; break; + case 'a': k = ScanfConversionSpecifier::aArg; break; + case 'd': k = ScanfConversionSpecifier::dArg; break; + case 'e': k = ScanfConversionSpecifier::eArg; break; + case 'f': k = ScanfConversionSpecifier::fArg; break; + case 'g': k = ScanfConversionSpecifier::gArg; break; + case 'i': k = ScanfConversionSpecifier::iArg; break; + case 'n': k = ScanfConversionSpecifier::nArg; break; + case 'c': k = ScanfConversionSpecifier::cArg; break; + case 'C': k = ScanfConversionSpecifier::CArg; break; + case 'S': k = ScanfConversionSpecifier::SArg; break; + case '[': k = ScanfConversionSpecifier::ScanListArg; break; + case 'u': k = ScanfConversionSpecifier::uArg; break; + case 'x': k = ScanfConversionSpecifier::xArg; break; + case 'o': k = ScanfConversionSpecifier::oArg; break; + case 's': k = ScanfConversionSpecifier::sArg; break; } - ConversionSpecifier CS(conversionPosition, k); - if (k == ConversionSpecifier::ScanListArg) { + ScanfConversionSpecifier CS(conversionPosition, k); + if (k == ScanfConversionSpecifier::ScanListArg) { if (!ParseScanList(H, CS, I, E)) return true; } @@ -181,7 +181,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, // FIXME: '%' and '*' doesn't make sense. Issue a warning. // FIXME: 'ConsumedSoFar' and '*' doesn't make sense. - if (k == ConversionSpecifier::InvalidSpecifier) { + if (k == ScanfConversionSpecifier::InvalidSpecifier) { // Assume the conversion takes one argument. return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, I - Beg); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 6d71b103ba..8846c25724 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1316,7 +1316,7 @@ bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - const analyze_printf::ConversionSpecifier &CS = + const analyze_printf::PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); return HandleInvalidConversionSpecifier(FS.getArgIndex(), @@ -1375,7 +1375,8 @@ void CheckPrintfHandler::HandleInvalidAmount( unsigned type, const char *startSpecifier, unsigned specifierLen) { - const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier(); + const analyze_printf::PrintfConversionSpecifier &CS = + FS.getConversionSpecifier(); switch (Amt.getHowSpecified()) { case analyze_printf::OptionalAmount::Constant: S.Diag(getLocationOfByte(Amt.getStart()), @@ -1402,7 +1403,8 @@ void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { // Warn about pointless flag with a fixit removal. - const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier(); + const analyze_printf::PrintfConversionSpecifier &CS = + FS.getConversionSpecifier(); S.Diag(getLocationOfByte(flag.getPosition()), diag::warn_printf_nonsensical_flag) << flag.toString() << CS.toString() @@ -1431,8 +1433,9 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier const char *startSpecifier, unsigned specifierLen) { + using namespace analyze_format_string; using namespace analyze_printf; - const ConversionSpecifier &CS = FS.getConversionSpecifier(); + const PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); if (FS.consumesDataArgument()) { if (atFirstArg) { @@ -1636,7 +1639,7 @@ bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier( const char *startSpecifier, unsigned specifierLen) { - const analyze_scanf::ConversionSpecifier &CS = + const analyze_scanf::ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); return HandleInvalidConversionSpecifier(FS.getArgIndex(), @@ -1653,7 +1656,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( using namespace analyze_scanf; using namespace analyze_format_string; - const ConversionSpecifier &CS = FS.getConversionSpecifier(); + const ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); // Handle case where '%' and '*' don't consume an argument. These shouldn't // be used to decide if we are using positional arguments consistently.