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:
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) {
}
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;
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) {
// Methods for querying the format specifier.
- const ConversionSpecifier &getConversionSpecifier() const {
- return CS;
+ const PrintfConversionSpecifier &getConversionSpecifier() const {
+ return cast<PrintfConversionSpecifier>(CS);
}
void setPrecision(const OptionalAmount &Amt) {
}
bool consumesDataArgument() const {
- return CS.consumesDataArgument();
+ return getConversionSpecifier().consumesDataArgument();
}
/// \brief Returns the builtin type that a data argument
namespace analyze_scanf {
-class ConversionSpecifier {
+class ScanfConversionSpecifier {
public:
enum Kind {
InvalidSpecifier = 0,
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 {
class ScanfSpecifier : public analyze_format_string::FormatSpecifier {
OptionalFlag SuppressAssignment; // '*'
- ConversionSpecifier CS;
+ ScanfConversionSpecifier CS;
public:
ScanfSpecifier() : SuppressAssignment("*") {}
return SuppressAssignment;
}
- void setConversionSpecifier(const ConversionSpecifier &cs) {
+ void setConversionSpecifier(const ScanfConversionSpecifier &cs) {
CS = cs;
}
- const ConversionSpecifier &getConversionSpecifier() const {
+ const ScanfConversionSpecifier &getConversionSpecifier() const {
return CS;
}
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;
const char *E,
unsigned &argIndex) {
+ using namespace clang::analyze_format_string;
using namespace clang::analyze_printf;
const char *I = Beg;
// 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++);
//===----------------------------------------------------------------------===//
ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
+ const PrintfConversionSpecifier &CS = getConversionSpecifier();
+
if (!CS.consumesDataArgument())
return ArgTypeResult::Invalid();
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<ScanfSpecifier>
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;
// 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;
}
// 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);
}
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(),
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()),
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()
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) {
const char *startSpecifier,
unsigned specifierLen) {
- const analyze_scanf::ConversionSpecifier &CS =
+ const analyze_scanf::ScanfConversionSpecifier &CS =
FS.getConversionSpecifier();
return HandleInvalidConversionSpecifier(FS.getArgIndex(),
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.