//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Handling of format string in printf and friends. The structure of format
// strings for fprintf() are described in C99 7.19.6.1.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/PrintfFormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
#include "llvm/Support/raw_ostream.h"
using clang::analyze_printf::ArgTypeResult;
using clang::analyze_printf::FormatSpecifier;
using clang::analyze_printf::FormatStringHandler;
using clang::analyze_printf::OptionalAmount;
using clang::analyze_printf::PositionContext;
using clang::analyze_printf::ConversionSpecifier;
using clang::analyze_printf::LengthModifier;
using namespace clang;
namespace {
class FormatSpecifierResult {
FormatSpecifier FS;
const char *Start;
bool Stop;
public:
FormatSpecifierResult(bool stop = false)
: Start(0), Stop(stop) {}
FormatSpecifierResult(const char *start,
const FormatSpecifier &fs)
: FS(fs), Start(start), Stop(false) {}
const char *getStart() const { return Start; }
bool shouldStop() const { return Stop; }
bool hasValue() const { return Start != 0; }
const FormatSpecifier &getValue() const {
assert(hasValue());
return FS;
}
const FormatSpecifier &getValue() { return FS; }
};
} // end anonymous namespace
template <typename T>
class UpdateOnReturn {
T &ValueToUpdate;
const T &ValueToCopy;
public:
UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
: ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
~UpdateOnReturn() {
ValueToUpdate = ValueToCopy;
}
};
//===----------------------------------------------------------------------===//
// Methods for parsing format strings.
//===----------------------------------------------------------------------===//
static OptionalAmount ParseAmount(const char *&Beg, const char *E) {
const char *I = Beg;
UpdateOnReturn <const char*> UpdateBeg(Beg, I);
unsigned accumulator = 0;
bool hasDigits = false;
for ( ; I != E; ++I) {
char c = *I;
if (c >= '0' && c <= '9') {
hasDigits = true;
accumulator = (accumulator * 10) + (c - '0');
continue;
}
if (hasDigits)
return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
false);
break;
}
return OptionalAmount();
}
static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
unsigned &argIndex) {
if (*Beg == '*') {
++Beg;
return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
}
return ParseAmount(Beg, E);
}
static OptionalAmount ParsePositionAmount(FormatStringHandler &H,
const char *Start,
const char *&Beg, const char *E,
PositionContext p) {
if (*Beg == '*') {
const char *I = Beg + 1;
const OptionalAmount &Amt = ParseAmount(I, E);
if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
H.HandleInvalidPosition(Beg, I - Beg, p);
return OptionalAmount(false);
}
if (I== E) {
// No more characters left?
H.HandleIncompleteFormatSpecifier(Start, E - Start);
<