PrintfFormatString.cpp revision 876e994957472eda4b40136d4e1d6e08e2be338f
18f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==//
28f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//
38f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//                     The LLVM Compiler Infrastructure
48f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//
58f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// This file is distributed under the University of Illinois Open Source
68f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// License. See LICENSE.TXT for details.
78f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//
88f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//===----------------------------------------------------------------------===//
98f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//
108f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// Handling of format string in printf and friends.  The structure of format
118f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek// strings for fprintf() are described in C99 7.19.6.1.
128f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//
138f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek//===----------------------------------------------------------------------===//
148f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
158f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek#include "clang/Analysis/Analyses/PrintfFormatString.h"
1633567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek#include "clang/AST/ASTContext.h"
173bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care#include "clang/AST/Type.h"
183bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care#include "llvm/Support/raw_ostream.h"
198f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
2033567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenekusing clang::analyze_printf::ArgTypeResult;
21efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekusing clang::analyze_printf::FormatSpecifier;
2274d56a168966ff015824279a24aaf566180ed97dTed Kremenekusing clang::analyze_printf::FormatStringHandler;
23efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekusing clang::analyze_printf::OptionalAmount;
24efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekusing clang::analyze_printf::PositionContext;
253bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Careusing clang::analyze_printf::ConversionSpecifier;
263bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Careusing clang::analyze_printf::LengthModifier;
27efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
28808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenekusing namespace clang;
298f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
308f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremeneknamespace {
318f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekclass FormatSpecifierResult {
328f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  FormatSpecifier FS;
338f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  const char *Start;
3426ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek  bool Stop;
358f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekpublic:
3626ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek  FormatSpecifierResult(bool stop = false)
3726ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek    : Start(0), Stop(stop) {}
388f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  FormatSpecifierResult(const char *start,
39d2dcece5882215e92a80bff8a7b7fd2fd81d7086Ted Kremenek                        const FormatSpecifier &fs)
4026ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek    : FS(fs), Start(start), Stop(false) {}
418f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
424e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
438f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  const char *getStart() const { return Start; }
4426ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek  bool shouldStop() const { return Stop; }
458f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  bool hasValue() const { return Start != 0; }
468f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  const FormatSpecifier &getValue() const {
478f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    assert(hasValue());
488f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    return FS;
498f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
50d2dcece5882215e92a80bff8a7b7fd2fd81d7086Ted Kremenek  const FormatSpecifier &getValue() { return FS; }
518f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek};
528f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek} // end anonymous namespace
538f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
548f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenektemplate <typename T>
558f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekclass UpdateOnReturn {
568f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  T &ValueToUpdate;
578f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  const T &ValueToCopy;
588f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenekpublic:
598f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
608f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
614e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
628f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  ~UpdateOnReturn() {
638f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    ValueToUpdate = ValueToCopy;
648f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
654e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek};
664e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
674e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===//
684e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek// Methods for parsing format strings.
694e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===//
708f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
71efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekstatic OptionalAmount ParseAmount(const char *&Beg, const char *E) {
728f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  const char *I = Beg;
738f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
744e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
758f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  unsigned accumulator = 0;
76d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek  bool hasDigits = false;
778f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
788f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  for ( ; I != E; ++I) {
798f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    char c = *I;
808f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    if (c >= '0' && c <= '9') {
81d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek      hasDigits = true;
82fdb703ab3a3c28aeb53b3db4c54e14a30d78dc4eTed Kremenek      accumulator = (accumulator * 10) + (c - '0');
838f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      continue;
848f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    }
858f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
86d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek    if (hasDigits)
873bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, 0);
884e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
898f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    break;
908f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
914e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
924e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  return OptionalAmount();
938f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek}
948f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
95efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekstatic OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
96efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                                             unsigned &argIndex) {
97efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (*Beg == '*') {
98efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    ++Beg;
993bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0);
100efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
101efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
102efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  return ParseAmount(Beg, E);
103efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek}
104efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
105efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekstatic OptionalAmount ParsePositionAmount(FormatStringHandler &H,
106efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                                          const char *Start,
107efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                                          const char *&Beg, const char *E,
108efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                                          PositionContext p) {
109efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (*Beg == '*') {
110efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    const char *I = Beg + 1;
111efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    const OptionalAmount &Amt = ParseAmount(I, E);
112efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
113efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
114efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      H.HandleInvalidPosition(Beg, I - Beg, p);
115efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      return OptionalAmount(false);
116efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    }
117efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
118efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    if (I== E) {
119efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      // No more characters left?
120efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      H.HandleIncompleteFormatSpecifier(Start, E - Start);
121efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      return OptionalAmount(false);
122efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    }
123efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
124d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
125d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek
126efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    if (*I == '$') {
1273bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      // Handle positional arguments
1283bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
129d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek      // Special case: '*0$', since this is an easy mistake.
130d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek      if (Amt.getConstantAmount() == 0) {
131d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek        H.HandleZeroPosition(Beg, I - Beg + 1);
132d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek        return OptionalAmount(false);
133d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek      }
134d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek
135efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      const char *Tmp = Beg;
136efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      Beg = ++I;
137d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek
138efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
1393bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care                            Tmp, 1);
140efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    }
141efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
142efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    H.HandleInvalidPosition(Beg, I - Beg, p);
143efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    return OptionalAmount(false);
144efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
145efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
146efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  return ParseAmount(Beg, E);
147efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek}
148efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
149efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekstatic bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS,
150efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                           const char *Start, const char *&Beg, const char *E,
151efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                           unsigned *argIndex) {
152efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (argIndex) {
153efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
154efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
155efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  else {
156efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
157efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                                                  analyze_printf::PrecisionPos);
158efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    if (Amt.isInvalid())
159efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      return true;
160efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    FS.setPrecision(Amt);
161efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
162efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  return false;
163efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek}
164efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
165efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekstatic bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS,
166efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                            const char *Start, const char *&Beg, const char *E,
167efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                            unsigned *argIndex) {
168efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  // FIXME: Support negative field widths.
169efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (argIndex) {
170efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
171efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
172efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  else {
173efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
174efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                                                 analyze_printf::FieldWidthPos);
175efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    if (Amt.isInvalid())
176efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      return true;
177efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    FS.setFieldWidth(Amt);
178efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
179efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  return false;
180efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek}
181efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
182efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
183efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenekstatic bool ParseArgPosition(FormatStringHandler &H,
184efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                             FormatSpecifier &FS, const char *Start,
185efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                             const char *&Beg, const char *E) {
186efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
187efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  using namespace clang::analyze_printf;
188efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  const char *I = Beg;
189efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
190efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  const OptionalAmount &Amt = ParseAmount(I, E);
191efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
192efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (I == E) {
193efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    // No more characters left?
194efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    H.HandleIncompleteFormatSpecifier(Start, E - Start);
195efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    return true;
196efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
197efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
198efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
199d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek    // Special case: '%0$', since this is an easy mistake.
200d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek    if (Amt.getConstantAmount() == 0) {
201d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek      H.HandleZeroPosition(Start, I - Start);
202d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek      return true;
203d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek    }
204d49d87719b8e272134e76601e3efc0197785aa8aTed Kremenek
205efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    FS.setArgIndex(Amt.getConstantAmount() - 1);
206efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    FS.setUsesPositionalArg();
207efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    // Update the caller's pointer if we decided to consume
208efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    // these characters.
209efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    Beg = I;
210efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    return false;
211efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
212efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
213efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  return false;
214efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek}
215efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
216808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenekstatic FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H,
21774d56a168966ff015824279a24aaf566180ed97dTed Kremenek                                                  const char *&Beg,
2187f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek                                                  const char *E,
2197f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek                                                  unsigned &argIndex) {
2204e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2214b220fae2f525fda39685ddfa7759950db1185e2Ted Kremenek  using namespace clang::analyze_printf;
2224e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2238f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  const char *I = Beg;
224c7ae51a3cd9460db8280e8623c90614f246e46d2Ted Kremenek  const char *Start = 0;
2258f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
2268f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
2278f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  // Look for a '%' character that indicates the start of a format specifier.
228e729acbba75903f42e79e72e46cdebe3f4c35521Ted Kremenek  for ( ; I != E ; ++I) {
2298f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    char c = *I;
2308f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    if (c == '\0') {
2318f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      // Detect spurious null characters, which are likely errors.
2328f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      H.HandleNullChar(I);
2338f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      return true;
2348f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    }
2358f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    if (c == '%') {
236e729acbba75903f42e79e72e46cdebe3f4c35521Ted Kremenek      Start = I++;  // Record the start of the format specifier.
2378f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      break;
2388f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    }
2398f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
2404e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2418f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  // No format specifier found?
2428f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  if (!Start)
2438f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    return false;
2444e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2458f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  if (I == E) {
2468f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    // No more characters left?
247808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenek    H.HandleIncompleteFormatSpecifier(Start, E - Start);
2488f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    return true;
2498f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
2504e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2518f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  FormatSpecifier FS;
252efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (ParseArgPosition(H, FS, Start, I, E))
253efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    return true;
254efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek
255efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (I == E) {
256efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    // No more characters left?
257efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    H.HandleIncompleteFormatSpecifier(Start, E - Start);
258efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    return true;
259efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  }
2604e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2618f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  // Look for flags (if any).
2628f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  bool hasMore = true;
2638f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  for ( ; I != E; ++I) {
2648f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    switch (*I) {
2658f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      default: hasMore = false; break;
2668f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      case '-': FS.setIsLeftJustified(); break;
2678f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      case '+': FS.setHasPlusPrefix(); break;
2688f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      case ' ': FS.setHasSpacePrefix(); break;
2698f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      case '#': FS.setHasAlternativeForm(); break;
2708f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      case '0': FS.setHasLeadingZeros(); break;
2718f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    }
2728f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    if (!hasMore)
2738f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      break;
2744e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  }
2758f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
2768f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  if (I == E) {
2778f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    // No more characters left?
278808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenek    H.HandleIncompleteFormatSpecifier(Start, E - Start);
2798f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    return true;
2808f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
2814e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2828f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  // Look for the field width (if any).
283efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (ParseFieldWidth(H, FS, Start, I, E,
284efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                      FS.usesPositionalArg() ? 0 : &argIndex))
285efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    return true;
2864e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2878f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  if (I == E) {
2888f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    // No more characters left?
289808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenek    H.HandleIncompleteFormatSpecifier(Start, E - Start);
2908f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    return true;
2914e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  }
2924e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
2934e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  // Look for the precision (if any).
2948f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  if (*I == '.') {
295808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenek    ++I;
2968f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    if (I == E) {
297808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenek      H.HandleIncompleteFormatSpecifier(Start, E - Start);
2988f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      return true;
2998f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    }
3004e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
301efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek    if (ParsePrecision(H, FS, Start, I, E,
302efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek                       FS.usesPositionalArg() ? 0 : &argIndex))
303efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek      return true;
3048f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
3058f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    if (I == E) {
3068f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      // No more characters left?
307808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenek      H.HandleIncompleteFormatSpecifier(Start, E - Start);
3088f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      return true;
3098f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    }
3108f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
3118f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
3128f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  // Look for the length modifier.
3133bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  LengthModifier::Kind lmKind = LengthModifier::None;
3143bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  const char *lmPosition = I;
3158f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  switch (*I) {
3168f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    default:
3178f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      break;
3188f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    case 'h':
3198f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      ++I;
3203bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      lmKind = (I != E && *I == 'h') ?
3213bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care          ++I, LengthModifier::AsChar : LengthModifier::AsShort;
3228f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      break;
3238f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    case 'l':
3248f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      ++I;
3253bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      lmKind = (I != E && *I == 'l') ?
3263bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care          ++I, LengthModifier::AsLongLong : LengthModifier::AsLong;
3278f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      break;
3283bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
3293bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
3303bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
3313bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
3323bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    case 'q': lmKind = LengthModifier::AsLongLong;   ++I; break;
3338f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
3343bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  LengthModifier lm(lmPosition, lmKind);
3358f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  FS.setLengthModifier(lm);
3364e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
3378f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  if (I == E) {
3388f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    // No more characters left?
339808015a18bd97781ce437831a95a92fdfc8d5136Ted Kremenek    H.HandleIncompleteFormatSpecifier(Start, E - Start);
3408f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    return true;
3418f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
342df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek
3434dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek  if (*I == '\0') {
344df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek    // Detect spurious null characters, which are likely errors.
345df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek    H.HandleNullChar(I);
346df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek    return true;
3474dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek  }
3484e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
3498f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  // Finally, look for the conversion specifier.
350a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek  const char *conversionPosition = I++;
35126ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek  ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
352a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek  switch (*conversionPosition) {
3538f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    default:
35426ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek      break;
355c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek    // C99: 7.19.6.1 (section 8).
35687260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case '%': k = ConversionSpecifier::PercentArg;   break;
35787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'A': k = ConversionSpecifier::AArg; break;
358a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek    case 'E': k = ConversionSpecifier::EArg; break;
35987260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'F': k = ConversionSpecifier::FArg; break;
360a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek    case 'G': k = ConversionSpecifier::GArg; break;
36187260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'X': k = ConversionSpecifier::XArg; break;
362a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek    case 'a': k = ConversionSpecifier::aArg; break;
363a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek    case 'c': k = ConversionSpecifier::IntAsCharArg; break;
36487260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'd': k = ConversionSpecifier::dArg; break;
36587260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'e': k = ConversionSpecifier::eArg; break;
36687260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'f': k = ConversionSpecifier::fArg; break;
36787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'g': k = ConversionSpecifier::gArg; break;
36887260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'i': k = ConversionSpecifier::iArg; break;
369a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek    case 'n': k = ConversionSpecifier::OutIntPtrArg; break;
37087260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'o': k = ConversionSpecifier::oArg; break;
37187260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'p': k = ConversionSpecifier::VoidPtrArg;   break;
37287260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 's': k = ConversionSpecifier::CStrArg;      break;
37387260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'u': k = ConversionSpecifier::uArg; break;
37487260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'x': k = ConversionSpecifier::xArg; break;
37587260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    // Mac OS X (unicode) specific
37687260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'C': k = ConversionSpecifier::CArg; break;
37787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case 'S': k = ConversionSpecifier::UnicodeStrArg; break;
378c7cbb9bf8e0bf8c3191ef0b782ec198c433d2a4eTed Kremenek    // Objective-C.
3794dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek    case '@': k = ConversionSpecifier::ObjCObjArg; break;
380df17f9d95ba03ba41d8d39ccb688a4eb2ee00e9aTed Kremenek    // Glibc specific.
3814dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek    case 'm': k = ConversionSpecifier::PrintErrno; break;
3828f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  }
3837f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek  ConversionSpecifier CS(conversionPosition, k);
3847f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek  FS.setConversionSpecifier(CS);
385efaff195ba1fa55b6fe0b0b2435b81451387d241Ted Kremenek  if (CS.consumesDataArgument() && !FS.usesPositionalArg())
3867f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek    FS.setArgIndex(argIndex++);
38726ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek
38826ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek  if (k == ConversionSpecifier::InvalidSpecifier) {
3897f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek    // Assume the conversion takes one argument.
3907f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek    return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg);
39126ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek  }
3928f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  return FormatSpecifierResult(Start, FS);
3938f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek}
3948f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
39574d56a168966ff015824279a24aaf566180ed97dTed Kremenekbool clang::analyze_printf::ParseFormatString(FormatStringHandler &H,
396a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek                       const char *I, const char *E) {
3977f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek
3987f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek  unsigned argIndex = 0;
3997f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek
4008f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  // Keep looking for a format specifier until we have exhausted the string.
4018f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  while (I != E) {
4027f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek    const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex);
40326ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek    // Did a fail-stop error of any kind occur when parsing the specifier?
40426ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek    // If so, don't do any more processing.
40526ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek    if (FSR.shouldStop())
4068f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek      return true;;
40726ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek    // Did we exhaust the string or encounter an error that
40826ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek    // we can recover from?
4098f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    if (!FSR.hasValue())
41026ac2e07b46bfb4d4f00752c96481c0a98c79c69Ted Kremenek      continue;
4118f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek    // We have a format specifier.  Pass it to the callback.
412a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek    if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(),
413a8d8fec7876666d90bb2a144d3b832b2d89a088aTed Kremenek                                 I - FSR.getStart()))
4144dcb18ff9d92c66c78077ac5cae4b83af37292e4Ted Kremenek      return true;
4154e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  }
4164e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  assert(I == E && "Format string not exhausted");
4178f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek  return false;
4188f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek}
4198f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted Kremenek
4208f0a1c73fd2b83afd4b1fce6f964535b51d13659Ted KremenekFormatStringHandler::~FormatStringHandler() {}
42133567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek
42233567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek//===----------------------------------------------------------------------===//
4234e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek// Methods on ArgTypeResult.
4244e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===//
4254e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4264e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenekbool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
4274e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  assert(isValid());
4284e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4294e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  if (K == UnknownTy)
4304e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    return true;
4314e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4324e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  if (K == SpecificTy) {
4334e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    argTy = C.getCanonicalType(argTy).getUnqualifiedType();
4344e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4354e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    if (T == argTy)
4364e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek      return true;
4374e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4384e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
4394e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek      switch (BT->getKind()) {
4404e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        default:
4414e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          break;
4424e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::Char_S:
4434e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::SChar:
4444e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.UnsignedCharTy;
4454e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::Char_U:
4464e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::UChar:
4474e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.SignedCharTy;
4484e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::Short:
4494e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.UnsignedShortTy;
4504e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::UShort:
4514e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.ShortTy;
4524e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::Int:
4534e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.UnsignedIntTy;
4544e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::UInt:
4554e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.IntTy;
4564e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::Long:
4574e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.UnsignedLongTy;
4584e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::ULong:
4594e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.LongTy;
4604e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::LongLong:
4614e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.UnsignedLongLongTy;
4624e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::ULongLong:
4634e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return T == C.LongLongTy;
4644e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek      }
4654e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4664e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    return false;
4674e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  }
4684e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4694e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  if (K == CStrTy) {
4704e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    const PointerType *PT = argTy->getAs<PointerType>();
4714e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    if (!PT)
4724e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek      return false;
4734e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4744e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    QualType pointeeTy = PT->getPointeeType();
4754e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4764e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
4774e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek      switch (BT->getKind()) {
4784e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::Void:
4794e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::Char_U:
4804e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::UChar:
4814e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::Char_S:
4824e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        case BuiltinType::SChar:
4834e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          return true;
4844e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek        default:
4854e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek          break;
4864e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek      }
4874e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4884e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    return false;
4894e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  }
4904e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
4914e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  if (K == WCStrTy) {
4924e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    const PointerType *PT = argTy->getAs<PointerType>();
4934e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    if (!PT)
4944e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek      return false;
4954e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
49687260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    QualType pointeeTy =
49787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek      C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
49887260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek
49987260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    return pointeeTy == C.getWCharType();
5004e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  }
5014e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
5024e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  return false;
5034e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek}
5044e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
5054e4b30ec62d78b24e6556fea2624855c193d0e3eTed KremenekQualType ArgTypeResult::getRepresentativeType(ASTContext &C) const {
5064e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  assert(isValid());
5074e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  if (K == SpecificTy)
5084e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    return T;
5094e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  if (K == CStrTy)
5104e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    return C.getPointerType(C.CharTy);
5114e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  if (K == WCStrTy)
51287260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    return C.getPointerType(C.getWCharType());
5134e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  if (K == ObjCPointerTy)
5144e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek    return C.ObjCBuiltinIdTy;
5154e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
5164e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  return QualType();
5174e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek}
5184e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
5194e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===//
5204e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek// Methods on OptionalAmount.
5214e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===//
5224e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
5234e4b30ec62d78b24e6556fea2624855c193d0e3eTed KremenekArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const {
5244e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek  return Ctx.IntTy;
5254e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek}
5264e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
5274e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek//===----------------------------------------------------------------------===//
5283bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care// Methods on ConversionSpecifier.
5293bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care//===----------------------------------------------------------------------===//
5303bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Careconst char *ConversionSpecifier::toString() const {
5313bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  switch (kind) {
5323bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case dArg: return "d";
5333bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case iArg: return "i";
5343bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case oArg: return "o";
5353bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case uArg: return "u";
5363bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case xArg: return "x";
5373bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case XArg: return "X";
5383bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case fArg: return "f";
5393bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case FArg: return "F";
5403bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case eArg: return "e";
5413bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case EArg: return "E";
5423bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case gArg: return "g";
5433bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case GArg: return "G";
5443bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case aArg: return "a";
5453bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AArg: return "A";
5463bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case IntAsCharArg:     return "c";
5473bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case CStrArg:          return "s";
5483bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case VoidPtrArg:       return "p";
5493bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case OutIntPtrArg:     return "n";
5503bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case PercentArg:       return "%";
5513bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case InvalidSpecifier: return NULL;
5523bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
5533bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // MacOS X unicode extensions.
5543bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case CArg:          return "C";
5553bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case UnicodeStrArg: return "S";
5563bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
5573bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Objective-C specific specifiers.
5583bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case ObjCObjArg: return "@";
5593bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
5603bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // GlibC specific specifiers.
5613bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case PrintErrno: return "m";
5623bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
5633bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  return NULL;
5643bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care}
5653bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
5663bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care//===----------------------------------------------------------------------===//
5673bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care// Methods on LengthModifier.
5683bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care//===----------------------------------------------------------------------===//
5693bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
5703bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Careconst char *LengthModifier::toString() const {
5713bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  switch (kind) {
5723bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AsChar:
5733bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "hh";
5743bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AsShort:
5753bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "h";
5763bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AsLong: // or AsWideChar
5773bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "l";
5783bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AsLongLong:
5793bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "ll";
5803bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AsIntMax:
5813bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "j";
5823bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AsSizeT:
5833bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "z";
5843bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AsPtrDiff:
5853bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "t";
5863bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case AsLongDouble:
5873bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "L";
5883bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case None:
5893bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return "";
5903bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
5913bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  return NULL;
5923bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care}
5933bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
5943bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care//===----------------------------------------------------------------------===//
5953bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care// Methods on OptionalAmount.
5963bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care//===----------------------------------------------------------------------===//
5973bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
5983bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Carevoid OptionalAmount::toString(llvm::raw_ostream &os) const {
5993bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  switch (hs) {
6003bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case Invalid:
6013bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case NotSpecified:
6023bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return;
6033bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case Arg:
6043bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    if (usesPositionalArg())
6053bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      os << ".*" << getPositionalArgIndex() << "$";
6063bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    else
6073bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      os << ".*";
6083bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    break;
6093bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case Constant:
6103bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    os << "." << amt;
6113bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    break;
6123bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
6133bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care}
6143bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
6153bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care//===----------------------------------------------------------------------===//
61633567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek// Methods on FormatSpecifier.
61733567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek//===----------------------------------------------------------------------===//
61833567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek
61933567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted KremenekArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const {
62033567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek  if (!CS.consumesDataArgument())
62133567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek    return ArgTypeResult::Invalid();
6224e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
62333567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek  if (CS.isIntArg())
6243bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    switch (LM.getKind()) {
6253bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsLongDouble:
62633567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        return ArgTypeResult::Invalid();
6273bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::None: return Ctx.IntTy;
6283bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsChar: return Ctx.SignedCharTy;
6293bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsShort: return Ctx.ShortTy;
6303bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsLong: return Ctx.LongTy;
6313bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsLongLong: return Ctx.LongLongTy;
6323bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsIntMax:
63333567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        // FIXME: Return unknown for now.
63433567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        return ArgTypeResult();
6353bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsSizeT: return Ctx.getSizeType();
6363bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType();
63733567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek    }
63833567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek
63933567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek  if (CS.isUIntArg())
6403bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    switch (LM.getKind()) {
6413bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsLongDouble:
64233567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        return ArgTypeResult::Invalid();
6433bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::None: return Ctx.UnsignedIntTy;
6443bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
6453bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
6463bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
6473bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy;
6483bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsIntMax:
64933567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        // FIXME: Return unknown for now.
65033567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        return ArgTypeResult();
6513bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsSizeT:
65233567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        // FIXME: How to get the corresponding unsigned
65333567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        // version of size_t?
65433567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        return ArgTypeResult();
6553bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      case LengthModifier::AsPtrDiff:
65633567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        // FIXME: How to get the corresponding unsigned
65733567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        // version of ptrdiff_t?
65833567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek        return ArgTypeResult();
65933567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek    }
6604e4b30ec62d78b24e6556fea2624855c193d0e3eTed Kremenek
661f911eba72e6d7275e5cfdb79ab23fb2aa9cc01d0Ted Kremenek  if (CS.isDoubleArg()) {
6623bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    if (LM.getKind() == LengthModifier::AsLongDouble)
663f911eba72e6d7275e5cfdb79ab23fb2aa9cc01d0Ted Kremenek      return Ctx.LongDoubleTy;
664c9a89fec60a20eb3269caa95eca048d45ab215adTed Kremenek    return Ctx.DoubleTy;
665f911eba72e6d7275e5cfdb79ab23fb2aa9cc01d0Ted Kremenek  }
6667f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek
66787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek  switch (CS.getKind()) {
66887260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case ConversionSpecifier::CStrArg:
6693bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ?
6703bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care          ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy);
67187260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case ConversionSpecifier::UnicodeStrArg:
67287260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek      // FIXME: This appears to be Mac OS X specific.
67387260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek      return ArgTypeResult::WCStrTy;
67487260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    case ConversionSpecifier::CArg:
6757f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek      return Ctx.WCharTy;
67687260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek    default:
67787260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek      break;
67887260c7eabf88eb2009ba2ba20150cd897483241Ted Kremenek  }
6797f70dc85d5055c19c8003f43a59135de211ad1b9Ted Kremenek
68033567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek  // FIXME: Handle other cases.
68140888ada6022cfd4ab2a7c07ab276639860ffc5aTed Kremenek  return ArgTypeResult();
68233567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek}
68333567d2feb3e52fac6e0b46d5b3d137fc8467fb0Ted Kremenek
6843bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Carebool FormatSpecifier::fixType(QualType QT) {
6853bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Handle strings first (char *, wchar_t *)
6863bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
6873bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    CS.setKind(ConversionSpecifier::CStrArg);
6883bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
689876e994957472eda4b40136d4e1d6e08e2be338fTom Care    // Disable irrelevant flags
690876e994957472eda4b40136d4e1d6e08e2be338fTom Care    HasAlternativeForm = 0;
691876e994957472eda4b40136d4e1d6e08e2be338fTom Care    HasLeadingZeroes = 0;
692876e994957472eda4b40136d4e1d6e08e2be338fTom Care
6933bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    // Set the long length modifier for wide characters
6943bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    if (QT->getPointeeType()->isWideCharType())
6953bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care      LM.setKind(LengthModifier::AsWideChar);
6963bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
6973bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return true;
6983bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
6993bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7003bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // We can only work with builtin types.
7013bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (!QT->isBuiltinType())
7023bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return false;
7033bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7043bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Everything else should be a base type
7053bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  const BuiltinType *BT = QT->getAs<BuiltinType>();
706876e994957472eda4b40136d4e1d6e08e2be338fTom Care
7073bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Set length modifier
7083bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  switch (BT->getKind()) {
7093bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  default:
710876e994957472eda4b40136d4e1d6e08e2be338fTom Care    // The rest of the conversions are either optional or for non-builtin types
711876e994957472eda4b40136d4e1d6e08e2be338fTom Care    LM.setKind(LengthModifier::None);
7123bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    break;
713876e994957472eda4b40136d4e1d6e08e2be338fTom Care
7143bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case BuiltinType::WChar:
7153bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case BuiltinType::Long:
7163bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case BuiltinType::ULong:
7173bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    LM.setKind(LengthModifier::AsLong);
7183bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    break;
7193bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7203bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case BuiltinType::LongLong:
7213bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case BuiltinType::ULongLong:
7223bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    LM.setKind(LengthModifier::AsLongLong);
7233bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    break;
7243bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7253bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  case BuiltinType::LongDouble:
7263bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    LM.setKind(LengthModifier::AsLongDouble);
7273bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    break;
7283bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
7293bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7303bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Set conversion specifier and disable any flags which do not apply to it.
7313bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (QT->isAnyCharacterType()) {
7323bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    CS.setKind(ConversionSpecifier::IntAsCharArg);
7333bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    Precision.setHowSpecified(OptionalAmount::NotSpecified);
7343bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    HasAlternativeForm = 0;
7353bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    HasLeadingZeroes = 0;
7363bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
7373bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
7383bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  else if (QT->isFloatingType()) {
7393bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    CS.setKind(ConversionSpecifier::fArg);
7403bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
7413bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  else if (QT->isPointerType()) {
7423bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    CS.setKind(ConversionSpecifier::VoidPtrArg);
7433bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    Precision.setHowSpecified(OptionalAmount::NotSpecified);
7443bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    HasAlternativeForm = 0;
7453bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    HasLeadingZeroes = 0;
7463bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
7473bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  else if (QT->isSignedIntegerType()) {
7483bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    CS.setKind(ConversionSpecifier::dArg);
7493bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    HasAlternativeForm = 0;
7503bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
751c8c4b4088cf0b3afeda425b25fa7c77d3873b12cDouglas Gregor  else if (QT->isUnsignedIntegerType()) {
7523bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    CS.setKind(ConversionSpecifier::uArg);
7533bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    HasAlternativeForm = 0;
7543bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
7553bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  else {
7563bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    return false;
7573bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
7583bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7593bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  return true;
7603bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care}
7613bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7623bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Carevoid FormatSpecifier::toString(llvm::raw_ostream &os) const {
7633bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Whilst some features have no defined order, we are using the order
7643bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // appearing in the C99 standard (ISO/IEC 9899:1999 (E) �7.19.6.1)
7653bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  os << "%";
7663bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7673bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Positional args
7683bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (usesPositionalArg()) {
7693bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care    os << getPositionalArgIndex() << "$";
7703bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  }
7713bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7723bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Conversion flags
7733bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (IsLeftJustified)    os << "-";
7743bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (HasPlusPrefix)      os << "+";
7753bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (HasSpacePrefix)     os << " ";
7763bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (HasAlternativeForm) os << "#";
7773bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  if (HasLeadingZeroes)   os << "0";
7783bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care
7793bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Minimum field width
7803bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  FieldWidth.toString(os);
7813bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Precision
7823bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  Precision.toString(os);
7833bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Length modifier
7843bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  os << LM.toString();
7853bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  // Conversion specifier
7863bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care  os << CS.toString();
7873bfc5f49e0e37e235bb0d33bcbcb36af9d1f84abTom Care}
788