1212795Sdim//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//
2212795Sdim//
3212795Sdim//                     The LLVM Compiler Infrastructure
4212795Sdim//
5212795Sdim// This file is distributed under the University of Illinois Open Source
6212795Sdim// License. See LICENSE.TXT for details.
7212795Sdim//
8212795Sdim//===----------------------------------------------------------------------===//
9212795Sdim//
10212795Sdim// Handling of format string in scanf and friends.  The structure of format
11212795Sdim// strings for fscanf() are described in C99 7.19.6.2.
12212795Sdim//
13212795Sdim//===----------------------------------------------------------------------===//
14212795Sdim
15212795Sdim#include "clang/Analysis/Analyses/FormatString.h"
16249423Sdim#include "FormatStringParsing.h"
17243830Sdim#include "clang/Basic/TargetInfo.h"
18212795Sdim
19239462Sdimusing clang::analyze_format_string::ArgType;
20212795Sdimusing clang::analyze_format_string::FormatStringHandler;
21212795Sdimusing clang::analyze_format_string::LengthModifier;
22212795Sdimusing clang::analyze_format_string::OptionalAmount;
23212795Sdimusing clang::analyze_format_string::ConversionSpecifier;
24212795Sdimusing clang::analyze_scanf::ScanfConversionSpecifier;
25212795Sdimusing clang::analyze_scanf::ScanfSpecifier;
26212795Sdimusing clang::UpdateOnReturn;
27234353Sdimusing namespace clang;
28212795Sdim
29212795Sdimtypedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier>
30212795Sdim        ScanfSpecifierResult;
31212795Sdim
32212795Sdimstatic bool ParseScanList(FormatStringHandler &H,
33212795Sdim                          ScanfConversionSpecifier &CS,
34212795Sdim                          const char *&Beg, const char *E) {
35212795Sdim  const char *I = Beg;
36212795Sdim  const char *start = I - 1;
37212795Sdim  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
38212795Sdim
39212795Sdim  // No more characters?
40212795Sdim  if (I == E) {
41212795Sdim    H.HandleIncompleteScanList(start, I);
42212795Sdim    return true;
43212795Sdim  }
44212795Sdim
45212795Sdim  // Special case: ']' is the first character.
46212795Sdim  if (*I == ']') {
47212795Sdim    if (++I == E) {
48212795Sdim      H.HandleIncompleteScanList(start, I - 1);
49212795Sdim      return true;
50212795Sdim    }
51212795Sdim  }
52212795Sdim
53276479Sdim  // Special case: "^]" are the first characters.
54276479Sdim  if (I + 1 != E && I[0] == '^' && I[1] == ']') {
55276479Sdim    I += 2;
56276479Sdim    if (I == E) {
57276479Sdim      H.HandleIncompleteScanList(start, I - 1);
58276479Sdim      return true;
59276479Sdim    }
60276479Sdim  }
61276479Sdim
62212795Sdim  // Look for a ']' character which denotes the end of the scan list.
63212795Sdim  while (*I != ']') {
64212795Sdim    if (++I == E) {
65212795Sdim      H.HandleIncompleteScanList(start, I - 1);
66212795Sdim      return true;
67212795Sdim    }
68212795Sdim  }
69212795Sdim
70212795Sdim  CS.setEndScanList(I);
71212795Sdim  return false;
72212795Sdim}
73212795Sdim
74212795Sdim// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.
75212795Sdim// We can possibly refactor.
76212795Sdimstatic ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
77212795Sdim                                                const char *&Beg,
78212795Sdim                                                const char *E,
79234353Sdim                                                unsigned &argIndex,
80243830Sdim                                                const LangOptions &LO,
81243830Sdim                                                const TargetInfo &Target) {
82212795Sdim
83212795Sdim  using namespace clang::analyze_scanf;
84212795Sdim  const char *I = Beg;
85276479Sdim  const char *Start = nullptr;
86212795Sdim  UpdateOnReturn <const char*> UpdateBeg(Beg, I);
87212795Sdim
88212795Sdim    // Look for a '%' character that indicates the start of a format specifier.
89212795Sdim  for ( ; I != E ; ++I) {
90212795Sdim    char c = *I;
91212795Sdim    if (c == '\0') {
92212795Sdim        // Detect spurious null characters, which are likely errors.
93212795Sdim      H.HandleNullChar(I);
94212795Sdim      return true;
95212795Sdim    }
96212795Sdim    if (c == '%') {
97212795Sdim      Start = I++;  // Record the start of the format specifier.
98212795Sdim      break;
99212795Sdim    }
100212795Sdim  }
101212795Sdim
102212795Sdim    // No format specifier found?
103212795Sdim  if (!Start)
104212795Sdim    return false;
105212795Sdim
106212795Sdim  if (I == E) {
107212795Sdim      // No more characters left?
108212795Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
109212795Sdim    return true;
110212795Sdim  }
111212795Sdim
112212795Sdim  ScanfSpecifier FS;
113212795Sdim  if (ParseArgPosition(H, FS, Start, I, E))
114212795Sdim    return true;
115212795Sdim
116212795Sdim  if (I == E) {
117212795Sdim      // No more characters left?
118212795Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
119212795Sdim    return true;
120212795Sdim  }
121212795Sdim
122212795Sdim  // Look for '*' flag if it is present.
123212795Sdim  if (*I == '*') {
124212795Sdim    FS.setSuppressAssignment(I);
125212795Sdim    if (++I == E) {
126212795Sdim      H.HandleIncompleteSpecifier(Start, E - Start);
127212795Sdim      return true;
128212795Sdim    }
129212795Sdim  }
130212795Sdim
131212795Sdim  // Look for the field width (if any).  Unlike printf, this is either
132212795Sdim  // a fixed integer or isn't present.
133212795Sdim  const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);
134212795Sdim  if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {
135212795Sdim    assert(Amt.getHowSpecified() == OptionalAmount::Constant);
136212795Sdim    FS.setFieldWidth(Amt);
137212795Sdim
138212795Sdim    if (I == E) {
139212795Sdim      // No more characters left?
140212795Sdim      H.HandleIncompleteSpecifier(Start, E - Start);
141212795Sdim      return true;
142212795Sdim    }
143212795Sdim  }
144212795Sdim
145212795Sdim  // Look for the length modifier.
146234353Sdim  if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {
147212795Sdim      // No more characters left?
148212795Sdim    H.HandleIncompleteSpecifier(Start, E - Start);
149212795Sdim    return true;
150212795Sdim  }
151212795Sdim
152212795Sdim  // Detect spurious null characters, which are likely errors.
153212795Sdim  if (*I == '\0') {
154212795Sdim    H.HandleNullChar(I);
155212795Sdim    return true;
156212795Sdim  }
157212795Sdim
158212795Sdim  // Finally, look for the conversion specifier.
159212795Sdim  const char *conversionPosition = I++;
160212795Sdim  ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;
161212795Sdim  switch (*conversionPosition) {
162212795Sdim    default:
163212795Sdim      break;
164212795Sdim    case '%': k = ConversionSpecifier::PercentArg;   break;
165212795Sdim    case 'A': k = ConversionSpecifier::AArg; break;
166212795Sdim    case 'E': k = ConversionSpecifier::EArg; break;
167212795Sdim    case 'F': k = ConversionSpecifier::FArg; break;
168212795Sdim    case 'G': k = ConversionSpecifier::GArg; break;
169212795Sdim    case 'X': k = ConversionSpecifier::XArg; break;
170212795Sdim    case 'a': k = ConversionSpecifier::aArg; break;
171212795Sdim    case 'd': k = ConversionSpecifier::dArg; break;
172212795Sdim    case 'e': k = ConversionSpecifier::eArg; break;
173212795Sdim    case 'f': k = ConversionSpecifier::fArg; break;
174212795Sdim    case 'g': k = ConversionSpecifier::gArg; break;
175212795Sdim    case 'i': k = ConversionSpecifier::iArg; break;
176212795Sdim    case 'n': k = ConversionSpecifier::nArg; break;
177212795Sdim    case 'c': k = ConversionSpecifier::cArg; break;
178212795Sdim    case 'C': k = ConversionSpecifier::CArg; break;
179212795Sdim    case 'S': k = ConversionSpecifier::SArg; break;
180212795Sdim    case '[': k = ConversionSpecifier::ScanListArg; break;
181212795Sdim    case 'u': k = ConversionSpecifier::uArg; break;
182212795Sdim    case 'x': k = ConversionSpecifier::xArg; break;
183212795Sdim    case 'o': k = ConversionSpecifier::oArg; break;
184212795Sdim    case 's': k = ConversionSpecifier::sArg; break;
185212795Sdim    case 'p': k = ConversionSpecifier::pArg; break;
186243830Sdim    // Apple extensions
187243830Sdim      // Apple-specific
188243830Sdim    case 'D':
189243830Sdim      if (Target.getTriple().isOSDarwin())
190243830Sdim        k = ConversionSpecifier::DArg;
191243830Sdim      break;
192243830Sdim    case 'O':
193243830Sdim      if (Target.getTriple().isOSDarwin())
194243830Sdim        k = ConversionSpecifier::OArg;
195243830Sdim      break;
196243830Sdim    case 'U':
197243830Sdim      if (Target.getTriple().isOSDarwin())
198243830Sdim        k = ConversionSpecifier::UArg;
199243830Sdim      break;
200212795Sdim  }
201212795Sdim  ScanfConversionSpecifier CS(conversionPosition, k);
202212795Sdim  if (k == ScanfConversionSpecifier::ScanListArg) {
203234353Sdim    if (ParseScanList(H, CS, I, E))
204212795Sdim      return true;
205212795Sdim  }
206212795Sdim  FS.setConversionSpecifier(CS);
207212795Sdim  if (CS.consumesDataArgument() && !FS.getSuppressAssignment()
208212795Sdim      && !FS.usesPositionalArg())
209212795Sdim    FS.setArgIndex(argIndex++);
210212795Sdim
211212795Sdim  // FIXME: '%' and '*' doesn't make sense.  Issue a warning.
212212795Sdim  // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.
213212795Sdim
214212795Sdim  if (k == ScanfConversionSpecifier::InvalidSpecifier) {
215212795Sdim    // Assume the conversion takes one argument.
216212795Sdim    return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, I - Beg);
217212795Sdim  }
218212795Sdim  return ScanfSpecifierResult(Start, FS);
219212795Sdim}
220234353Sdim
221239462SdimArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
222234353Sdim  const ScanfConversionSpecifier &CS = getConversionSpecifier();
223234353Sdim
224234353Sdim  if (!CS.consumesDataArgument())
225239462Sdim    return ArgType::Invalid();
226234353Sdim
227234353Sdim  switch(CS.getKind()) {
228234353Sdim    // Signed int.
229234353Sdim    case ConversionSpecifier::dArg:
230243830Sdim    case ConversionSpecifier::DArg:
231234353Sdim    case ConversionSpecifier::iArg:
232234353Sdim      switch (LM.getKind()) {
233239462Sdim        case LengthModifier::None:
234239462Sdim          return ArgType::PtrTo(Ctx.IntTy);
235234353Sdim        case LengthModifier::AsChar:
236239462Sdim          return ArgType::PtrTo(ArgType::AnyCharTy);
237239462Sdim        case LengthModifier::AsShort:
238239462Sdim          return ArgType::PtrTo(Ctx.ShortTy);
239239462Sdim        case LengthModifier::AsLong:
240239462Sdim          return ArgType::PtrTo(Ctx.LongTy);
241234353Sdim        case LengthModifier::AsLongLong:
242234353Sdim        case LengthModifier::AsQuad:
243239462Sdim          return ArgType::PtrTo(Ctx.LongLongTy);
244261991Sdim        case LengthModifier::AsInt64:
245261991Sdim          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
246234353Sdim        case LengthModifier::AsIntMax:
247239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
248234353Sdim        case LengthModifier::AsSizeT:
249234353Sdim          // FIXME: ssize_t.
250239462Sdim          return ArgType();
251234353Sdim        case LengthModifier::AsPtrDiff:
252239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
253234353Sdim        case LengthModifier::AsLongDouble:
254234353Sdim          // GNU extension.
255239462Sdim          return ArgType::PtrTo(Ctx.LongLongTy);
256239462Sdim        case LengthModifier::AsAllocate:
257239462Sdim        case LengthModifier::AsMAllocate:
258261991Sdim        case LengthModifier::AsInt32:
259261991Sdim        case LengthModifier::AsInt3264:
260280031Sdim        case LengthModifier::AsWide:
261239462Sdim          return ArgType::Invalid();
262234353Sdim      }
263234353Sdim
264234353Sdim    // Unsigned int.
265234353Sdim    case ConversionSpecifier::oArg:
266243830Sdim    case ConversionSpecifier::OArg:
267234353Sdim    case ConversionSpecifier::uArg:
268243830Sdim    case ConversionSpecifier::UArg:
269234353Sdim    case ConversionSpecifier::xArg:
270234353Sdim    case ConversionSpecifier::XArg:
271234353Sdim      switch (LM.getKind()) {
272239462Sdim        case LengthModifier::None:
273239462Sdim          return ArgType::PtrTo(Ctx.UnsignedIntTy);
274239462Sdim        case LengthModifier::AsChar:
275239462Sdim          return ArgType::PtrTo(Ctx.UnsignedCharTy);
276239462Sdim        case LengthModifier::AsShort:
277239462Sdim          return ArgType::PtrTo(Ctx.UnsignedShortTy);
278239462Sdim        case LengthModifier::AsLong:
279239462Sdim          return ArgType::PtrTo(Ctx.UnsignedLongTy);
280234353Sdim        case LengthModifier::AsLongLong:
281234353Sdim        case LengthModifier::AsQuad:
282239462Sdim          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
283261991Sdim        case LengthModifier::AsInt64:
284261991Sdim          return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));
285234353Sdim        case LengthModifier::AsIntMax:
286239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));
287234353Sdim        case LengthModifier::AsSizeT:
288239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));
289234353Sdim        case LengthModifier::AsPtrDiff:
290234353Sdim          // FIXME: Unsigned version of ptrdiff_t?
291239462Sdim          return ArgType();
292234353Sdim        case LengthModifier::AsLongDouble:
293234353Sdim          // GNU extension.
294239462Sdim          return ArgType::PtrTo(Ctx.UnsignedLongLongTy);
295239462Sdim        case LengthModifier::AsAllocate:
296239462Sdim        case LengthModifier::AsMAllocate:
297261991Sdim        case LengthModifier::AsInt32:
298261991Sdim        case LengthModifier::AsInt3264:
299280031Sdim        case LengthModifier::AsWide:
300239462Sdim          return ArgType::Invalid();
301234353Sdim      }
302234353Sdim
303234353Sdim    // Float.
304234353Sdim    case ConversionSpecifier::aArg:
305234353Sdim    case ConversionSpecifier::AArg:
306234353Sdim    case ConversionSpecifier::eArg:
307234353Sdim    case ConversionSpecifier::EArg:
308234353Sdim    case ConversionSpecifier::fArg:
309234353Sdim    case ConversionSpecifier::FArg:
310234353Sdim    case ConversionSpecifier::gArg:
311234353Sdim    case ConversionSpecifier::GArg:
312234353Sdim      switch (LM.getKind()) {
313239462Sdim        case LengthModifier::None:
314239462Sdim          return ArgType::PtrTo(Ctx.FloatTy);
315239462Sdim        case LengthModifier::AsLong:
316239462Sdim          return ArgType::PtrTo(Ctx.DoubleTy);
317234353Sdim        case LengthModifier::AsLongDouble:
318239462Sdim          return ArgType::PtrTo(Ctx.LongDoubleTy);
319234353Sdim        default:
320239462Sdim          return ArgType::Invalid();
321234353Sdim      }
322234353Sdim
323234353Sdim    // Char, string and scanlist.
324234353Sdim    case ConversionSpecifier::cArg:
325234353Sdim    case ConversionSpecifier::sArg:
326234353Sdim    case ConversionSpecifier::ScanListArg:
327234353Sdim      switch (LM.getKind()) {
328239462Sdim        case LengthModifier::None:
329239462Sdim          return ArgType::PtrTo(ArgType::AnyCharTy);
330234353Sdim        case LengthModifier::AsLong:
331280031Sdim        case LengthModifier::AsWide:
332261991Sdim          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
333234353Sdim        case LengthModifier::AsAllocate:
334234353Sdim        case LengthModifier::AsMAllocate:
335239462Sdim          return ArgType::PtrTo(ArgType::CStrTy);
336280031Sdim        case LengthModifier::AsShort:
337280031Sdim          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
338280031Sdim            return ArgType::PtrTo(ArgType::AnyCharTy);
339234353Sdim        default:
340239462Sdim          return ArgType::Invalid();
341234353Sdim      }
342234353Sdim    case ConversionSpecifier::CArg:
343234353Sdim    case ConversionSpecifier::SArg:
344234353Sdim      // FIXME: Mac OS X specific?
345234353Sdim      switch (LM.getKind()) {
346234353Sdim        case LengthModifier::None:
347280031Sdim        case LengthModifier::AsWide:
348261991Sdim          return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));
349234353Sdim        case LengthModifier::AsAllocate:
350234353Sdim        case LengthModifier::AsMAllocate:
351239462Sdim          return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));
352280031Sdim        case LengthModifier::AsShort:
353280031Sdim          if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
354280031Sdim            return ArgType::PtrTo(ArgType::AnyCharTy);
355234353Sdim        default:
356239462Sdim          return ArgType::Invalid();
357234353Sdim      }
358234353Sdim
359234353Sdim    // Pointer.
360234353Sdim    case ConversionSpecifier::pArg:
361239462Sdim      return ArgType::PtrTo(ArgType::CPointerTy);
362234353Sdim
363239462Sdim    // Write-back.
364239462Sdim    case ConversionSpecifier::nArg:
365239462Sdim      switch (LM.getKind()) {
366239462Sdim        case LengthModifier::None:
367239462Sdim          return ArgType::PtrTo(Ctx.IntTy);
368239462Sdim        case LengthModifier::AsChar:
369239462Sdim          return ArgType::PtrTo(Ctx.SignedCharTy);
370239462Sdim        case LengthModifier::AsShort:
371239462Sdim          return ArgType::PtrTo(Ctx.ShortTy);
372239462Sdim        case LengthModifier::AsLong:
373239462Sdim          return ArgType::PtrTo(Ctx.LongTy);
374239462Sdim        case LengthModifier::AsLongLong:
375239462Sdim        case LengthModifier::AsQuad:
376239462Sdim          return ArgType::PtrTo(Ctx.LongLongTy);
377261991Sdim        case LengthModifier::AsInt64:
378261991Sdim          return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));
379239462Sdim        case LengthModifier::AsIntMax:
380239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
381239462Sdim        case LengthModifier::AsSizeT:
382239462Sdim          return ArgType(); // FIXME: ssize_t
383239462Sdim        case LengthModifier::AsPtrDiff:
384239462Sdim          return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
385239462Sdim        case LengthModifier::AsLongDouble:
386239462Sdim          return ArgType(); // FIXME: Is this a known extension?
387239462Sdim        case LengthModifier::AsAllocate:
388239462Sdim        case LengthModifier::AsMAllocate:
389261991Sdim        case LengthModifier::AsInt32:
390261991Sdim        case LengthModifier::AsInt3264:
391280031Sdim        case LengthModifier::AsWide:
392239462Sdim          return ArgType::Invalid();
393239462Sdim        }
394239462Sdim
395234353Sdim    default:
396234353Sdim      break;
397234353Sdim  }
398234353Sdim
399239462Sdim  return ArgType();
400234353Sdim}
401234353Sdim
402276479Sdimbool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
403276479Sdim                             const LangOptions &LangOpt,
404234353Sdim                             ASTContext &Ctx) {
405234353Sdim
406239462Sdim  // %n is different from other conversion specifiers; don't try to fix it.
407239462Sdim  if (CS.getKind() == ConversionSpecifier::nArg)
408239462Sdim    return false;
409239462Sdim
410276479Sdim  if (!QT->isPointerType())
411276479Sdim    return false;
412276479Sdim
413234353Sdim  QualType PT = QT->getPointeeType();
414239462Sdim
415239462Sdim  // If it's an enum, get its underlying type.
416276479Sdim  if (const EnumType *ETy = PT->getAs<EnumType>())
417276479Sdim    PT = ETy->getDecl()->getIntegerType();
418276479Sdim
419234353Sdim  const BuiltinType *BT = PT->getAs<BuiltinType>();
420234353Sdim  if (!BT)
421234353Sdim    return false;
422234353Sdim
423234353Sdim  // Pointer to a character.
424234353Sdim  if (PT->isAnyCharacterType()) {
425234353Sdim    CS.setKind(ConversionSpecifier::sArg);
426234353Sdim    if (PT->isWideCharType())
427234353Sdim      LM.setKind(LengthModifier::AsWideChar);
428234353Sdim    else
429234353Sdim      LM.setKind(LengthModifier::None);
430276479Sdim
431276479Sdim    // If we know the target array length, we can use it as a field width.
432276479Sdim    if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {
433276479Sdim      if (CAT->getSizeModifier() == ArrayType::Normal)
434276479Sdim        FieldWidth = OptionalAmount(OptionalAmount::Constant,
435276479Sdim                                    CAT->getSize().getZExtValue() - 1,
436276479Sdim                                    "", 0, false);
437276479Sdim
438276479Sdim    }
439234353Sdim    return true;
440234353Sdim  }
441234353Sdim
442234353Sdim  // Figure out the length modifier.
443234353Sdim  switch (BT->getKind()) {
444234353Sdim    // no modifier
445234353Sdim    case BuiltinType::UInt:
446234353Sdim    case BuiltinType::Int:
447234353Sdim    case BuiltinType::Float:
448234353Sdim      LM.setKind(LengthModifier::None);
449234353Sdim      break;
450234353Sdim
451234353Sdim    // hh
452234353Sdim    case BuiltinType::Char_U:
453234353Sdim    case BuiltinType::UChar:
454234353Sdim    case BuiltinType::Char_S:
455234353Sdim    case BuiltinType::SChar:
456234353Sdim      LM.setKind(LengthModifier::AsChar);
457234353Sdim      break;
458234353Sdim
459234353Sdim    // h
460234353Sdim    case BuiltinType::Short:
461234353Sdim    case BuiltinType::UShort:
462234353Sdim      LM.setKind(LengthModifier::AsShort);
463234353Sdim      break;
464234353Sdim
465234353Sdim    // l
466234353Sdim    case BuiltinType::Long:
467234353Sdim    case BuiltinType::ULong:
468234353Sdim    case BuiltinType::Double:
469234353Sdim      LM.setKind(LengthModifier::AsLong);
470234353Sdim      break;
471234353Sdim
472234353Sdim    // ll
473234353Sdim    case BuiltinType::LongLong:
474234353Sdim    case BuiltinType::ULongLong:
475234353Sdim      LM.setKind(LengthModifier::AsLongLong);
476234353Sdim      break;
477234353Sdim
478234353Sdim    // L
479234353Sdim    case BuiltinType::LongDouble:
480234353Sdim      LM.setKind(LengthModifier::AsLongDouble);
481234353Sdim      break;
482234353Sdim
483234353Sdim    // Don't know.
484234353Sdim    default:
485234353Sdim      return false;
486234353Sdim  }
487234353Sdim
488234353Sdim  // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
489249423Sdim  if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
490239462Sdim    namedTypeToLengthModifier(PT, LM);
491234353Sdim
492234353Sdim  // If fixing the length modifier was enough, we are done.
493243830Sdim  if (hasValidLengthModifier(Ctx.getTargetInfo())) {
494243830Sdim    const analyze_scanf::ArgType &AT = getArgType(Ctx);
495243830Sdim    if (AT.isValid() && AT.matchesType(Ctx, QT))
496243830Sdim      return true;
497243830Sdim  }
498234353Sdim
499234353Sdim  // Figure out the conversion specifier.
500234353Sdim  if (PT->isRealFloatingType())
501234353Sdim    CS.setKind(ConversionSpecifier::fArg);
502234353Sdim  else if (PT->isSignedIntegerType())
503234353Sdim    CS.setKind(ConversionSpecifier::dArg);
504234353Sdim  else if (PT->isUnsignedIntegerType())
505234353Sdim    CS.setKind(ConversionSpecifier::uArg);
506234353Sdim  else
507234353Sdim    llvm_unreachable("Unexpected type");
508234353Sdim
509234353Sdim  return true;
510234353Sdim}
511234353Sdim
512234353Sdimvoid ScanfSpecifier::toString(raw_ostream &os) const {
513234353Sdim  os << "%";
514234353Sdim
515234353Sdim  if (usesPositionalArg())
516234353Sdim    os << getPositionalArgIndex() << "$";
517234353Sdim  if (SuppressAssignment)
518234353Sdim    os << "*";
519234353Sdim
520234353Sdim  FieldWidth.toString(os);
521234353Sdim  os << LM.toString();
522234353Sdim  os << CS.toString();
523234353Sdim}
524234353Sdim
525212795Sdimbool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,
526212795Sdim                                                    const char *I,
527234353Sdim                                                    const char *E,
528243830Sdim                                                    const LangOptions &LO,
529243830Sdim                                                    const TargetInfo &Target) {
530212795Sdim
531212795Sdim  unsigned argIndex = 0;
532212795Sdim
533212795Sdim  // Keep looking for a format specifier until we have exhausted the string.
534212795Sdim  while (I != E) {
535234353Sdim    const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,
536243830Sdim                                                          LO, Target);
537212795Sdim    // Did a fail-stop error of any kind occur when parsing the specifier?
538212795Sdim    // If so, don't do any more processing.
539212795Sdim    if (FSR.shouldStop())
540243830Sdim      return true;
541212795Sdim      // Did we exhaust the string or encounter an error that
542212795Sdim      // we can recover from?
543212795Sdim    if (!FSR.hasValue())
544212795Sdim      continue;
545212795Sdim      // We have a format specifier.  Pass it to the callback.
546212795Sdim    if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),
547212795Sdim                                I - FSR.getStart())) {
548212795Sdim      return true;
549212795Sdim    }
550212795Sdim  }
551212795Sdim  assert(I == E && "Format string not exhausted");
552212795Sdim  return false;
553212795Sdim}
554