1314fbfa1STim Northover //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
2314fbfa1STim Northover //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6314fbfa1STim Northover //
7314fbfa1STim Northover //===----------------------------------------------------------------------===//
8314fbfa1STim Northover //
9314fbfa1STim Northover // Handling of format string in printf and friends.  The structure of format
10314fbfa1STim Northover // strings for fprintf() are described in C99 7.19.6.1.
11314fbfa1STim Northover //
12314fbfa1STim Northover //===----------------------------------------------------------------------===//
13314fbfa1STim Northover 
147314aea5SDaniel Kiss #include "FormatStringParsing.h"
15314fbfa1STim Northover #include "clang/AST/FormatString.h"
16314fbfa1STim Northover #include "clang/AST/OSLog.h"
17314fbfa1STim Northover #include "clang/Basic/TargetInfo.h"
187314aea5SDaniel Kiss #include "llvm/Support/Regex.h"
19314fbfa1STim Northover 
20314fbfa1STim Northover using clang::analyze_format_string::ArgType;
21314fbfa1STim Northover using clang::analyze_format_string::FormatStringHandler;
22314fbfa1STim Northover using clang::analyze_format_string::LengthModifier;
23314fbfa1STim Northover using clang::analyze_format_string::OptionalAmount;
24314fbfa1STim Northover using clang::analyze_format_string::ConversionSpecifier;
25314fbfa1STim Northover using clang::analyze_printf::PrintfSpecifier;
26314fbfa1STim Northover 
27314fbfa1STim Northover using namespace clang;
28314fbfa1STim Northover 
29314fbfa1STim Northover typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
30314fbfa1STim Northover         PrintfSpecifierResult;
31314fbfa1STim Northover 
32314fbfa1STim Northover //===----------------------------------------------------------------------===//
33314fbfa1STim Northover // Methods for parsing format strings.
34314fbfa1STim Northover //===----------------------------------------------------------------------===//
35314fbfa1STim Northover 
36314fbfa1STim Northover using analyze_format_string::ParseNonPositionAmount;
37314fbfa1STim Northover 
ParsePrecision(FormatStringHandler & H,PrintfSpecifier & FS,const char * Start,const char * & Beg,const char * E,unsigned * argIndex)38314fbfa1STim Northover static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
39314fbfa1STim Northover                            const char *Start, const char *&Beg, const char *E,
40314fbfa1STim Northover                            unsigned *argIndex) {
41314fbfa1STim Northover   if (argIndex) {
42314fbfa1STim Northover     FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
43314fbfa1STim Northover   } else {
44314fbfa1STim Northover     const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
45314fbfa1STim Northover                                            analyze_format_string::PrecisionPos);
46314fbfa1STim Northover     if (Amt.isInvalid())
47314fbfa1STim Northover       return true;
48314fbfa1STim Northover     FS.setPrecision(Amt);
49314fbfa1STim Northover   }
50314fbfa1STim Northover   return false;
51314fbfa1STim Northover }
52314fbfa1STim Northover 
ParseObjCFlags(FormatStringHandler & H,PrintfSpecifier & FS,const char * FlagBeg,const char * E,bool Warn)53314fbfa1STim Northover static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
54314fbfa1STim Northover                            const char *FlagBeg, const char *E, bool Warn) {
55314fbfa1STim Northover    StringRef Flag(FlagBeg, E - FlagBeg);
56314fbfa1STim Northover    // Currently there is only one flag.
57314fbfa1STim Northover    if (Flag == "tt") {
58314fbfa1STim Northover      FS.setHasObjCTechnicalTerm(FlagBeg);
59314fbfa1STim Northover      return false;
60314fbfa1STim Northover    }
61314fbfa1STim Northover    // Handle either the case of no flag or an invalid flag.
62314fbfa1STim Northover    if (Warn) {
63314fbfa1STim Northover      if (Flag == "")
64314fbfa1STim Northover        H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg);
65314fbfa1STim Northover      else
66314fbfa1STim Northover        H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg);
67314fbfa1STim Northover    }
68314fbfa1STim Northover    return true;
69314fbfa1STim Northover }
70314fbfa1STim Northover 
ParsePrintfSpecifier(FormatStringHandler & H,const char * & Beg,const char * E,unsigned & argIndex,const LangOptions & LO,const TargetInfo & Target,bool Warn,bool isFreeBSDKPrintf)71314fbfa1STim Northover static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
72314fbfa1STim Northover                                                   const char *&Beg,
73314fbfa1STim Northover                                                   const char *E,
74314fbfa1STim Northover                                                   unsigned &argIndex,
75314fbfa1STim Northover                                                   const LangOptions &LO,
76314fbfa1STim Northover                                                   const TargetInfo &Target,
77314fbfa1STim Northover                                                   bool Warn,
78314fbfa1STim Northover                                                   bool isFreeBSDKPrintf) {
79314fbfa1STim Northover 
80314fbfa1STim Northover   using namespace clang::analyze_format_string;
81314fbfa1STim Northover   using namespace clang::analyze_printf;
82314fbfa1STim Northover 
83314fbfa1STim Northover   const char *I = Beg;
84314fbfa1STim Northover   const char *Start = nullptr;
85314fbfa1STim Northover   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
86314fbfa1STim Northover 
87314fbfa1STim Northover   // Look for a '%' character that indicates the start of a format specifier.
88314fbfa1STim Northover   for ( ; I != E ; ++I) {
89314fbfa1STim Northover     char c = *I;
90314fbfa1STim Northover     if (c == '\0') {
91314fbfa1STim Northover       // Detect spurious null characters, which are likely errors.
92314fbfa1STim Northover       H.HandleNullChar(I);
93314fbfa1STim Northover       return true;
94314fbfa1STim Northover     }
95314fbfa1STim Northover     if (c == '%') {
96314fbfa1STim Northover       Start = I++;  // Record the start of the format specifier.
97314fbfa1STim Northover       break;
98314fbfa1STim Northover     }
99314fbfa1STim Northover   }
100314fbfa1STim Northover 
101314fbfa1STim Northover   // No format specifier found?
102314fbfa1STim Northover   if (!Start)
103314fbfa1STim Northover     return false;
104314fbfa1STim Northover 
105314fbfa1STim Northover   if (I == E) {
106314fbfa1STim Northover     // No more characters left?
107314fbfa1STim Northover     if (Warn)
108314fbfa1STim Northover       H.HandleIncompleteSpecifier(Start, E - Start);
109314fbfa1STim Northover     return true;
110314fbfa1STim Northover   }
111314fbfa1STim Northover 
112314fbfa1STim Northover   PrintfSpecifier FS;
113314fbfa1STim Northover   if (ParseArgPosition(H, FS, Start, I, E))
114314fbfa1STim Northover     return true;
115314fbfa1STim Northover 
116314fbfa1STim Northover   if (I == E) {
117314fbfa1STim Northover     // No more characters left?
118314fbfa1STim Northover     if (Warn)
119314fbfa1STim Northover       H.HandleIncompleteSpecifier(Start, E - Start);
120314fbfa1STim Northover     return true;
121314fbfa1STim Northover   }
122314fbfa1STim Northover 
123314fbfa1STim Northover   if (*I == '{') {
124314fbfa1STim Northover     ++I;
125314fbfa1STim Northover     unsigned char PrivacyFlags = 0;
126314fbfa1STim Northover     StringRef MatchedStr;
127314fbfa1STim Northover 
128314fbfa1STim Northover     do {
129314fbfa1STim Northover       StringRef Str(I, E - I);
130d572cf49SAkira Hatanaka       std::string Match = "^[[:space:]]*"
131d572cf49SAkira Hatanaka                           "(private|public|sensitive|mask\\.[^[:space:],}]*)"
132fb1e4465SAkira Hatanaka                           "[[:space:]]*(,|})";
133314fbfa1STim Northover       llvm::Regex R(Match);
134314fbfa1STim Northover       SmallVector<StringRef, 2> Matches;
135314fbfa1STim Northover 
136314fbfa1STim Northover       if (R.match(Str, &Matches)) {
137314fbfa1STim Northover         MatchedStr = Matches[1];
138314fbfa1STim Northover         I += Matches[0].size();
139314fbfa1STim Northover 
140314fbfa1STim Northover         // Set the privacy flag if the privacy annotation in the
141314fbfa1STim Northover         // comma-delimited segment is at least as strict as the privacy
142314fbfa1STim Northover         // annotations in previous comma-delimited segments.
143d572cf49SAkira Hatanaka         if (MatchedStr.startswith("mask")) {
144d572cf49SAkira Hatanaka           StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
145d572cf49SAkira Hatanaka           unsigned Size = MaskType.size();
146d572cf49SAkira Hatanaka           if (Warn && (Size == 0 || Size > 8))
147d572cf49SAkira Hatanaka             H.handleInvalidMaskType(MaskType);
148d572cf49SAkira Hatanaka           FS.setMaskType(MaskType);
149d572cf49SAkira Hatanaka         } else if (MatchedStr.equals("sensitive"))
150fb1e4465SAkira Hatanaka           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;
151fb1e4465SAkira Hatanaka         else if (PrivacyFlags !=
152fb1e4465SAkira Hatanaka                  clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
153fb1e4465SAkira Hatanaka                  MatchedStr.equals("private"))
154314fbfa1STim Northover           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
155314fbfa1STim Northover         else if (PrivacyFlags == 0 && MatchedStr.equals("public"))
156314fbfa1STim Northover           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
157314fbfa1STim Northover       } else {
158314fbfa1STim Northover         size_t CommaOrBracePos =
159314fbfa1STim Northover             Str.find_if([](char c) { return c == ',' || c == '}'; });
160314fbfa1STim Northover 
161314fbfa1STim Northover         if (CommaOrBracePos == StringRef::npos) {
162314fbfa1STim Northover           // Neither a comma nor the closing brace was found.
163314fbfa1STim Northover           if (Warn)
164314fbfa1STim Northover             H.HandleIncompleteSpecifier(Start, E - Start);
165314fbfa1STim Northover           return true;
166314fbfa1STim Northover         }
167314fbfa1STim Northover 
168314fbfa1STim Northover         I += CommaOrBracePos + 1;
169314fbfa1STim Northover       }
170314fbfa1STim Northover       // Continue until the closing brace is found.
171314fbfa1STim Northover     } while (*(I - 1) == ',');
172314fbfa1STim Northover 
173314fbfa1STim Northover     // Set the privacy flag.
174314fbfa1STim Northover     switch (PrivacyFlags) {
175314fbfa1STim Northover     case 0:
176314fbfa1STim Northover       break;
177314fbfa1STim Northover     case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
178314fbfa1STim Northover       FS.setIsPrivate(MatchedStr.data());
179314fbfa1STim Northover       break;
180314fbfa1STim Northover     case clang::analyze_os_log::OSLogBufferItem::IsPublic:
181314fbfa1STim Northover       FS.setIsPublic(MatchedStr.data());
182314fbfa1STim Northover       break;
183fb1e4465SAkira Hatanaka     case clang::analyze_os_log::OSLogBufferItem::IsSensitive:
184fb1e4465SAkira Hatanaka       FS.setIsSensitive(MatchedStr.data());
185fb1e4465SAkira Hatanaka       break;
186314fbfa1STim Northover     default:
187314fbfa1STim Northover       llvm_unreachable("Unexpected privacy flag value");
188314fbfa1STim Northover     }
189314fbfa1STim Northover   }
190314fbfa1STim Northover 
191314fbfa1STim Northover   // Look for flags (if any).
192314fbfa1STim Northover   bool hasMore = true;
193314fbfa1STim Northover   for ( ; I != E; ++I) {
194314fbfa1STim Northover     switch (*I) {
195314fbfa1STim Northover       default: hasMore = false; break;
196314fbfa1STim Northover       case '\'':
197314fbfa1STim Northover         // FIXME: POSIX specific.  Always accept?
198314fbfa1STim Northover         FS.setHasThousandsGrouping(I);
199314fbfa1STim Northover         break;
200314fbfa1STim Northover       case '-': FS.setIsLeftJustified(I); break;
201314fbfa1STim Northover       case '+': FS.setHasPlusPrefix(I); break;
202314fbfa1STim Northover       case ' ': FS.setHasSpacePrefix(I); break;
203314fbfa1STim Northover       case '#': FS.setHasAlternativeForm(I); break;
204314fbfa1STim Northover       case '0': FS.setHasLeadingZeros(I); break;
205314fbfa1STim Northover     }
206314fbfa1STim Northover     if (!hasMore)
207314fbfa1STim Northover       break;
208314fbfa1STim Northover   }
209314fbfa1STim Northover 
210314fbfa1STim Northover   if (I == E) {
211314fbfa1STim Northover     // No more characters left?
212314fbfa1STim Northover     if (Warn)
213314fbfa1STim Northover       H.HandleIncompleteSpecifier(Start, E - Start);
214314fbfa1STim Northover     return true;
215314fbfa1STim Northover   }
216314fbfa1STim Northover 
217314fbfa1STim Northover   // Look for the field width (if any).
218314fbfa1STim Northover   if (ParseFieldWidth(H, FS, Start, I, E,
219314fbfa1STim Northover                       FS.usesPositionalArg() ? nullptr : &argIndex))
220314fbfa1STim Northover     return true;
221314fbfa1STim Northover 
222314fbfa1STim Northover   if (I == E) {
223314fbfa1STim Northover     // No more characters left?
224314fbfa1STim Northover     if (Warn)
225314fbfa1STim Northover       H.HandleIncompleteSpecifier(Start, E - Start);
226314fbfa1STim Northover     return true;
227314fbfa1STim Northover   }
228314fbfa1STim Northover 
229314fbfa1STim Northover   // Look for the precision (if any).
230314fbfa1STim Northover   if (*I == '.') {
231314fbfa1STim Northover     ++I;
232314fbfa1STim Northover     if (I == E) {
233314fbfa1STim Northover       if (Warn)
234314fbfa1STim Northover         H.HandleIncompleteSpecifier(Start, E - Start);
235314fbfa1STim Northover       return true;
236314fbfa1STim Northover     }
237314fbfa1STim Northover 
238314fbfa1STim Northover     if (ParsePrecision(H, FS, Start, I, E,
239314fbfa1STim Northover                        FS.usesPositionalArg() ? nullptr : &argIndex))
240314fbfa1STim Northover       return true;
241314fbfa1STim Northover 
242314fbfa1STim Northover     if (I == E) {
243314fbfa1STim Northover       // No more characters left?
244314fbfa1STim Northover       if (Warn)
245314fbfa1STim Northover         H.HandleIncompleteSpecifier(Start, E - Start);
246314fbfa1STim Northover       return true;
247314fbfa1STim Northover     }
248314fbfa1STim Northover   }
249314fbfa1STim Northover 
2500ff50d49SMatt Arsenault   if (ParseVectorModifier(H, FS, I, E, LO))
2510ff50d49SMatt Arsenault     return true;
2520ff50d49SMatt Arsenault 
253314fbfa1STim Northover   // Look for the length modifier.
254314fbfa1STim Northover   if (ParseLengthModifier(FS, I, E, LO) && I == E) {
255314fbfa1STim Northover     // No more characters left?
256314fbfa1STim Northover     if (Warn)
257314fbfa1STim Northover       H.HandleIncompleteSpecifier(Start, E - Start);
258314fbfa1STim Northover     return true;
259314fbfa1STim Northover   }
260314fbfa1STim Northover 
261314fbfa1STim Northover   // Look for the Objective-C modifier flags, if any.
262314fbfa1STim Northover   // We parse these here, even if they don't apply to
263314fbfa1STim Northover   // the conversion specifier, and then emit an error
264314fbfa1STim Northover   // later if the conversion specifier isn't '@'.  This
265314fbfa1STim Northover   // enables better recovery, and we don't know if
266314fbfa1STim Northover   // these flags are applicable until later.
267314fbfa1STim Northover   const char *ObjCModifierFlagsStart = nullptr,
268314fbfa1STim Northover              *ObjCModifierFlagsEnd = nullptr;
269314fbfa1STim Northover   if (*I == '[') {
270314fbfa1STim Northover     ObjCModifierFlagsStart = I;
271314fbfa1STim Northover     ++I;
272314fbfa1STim Northover     auto flagStart = I;
273314fbfa1STim Northover     for (;; ++I) {
274314fbfa1STim Northover       ObjCModifierFlagsEnd = I;
275314fbfa1STim Northover       if (I == E) {
276314fbfa1STim Northover         if (Warn)
277314fbfa1STim Northover           H.HandleIncompleteSpecifier(Start, E - Start);
278314fbfa1STim Northover         return true;
279314fbfa1STim Northover       }
280314fbfa1STim Northover       // Did we find the closing ']'?
281314fbfa1STim Northover       if (*I == ']') {
282314fbfa1STim Northover         if (ParseObjCFlags(H, FS, flagStart, I, Warn))
283314fbfa1STim Northover           return true;
284314fbfa1STim Northover         ++I;
285314fbfa1STim Northover         break;
286314fbfa1STim Northover       }
287314fbfa1STim Northover       // There are no separators defined yet for multiple
288314fbfa1STim Northover       // Objective-C modifier flags.  When those are
289314fbfa1STim Northover       // defined, this is the place to check.
290314fbfa1STim Northover     }
291314fbfa1STim Northover   }
292314fbfa1STim Northover 
293314fbfa1STim Northover   if (*I == '\0') {
294314fbfa1STim Northover     // Detect spurious null characters, which are likely errors.
295314fbfa1STim Northover     H.HandleNullChar(I);
296314fbfa1STim Northover     return true;
297314fbfa1STim Northover   }
298314fbfa1STim Northover 
299314fbfa1STim Northover   // Finally, look for the conversion specifier.
300314fbfa1STim Northover   const char *conversionPosition = I++;
301314fbfa1STim Northover   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
302314fbfa1STim Northover   switch (*conversionPosition) {
303314fbfa1STim Northover     default:
304314fbfa1STim Northover       break;
305314fbfa1STim Northover     // C99: 7.19.6.1 (section 8).
306314fbfa1STim Northover     case '%': k = ConversionSpecifier::PercentArg;   break;
307314fbfa1STim Northover     case 'A': k = ConversionSpecifier::AArg; break;
308314fbfa1STim Northover     case 'E': k = ConversionSpecifier::EArg; break;
309314fbfa1STim Northover     case 'F': k = ConversionSpecifier::FArg; break;
310314fbfa1STim Northover     case 'G': k = ConversionSpecifier::GArg; break;
311314fbfa1STim Northover     case 'X': k = ConversionSpecifier::XArg; break;
312314fbfa1STim Northover     case 'a': k = ConversionSpecifier::aArg; break;
313314fbfa1STim Northover     case 'c': k = ConversionSpecifier::cArg; break;
314314fbfa1STim Northover     case 'd': k = ConversionSpecifier::dArg; break;
315314fbfa1STim Northover     case 'e': k = ConversionSpecifier::eArg; break;
316314fbfa1STim Northover     case 'f': k = ConversionSpecifier::fArg; break;
317314fbfa1STim Northover     case 'g': k = ConversionSpecifier::gArg; break;
318314fbfa1STim Northover     case 'i': k = ConversionSpecifier::iArg; break;
31958fc8082SMatt Arsenault     case 'n':
32058fc8082SMatt Arsenault       // Not handled, but reserved in OpenCL.
32158fc8082SMatt Arsenault       if (!LO.OpenCL)
32258fc8082SMatt Arsenault         k = ConversionSpecifier::nArg;
32358fc8082SMatt Arsenault       break;
324314fbfa1STim Northover     case 'o': k = ConversionSpecifier::oArg; break;
325314fbfa1STim Northover     case 'p': k = ConversionSpecifier::pArg; break;
326314fbfa1STim Northover     case 's': k = ConversionSpecifier::sArg; break;
327314fbfa1STim Northover     case 'u': k = ConversionSpecifier::uArg; break;
328314fbfa1STim Northover     case 'x': k = ConversionSpecifier::xArg; break;
329314fbfa1STim Northover     // POSIX specific.
330314fbfa1STim Northover     case 'C': k = ConversionSpecifier::CArg; break;
331314fbfa1STim Northover     case 'S': k = ConversionSpecifier::SArg; break;
332314fbfa1STim Northover     // Apple extension for os_log
333314fbfa1STim Northover     case 'P':
334314fbfa1STim Northover       k = ConversionSpecifier::PArg;
335314fbfa1STim Northover       break;
336314fbfa1STim Northover     // Objective-C.
337314fbfa1STim Northover     case '@': k = ConversionSpecifier::ObjCObjArg; break;
338314fbfa1STim Northover     // Glibc specific.
339314fbfa1STim Northover     case 'm': k = ConversionSpecifier::PrintErrno; break;
340314fbfa1STim Northover     // FreeBSD kernel specific.
341314fbfa1STim Northover     case 'b':
342314fbfa1STim Northover       if (isFreeBSDKPrintf)
343314fbfa1STim Northover         k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
344314fbfa1STim Northover       break;
345314fbfa1STim Northover     case 'r':
346314fbfa1STim Northover       if (isFreeBSDKPrintf)
347314fbfa1STim Northover         k = ConversionSpecifier::FreeBSDrArg; // int
348314fbfa1STim Northover       break;
349314fbfa1STim Northover     case 'y':
350314fbfa1STim Northover       if (isFreeBSDKPrintf)
351314fbfa1STim Northover         k = ConversionSpecifier::FreeBSDyArg; // int
352314fbfa1STim Northover       break;
353314fbfa1STim Northover     // Apple-specific.
354314fbfa1STim Northover     case 'D':
355314fbfa1STim Northover       if (isFreeBSDKPrintf)
356314fbfa1STim Northover         k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
357314fbfa1STim Northover       else if (Target.getTriple().isOSDarwin())
358314fbfa1STim Northover         k = ConversionSpecifier::DArg;
359314fbfa1STim Northover       break;
360314fbfa1STim Northover     case 'O':
361314fbfa1STim Northover       if (Target.getTriple().isOSDarwin())
362314fbfa1STim Northover         k = ConversionSpecifier::OArg;
363314fbfa1STim Northover       break;
364314fbfa1STim Northover     case 'U':
365314fbfa1STim Northover       if (Target.getTriple().isOSDarwin())
366314fbfa1STim Northover         k = ConversionSpecifier::UArg;
367314fbfa1STim Northover       break;
368314fbfa1STim Northover     // MS specific.
369314fbfa1STim Northover     case 'Z':
370314fbfa1STim Northover       if (Target.getTriple().isOSMSVCRT())
371314fbfa1STim Northover         k = ConversionSpecifier::ZArg;
372e19dc613SMatt Arsenault       break;
373314fbfa1STim Northover   }
374314fbfa1STim Northover 
375314fbfa1STim Northover   // Check to see if we used the Objective-C modifier flags with
376314fbfa1STim Northover   // a conversion specifier other than '@'.
377314fbfa1STim Northover   if (k != ConversionSpecifier::ObjCObjArg &&
378314fbfa1STim Northover       k != ConversionSpecifier::InvalidSpecifier &&
379314fbfa1STim Northover       ObjCModifierFlagsStart) {
380314fbfa1STim Northover     H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
381314fbfa1STim Northover                                            ObjCModifierFlagsEnd + 1,
382314fbfa1STim Northover                                            conversionPosition);
383314fbfa1STim Northover     return true;
384314fbfa1STim Northover   }
385314fbfa1STim Northover 
386314fbfa1STim Northover   PrintfConversionSpecifier CS(conversionPosition, k);
387314fbfa1STim Northover   FS.setConversionSpecifier(CS);
388314fbfa1STim Northover   if (CS.consumesDataArgument() && !FS.usesPositionalArg())
389314fbfa1STim Northover     FS.setArgIndex(argIndex++);
390314fbfa1STim Northover   // FreeBSD kernel specific.
391314fbfa1STim Northover   if (k == ConversionSpecifier::FreeBSDbArg ||
392314fbfa1STim Northover       k == ConversionSpecifier::FreeBSDDArg)
393314fbfa1STim Northover     argIndex++;
394314fbfa1STim Northover 
395314fbfa1STim Northover   if (k == ConversionSpecifier::InvalidSpecifier) {
396314fbfa1STim Northover     unsigned Len = I - Start;
397314fbfa1STim Northover     if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
398314fbfa1STim Northover       CS.setEndScanList(Start + Len);
399314fbfa1STim Northover       FS.setConversionSpecifier(CS);
400314fbfa1STim Northover     }
401314fbfa1STim Northover     // Assume the conversion takes one argument.
402314fbfa1STim Northover     return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
403314fbfa1STim Northover   }
404314fbfa1STim Northover   return PrintfSpecifierResult(Start, FS);
405314fbfa1STim Northover }
406314fbfa1STim Northover 
ParsePrintfString(FormatStringHandler & H,const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target,bool isFreeBSDKPrintf)407314fbfa1STim Northover bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
408314fbfa1STim Northover                                                      const char *I,
409314fbfa1STim Northover                                                      const char *E,
410314fbfa1STim Northover                                                      const LangOptions &LO,
411314fbfa1STim Northover                                                      const TargetInfo &Target,
412314fbfa1STim Northover                                                      bool isFreeBSDKPrintf) {
413314fbfa1STim Northover 
414314fbfa1STim Northover   unsigned argIndex = 0;
415314fbfa1STim Northover 
416314fbfa1STim Northover   // Keep looking for a format specifier until we have exhausted the string.
417314fbfa1STim Northover   while (I != E) {
418314fbfa1STim Northover     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
419314fbfa1STim Northover                                                             LO, Target, true,
420314fbfa1STim Northover                                                             isFreeBSDKPrintf);
421314fbfa1STim Northover     // Did a fail-stop error of any kind occur when parsing the specifier?
422314fbfa1STim Northover     // If so, don't do any more processing.
423314fbfa1STim Northover     if (FSR.shouldStop())
424314fbfa1STim Northover       return true;
425314fbfa1STim Northover     // Did we exhaust the string or encounter an error that
426314fbfa1STim Northover     // we can recover from?
427314fbfa1STim Northover     if (!FSR.hasValue())
428314fbfa1STim Northover       continue;
429314fbfa1STim Northover     // We have a format specifier.  Pass it to the callback.
430314fbfa1STim Northover     if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
431cd4e600fSAlex Brachet                                  I - FSR.getStart(), Target))
432314fbfa1STim Northover       return true;
433314fbfa1STim Northover   }
434314fbfa1STim Northover   assert(I == E && "Format string not exhausted");
435314fbfa1STim Northover   return false;
436314fbfa1STim Northover }
437314fbfa1STim Northover 
ParseFormatStringHasSArg(const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)438314fbfa1STim Northover bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
439314fbfa1STim Northover                                                             const char *E,
440314fbfa1STim Northover                                                             const LangOptions &LO,
441314fbfa1STim Northover                                                             const TargetInfo &Target) {
442314fbfa1STim Northover 
443314fbfa1STim Northover   unsigned argIndex = 0;
444314fbfa1STim Northover 
445314fbfa1STim Northover   // Keep looking for a %s format specifier until we have exhausted the string.
446314fbfa1STim Northover   FormatStringHandler H;
447314fbfa1STim Northover   while (I != E) {
448314fbfa1STim Northover     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
449314fbfa1STim Northover                                                             LO, Target, false,
450314fbfa1STim Northover                                                             false);
451314fbfa1STim Northover     // Did a fail-stop error of any kind occur when parsing the specifier?
452314fbfa1STim Northover     // If so, don't do any more processing.
453314fbfa1STim Northover     if (FSR.shouldStop())
454314fbfa1STim Northover       return false;
455314fbfa1STim Northover     // Did we exhaust the string or encounter an error that
456314fbfa1STim Northover     // we can recover from?
457314fbfa1STim Northover     if (!FSR.hasValue())
458314fbfa1STim Northover       continue;
459314fbfa1STim Northover     const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
460314fbfa1STim Northover     // Return true if this a %s format specifier.
461314fbfa1STim Northover     if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
462314fbfa1STim Northover       return true;
463314fbfa1STim Northover   }
464314fbfa1STim Northover   return false;
465314fbfa1STim Northover }
466314fbfa1STim Northover 
parseFormatStringHasFormattingSpecifiers(const char * Begin,const char * End,const LangOptions & LO,const TargetInfo & Target)467aa385569SErik Pilkington bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
468aa385569SErik Pilkington     const char *Begin, const char *End, const LangOptions &LO,
469aa385569SErik Pilkington     const TargetInfo &Target) {
470aa385569SErik Pilkington   unsigned ArgIndex = 0;
471aa385569SErik Pilkington   // Keep looking for a formatting specifier until we have exhausted the string.
472aa385569SErik Pilkington   FormatStringHandler H;
473aa385569SErik Pilkington   while (Begin != End) {
474aa385569SErik Pilkington     const PrintfSpecifierResult &FSR =
475aa385569SErik Pilkington         ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
476aa385569SErik Pilkington     if (FSR.shouldStop())
477aa385569SErik Pilkington       break;
478aa385569SErik Pilkington     if (FSR.hasValue())
479aa385569SErik Pilkington       return true;
480aa385569SErik Pilkington   }
481aa385569SErik Pilkington   return false;
482aa385569SErik Pilkington }
483aa385569SErik Pilkington 
484314fbfa1STim Northover //===----------------------------------------------------------------------===//
485314fbfa1STim Northover // Methods on PrintfSpecifier.
486314fbfa1STim Northover //===----------------------------------------------------------------------===//
487314fbfa1STim Northover 
getScalarArgType(ASTContext & Ctx,bool IsObjCLiteral) const4880ff50d49SMatt Arsenault ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
489314fbfa1STim Northover                                           bool IsObjCLiteral) const {
490314fbfa1STim Northover   if (CS.getKind() == ConversionSpecifier::cArg)
491314fbfa1STim Northover     switch (LM.getKind()) {
492314fbfa1STim Northover       case LengthModifier::None:
493314fbfa1STim Northover         return Ctx.IntTy;
494314fbfa1STim Northover       case LengthModifier::AsLong:
495314fbfa1STim Northover       case LengthModifier::AsWide:
496314fbfa1STim Northover         return ArgType(ArgType::WIntTy, "wint_t");
497314fbfa1STim Northover       case LengthModifier::AsShort:
498314fbfa1STim Northover         if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
499314fbfa1STim Northover           return Ctx.IntTy;
500314fbfa1STim Northover         LLVM_FALLTHROUGH;
501314fbfa1STim Northover       default:
502314fbfa1STim Northover         return ArgType::Invalid();
503314fbfa1STim Northover     }
504314fbfa1STim Northover 
505314fbfa1STim Northover   if (CS.isIntArg())
506314fbfa1STim Northover     switch (LM.getKind()) {
507314fbfa1STim Northover       case LengthModifier::AsLongDouble:
508314fbfa1STim Northover         // GNU extension.
509314fbfa1STim Northover         return Ctx.LongLongTy;
510314fbfa1STim Northover       case LengthModifier::None:
51158fc8082SMatt Arsenault       case LengthModifier::AsShortLong:
512314fbfa1STim Northover         return Ctx.IntTy;
513314fbfa1STim Northover       case LengthModifier::AsInt32:
514314fbfa1STim Northover         return ArgType(Ctx.IntTy, "__int32");
51558fc8082SMatt Arsenault       case LengthModifier::AsChar:
51658fc8082SMatt Arsenault         return ArgType::AnyCharTy;
517314fbfa1STim Northover       case LengthModifier::AsShort: return Ctx.ShortTy;
518314fbfa1STim Northover       case LengthModifier::AsLong: return Ctx.LongTy;
519314fbfa1STim Northover       case LengthModifier::AsLongLong:
520314fbfa1STim Northover       case LengthModifier::AsQuad:
521314fbfa1STim Northover         return Ctx.LongLongTy;
522314fbfa1STim Northover       case LengthModifier::AsInt64:
523314fbfa1STim Northover         return ArgType(Ctx.LongLongTy, "__int64");
524314fbfa1STim Northover       case LengthModifier::AsIntMax:
525314fbfa1STim Northover         return ArgType(Ctx.getIntMaxType(), "intmax_t");
526314fbfa1STim Northover       case LengthModifier::AsSizeT:
527314fbfa1STim Northover         return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
528314fbfa1STim Northover       case LengthModifier::AsInt3264:
529314fbfa1STim Northover         return Ctx.getTargetInfo().getTriple().isArch64Bit()
530314fbfa1STim Northover                    ? ArgType(Ctx.LongLongTy, "__int64")
531314fbfa1STim Northover                    : ArgType(Ctx.IntTy, "__int32");
532314fbfa1STim Northover       case LengthModifier::AsPtrDiff:
533314fbfa1STim Northover         return ArgType::makePtrdiffT(
534314fbfa1STim Northover             ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
535314fbfa1STim Northover       case LengthModifier::AsAllocate:
536314fbfa1STim Northover       case LengthModifier::AsMAllocate:
537314fbfa1STim Northover       case LengthModifier::AsWide:
538314fbfa1STim Northover         return ArgType::Invalid();
539314fbfa1STim Northover     }
540314fbfa1STim Northover 
541314fbfa1STim Northover   if (CS.isUIntArg())
542314fbfa1STim Northover     switch (LM.getKind()) {
543314fbfa1STim Northover       case LengthModifier::AsLongDouble:
544314fbfa1STim Northover         // GNU extension.
545314fbfa1STim Northover         return Ctx.UnsignedLongLongTy;
546314fbfa1STim Northover       case LengthModifier::None:
54758fc8082SMatt Arsenault       case LengthModifier::AsShortLong:
548314fbfa1STim Northover         return Ctx.UnsignedIntTy;
549314fbfa1STim Northover       case LengthModifier::AsInt32:
550314fbfa1STim Northover         return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
551314fbfa1STim Northover       case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
552314fbfa1STim Northover       case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
553314fbfa1STim Northover       case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
554314fbfa1STim Northover       case LengthModifier::AsLongLong:
555314fbfa1STim Northover       case LengthModifier::AsQuad:
556314fbfa1STim Northover         return Ctx.UnsignedLongLongTy;
557314fbfa1STim Northover       case LengthModifier::AsInt64:
558314fbfa1STim Northover         return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
559314fbfa1STim Northover       case LengthModifier::AsIntMax:
560314fbfa1STim Northover         return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
561314fbfa1STim Northover       case LengthModifier::AsSizeT:
562314fbfa1STim Northover         return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
563314fbfa1STim Northover       case LengthModifier::AsInt3264:
564314fbfa1STim Northover         return Ctx.getTargetInfo().getTriple().isArch64Bit()
565314fbfa1STim Northover                    ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
566314fbfa1STim Northover                    : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
567314fbfa1STim Northover       case LengthModifier::AsPtrDiff:
568314fbfa1STim Northover         return ArgType::makePtrdiffT(
569314fbfa1STim Northover             ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
570314fbfa1STim Northover       case LengthModifier::AsAllocate:
571314fbfa1STim Northover       case LengthModifier::AsMAllocate:
572314fbfa1STim Northover       case LengthModifier::AsWide:
573314fbfa1STim Northover         return ArgType::Invalid();
574314fbfa1STim Northover     }
575314fbfa1STim Northover 
576314fbfa1STim Northover   if (CS.isDoubleArg()) {
57758fc8082SMatt Arsenault     if (!VectorNumElts.isInvalid()) {
57858fc8082SMatt Arsenault       switch (LM.getKind()) {
57958fc8082SMatt Arsenault       case LengthModifier::AsShort:
58058fc8082SMatt Arsenault         return Ctx.HalfTy;
58158fc8082SMatt Arsenault       case LengthModifier::AsShortLong:
58258fc8082SMatt Arsenault         return Ctx.FloatTy;
58358fc8082SMatt Arsenault       case LengthModifier::AsLong:
58458fc8082SMatt Arsenault       default:
58558fc8082SMatt Arsenault         return Ctx.DoubleTy;
58658fc8082SMatt Arsenault       }
58758fc8082SMatt Arsenault     }
58858fc8082SMatt Arsenault 
589314fbfa1STim Northover     if (LM.getKind() == LengthModifier::AsLongDouble)
590314fbfa1STim Northover       return Ctx.LongDoubleTy;
591314fbfa1STim Northover     return Ctx.DoubleTy;
592314fbfa1STim Northover   }
593314fbfa1STim Northover 
594314fbfa1STim Northover   if (CS.getKind() == ConversionSpecifier::nArg) {
595314fbfa1STim Northover     switch (LM.getKind()) {
596314fbfa1STim Northover       case LengthModifier::None:
597314fbfa1STim Northover         return ArgType::PtrTo(Ctx.IntTy);
598314fbfa1STim Northover       case LengthModifier::AsChar:
599314fbfa1STim Northover         return ArgType::PtrTo(Ctx.SignedCharTy);
600314fbfa1STim Northover       case LengthModifier::AsShort:
601314fbfa1STim Northover         return ArgType::PtrTo(Ctx.ShortTy);
602314fbfa1STim Northover       case LengthModifier::AsLong:
603314fbfa1STim Northover         return ArgType::PtrTo(Ctx.LongTy);
604314fbfa1STim Northover       case LengthModifier::AsLongLong:
605314fbfa1STim Northover       case LengthModifier::AsQuad:
606314fbfa1STim Northover         return ArgType::PtrTo(Ctx.LongLongTy);
607314fbfa1STim Northover       case LengthModifier::AsIntMax:
608314fbfa1STim Northover         return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
609314fbfa1STim Northover       case LengthModifier::AsSizeT:
610314fbfa1STim Northover         return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
611314fbfa1STim Northover       case LengthModifier::AsPtrDiff:
612314fbfa1STim Northover         return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
613314fbfa1STim Northover       case LengthModifier::AsLongDouble:
614314fbfa1STim Northover         return ArgType(); // FIXME: Is this a known extension?
615314fbfa1STim Northover       case LengthModifier::AsAllocate:
616314fbfa1STim Northover       case LengthModifier::AsMAllocate:
617314fbfa1STim Northover       case LengthModifier::AsInt32:
618314fbfa1STim Northover       case LengthModifier::AsInt3264:
619314fbfa1STim Northover       case LengthModifier::AsInt64:
620314fbfa1STim Northover       case LengthModifier::AsWide:
621314fbfa1STim Northover         return ArgType::Invalid();
62258fc8082SMatt Arsenault       case LengthModifier::AsShortLong:
62358fc8082SMatt Arsenault         llvm_unreachable("only used for OpenCL which doesn not handle nArg");
624314fbfa1STim Northover     }
625314fbfa1STim Northover   }
626314fbfa1STim Northover 
627314fbfa1STim Northover   switch (CS.getKind()) {
628314fbfa1STim Northover     case ConversionSpecifier::sArg:
629314fbfa1STim Northover       if (LM.getKind() == LengthModifier::AsWideChar) {
630314fbfa1STim Northover         if (IsObjCLiteral)
631314fbfa1STim Northover           return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
632314fbfa1STim Northover                          "const unichar *");
633314fbfa1STim Northover         return ArgType(ArgType::WCStrTy, "wchar_t *");
634314fbfa1STim Northover       }
635314fbfa1STim Northover       if (LM.getKind() == LengthModifier::AsWide)
636314fbfa1STim Northover         return ArgType(ArgType::WCStrTy, "wchar_t *");
637314fbfa1STim Northover       return ArgType::CStrTy;
638314fbfa1STim Northover     case ConversionSpecifier::SArg:
639314fbfa1STim Northover       if (IsObjCLiteral)
640314fbfa1STim Northover         return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
641314fbfa1STim Northover                        "const unichar *");
642314fbfa1STim Northover       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
643314fbfa1STim Northover           LM.getKind() == LengthModifier::AsShort)
644314fbfa1STim Northover         return ArgType::CStrTy;
645314fbfa1STim Northover       return ArgType(ArgType::WCStrTy, "wchar_t *");
646314fbfa1STim Northover     case ConversionSpecifier::CArg:
647314fbfa1STim Northover       if (IsObjCLiteral)
648314fbfa1STim Northover         return ArgType(Ctx.UnsignedShortTy, "unichar");
649314fbfa1STim Northover       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
650314fbfa1STim Northover           LM.getKind() == LengthModifier::AsShort)
651314fbfa1STim Northover         return Ctx.IntTy;
652314fbfa1STim Northover       return ArgType(Ctx.WideCharTy, "wchar_t");
653314fbfa1STim Northover     case ConversionSpecifier::pArg:
654314fbfa1STim Northover     case ConversionSpecifier::PArg:
655314fbfa1STim Northover       return ArgType::CPointerTy;
656314fbfa1STim Northover     case ConversionSpecifier::ObjCObjArg:
657314fbfa1STim Northover       return ArgType::ObjCPointerTy;
658314fbfa1STim Northover     default:
659314fbfa1STim Northover       break;
660314fbfa1STim Northover   }
661314fbfa1STim Northover 
662314fbfa1STim Northover   // FIXME: Handle other cases.
663314fbfa1STim Northover   return ArgType();
664314fbfa1STim Northover }
665314fbfa1STim Northover 
6660ff50d49SMatt Arsenault 
getArgType(ASTContext & Ctx,bool IsObjCLiteral) const6670ff50d49SMatt Arsenault ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
6680ff50d49SMatt Arsenault                                     bool IsObjCLiteral) const {
6690ff50d49SMatt Arsenault   const PrintfConversionSpecifier &CS = getConversionSpecifier();
6700ff50d49SMatt Arsenault 
6710ff50d49SMatt Arsenault   if (!CS.consumesDataArgument())
6720ff50d49SMatt Arsenault     return ArgType::Invalid();
6730ff50d49SMatt Arsenault 
6740ff50d49SMatt Arsenault   ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
6750ff50d49SMatt Arsenault   if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
6760ff50d49SMatt Arsenault     return ScalarTy;
6770ff50d49SMatt Arsenault 
6780ff50d49SMatt Arsenault   return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());
6790ff50d49SMatt Arsenault }
6800ff50d49SMatt Arsenault 
fixType(QualType QT,const LangOptions & LangOpt,ASTContext & Ctx,bool IsObjCLiteral)681314fbfa1STim Northover bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
682314fbfa1STim Northover                               ASTContext &Ctx, bool IsObjCLiteral) {
683314fbfa1STim Northover   // %n is different from other conversion specifiers; don't try to fix it.
684314fbfa1STim Northover   if (CS.getKind() == ConversionSpecifier::nArg)
685314fbfa1STim Northover     return false;
686314fbfa1STim Northover 
687314fbfa1STim Northover   // Handle Objective-C objects first. Note that while the '%@' specifier will
688314fbfa1STim Northover   // not warn for structure pointer or void pointer arguments (because that's
689314fbfa1STim Northover   // how CoreFoundation objects are implemented), we only show a fixit for '%@'
690314fbfa1STim Northover   // if we know it's an object (block, id, class, or __attribute__((NSObject))).
691314fbfa1STim Northover   if (QT->isObjCRetainableType()) {
692314fbfa1STim Northover     if (!IsObjCLiteral)
693314fbfa1STim Northover       return false;
694314fbfa1STim Northover 
695314fbfa1STim Northover     CS.setKind(ConversionSpecifier::ObjCObjArg);
696314fbfa1STim Northover 
697314fbfa1STim Northover     // Disable irrelevant flags
698314fbfa1STim Northover     HasThousandsGrouping = false;
699314fbfa1STim Northover     HasPlusPrefix = false;
700314fbfa1STim Northover     HasSpacePrefix = false;
701314fbfa1STim Northover     HasAlternativeForm = false;
702314fbfa1STim Northover     HasLeadingZeroes = false;
703314fbfa1STim Northover     Precision.setHowSpecified(OptionalAmount::NotSpecified);
704314fbfa1STim Northover     LM.setKind(LengthModifier::None);
705314fbfa1STim Northover 
706314fbfa1STim Northover     return true;
707314fbfa1STim Northover   }
708314fbfa1STim Northover 
709314fbfa1STim Northover   // Handle strings next (char *, wchar_t *)
710314fbfa1STim Northover   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
711314fbfa1STim Northover     CS.setKind(ConversionSpecifier::sArg);
712314fbfa1STim Northover 
713314fbfa1STim Northover     // Disable irrelevant flags
71440446663SKazu Hirata     HasAlternativeForm = false;
71540446663SKazu Hirata     HasLeadingZeroes = false;
716314fbfa1STim Northover 
717314fbfa1STim Northover     // Set the long length modifier for wide characters
718314fbfa1STim Northover     if (QT->getPointeeType()->isWideCharType())
719314fbfa1STim Northover       LM.setKind(LengthModifier::AsWideChar);
720314fbfa1STim Northover     else
721314fbfa1STim Northover       LM.setKind(LengthModifier::None);
722314fbfa1STim Northover 
723314fbfa1STim Northover     return true;
724314fbfa1STim Northover   }
725314fbfa1STim Northover 
726314fbfa1STim Northover   // If it's an enum, get its underlying type.
727314fbfa1STim Northover   if (const EnumType *ETy = QT->getAs<EnumType>())
728314fbfa1STim Northover     QT = ETy->getDecl()->getIntegerType();
729314fbfa1STim Northover 
730314fbfa1STim Northover   const BuiltinType *BT = QT->getAs<BuiltinType>();
7310ff50d49SMatt Arsenault   if (!BT) {
7320ff50d49SMatt Arsenault     const VectorType *VT = QT->getAs<VectorType>();
7330ff50d49SMatt Arsenault     if (VT) {
7340ff50d49SMatt Arsenault       QT = VT->getElementType();
7350ff50d49SMatt Arsenault       BT = QT->getAs<BuiltinType>();
7360ff50d49SMatt Arsenault       VectorNumElts = OptionalAmount(VT->getNumElements());
7370ff50d49SMatt Arsenault     }
7380ff50d49SMatt Arsenault   }
7390ff50d49SMatt Arsenault 
7400ff50d49SMatt Arsenault   // We can only work with builtin types.
741314fbfa1STim Northover   if (!BT)
742314fbfa1STim Northover     return false;
743314fbfa1STim Northover 
744314fbfa1STim Northover   // Set length modifier
745314fbfa1STim Northover   switch (BT->getKind()) {
746314fbfa1STim Northover   case BuiltinType::Bool:
747314fbfa1STim Northover   case BuiltinType::WChar_U:
748314fbfa1STim Northover   case BuiltinType::WChar_S:
749314fbfa1STim Northover   case BuiltinType::Char8: // FIXME: Treat like 'char'?
750314fbfa1STim Northover   case BuiltinType::Char16:
751314fbfa1STim Northover   case BuiltinType::Char32:
752314fbfa1STim Northover   case BuiltinType::UInt128:
753314fbfa1STim Northover   case BuiltinType::Int128:
754314fbfa1STim Northover   case BuiltinType::Half:
755ecd682bbSTies Stuij   case BuiltinType::BFloat16:
756314fbfa1STim Northover   case BuiltinType::Float16:
757314fbfa1STim Northover   case BuiltinType::Float128:
758fae0dfa6SQiu Chaofan   case BuiltinType::Ibm128:
759314fbfa1STim Northover   case BuiltinType::ShortAccum:
760314fbfa1STim Northover   case BuiltinType::Accum:
761314fbfa1STim Northover   case BuiltinType::LongAccum:
762314fbfa1STim Northover   case BuiltinType::UShortAccum:
763314fbfa1STim Northover   case BuiltinType::UAccum:
764314fbfa1STim Northover   case BuiltinType::ULongAccum:
765314fbfa1STim Northover   case BuiltinType::ShortFract:
766314fbfa1STim Northover   case BuiltinType::Fract:
767314fbfa1STim Northover   case BuiltinType::LongFract:
768314fbfa1STim Northover   case BuiltinType::UShortFract:
769314fbfa1STim Northover   case BuiltinType::UFract:
770314fbfa1STim Northover   case BuiltinType::ULongFract:
771314fbfa1STim Northover   case BuiltinType::SatShortAccum:
772314fbfa1STim Northover   case BuiltinType::SatAccum:
773314fbfa1STim Northover   case BuiltinType::SatLongAccum:
774314fbfa1STim Northover   case BuiltinType::SatUShortAccum:
775314fbfa1STim Northover   case BuiltinType::SatUAccum:
776314fbfa1STim Northover   case BuiltinType::SatULongAccum:
777314fbfa1STim Northover   case BuiltinType::SatShortFract:
778314fbfa1STim Northover   case BuiltinType::SatFract:
779314fbfa1STim Northover   case BuiltinType::SatLongFract:
780314fbfa1STim Northover   case BuiltinType::SatUShortFract:
781314fbfa1STim Northover   case BuiltinType::SatUFract:
782314fbfa1STim Northover   case BuiltinType::SatULongFract:
783314fbfa1STim Northover     // Various types which are non-trivial to correct.
784314fbfa1STim Northover     return false;
785314fbfa1STim Northover 
786314fbfa1STim Northover #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
787314fbfa1STim Northover   case BuiltinType::Id:
788314fbfa1STim Northover #include "clang/Basic/OpenCLImageTypes.def"
7893fee3518SAndrew Savonichev #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
7903fee3518SAndrew Savonichev   case BuiltinType::Id:
7913fee3518SAndrew Savonichev #include "clang/Basic/OpenCLExtensionTypes.def"
792eb485fbcSRichard Sandiford #define SVE_TYPE(Name, Id, SingletonId) \
793eb485fbcSRichard Sandiford   case BuiltinType::Id:
794eb485fbcSRichard Sandiford #include "clang/Basic/AArch64SVEACLETypes.def"
79557d83c3aSBaptiste Saleil #define PPC_VECTOR_TYPE(Name, Id, Size) \
79640dd4d52SBaptiste Saleil   case BuiltinType::Id:
79740dd4d52SBaptiste Saleil #include "clang/Basic/PPCTypes.def"
798766ee109SHsiangkai Wang #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
799766ee109SHsiangkai Wang #include "clang/Basic/RISCVVTypes.def"
800314fbfa1STim Northover #define SIGNED_TYPE(Id, SingletonId)
801314fbfa1STim Northover #define UNSIGNED_TYPE(Id, SingletonId)
802314fbfa1STim Northover #define FLOATING_TYPE(Id, SingletonId)
803314fbfa1STim Northover #define BUILTIN_TYPE(Id, SingletonId) \
804314fbfa1STim Northover   case BuiltinType::Id:
805314fbfa1STim Northover #include "clang/AST/BuiltinTypes.def"
806314fbfa1STim Northover     // Misc other stuff which doesn't make sense here.
807314fbfa1STim Northover     return false;
808314fbfa1STim Northover 
809314fbfa1STim Northover   case BuiltinType::UInt:
810314fbfa1STim Northover   case BuiltinType::Int:
811314fbfa1STim Northover   case BuiltinType::Float:
81258fc8082SMatt Arsenault     LM.setKind(VectorNumElts.isInvalid() ?
81358fc8082SMatt Arsenault                LengthModifier::None : LengthModifier::AsShortLong);
814314fbfa1STim Northover     break;
81558fc8082SMatt Arsenault   case BuiltinType::Double:
81658fc8082SMatt Arsenault     LM.setKind(VectorNumElts.isInvalid() ?
81758fc8082SMatt Arsenault                LengthModifier::None : LengthModifier::AsLong);
81858fc8082SMatt Arsenault     break;
819314fbfa1STim Northover   case BuiltinType::Char_U:
820314fbfa1STim Northover   case BuiltinType::UChar:
821314fbfa1STim Northover   case BuiltinType::Char_S:
822314fbfa1STim Northover   case BuiltinType::SChar:
823314fbfa1STim Northover     LM.setKind(LengthModifier::AsChar);
824314fbfa1STim Northover     break;
825314fbfa1STim Northover 
826314fbfa1STim Northover   case BuiltinType::Short:
827314fbfa1STim Northover   case BuiltinType::UShort:
828314fbfa1STim Northover     LM.setKind(LengthModifier::AsShort);
829314fbfa1STim Northover     break;
830314fbfa1STim Northover 
831314fbfa1STim Northover   case BuiltinType::Long:
832314fbfa1STim Northover   case BuiltinType::ULong:
833314fbfa1STim Northover     LM.setKind(LengthModifier::AsLong);
834314fbfa1STim Northover     break;
835314fbfa1STim Northover 
836314fbfa1STim Northover   case BuiltinType::LongLong:
837314fbfa1STim Northover   case BuiltinType::ULongLong:
838314fbfa1STim Northover     LM.setKind(LengthModifier::AsLongLong);
839314fbfa1STim Northover     break;
840314fbfa1STim Northover 
841314fbfa1STim Northover   case BuiltinType::LongDouble:
842314fbfa1STim Northover     LM.setKind(LengthModifier::AsLongDouble);
843314fbfa1STim Northover     break;
844314fbfa1STim Northover   }
845314fbfa1STim Northover 
846314fbfa1STim Northover   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
847*888673b6SJonas Devlieghere   if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
848314fbfa1STim Northover     namedTypeToLengthModifier(QT, LM);
849314fbfa1STim Northover 
850314fbfa1STim Northover   // If fixing the length modifier was enough, we might be done.
85158fc8082SMatt Arsenault   if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
852314fbfa1STim Northover     // If we're going to offer a fix anyway, make sure the sign matches.
853314fbfa1STim Northover     switch (CS.getKind()) {
854314fbfa1STim Northover     case ConversionSpecifier::uArg:
855314fbfa1STim Northover     case ConversionSpecifier::UArg:
856314fbfa1STim Northover       if (QT->isSignedIntegerType())
857314fbfa1STim Northover         CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
858314fbfa1STim Northover       break;
859314fbfa1STim Northover     case ConversionSpecifier::dArg:
860314fbfa1STim Northover     case ConversionSpecifier::DArg:
861314fbfa1STim Northover     case ConversionSpecifier::iArg:
862314fbfa1STim Northover       if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
863314fbfa1STim Northover         CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
864314fbfa1STim Northover       break;
865314fbfa1STim Northover     default:
866314fbfa1STim Northover       // Other specifiers do not have signed/unsigned variants.
867314fbfa1STim Northover       break;
868314fbfa1STim Northover     }
869314fbfa1STim Northover 
870314fbfa1STim Northover     const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
871314fbfa1STim Northover     if (ATR.isValid() && ATR.matchesType(Ctx, QT))
872314fbfa1STim Northover       return true;
873314fbfa1STim Northover   }
874314fbfa1STim Northover 
875314fbfa1STim Northover   // Set conversion specifier and disable any flags which do not apply to it.
876314fbfa1STim Northover   // Let typedefs to char fall through to int, as %c is silly for uint8_t.
877*888673b6SJonas Devlieghere   if (!isa<TypedefType>(QT) && QT->isCharType()) {
878314fbfa1STim Northover     CS.setKind(ConversionSpecifier::cArg);
879314fbfa1STim Northover     LM.setKind(LengthModifier::None);
880314fbfa1STim Northover     Precision.setHowSpecified(OptionalAmount::NotSpecified);
88140446663SKazu Hirata     HasAlternativeForm = false;
88240446663SKazu Hirata     HasLeadingZeroes = false;
88340446663SKazu Hirata     HasPlusPrefix = false;
884314fbfa1STim Northover   }
885314fbfa1STim Northover   // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
886314fbfa1STim Northover   else if (QT->isRealFloatingType()) {
887314fbfa1STim Northover     CS.setKind(ConversionSpecifier::fArg);
888*888673b6SJonas Devlieghere   }
889*888673b6SJonas Devlieghere   else if (QT->isSignedIntegerType()) {
890314fbfa1STim Northover     CS.setKind(ConversionSpecifier::dArg);
89140446663SKazu Hirata     HasAlternativeForm = false;
892*888673b6SJonas Devlieghere   }
893*888673b6SJonas Devlieghere   else if (QT->isUnsignedIntegerType()) {
894314fbfa1STim Northover     CS.setKind(ConversionSpecifier::uArg);
89540446663SKazu Hirata     HasAlternativeForm = false;
89640446663SKazu Hirata     HasPlusPrefix = false;
897314fbfa1STim Northover   } else {
898314fbfa1STim Northover     llvm_unreachable("Unexpected type");
899314fbfa1STim Northover   }
900314fbfa1STim Northover 
901314fbfa1STim Northover   return true;
902314fbfa1STim Northover }
903314fbfa1STim Northover 
toString(raw_ostream & os) const904314fbfa1STim Northover void PrintfSpecifier::toString(raw_ostream &os) const {
905314fbfa1STim Northover   // Whilst some features have no defined order, we are using the order
906314fbfa1STim Northover   // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
907314fbfa1STim Northover   os << "%";
908314fbfa1STim Northover 
909314fbfa1STim Northover   // Positional args
910314fbfa1STim Northover   if (usesPositionalArg()) {
911314fbfa1STim Northover     os << getPositionalArgIndex() << "$";
912314fbfa1STim Northover   }
913314fbfa1STim Northover 
914314fbfa1STim Northover   // Conversion flags
915314fbfa1STim Northover   if (IsLeftJustified)    os << "-";
916314fbfa1STim Northover   if (HasPlusPrefix)      os << "+";
917314fbfa1STim Northover   if (HasSpacePrefix)     os << " ";
918314fbfa1STim Northover   if (HasAlternativeForm) os << "#";
919314fbfa1STim Northover   if (HasLeadingZeroes)   os << "0";
920314fbfa1STim Northover 
921314fbfa1STim Northover   // Minimum field width
922314fbfa1STim Northover   FieldWidth.toString(os);
923314fbfa1STim Northover   // Precision
924314fbfa1STim Northover   Precision.toString(os);
9250ff50d49SMatt Arsenault 
9260ff50d49SMatt Arsenault   // Vector modifier
9270ff50d49SMatt Arsenault   if (!VectorNumElts.isInvalid())
9280ff50d49SMatt Arsenault     os << 'v' << VectorNumElts.getConstantAmount();
9290ff50d49SMatt Arsenault 
930314fbfa1STim Northover   // Length modifier
931314fbfa1STim Northover   os << LM.toString();
932314fbfa1STim Northover   // Conversion specifier
933314fbfa1STim Northover   os << CS.toString();
934314fbfa1STim Northover }
935314fbfa1STim Northover 
hasValidPlusPrefix() const936314fbfa1STim Northover bool PrintfSpecifier::hasValidPlusPrefix() const {
937314fbfa1STim Northover   if (!HasPlusPrefix)
938314fbfa1STim Northover     return true;
939314fbfa1STim Northover 
940314fbfa1STim Northover   // The plus prefix only makes sense for signed conversions
941314fbfa1STim Northover   switch (CS.getKind()) {
942314fbfa1STim Northover   case ConversionSpecifier::dArg:
943314fbfa1STim Northover   case ConversionSpecifier::DArg:
944314fbfa1STim Northover   case ConversionSpecifier::iArg:
945314fbfa1STim Northover   case ConversionSpecifier::fArg:
946314fbfa1STim Northover   case ConversionSpecifier::FArg:
947314fbfa1STim Northover   case ConversionSpecifier::eArg:
948314fbfa1STim Northover   case ConversionSpecifier::EArg:
949314fbfa1STim Northover   case ConversionSpecifier::gArg:
950314fbfa1STim Northover   case ConversionSpecifier::GArg:
951314fbfa1STim Northover   case ConversionSpecifier::aArg:
952314fbfa1STim Northover   case ConversionSpecifier::AArg:
953314fbfa1STim Northover   case ConversionSpecifier::FreeBSDrArg:
954314fbfa1STim Northover   case ConversionSpecifier::FreeBSDyArg:
955314fbfa1STim Northover     return true;
956314fbfa1STim Northover 
957314fbfa1STim Northover   default:
958314fbfa1STim Northover     return false;
959314fbfa1STim Northover   }
960314fbfa1STim Northover }
961314fbfa1STim Northover 
hasValidAlternativeForm() const962314fbfa1STim Northover bool PrintfSpecifier::hasValidAlternativeForm() const {
963314fbfa1STim Northover   if (!HasAlternativeForm)
964314fbfa1STim Northover     return true;
965314fbfa1STim Northover 
966314fbfa1STim Northover   // Alternate form flag only valid with the oxXaAeEfFgG conversions
967314fbfa1STim Northover   switch (CS.getKind()) {
968314fbfa1STim Northover   case ConversionSpecifier::oArg:
969314fbfa1STim Northover   case ConversionSpecifier::OArg:
970314fbfa1STim Northover   case ConversionSpecifier::xArg:
971314fbfa1STim Northover   case ConversionSpecifier::XArg:
972314fbfa1STim Northover   case ConversionSpecifier::aArg:
973314fbfa1STim Northover   case ConversionSpecifier::AArg:
974314fbfa1STim Northover   case ConversionSpecifier::eArg:
975314fbfa1STim Northover   case ConversionSpecifier::EArg:
976314fbfa1STim Northover   case ConversionSpecifier::fArg:
977314fbfa1STim Northover   case ConversionSpecifier::FArg:
978314fbfa1STim Northover   case ConversionSpecifier::gArg:
979314fbfa1STim Northover   case ConversionSpecifier::GArg:
980314fbfa1STim Northover   case ConversionSpecifier::FreeBSDrArg:
981314fbfa1STim Northover   case ConversionSpecifier::FreeBSDyArg:
982314fbfa1STim Northover     return true;
983314fbfa1STim Northover 
984314fbfa1STim Northover   default:
985314fbfa1STim Northover     return false;
986314fbfa1STim Northover   }
987314fbfa1STim Northover }
988314fbfa1STim Northover 
hasValidLeadingZeros() const989314fbfa1STim Northover bool PrintfSpecifier::hasValidLeadingZeros() const {
990314fbfa1STim Northover   if (!HasLeadingZeroes)
991314fbfa1STim Northover     return true;
992314fbfa1STim Northover 
993314fbfa1STim Northover   // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
994314fbfa1STim Northover   switch (CS.getKind()) {
995314fbfa1STim Northover   case ConversionSpecifier::dArg:
996314fbfa1STim Northover   case ConversionSpecifier::DArg:
997314fbfa1STim Northover   case ConversionSpecifier::iArg:
998314fbfa1STim Northover   case ConversionSpecifier::oArg:
999314fbfa1STim Northover   case ConversionSpecifier::OArg:
1000314fbfa1STim Northover   case ConversionSpecifier::uArg:
1001314fbfa1STim Northover   case ConversionSpecifier::UArg:
1002314fbfa1STim Northover   case ConversionSpecifier::xArg:
1003314fbfa1STim Northover   case ConversionSpecifier::XArg:
1004314fbfa1STim Northover   case ConversionSpecifier::aArg:
1005314fbfa1STim Northover   case ConversionSpecifier::AArg:
1006314fbfa1STim Northover   case ConversionSpecifier::eArg:
1007314fbfa1STim Northover   case ConversionSpecifier::EArg:
1008314fbfa1STim Northover   case ConversionSpecifier::fArg:
1009314fbfa1STim Northover   case ConversionSpecifier::FArg:
1010314fbfa1STim Northover   case ConversionSpecifier::gArg:
1011314fbfa1STim Northover   case ConversionSpecifier::GArg:
1012314fbfa1STim Northover   case ConversionSpecifier::FreeBSDrArg:
1013314fbfa1STim Northover   case ConversionSpecifier::FreeBSDyArg:
1014314fbfa1STim Northover     return true;
1015314fbfa1STim Northover 
1016314fbfa1STim Northover   default:
1017314fbfa1STim Northover     return false;
1018314fbfa1STim Northover   }
1019314fbfa1STim Northover }
1020314fbfa1STim Northover 
hasValidSpacePrefix() const1021314fbfa1STim Northover bool PrintfSpecifier::hasValidSpacePrefix() const {
1022314fbfa1STim Northover   if (!HasSpacePrefix)
1023314fbfa1STim Northover     return true;
1024314fbfa1STim Northover 
1025314fbfa1STim Northover   // The space prefix only makes sense for signed conversions
1026314fbfa1STim Northover   switch (CS.getKind()) {
1027314fbfa1STim Northover   case ConversionSpecifier::dArg:
1028314fbfa1STim Northover   case ConversionSpecifier::DArg:
1029314fbfa1STim Northover   case ConversionSpecifier::iArg:
1030314fbfa1STim Northover   case ConversionSpecifier::fArg:
1031314fbfa1STim Northover   case ConversionSpecifier::FArg:
1032314fbfa1STim Northover   case ConversionSpecifier::eArg:
1033314fbfa1STim Northover   case ConversionSpecifier::EArg:
1034314fbfa1STim Northover   case ConversionSpecifier::gArg:
1035314fbfa1STim Northover   case ConversionSpecifier::GArg:
1036314fbfa1STim Northover   case ConversionSpecifier::aArg:
1037314fbfa1STim Northover   case ConversionSpecifier::AArg:
1038314fbfa1STim Northover   case ConversionSpecifier::FreeBSDrArg:
1039314fbfa1STim Northover   case ConversionSpecifier::FreeBSDyArg:
1040314fbfa1STim Northover     return true;
1041314fbfa1STim Northover 
1042314fbfa1STim Northover   default:
1043314fbfa1STim Northover     return false;
1044314fbfa1STim Northover   }
1045314fbfa1STim Northover }
1046314fbfa1STim Northover 
hasValidLeftJustified() const1047314fbfa1STim Northover bool PrintfSpecifier::hasValidLeftJustified() const {
1048314fbfa1STim Northover   if (!IsLeftJustified)
1049314fbfa1STim Northover     return true;
1050314fbfa1STim Northover 
1051314fbfa1STim Northover   // The left justified flag is valid for all conversions except n
1052314fbfa1STim Northover   switch (CS.getKind()) {
1053314fbfa1STim Northover   case ConversionSpecifier::nArg:
1054314fbfa1STim Northover     return false;
1055314fbfa1STim Northover 
1056314fbfa1STim Northover   default:
1057314fbfa1STim Northover     return true;
1058314fbfa1STim Northover   }
1059314fbfa1STim Northover }
1060314fbfa1STim Northover 
hasValidThousandsGroupingPrefix() const1061314fbfa1STim Northover bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
1062314fbfa1STim Northover   if (!HasThousandsGrouping)
1063314fbfa1STim Northover     return true;
1064314fbfa1STim Northover 
1065314fbfa1STim Northover   switch (CS.getKind()) {
1066314fbfa1STim Northover     case ConversionSpecifier::dArg:
1067314fbfa1STim Northover     case ConversionSpecifier::DArg:
1068314fbfa1STim Northover     case ConversionSpecifier::iArg:
1069314fbfa1STim Northover     case ConversionSpecifier::uArg:
1070314fbfa1STim Northover     case ConversionSpecifier::UArg:
1071314fbfa1STim Northover     case ConversionSpecifier::fArg:
1072314fbfa1STim Northover     case ConversionSpecifier::FArg:
1073314fbfa1STim Northover     case ConversionSpecifier::gArg:
1074314fbfa1STim Northover     case ConversionSpecifier::GArg:
1075314fbfa1STim Northover       return true;
1076314fbfa1STim Northover     default:
1077314fbfa1STim Northover       return false;
1078314fbfa1STim Northover   }
1079314fbfa1STim Northover }
1080314fbfa1STim Northover 
hasValidPrecision() const1081314fbfa1STim Northover bool PrintfSpecifier::hasValidPrecision() const {
1082314fbfa1STim Northover   if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1083314fbfa1STim Northover     return true;
1084314fbfa1STim Northover 
1085314fbfa1STim Northover   // Precision is only valid with the diouxXaAeEfFgGsP conversions
1086314fbfa1STim Northover   switch (CS.getKind()) {
1087314fbfa1STim Northover   case ConversionSpecifier::dArg:
1088314fbfa1STim Northover   case ConversionSpecifier::DArg:
1089314fbfa1STim Northover   case ConversionSpecifier::iArg:
1090314fbfa1STim Northover   case ConversionSpecifier::oArg:
1091314fbfa1STim Northover   case ConversionSpecifier::OArg:
1092314fbfa1STim Northover   case ConversionSpecifier::uArg:
1093314fbfa1STim Northover   case ConversionSpecifier::UArg:
1094314fbfa1STim Northover   case ConversionSpecifier::xArg:
1095314fbfa1STim Northover   case ConversionSpecifier::XArg:
1096314fbfa1STim Northover   case ConversionSpecifier::aArg:
1097314fbfa1STim Northover   case ConversionSpecifier::AArg:
1098314fbfa1STim Northover   case ConversionSpecifier::eArg:
1099314fbfa1STim Northover   case ConversionSpecifier::EArg:
1100314fbfa1STim Northover   case ConversionSpecifier::fArg:
1101314fbfa1STim Northover   case ConversionSpecifier::FArg:
1102314fbfa1STim Northover   case ConversionSpecifier::gArg:
1103314fbfa1STim Northover   case ConversionSpecifier::GArg:
1104314fbfa1STim Northover   case ConversionSpecifier::sArg:
1105314fbfa1STim Northover   case ConversionSpecifier::FreeBSDrArg:
1106314fbfa1STim Northover   case ConversionSpecifier::FreeBSDyArg:
1107314fbfa1STim Northover   case ConversionSpecifier::PArg:
1108314fbfa1STim Northover     return true;
1109314fbfa1STim Northover 
1110314fbfa1STim Northover   default:
1111314fbfa1STim Northover     return false;
1112314fbfa1STim Northover   }
1113314fbfa1STim Northover }
hasValidFieldWidth() const1114314fbfa1STim Northover bool PrintfSpecifier::hasValidFieldWidth() const {
1115314fbfa1STim Northover   if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1116314fbfa1STim Northover       return true;
1117314fbfa1STim Northover 
1118314fbfa1STim Northover   // The field width is valid for all conversions except n
1119314fbfa1STim Northover   switch (CS.getKind()) {
1120314fbfa1STim Northover   case ConversionSpecifier::nArg:
1121314fbfa1STim Northover     return false;
1122314fbfa1STim Northover 
1123314fbfa1STim Northover   default:
1124314fbfa1STim Northover     return true;
1125314fbfa1STim Northover   }
1126314fbfa1STim Northover }
1127