xref: /openbsd-src/gnu/llvm/clang/lib/AST/PrintfFormatString.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Handling of format string in printf and friends.  The structure of format
10e5dd7070Spatrick // strings for fprintf() are described in C99 7.19.6.1.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick 
14ec727ea7Spatrick #include "FormatStringParsing.h"
15e5dd7070Spatrick #include "clang/AST/FormatString.h"
16e5dd7070Spatrick #include "clang/AST/OSLog.h"
17e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
18ec727ea7Spatrick #include "llvm/Support/Regex.h"
19e5dd7070Spatrick 
20e5dd7070Spatrick using clang::analyze_format_string::ArgType;
21e5dd7070Spatrick using clang::analyze_format_string::FormatStringHandler;
22e5dd7070Spatrick using clang::analyze_format_string::LengthModifier;
23e5dd7070Spatrick using clang::analyze_format_string::OptionalAmount;
24e5dd7070Spatrick using clang::analyze_format_string::ConversionSpecifier;
25e5dd7070Spatrick using clang::analyze_printf::PrintfSpecifier;
26e5dd7070Spatrick 
27e5dd7070Spatrick using namespace clang;
28e5dd7070Spatrick 
29e5dd7070Spatrick typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
30e5dd7070Spatrick         PrintfSpecifierResult;
31e5dd7070Spatrick 
32e5dd7070Spatrick //===----------------------------------------------------------------------===//
33e5dd7070Spatrick // Methods for parsing format strings.
34e5dd7070Spatrick //===----------------------------------------------------------------------===//
35e5dd7070Spatrick 
36e5dd7070Spatrick using analyze_format_string::ParseNonPositionAmount;
37e5dd7070Spatrick 
ParsePrecision(FormatStringHandler & H,PrintfSpecifier & FS,const char * Start,const char * & Beg,const char * E,unsigned * argIndex)38e5dd7070Spatrick static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
39e5dd7070Spatrick                            const char *Start, const char *&Beg, const char *E,
40e5dd7070Spatrick                            unsigned *argIndex) {
41e5dd7070Spatrick   if (argIndex) {
42e5dd7070Spatrick     FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
43e5dd7070Spatrick   } else {
44e5dd7070Spatrick     const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
45e5dd7070Spatrick                                            analyze_format_string::PrecisionPos);
46e5dd7070Spatrick     if (Amt.isInvalid())
47e5dd7070Spatrick       return true;
48e5dd7070Spatrick     FS.setPrecision(Amt);
49e5dd7070Spatrick   }
50e5dd7070Spatrick   return false;
51e5dd7070Spatrick }
52e5dd7070Spatrick 
ParseObjCFlags(FormatStringHandler & H,PrintfSpecifier & FS,const char * FlagBeg,const char * E,bool Warn)53e5dd7070Spatrick static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,
54e5dd7070Spatrick                            const char *FlagBeg, const char *E, bool Warn) {
55e5dd7070Spatrick    StringRef Flag(FlagBeg, E - FlagBeg);
56e5dd7070Spatrick    // Currently there is only one flag.
57e5dd7070Spatrick    if (Flag == "tt") {
58e5dd7070Spatrick      FS.setHasObjCTechnicalTerm(FlagBeg);
59e5dd7070Spatrick      return false;
60e5dd7070Spatrick    }
61e5dd7070Spatrick    // Handle either the case of no flag or an invalid flag.
62e5dd7070Spatrick    if (Warn) {
63e5dd7070Spatrick      if (Flag == "")
64e5dd7070Spatrick        H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg);
65e5dd7070Spatrick      else
66e5dd7070Spatrick        H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg);
67e5dd7070Spatrick    }
68e5dd7070Spatrick    return true;
69e5dd7070Spatrick }
70e5dd7070Spatrick 
ParsePrintfSpecifier(FormatStringHandler & H,const char * & Beg,const char * E,unsigned & argIndex,const LangOptions & LO,const TargetInfo & Target,bool Warn,bool isFreeBSDKPrintf)71e5dd7070Spatrick static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
72e5dd7070Spatrick                                                   const char *&Beg,
73e5dd7070Spatrick                                                   const char *E,
74e5dd7070Spatrick                                                   unsigned &argIndex,
75e5dd7070Spatrick                                                   const LangOptions &LO,
76e5dd7070Spatrick                                                   const TargetInfo &Target,
77e5dd7070Spatrick                                                   bool Warn,
78e5dd7070Spatrick                                                   bool isFreeBSDKPrintf) {
79e5dd7070Spatrick 
80e5dd7070Spatrick   using namespace clang::analyze_format_string;
81e5dd7070Spatrick   using namespace clang::analyze_printf;
82e5dd7070Spatrick 
83e5dd7070Spatrick   const char *I = Beg;
84e5dd7070Spatrick   const char *Start = nullptr;
85e5dd7070Spatrick   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
86e5dd7070Spatrick 
87e5dd7070Spatrick   // Look for a '%' character that indicates the start of a format specifier.
88e5dd7070Spatrick   for ( ; I != E ; ++I) {
89e5dd7070Spatrick     char c = *I;
90e5dd7070Spatrick     if (c == '\0') {
91e5dd7070Spatrick       // Detect spurious null characters, which are likely errors.
92e5dd7070Spatrick       H.HandleNullChar(I);
93e5dd7070Spatrick       return true;
94e5dd7070Spatrick     }
95e5dd7070Spatrick     if (c == '%') {
96e5dd7070Spatrick       Start = I++;  // Record the start of the format specifier.
97e5dd7070Spatrick       break;
98e5dd7070Spatrick     }
99e5dd7070Spatrick   }
100e5dd7070Spatrick 
101e5dd7070Spatrick   // No format specifier found?
102e5dd7070Spatrick   if (!Start)
103e5dd7070Spatrick     return false;
104e5dd7070Spatrick 
105e5dd7070Spatrick   if (I == E) {
106e5dd7070Spatrick     // No more characters left?
107e5dd7070Spatrick     if (Warn)
108e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
109e5dd7070Spatrick     return true;
110e5dd7070Spatrick   }
111e5dd7070Spatrick 
112e5dd7070Spatrick   PrintfSpecifier FS;
113e5dd7070Spatrick   if (ParseArgPosition(H, FS, Start, I, E))
114e5dd7070Spatrick     return true;
115e5dd7070Spatrick 
116e5dd7070Spatrick   if (I == E) {
117e5dd7070Spatrick     // No more characters left?
118e5dd7070Spatrick     if (Warn)
119e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
120e5dd7070Spatrick     return true;
121e5dd7070Spatrick   }
122e5dd7070Spatrick 
123e5dd7070Spatrick   if (*I == '{') {
124e5dd7070Spatrick     ++I;
125e5dd7070Spatrick     unsigned char PrivacyFlags = 0;
126e5dd7070Spatrick     StringRef MatchedStr;
127e5dd7070Spatrick 
128e5dd7070Spatrick     do {
129e5dd7070Spatrick       StringRef Str(I, E - I);
130e5dd7070Spatrick       std::string Match = "^[[:space:]]*"
131e5dd7070Spatrick                           "(private|public|sensitive|mask\\.[^[:space:],}]*)"
132e5dd7070Spatrick                           "[[:space:]]*(,|})";
133e5dd7070Spatrick       llvm::Regex R(Match);
134e5dd7070Spatrick       SmallVector<StringRef, 2> Matches;
135e5dd7070Spatrick 
136e5dd7070Spatrick       if (R.match(Str, &Matches)) {
137e5dd7070Spatrick         MatchedStr = Matches[1];
138e5dd7070Spatrick         I += Matches[0].size();
139e5dd7070Spatrick 
140e5dd7070Spatrick         // Set the privacy flag if the privacy annotation in the
141e5dd7070Spatrick         // comma-delimited segment is at least as strict as the privacy
142e5dd7070Spatrick         // annotations in previous comma-delimited segments.
143e5dd7070Spatrick         if (MatchedStr.startswith("mask")) {
144e5dd7070Spatrick           StringRef MaskType = MatchedStr.substr(sizeof("mask.") - 1);
145e5dd7070Spatrick           unsigned Size = MaskType.size();
146e5dd7070Spatrick           if (Warn && (Size == 0 || Size > 8))
147e5dd7070Spatrick             H.handleInvalidMaskType(MaskType);
148e5dd7070Spatrick           FS.setMaskType(MaskType);
149e5dd7070Spatrick         } else if (MatchedStr.equals("sensitive"))
150e5dd7070Spatrick           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsSensitive;
151e5dd7070Spatrick         else if (PrivacyFlags !=
152e5dd7070Spatrick                  clang::analyze_os_log::OSLogBufferItem::IsSensitive &&
153e5dd7070Spatrick                  MatchedStr.equals("private"))
154e5dd7070Spatrick           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;
155e5dd7070Spatrick         else if (PrivacyFlags == 0 && MatchedStr.equals("public"))
156e5dd7070Spatrick           PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;
157e5dd7070Spatrick       } else {
158e5dd7070Spatrick         size_t CommaOrBracePos =
159e5dd7070Spatrick             Str.find_if([](char c) { return c == ',' || c == '}'; });
160e5dd7070Spatrick 
161e5dd7070Spatrick         if (CommaOrBracePos == StringRef::npos) {
162e5dd7070Spatrick           // Neither a comma nor the closing brace was found.
163e5dd7070Spatrick           if (Warn)
164e5dd7070Spatrick             H.HandleIncompleteSpecifier(Start, E - Start);
165e5dd7070Spatrick           return true;
166e5dd7070Spatrick         }
167e5dd7070Spatrick 
168e5dd7070Spatrick         I += CommaOrBracePos + 1;
169e5dd7070Spatrick       }
170e5dd7070Spatrick       // Continue until the closing brace is found.
171e5dd7070Spatrick     } while (*(I - 1) == ',');
172e5dd7070Spatrick 
173e5dd7070Spatrick     // Set the privacy flag.
174e5dd7070Spatrick     switch (PrivacyFlags) {
175e5dd7070Spatrick     case 0:
176e5dd7070Spatrick       break;
177e5dd7070Spatrick     case clang::analyze_os_log::OSLogBufferItem::IsPrivate:
178e5dd7070Spatrick       FS.setIsPrivate(MatchedStr.data());
179e5dd7070Spatrick       break;
180e5dd7070Spatrick     case clang::analyze_os_log::OSLogBufferItem::IsPublic:
181e5dd7070Spatrick       FS.setIsPublic(MatchedStr.data());
182e5dd7070Spatrick       break;
183e5dd7070Spatrick     case clang::analyze_os_log::OSLogBufferItem::IsSensitive:
184e5dd7070Spatrick       FS.setIsSensitive(MatchedStr.data());
185e5dd7070Spatrick       break;
186e5dd7070Spatrick     default:
187e5dd7070Spatrick       llvm_unreachable("Unexpected privacy flag value");
188e5dd7070Spatrick     }
189e5dd7070Spatrick   }
190e5dd7070Spatrick 
191e5dd7070Spatrick   // Look for flags (if any).
192e5dd7070Spatrick   bool hasMore = true;
193e5dd7070Spatrick   for ( ; I != E; ++I) {
194e5dd7070Spatrick     switch (*I) {
195e5dd7070Spatrick       default: hasMore = false; break;
196e5dd7070Spatrick       case '\'':
197e5dd7070Spatrick         // FIXME: POSIX specific.  Always accept?
198e5dd7070Spatrick         FS.setHasThousandsGrouping(I);
199e5dd7070Spatrick         break;
200e5dd7070Spatrick       case '-': FS.setIsLeftJustified(I); break;
201e5dd7070Spatrick       case '+': FS.setHasPlusPrefix(I); break;
202e5dd7070Spatrick       case ' ': FS.setHasSpacePrefix(I); break;
203e5dd7070Spatrick       case '#': FS.setHasAlternativeForm(I); break;
204e5dd7070Spatrick       case '0': FS.setHasLeadingZeros(I); break;
205e5dd7070Spatrick     }
206e5dd7070Spatrick     if (!hasMore)
207e5dd7070Spatrick       break;
208e5dd7070Spatrick   }
209e5dd7070Spatrick 
210e5dd7070Spatrick   if (I == E) {
211e5dd7070Spatrick     // No more characters left?
212e5dd7070Spatrick     if (Warn)
213e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
214e5dd7070Spatrick     return true;
215e5dd7070Spatrick   }
216e5dd7070Spatrick 
217e5dd7070Spatrick   // Look for the field width (if any).
218e5dd7070Spatrick   if (ParseFieldWidth(H, FS, Start, I, E,
219e5dd7070Spatrick                       FS.usesPositionalArg() ? nullptr : &argIndex))
220e5dd7070Spatrick     return true;
221e5dd7070Spatrick 
222e5dd7070Spatrick   if (I == E) {
223e5dd7070Spatrick     // No more characters left?
224e5dd7070Spatrick     if (Warn)
225e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
226e5dd7070Spatrick     return true;
227e5dd7070Spatrick   }
228e5dd7070Spatrick 
229e5dd7070Spatrick   // Look for the precision (if any).
230e5dd7070Spatrick   if (*I == '.') {
231e5dd7070Spatrick     ++I;
232e5dd7070Spatrick     if (I == E) {
233e5dd7070Spatrick       if (Warn)
234e5dd7070Spatrick         H.HandleIncompleteSpecifier(Start, E - Start);
235e5dd7070Spatrick       return true;
236e5dd7070Spatrick     }
237e5dd7070Spatrick 
238e5dd7070Spatrick     if (ParsePrecision(H, FS, Start, I, E,
239e5dd7070Spatrick                        FS.usesPositionalArg() ? nullptr : &argIndex))
240e5dd7070Spatrick       return true;
241e5dd7070Spatrick 
242e5dd7070Spatrick     if (I == E) {
243e5dd7070Spatrick       // No more characters left?
244e5dd7070Spatrick       if (Warn)
245e5dd7070Spatrick         H.HandleIncompleteSpecifier(Start, E - Start);
246e5dd7070Spatrick       return true;
247e5dd7070Spatrick     }
248e5dd7070Spatrick   }
249e5dd7070Spatrick 
250e5dd7070Spatrick   if (ParseVectorModifier(H, FS, I, E, LO))
251e5dd7070Spatrick     return true;
252e5dd7070Spatrick 
253e5dd7070Spatrick   // Look for the length modifier.
254e5dd7070Spatrick   if (ParseLengthModifier(FS, I, E, LO) && I == E) {
255e5dd7070Spatrick     // No more characters left?
256e5dd7070Spatrick     if (Warn)
257e5dd7070Spatrick       H.HandleIncompleteSpecifier(Start, E - Start);
258e5dd7070Spatrick     return true;
259e5dd7070Spatrick   }
260e5dd7070Spatrick 
261e5dd7070Spatrick   // Look for the Objective-C modifier flags, if any.
262e5dd7070Spatrick   // We parse these here, even if they don't apply to
263e5dd7070Spatrick   // the conversion specifier, and then emit an error
264e5dd7070Spatrick   // later if the conversion specifier isn't '@'.  This
265e5dd7070Spatrick   // enables better recovery, and we don't know if
266e5dd7070Spatrick   // these flags are applicable until later.
267e5dd7070Spatrick   const char *ObjCModifierFlagsStart = nullptr,
268e5dd7070Spatrick              *ObjCModifierFlagsEnd = nullptr;
269e5dd7070Spatrick   if (*I == '[') {
270e5dd7070Spatrick     ObjCModifierFlagsStart = I;
271e5dd7070Spatrick     ++I;
272e5dd7070Spatrick     auto flagStart = I;
273e5dd7070Spatrick     for (;; ++I) {
274e5dd7070Spatrick       ObjCModifierFlagsEnd = I;
275e5dd7070Spatrick       if (I == E) {
276e5dd7070Spatrick         if (Warn)
277e5dd7070Spatrick           H.HandleIncompleteSpecifier(Start, E - Start);
278e5dd7070Spatrick         return true;
279e5dd7070Spatrick       }
280e5dd7070Spatrick       // Did we find the closing ']'?
281e5dd7070Spatrick       if (*I == ']') {
282e5dd7070Spatrick         if (ParseObjCFlags(H, FS, flagStart, I, Warn))
283e5dd7070Spatrick           return true;
284e5dd7070Spatrick         ++I;
285e5dd7070Spatrick         break;
286e5dd7070Spatrick       }
287e5dd7070Spatrick       // There are no separators defined yet for multiple
288e5dd7070Spatrick       // Objective-C modifier flags.  When those are
289e5dd7070Spatrick       // defined, this is the place to check.
290e5dd7070Spatrick     }
291e5dd7070Spatrick   }
292e5dd7070Spatrick 
293e5dd7070Spatrick   if (*I == '\0') {
294e5dd7070Spatrick     // Detect spurious null characters, which are likely errors.
295e5dd7070Spatrick     H.HandleNullChar(I);
296e5dd7070Spatrick     return true;
297e5dd7070Spatrick   }
298e5dd7070Spatrick 
299e5dd7070Spatrick   // Finally, look for the conversion specifier.
300e5dd7070Spatrick   const char *conversionPosition = I++;
301e5dd7070Spatrick   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
302e5dd7070Spatrick   switch (*conversionPosition) {
303e5dd7070Spatrick     default:
304e5dd7070Spatrick       break;
305e5dd7070Spatrick     // C99: 7.19.6.1 (section 8).
306e5dd7070Spatrick     case '%': k = ConversionSpecifier::PercentArg;   break;
307e5dd7070Spatrick     case 'A': k = ConversionSpecifier::AArg; break;
308e5dd7070Spatrick     case 'E': k = ConversionSpecifier::EArg; break;
309e5dd7070Spatrick     case 'F': k = ConversionSpecifier::FArg; break;
310e5dd7070Spatrick     case 'G': k = ConversionSpecifier::GArg; break;
311e5dd7070Spatrick     case 'X': k = ConversionSpecifier::XArg; break;
312e5dd7070Spatrick     case 'a': k = ConversionSpecifier::aArg; break;
313e5dd7070Spatrick     case 'c': k = ConversionSpecifier::cArg; break;
314e5dd7070Spatrick     case 'd': k = ConversionSpecifier::dArg; break;
315e5dd7070Spatrick     case 'e': k = ConversionSpecifier::eArg; break;
316e5dd7070Spatrick     case 'f': k = ConversionSpecifier::fArg; break;
317e5dd7070Spatrick     case 'g': k = ConversionSpecifier::gArg; break;
318e5dd7070Spatrick     case 'i': k = ConversionSpecifier::iArg; break;
319e5dd7070Spatrick     case 'n':
320e5dd7070Spatrick       // Not handled, but reserved in OpenCL.
321e5dd7070Spatrick       if (!LO.OpenCL)
322e5dd7070Spatrick         k = ConversionSpecifier::nArg;
323e5dd7070Spatrick       break;
324e5dd7070Spatrick     case 'o': k = ConversionSpecifier::oArg; break;
325e5dd7070Spatrick     case 'p': k = ConversionSpecifier::pArg; break;
326e5dd7070Spatrick     case 's': k = ConversionSpecifier::sArg; break;
327e5dd7070Spatrick     case 'u': k = ConversionSpecifier::uArg; break;
328e5dd7070Spatrick     case 'x': k = ConversionSpecifier::xArg; break;
329*12c85518Srobert     // C23.
330*12c85518Srobert     case 'b':
331*12c85518Srobert       if (isFreeBSDKPrintf)
332*12c85518Srobert         k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
333*12c85518Srobert       else
334*12c85518Srobert         k = ConversionSpecifier::bArg;
335*12c85518Srobert       break;
336*12c85518Srobert     case 'B': k = ConversionSpecifier::BArg; break;
337e5dd7070Spatrick     // POSIX specific.
338e5dd7070Spatrick     case 'C': k = ConversionSpecifier::CArg; break;
339e5dd7070Spatrick     case 'S': k = ConversionSpecifier::SArg; break;
340e5dd7070Spatrick     // Apple extension for os_log
341e5dd7070Spatrick     case 'P':
342e5dd7070Spatrick       k = ConversionSpecifier::PArg;
343e5dd7070Spatrick       break;
344e5dd7070Spatrick     // Objective-C.
345e5dd7070Spatrick     case '@': k = ConversionSpecifier::ObjCObjArg; break;
346e5dd7070Spatrick     // Glibc specific.
347e5dd7070Spatrick     case 'm': k = ConversionSpecifier::PrintErrno; break;
348e5dd7070Spatrick     case 'r':
349e5dd7070Spatrick       if (isFreeBSDKPrintf)
350e5dd7070Spatrick         k = ConversionSpecifier::FreeBSDrArg; // int
351e5dd7070Spatrick       break;
352e5dd7070Spatrick     case 'y':
353e5dd7070Spatrick       if (isFreeBSDKPrintf)
354e5dd7070Spatrick         k = ConversionSpecifier::FreeBSDyArg; // int
355e5dd7070Spatrick       break;
356e5dd7070Spatrick     // Apple-specific.
357e5dd7070Spatrick     case 'D':
358e5dd7070Spatrick       if (isFreeBSDKPrintf)
359e5dd7070Spatrick         k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *
360e5dd7070Spatrick       else if (Target.getTriple().isOSDarwin())
361e5dd7070Spatrick         k = ConversionSpecifier::DArg;
362e5dd7070Spatrick       break;
363e5dd7070Spatrick     case 'O':
364e5dd7070Spatrick       if (Target.getTriple().isOSDarwin())
365e5dd7070Spatrick         k = ConversionSpecifier::OArg;
366e5dd7070Spatrick       break;
367e5dd7070Spatrick     case 'U':
368e5dd7070Spatrick       if (Target.getTriple().isOSDarwin())
369e5dd7070Spatrick         k = ConversionSpecifier::UArg;
370e5dd7070Spatrick       break;
371e5dd7070Spatrick     // MS specific.
372e5dd7070Spatrick     case 'Z':
373e5dd7070Spatrick       if (Target.getTriple().isOSMSVCRT())
374e5dd7070Spatrick         k = ConversionSpecifier::ZArg;
375e5dd7070Spatrick       break;
376e5dd7070Spatrick   }
377e5dd7070Spatrick 
378e5dd7070Spatrick   // Check to see if we used the Objective-C modifier flags with
379e5dd7070Spatrick   // a conversion specifier other than '@'.
380e5dd7070Spatrick   if (k != ConversionSpecifier::ObjCObjArg &&
381e5dd7070Spatrick       k != ConversionSpecifier::InvalidSpecifier &&
382e5dd7070Spatrick       ObjCModifierFlagsStart) {
383e5dd7070Spatrick     H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,
384e5dd7070Spatrick                                            ObjCModifierFlagsEnd + 1,
385e5dd7070Spatrick                                            conversionPosition);
386e5dd7070Spatrick     return true;
387e5dd7070Spatrick   }
388e5dd7070Spatrick 
389e5dd7070Spatrick   PrintfConversionSpecifier CS(conversionPosition, k);
390e5dd7070Spatrick   FS.setConversionSpecifier(CS);
391e5dd7070Spatrick   if (CS.consumesDataArgument() && !FS.usesPositionalArg())
392e5dd7070Spatrick     FS.setArgIndex(argIndex++);
393e5dd7070Spatrick   // FreeBSD kernel specific.
394e5dd7070Spatrick   if (k == ConversionSpecifier::FreeBSDbArg ||
395e5dd7070Spatrick       k == ConversionSpecifier::FreeBSDDArg)
396e5dd7070Spatrick     argIndex++;
397e5dd7070Spatrick 
398e5dd7070Spatrick   if (k == ConversionSpecifier::InvalidSpecifier) {
399e5dd7070Spatrick     unsigned Len = I - Start;
400e5dd7070Spatrick     if (ParseUTF8InvalidSpecifier(Start, E, Len)) {
401e5dd7070Spatrick       CS.setEndScanList(Start + Len);
402e5dd7070Spatrick       FS.setConversionSpecifier(CS);
403e5dd7070Spatrick     }
404e5dd7070Spatrick     // Assume the conversion takes one argument.
405e5dd7070Spatrick     return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);
406e5dd7070Spatrick   }
407e5dd7070Spatrick   return PrintfSpecifierResult(Start, FS);
408e5dd7070Spatrick }
409e5dd7070Spatrick 
ParsePrintfString(FormatStringHandler & H,const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target,bool isFreeBSDKPrintf)410e5dd7070Spatrick bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
411e5dd7070Spatrick                                                      const char *I,
412e5dd7070Spatrick                                                      const char *E,
413e5dd7070Spatrick                                                      const LangOptions &LO,
414e5dd7070Spatrick                                                      const TargetInfo &Target,
415e5dd7070Spatrick                                                      bool isFreeBSDKPrintf) {
416e5dd7070Spatrick 
417e5dd7070Spatrick   unsigned argIndex = 0;
418e5dd7070Spatrick 
419e5dd7070Spatrick   // Keep looking for a format specifier until we have exhausted the string.
420e5dd7070Spatrick   while (I != E) {
421e5dd7070Spatrick     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
422e5dd7070Spatrick                                                             LO, Target, true,
423e5dd7070Spatrick                                                             isFreeBSDKPrintf);
424e5dd7070Spatrick     // Did a fail-stop error of any kind occur when parsing the specifier?
425e5dd7070Spatrick     // If so, don't do any more processing.
426e5dd7070Spatrick     if (FSR.shouldStop())
427e5dd7070Spatrick       return true;
428e5dd7070Spatrick     // Did we exhaust the string or encounter an error that
429e5dd7070Spatrick     // we can recover from?
430e5dd7070Spatrick     if (!FSR.hasValue())
431e5dd7070Spatrick       continue;
432e5dd7070Spatrick     // We have a format specifier.  Pass it to the callback.
433e5dd7070Spatrick     if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
434*12c85518Srobert                                  I - FSR.getStart(), Target))
435e5dd7070Spatrick       return true;
436e5dd7070Spatrick   }
437e5dd7070Spatrick   assert(I == E && "Format string not exhausted");
438e5dd7070Spatrick   return false;
439e5dd7070Spatrick }
440e5dd7070Spatrick 
ParseFormatStringHasSArg(const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)441e5dd7070Spatrick bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
442e5dd7070Spatrick                                                             const char *E,
443e5dd7070Spatrick                                                             const LangOptions &LO,
444e5dd7070Spatrick                                                             const TargetInfo &Target) {
445e5dd7070Spatrick 
446e5dd7070Spatrick   unsigned argIndex = 0;
447e5dd7070Spatrick 
448e5dd7070Spatrick   // Keep looking for a %s format specifier until we have exhausted the string.
449e5dd7070Spatrick   FormatStringHandler H;
450e5dd7070Spatrick   while (I != E) {
451e5dd7070Spatrick     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
452e5dd7070Spatrick                                                             LO, Target, false,
453e5dd7070Spatrick                                                             false);
454e5dd7070Spatrick     // Did a fail-stop error of any kind occur when parsing the specifier?
455e5dd7070Spatrick     // If so, don't do any more processing.
456e5dd7070Spatrick     if (FSR.shouldStop())
457e5dd7070Spatrick       return false;
458e5dd7070Spatrick     // Did we exhaust the string or encounter an error that
459e5dd7070Spatrick     // we can recover from?
460e5dd7070Spatrick     if (!FSR.hasValue())
461e5dd7070Spatrick       continue;
462e5dd7070Spatrick     const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
463e5dd7070Spatrick     // Return true if this a %s format specifier.
464e5dd7070Spatrick     if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
465e5dd7070Spatrick       return true;
466e5dd7070Spatrick   }
467e5dd7070Spatrick   return false;
468e5dd7070Spatrick }
469e5dd7070Spatrick 
parseFormatStringHasFormattingSpecifiers(const char * Begin,const char * End,const LangOptions & LO,const TargetInfo & Target)470e5dd7070Spatrick bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
471e5dd7070Spatrick     const char *Begin, const char *End, const LangOptions &LO,
472e5dd7070Spatrick     const TargetInfo &Target) {
473e5dd7070Spatrick   unsigned ArgIndex = 0;
474e5dd7070Spatrick   // Keep looking for a formatting specifier until we have exhausted the string.
475e5dd7070Spatrick   FormatStringHandler H;
476e5dd7070Spatrick   while (Begin != End) {
477e5dd7070Spatrick     const PrintfSpecifierResult &FSR =
478e5dd7070Spatrick         ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
479e5dd7070Spatrick     if (FSR.shouldStop())
480e5dd7070Spatrick       break;
481e5dd7070Spatrick     if (FSR.hasValue())
482e5dd7070Spatrick       return true;
483e5dd7070Spatrick   }
484e5dd7070Spatrick   return false;
485e5dd7070Spatrick }
486e5dd7070Spatrick 
487e5dd7070Spatrick //===----------------------------------------------------------------------===//
488e5dd7070Spatrick // Methods on PrintfSpecifier.
489e5dd7070Spatrick //===----------------------------------------------------------------------===//
490e5dd7070Spatrick 
getScalarArgType(ASTContext & Ctx,bool IsObjCLiteral) const491e5dd7070Spatrick ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
492e5dd7070Spatrick                                           bool IsObjCLiteral) const {
493e5dd7070Spatrick   if (CS.getKind() == ConversionSpecifier::cArg)
494e5dd7070Spatrick     switch (LM.getKind()) {
495e5dd7070Spatrick       case LengthModifier::None:
496e5dd7070Spatrick         return Ctx.IntTy;
497e5dd7070Spatrick       case LengthModifier::AsLong:
498e5dd7070Spatrick       case LengthModifier::AsWide:
499e5dd7070Spatrick         return ArgType(ArgType::WIntTy, "wint_t");
500e5dd7070Spatrick       case LengthModifier::AsShort:
501e5dd7070Spatrick         if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
502e5dd7070Spatrick           return Ctx.IntTy;
503*12c85518Srobert         [[fallthrough]];
504e5dd7070Spatrick       default:
505e5dd7070Spatrick         return ArgType::Invalid();
506e5dd7070Spatrick     }
507e5dd7070Spatrick 
508e5dd7070Spatrick   if (CS.isIntArg())
509e5dd7070Spatrick     switch (LM.getKind()) {
510e5dd7070Spatrick       case LengthModifier::AsLongDouble:
511e5dd7070Spatrick         // GNU extension.
512e5dd7070Spatrick         return Ctx.LongLongTy;
513e5dd7070Spatrick       case LengthModifier::None:
514e5dd7070Spatrick       case LengthModifier::AsShortLong:
515e5dd7070Spatrick         return Ctx.IntTy;
516e5dd7070Spatrick       case LengthModifier::AsInt32:
517e5dd7070Spatrick         return ArgType(Ctx.IntTy, "__int32");
518e5dd7070Spatrick       case LengthModifier::AsChar:
519e5dd7070Spatrick         return ArgType::AnyCharTy;
520e5dd7070Spatrick       case LengthModifier::AsShort: return Ctx.ShortTy;
521e5dd7070Spatrick       case LengthModifier::AsLong: return Ctx.LongTy;
522e5dd7070Spatrick       case LengthModifier::AsLongLong:
523e5dd7070Spatrick       case LengthModifier::AsQuad:
524e5dd7070Spatrick         return Ctx.LongLongTy;
525e5dd7070Spatrick       case LengthModifier::AsInt64:
526e5dd7070Spatrick         return ArgType(Ctx.LongLongTy, "__int64");
527e5dd7070Spatrick       case LengthModifier::AsIntMax:
528e5dd7070Spatrick         return ArgType(Ctx.getIntMaxType(), "intmax_t");
529e5dd7070Spatrick       case LengthModifier::AsSizeT:
530e5dd7070Spatrick         return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
531e5dd7070Spatrick       case LengthModifier::AsInt3264:
532e5dd7070Spatrick         return Ctx.getTargetInfo().getTriple().isArch64Bit()
533e5dd7070Spatrick                    ? ArgType(Ctx.LongLongTy, "__int64")
534e5dd7070Spatrick                    : ArgType(Ctx.IntTy, "__int32");
535e5dd7070Spatrick       case LengthModifier::AsPtrDiff:
536e5dd7070Spatrick         return ArgType::makePtrdiffT(
537e5dd7070Spatrick             ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
538e5dd7070Spatrick       case LengthModifier::AsAllocate:
539e5dd7070Spatrick       case LengthModifier::AsMAllocate:
540e5dd7070Spatrick       case LengthModifier::AsWide:
541e5dd7070Spatrick         return ArgType::Invalid();
542e5dd7070Spatrick     }
543e5dd7070Spatrick 
544e5dd7070Spatrick   if (CS.isUIntArg())
545e5dd7070Spatrick     switch (LM.getKind()) {
546e5dd7070Spatrick       case LengthModifier::AsLongDouble:
547e5dd7070Spatrick         // GNU extension.
548e5dd7070Spatrick         return Ctx.UnsignedLongLongTy;
549e5dd7070Spatrick       case LengthModifier::None:
550e5dd7070Spatrick       case LengthModifier::AsShortLong:
551e5dd7070Spatrick         return Ctx.UnsignedIntTy;
552e5dd7070Spatrick       case LengthModifier::AsInt32:
553e5dd7070Spatrick         return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
554e5dd7070Spatrick       case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
555e5dd7070Spatrick       case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
556e5dd7070Spatrick       case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
557e5dd7070Spatrick       case LengthModifier::AsLongLong:
558e5dd7070Spatrick       case LengthModifier::AsQuad:
559e5dd7070Spatrick         return Ctx.UnsignedLongLongTy;
560e5dd7070Spatrick       case LengthModifier::AsInt64:
561e5dd7070Spatrick         return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
562e5dd7070Spatrick       case LengthModifier::AsIntMax:
563e5dd7070Spatrick         return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
564e5dd7070Spatrick       case LengthModifier::AsSizeT:
565e5dd7070Spatrick         return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));
566e5dd7070Spatrick       case LengthModifier::AsInt3264:
567e5dd7070Spatrick         return Ctx.getTargetInfo().getTriple().isArch64Bit()
568e5dd7070Spatrick                    ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
569e5dd7070Spatrick                    : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
570e5dd7070Spatrick       case LengthModifier::AsPtrDiff:
571e5dd7070Spatrick         return ArgType::makePtrdiffT(
572e5dd7070Spatrick             ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));
573e5dd7070Spatrick       case LengthModifier::AsAllocate:
574e5dd7070Spatrick       case LengthModifier::AsMAllocate:
575e5dd7070Spatrick       case LengthModifier::AsWide:
576e5dd7070Spatrick         return ArgType::Invalid();
577e5dd7070Spatrick     }
578e5dd7070Spatrick 
579e5dd7070Spatrick   if (CS.isDoubleArg()) {
580e5dd7070Spatrick     if (!VectorNumElts.isInvalid()) {
581e5dd7070Spatrick       switch (LM.getKind()) {
582e5dd7070Spatrick       case LengthModifier::AsShort:
583e5dd7070Spatrick         return Ctx.HalfTy;
584e5dd7070Spatrick       case LengthModifier::AsShortLong:
585e5dd7070Spatrick         return Ctx.FloatTy;
586e5dd7070Spatrick       case LengthModifier::AsLong:
587e5dd7070Spatrick       default:
588e5dd7070Spatrick         return Ctx.DoubleTy;
589e5dd7070Spatrick       }
590e5dd7070Spatrick     }
591e5dd7070Spatrick 
592e5dd7070Spatrick     if (LM.getKind() == LengthModifier::AsLongDouble)
593e5dd7070Spatrick       return Ctx.LongDoubleTy;
594e5dd7070Spatrick     return Ctx.DoubleTy;
595e5dd7070Spatrick   }
596e5dd7070Spatrick 
597e5dd7070Spatrick   if (CS.getKind() == ConversionSpecifier::nArg) {
598e5dd7070Spatrick     switch (LM.getKind()) {
599e5dd7070Spatrick       case LengthModifier::None:
600e5dd7070Spatrick         return ArgType::PtrTo(Ctx.IntTy);
601e5dd7070Spatrick       case LengthModifier::AsChar:
602e5dd7070Spatrick         return ArgType::PtrTo(Ctx.SignedCharTy);
603e5dd7070Spatrick       case LengthModifier::AsShort:
604e5dd7070Spatrick         return ArgType::PtrTo(Ctx.ShortTy);
605e5dd7070Spatrick       case LengthModifier::AsLong:
606e5dd7070Spatrick         return ArgType::PtrTo(Ctx.LongTy);
607e5dd7070Spatrick       case LengthModifier::AsLongLong:
608e5dd7070Spatrick       case LengthModifier::AsQuad:
609e5dd7070Spatrick         return ArgType::PtrTo(Ctx.LongLongTy);
610e5dd7070Spatrick       case LengthModifier::AsIntMax:
611e5dd7070Spatrick         return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
612e5dd7070Spatrick       case LengthModifier::AsSizeT:
613e5dd7070Spatrick         return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));
614e5dd7070Spatrick       case LengthModifier::AsPtrDiff:
615e5dd7070Spatrick         return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
616e5dd7070Spatrick       case LengthModifier::AsLongDouble:
617e5dd7070Spatrick         return ArgType(); // FIXME: Is this a known extension?
618e5dd7070Spatrick       case LengthModifier::AsAllocate:
619e5dd7070Spatrick       case LengthModifier::AsMAllocate:
620e5dd7070Spatrick       case LengthModifier::AsInt32:
621e5dd7070Spatrick       case LengthModifier::AsInt3264:
622e5dd7070Spatrick       case LengthModifier::AsInt64:
623e5dd7070Spatrick       case LengthModifier::AsWide:
624e5dd7070Spatrick         return ArgType::Invalid();
625e5dd7070Spatrick       case LengthModifier::AsShortLong:
626e5dd7070Spatrick         llvm_unreachable("only used for OpenCL which doesn not handle nArg");
627e5dd7070Spatrick     }
628e5dd7070Spatrick   }
629e5dd7070Spatrick 
630e5dd7070Spatrick   switch (CS.getKind()) {
631e5dd7070Spatrick     case ConversionSpecifier::sArg:
632e5dd7070Spatrick       if (LM.getKind() == LengthModifier::AsWideChar) {
633e5dd7070Spatrick         if (IsObjCLiteral)
634e5dd7070Spatrick           return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
635e5dd7070Spatrick                          "const unichar *");
636e5dd7070Spatrick         return ArgType(ArgType::WCStrTy, "wchar_t *");
637e5dd7070Spatrick       }
638e5dd7070Spatrick       if (LM.getKind() == LengthModifier::AsWide)
639e5dd7070Spatrick         return ArgType(ArgType::WCStrTy, "wchar_t *");
640e5dd7070Spatrick       return ArgType::CStrTy;
641e5dd7070Spatrick     case ConversionSpecifier::SArg:
642e5dd7070Spatrick       if (IsObjCLiteral)
643e5dd7070Spatrick         return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
644e5dd7070Spatrick                        "const unichar *");
645e5dd7070Spatrick       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
646e5dd7070Spatrick           LM.getKind() == LengthModifier::AsShort)
647e5dd7070Spatrick         return ArgType::CStrTy;
648e5dd7070Spatrick       return ArgType(ArgType::WCStrTy, "wchar_t *");
649e5dd7070Spatrick     case ConversionSpecifier::CArg:
650e5dd7070Spatrick       if (IsObjCLiteral)
651e5dd7070Spatrick         return ArgType(Ctx.UnsignedShortTy, "unichar");
652e5dd7070Spatrick       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
653e5dd7070Spatrick           LM.getKind() == LengthModifier::AsShort)
654e5dd7070Spatrick         return Ctx.IntTy;
655e5dd7070Spatrick       return ArgType(Ctx.WideCharTy, "wchar_t");
656e5dd7070Spatrick     case ConversionSpecifier::pArg:
657e5dd7070Spatrick     case ConversionSpecifier::PArg:
658e5dd7070Spatrick       return ArgType::CPointerTy;
659e5dd7070Spatrick     case ConversionSpecifier::ObjCObjArg:
660e5dd7070Spatrick       return ArgType::ObjCPointerTy;
661e5dd7070Spatrick     default:
662e5dd7070Spatrick       break;
663e5dd7070Spatrick   }
664e5dd7070Spatrick 
665e5dd7070Spatrick   // FIXME: Handle other cases.
666e5dd7070Spatrick   return ArgType();
667e5dd7070Spatrick }
668e5dd7070Spatrick 
669e5dd7070Spatrick 
getArgType(ASTContext & Ctx,bool IsObjCLiteral) const670e5dd7070Spatrick ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
671e5dd7070Spatrick                                     bool IsObjCLiteral) const {
672e5dd7070Spatrick   const PrintfConversionSpecifier &CS = getConversionSpecifier();
673e5dd7070Spatrick 
674e5dd7070Spatrick   if (!CS.consumesDataArgument())
675e5dd7070Spatrick     return ArgType::Invalid();
676e5dd7070Spatrick 
677e5dd7070Spatrick   ArgType ScalarTy = getScalarArgType(Ctx, IsObjCLiteral);
678e5dd7070Spatrick   if (!ScalarTy.isValid() || VectorNumElts.isInvalid())
679e5dd7070Spatrick     return ScalarTy;
680e5dd7070Spatrick 
681e5dd7070Spatrick   return ScalarTy.makeVectorType(Ctx, VectorNumElts.getConstantAmount());
682e5dd7070Spatrick }
683e5dd7070Spatrick 
fixType(QualType QT,const LangOptions & LangOpt,ASTContext & Ctx,bool IsObjCLiteral)684e5dd7070Spatrick bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
685e5dd7070Spatrick                               ASTContext &Ctx, bool IsObjCLiteral) {
686e5dd7070Spatrick   // %n is different from other conversion specifiers; don't try to fix it.
687e5dd7070Spatrick   if (CS.getKind() == ConversionSpecifier::nArg)
688e5dd7070Spatrick     return false;
689e5dd7070Spatrick 
690e5dd7070Spatrick   // Handle Objective-C objects first. Note that while the '%@' specifier will
691e5dd7070Spatrick   // not warn for structure pointer or void pointer arguments (because that's
692e5dd7070Spatrick   // how CoreFoundation objects are implemented), we only show a fixit for '%@'
693e5dd7070Spatrick   // if we know it's an object (block, id, class, or __attribute__((NSObject))).
694e5dd7070Spatrick   if (QT->isObjCRetainableType()) {
695e5dd7070Spatrick     if (!IsObjCLiteral)
696e5dd7070Spatrick       return false;
697e5dd7070Spatrick 
698e5dd7070Spatrick     CS.setKind(ConversionSpecifier::ObjCObjArg);
699e5dd7070Spatrick 
700e5dd7070Spatrick     // Disable irrelevant flags
701e5dd7070Spatrick     HasThousandsGrouping = false;
702e5dd7070Spatrick     HasPlusPrefix = false;
703e5dd7070Spatrick     HasSpacePrefix = false;
704e5dd7070Spatrick     HasAlternativeForm = false;
705e5dd7070Spatrick     HasLeadingZeroes = false;
706e5dd7070Spatrick     Precision.setHowSpecified(OptionalAmount::NotSpecified);
707e5dd7070Spatrick     LM.setKind(LengthModifier::None);
708e5dd7070Spatrick 
709e5dd7070Spatrick     return true;
710e5dd7070Spatrick   }
711e5dd7070Spatrick 
712e5dd7070Spatrick   // Handle strings next (char *, wchar_t *)
713e5dd7070Spatrick   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
714e5dd7070Spatrick     CS.setKind(ConversionSpecifier::sArg);
715e5dd7070Spatrick 
716e5dd7070Spatrick     // Disable irrelevant flags
717*12c85518Srobert     HasAlternativeForm = false;
718*12c85518Srobert     HasLeadingZeroes = false;
719e5dd7070Spatrick 
720e5dd7070Spatrick     // Set the long length modifier for wide characters
721e5dd7070Spatrick     if (QT->getPointeeType()->isWideCharType())
722e5dd7070Spatrick       LM.setKind(LengthModifier::AsWideChar);
723e5dd7070Spatrick     else
724e5dd7070Spatrick       LM.setKind(LengthModifier::None);
725e5dd7070Spatrick 
726e5dd7070Spatrick     return true;
727e5dd7070Spatrick   }
728e5dd7070Spatrick 
729e5dd7070Spatrick   // If it's an enum, get its underlying type.
730e5dd7070Spatrick   if (const EnumType *ETy = QT->getAs<EnumType>())
731e5dd7070Spatrick     QT = ETy->getDecl()->getIntegerType();
732e5dd7070Spatrick 
733e5dd7070Spatrick   const BuiltinType *BT = QT->getAs<BuiltinType>();
734e5dd7070Spatrick   if (!BT) {
735e5dd7070Spatrick     const VectorType *VT = QT->getAs<VectorType>();
736e5dd7070Spatrick     if (VT) {
737e5dd7070Spatrick       QT = VT->getElementType();
738e5dd7070Spatrick       BT = QT->getAs<BuiltinType>();
739e5dd7070Spatrick       VectorNumElts = OptionalAmount(VT->getNumElements());
740e5dd7070Spatrick     }
741e5dd7070Spatrick   }
742e5dd7070Spatrick 
743e5dd7070Spatrick   // We can only work with builtin types.
744e5dd7070Spatrick   if (!BT)
745e5dd7070Spatrick     return false;
746e5dd7070Spatrick 
747e5dd7070Spatrick   // Set length modifier
748e5dd7070Spatrick   switch (BT->getKind()) {
749e5dd7070Spatrick   case BuiltinType::Bool:
750e5dd7070Spatrick   case BuiltinType::WChar_U:
751e5dd7070Spatrick   case BuiltinType::WChar_S:
752e5dd7070Spatrick   case BuiltinType::Char8: // FIXME: Treat like 'char'?
753e5dd7070Spatrick   case BuiltinType::Char16:
754e5dd7070Spatrick   case BuiltinType::Char32:
755e5dd7070Spatrick   case BuiltinType::UInt128:
756e5dd7070Spatrick   case BuiltinType::Int128:
757e5dd7070Spatrick   case BuiltinType::Half:
758ec727ea7Spatrick   case BuiltinType::BFloat16:
759e5dd7070Spatrick   case BuiltinType::Float16:
760e5dd7070Spatrick   case BuiltinType::Float128:
761*12c85518Srobert   case BuiltinType::Ibm128:
762e5dd7070Spatrick   case BuiltinType::ShortAccum:
763e5dd7070Spatrick   case BuiltinType::Accum:
764e5dd7070Spatrick   case BuiltinType::LongAccum:
765e5dd7070Spatrick   case BuiltinType::UShortAccum:
766e5dd7070Spatrick   case BuiltinType::UAccum:
767e5dd7070Spatrick   case BuiltinType::ULongAccum:
768e5dd7070Spatrick   case BuiltinType::ShortFract:
769e5dd7070Spatrick   case BuiltinType::Fract:
770e5dd7070Spatrick   case BuiltinType::LongFract:
771e5dd7070Spatrick   case BuiltinType::UShortFract:
772e5dd7070Spatrick   case BuiltinType::UFract:
773e5dd7070Spatrick   case BuiltinType::ULongFract:
774e5dd7070Spatrick   case BuiltinType::SatShortAccum:
775e5dd7070Spatrick   case BuiltinType::SatAccum:
776e5dd7070Spatrick   case BuiltinType::SatLongAccum:
777e5dd7070Spatrick   case BuiltinType::SatUShortAccum:
778e5dd7070Spatrick   case BuiltinType::SatUAccum:
779e5dd7070Spatrick   case BuiltinType::SatULongAccum:
780e5dd7070Spatrick   case BuiltinType::SatShortFract:
781e5dd7070Spatrick   case BuiltinType::SatFract:
782e5dd7070Spatrick   case BuiltinType::SatLongFract:
783e5dd7070Spatrick   case BuiltinType::SatUShortFract:
784e5dd7070Spatrick   case BuiltinType::SatUFract:
785e5dd7070Spatrick   case BuiltinType::SatULongFract:
786e5dd7070Spatrick     // Various types which are non-trivial to correct.
787e5dd7070Spatrick     return false;
788e5dd7070Spatrick 
789e5dd7070Spatrick #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
790e5dd7070Spatrick   case BuiltinType::Id:
791e5dd7070Spatrick #include "clang/Basic/OpenCLImageTypes.def"
792e5dd7070Spatrick #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
793e5dd7070Spatrick   case BuiltinType::Id:
794e5dd7070Spatrick #include "clang/Basic/OpenCLExtensionTypes.def"
795e5dd7070Spatrick #define SVE_TYPE(Name, Id, SingletonId) \
796e5dd7070Spatrick   case BuiltinType::Id:
797e5dd7070Spatrick #include "clang/Basic/AArch64SVEACLETypes.def"
798a9ac8606Spatrick #define PPC_VECTOR_TYPE(Name, Id, Size) \
799a9ac8606Spatrick   case BuiltinType::Id:
800a9ac8606Spatrick #include "clang/Basic/PPCTypes.def"
801a9ac8606Spatrick #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
802a9ac8606Spatrick #include "clang/Basic/RISCVVTypes.def"
803e5dd7070Spatrick #define SIGNED_TYPE(Id, SingletonId)
804e5dd7070Spatrick #define UNSIGNED_TYPE(Id, SingletonId)
805e5dd7070Spatrick #define FLOATING_TYPE(Id, SingletonId)
806e5dd7070Spatrick #define BUILTIN_TYPE(Id, SingletonId) \
807e5dd7070Spatrick   case BuiltinType::Id:
808e5dd7070Spatrick #include "clang/AST/BuiltinTypes.def"
809e5dd7070Spatrick     // Misc other stuff which doesn't make sense here.
810e5dd7070Spatrick     return false;
811e5dd7070Spatrick 
812e5dd7070Spatrick   case BuiltinType::UInt:
813e5dd7070Spatrick   case BuiltinType::Int:
814e5dd7070Spatrick   case BuiltinType::Float:
815e5dd7070Spatrick     LM.setKind(VectorNumElts.isInvalid() ?
816e5dd7070Spatrick                LengthModifier::None : LengthModifier::AsShortLong);
817e5dd7070Spatrick     break;
818e5dd7070Spatrick   case BuiltinType::Double:
819e5dd7070Spatrick     LM.setKind(VectorNumElts.isInvalid() ?
820e5dd7070Spatrick                LengthModifier::None : LengthModifier::AsLong);
821e5dd7070Spatrick     break;
822e5dd7070Spatrick   case BuiltinType::Char_U:
823e5dd7070Spatrick   case BuiltinType::UChar:
824e5dd7070Spatrick   case BuiltinType::Char_S:
825e5dd7070Spatrick   case BuiltinType::SChar:
826e5dd7070Spatrick     LM.setKind(LengthModifier::AsChar);
827e5dd7070Spatrick     break;
828e5dd7070Spatrick 
829e5dd7070Spatrick   case BuiltinType::Short:
830e5dd7070Spatrick   case BuiltinType::UShort:
831e5dd7070Spatrick     LM.setKind(LengthModifier::AsShort);
832e5dd7070Spatrick     break;
833e5dd7070Spatrick 
834e5dd7070Spatrick   case BuiltinType::Long:
835e5dd7070Spatrick   case BuiltinType::ULong:
836e5dd7070Spatrick     LM.setKind(LengthModifier::AsLong);
837e5dd7070Spatrick     break;
838e5dd7070Spatrick 
839e5dd7070Spatrick   case BuiltinType::LongLong:
840e5dd7070Spatrick   case BuiltinType::ULongLong:
841e5dd7070Spatrick     LM.setKind(LengthModifier::AsLongLong);
842e5dd7070Spatrick     break;
843e5dd7070Spatrick 
844e5dd7070Spatrick   case BuiltinType::LongDouble:
845e5dd7070Spatrick     LM.setKind(LengthModifier::AsLongDouble);
846e5dd7070Spatrick     break;
847e5dd7070Spatrick   }
848e5dd7070Spatrick 
849e5dd7070Spatrick   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
850*12c85518Srobert   if (LangOpt.C99 || LangOpt.CPlusPlus11)
851e5dd7070Spatrick     namedTypeToLengthModifier(QT, LM);
852e5dd7070Spatrick 
853e5dd7070Spatrick   // If fixing the length modifier was enough, we might be done.
854e5dd7070Spatrick   if (hasValidLengthModifier(Ctx.getTargetInfo(), LangOpt)) {
855e5dd7070Spatrick     // If we're going to offer a fix anyway, make sure the sign matches.
856e5dd7070Spatrick     switch (CS.getKind()) {
857e5dd7070Spatrick     case ConversionSpecifier::uArg:
858e5dd7070Spatrick     case ConversionSpecifier::UArg:
859e5dd7070Spatrick       if (QT->isSignedIntegerType())
860e5dd7070Spatrick         CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
861e5dd7070Spatrick       break;
862e5dd7070Spatrick     case ConversionSpecifier::dArg:
863e5dd7070Spatrick     case ConversionSpecifier::DArg:
864e5dd7070Spatrick     case ConversionSpecifier::iArg:
865e5dd7070Spatrick       if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
866e5dd7070Spatrick         CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
867e5dd7070Spatrick       break;
868e5dd7070Spatrick     default:
869e5dd7070Spatrick       // Other specifiers do not have signed/unsigned variants.
870e5dd7070Spatrick       break;
871e5dd7070Spatrick     }
872e5dd7070Spatrick 
873e5dd7070Spatrick     const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
874e5dd7070Spatrick     if (ATR.isValid() && ATR.matchesType(Ctx, QT))
875e5dd7070Spatrick       return true;
876e5dd7070Spatrick   }
877e5dd7070Spatrick 
878e5dd7070Spatrick   // Set conversion specifier and disable any flags which do not apply to it.
879e5dd7070Spatrick   // Let typedefs to char fall through to int, as %c is silly for uint8_t.
880*12c85518Srobert   if (!QT->getAs<TypedefType>() && QT->isCharType()) {
881e5dd7070Spatrick     CS.setKind(ConversionSpecifier::cArg);
882e5dd7070Spatrick     LM.setKind(LengthModifier::None);
883e5dd7070Spatrick     Precision.setHowSpecified(OptionalAmount::NotSpecified);
884*12c85518Srobert     HasAlternativeForm = false;
885*12c85518Srobert     HasLeadingZeroes = false;
886*12c85518Srobert     HasPlusPrefix = false;
887e5dd7070Spatrick   }
888e5dd7070Spatrick   // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
889e5dd7070Spatrick   else if (QT->isRealFloatingType()) {
890e5dd7070Spatrick     CS.setKind(ConversionSpecifier::fArg);
891*12c85518Srobert   } else if (QT->isSignedIntegerType()) {
892e5dd7070Spatrick     CS.setKind(ConversionSpecifier::dArg);
893*12c85518Srobert     HasAlternativeForm = false;
894*12c85518Srobert   } else if (QT->isUnsignedIntegerType()) {
895e5dd7070Spatrick     CS.setKind(ConversionSpecifier::uArg);
896*12c85518Srobert     HasAlternativeForm = false;
897*12c85518Srobert     HasPlusPrefix = false;
898e5dd7070Spatrick   } else {
899e5dd7070Spatrick     llvm_unreachable("Unexpected type");
900e5dd7070Spatrick   }
901e5dd7070Spatrick 
902e5dd7070Spatrick   return true;
903e5dd7070Spatrick }
904e5dd7070Spatrick 
toString(raw_ostream & os) const905e5dd7070Spatrick void PrintfSpecifier::toString(raw_ostream &os) const {
906e5dd7070Spatrick   // Whilst some features have no defined order, we are using the order
907e5dd7070Spatrick   // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
908e5dd7070Spatrick   os << "%";
909e5dd7070Spatrick 
910e5dd7070Spatrick   // Positional args
911e5dd7070Spatrick   if (usesPositionalArg()) {
912e5dd7070Spatrick     os << getPositionalArgIndex() << "$";
913e5dd7070Spatrick   }
914e5dd7070Spatrick 
915e5dd7070Spatrick   // Conversion flags
916e5dd7070Spatrick   if (IsLeftJustified)    os << "-";
917e5dd7070Spatrick   if (HasPlusPrefix)      os << "+";
918e5dd7070Spatrick   if (HasSpacePrefix)     os << " ";
919e5dd7070Spatrick   if (HasAlternativeForm) os << "#";
920e5dd7070Spatrick   if (HasLeadingZeroes)   os << "0";
921e5dd7070Spatrick 
922e5dd7070Spatrick   // Minimum field width
923e5dd7070Spatrick   FieldWidth.toString(os);
924e5dd7070Spatrick   // Precision
925e5dd7070Spatrick   Precision.toString(os);
926e5dd7070Spatrick 
927e5dd7070Spatrick   // Vector modifier
928e5dd7070Spatrick   if (!VectorNumElts.isInvalid())
929e5dd7070Spatrick     os << 'v' << VectorNumElts.getConstantAmount();
930e5dd7070Spatrick 
931e5dd7070Spatrick   // Length modifier
932e5dd7070Spatrick   os << LM.toString();
933e5dd7070Spatrick   // Conversion specifier
934e5dd7070Spatrick   os << CS.toString();
935e5dd7070Spatrick }
936e5dd7070Spatrick 
hasValidPlusPrefix() const937e5dd7070Spatrick bool PrintfSpecifier::hasValidPlusPrefix() const {
938e5dd7070Spatrick   if (!HasPlusPrefix)
939e5dd7070Spatrick     return true;
940e5dd7070Spatrick 
941e5dd7070Spatrick   // The plus prefix only makes sense for signed conversions
942e5dd7070Spatrick   switch (CS.getKind()) {
943e5dd7070Spatrick   case ConversionSpecifier::dArg:
944e5dd7070Spatrick   case ConversionSpecifier::DArg:
945e5dd7070Spatrick   case ConversionSpecifier::iArg:
946e5dd7070Spatrick   case ConversionSpecifier::fArg:
947e5dd7070Spatrick   case ConversionSpecifier::FArg:
948e5dd7070Spatrick   case ConversionSpecifier::eArg:
949e5dd7070Spatrick   case ConversionSpecifier::EArg:
950e5dd7070Spatrick   case ConversionSpecifier::gArg:
951e5dd7070Spatrick   case ConversionSpecifier::GArg:
952e5dd7070Spatrick   case ConversionSpecifier::aArg:
953e5dd7070Spatrick   case ConversionSpecifier::AArg:
954e5dd7070Spatrick   case ConversionSpecifier::FreeBSDrArg:
955e5dd7070Spatrick   case ConversionSpecifier::FreeBSDyArg:
956e5dd7070Spatrick     return true;
957e5dd7070Spatrick 
958e5dd7070Spatrick   default:
959e5dd7070Spatrick     return false;
960e5dd7070Spatrick   }
961e5dd7070Spatrick }
962e5dd7070Spatrick 
hasValidAlternativeForm() const963e5dd7070Spatrick bool PrintfSpecifier::hasValidAlternativeForm() const {
964e5dd7070Spatrick   if (!HasAlternativeForm)
965e5dd7070Spatrick     return true;
966e5dd7070Spatrick 
967*12c85518Srobert   // Alternate form flag only valid with the bBoxXaAeEfFgG conversions
968e5dd7070Spatrick   switch (CS.getKind()) {
969*12c85518Srobert   case ConversionSpecifier::bArg:
970*12c85518Srobert   case ConversionSpecifier::BArg:
971e5dd7070Spatrick   case ConversionSpecifier::oArg:
972e5dd7070Spatrick   case ConversionSpecifier::OArg:
973e5dd7070Spatrick   case ConversionSpecifier::xArg:
974e5dd7070Spatrick   case ConversionSpecifier::XArg:
975e5dd7070Spatrick   case ConversionSpecifier::aArg:
976e5dd7070Spatrick   case ConversionSpecifier::AArg:
977e5dd7070Spatrick   case ConversionSpecifier::eArg:
978e5dd7070Spatrick   case ConversionSpecifier::EArg:
979e5dd7070Spatrick   case ConversionSpecifier::fArg:
980e5dd7070Spatrick   case ConversionSpecifier::FArg:
981e5dd7070Spatrick   case ConversionSpecifier::gArg:
982e5dd7070Spatrick   case ConversionSpecifier::GArg:
983e5dd7070Spatrick   case ConversionSpecifier::FreeBSDrArg:
984e5dd7070Spatrick   case ConversionSpecifier::FreeBSDyArg:
985e5dd7070Spatrick     return true;
986e5dd7070Spatrick 
987e5dd7070Spatrick   default:
988e5dd7070Spatrick     return false;
989e5dd7070Spatrick   }
990e5dd7070Spatrick }
991e5dd7070Spatrick 
hasValidLeadingZeros() const992e5dd7070Spatrick bool PrintfSpecifier::hasValidLeadingZeros() const {
993e5dd7070Spatrick   if (!HasLeadingZeroes)
994e5dd7070Spatrick     return true;
995e5dd7070Spatrick 
996*12c85518Srobert   // Leading zeroes flag only valid with the bBdiouxXaAeEfFgG conversions
997e5dd7070Spatrick   switch (CS.getKind()) {
998*12c85518Srobert   case ConversionSpecifier::bArg:
999*12c85518Srobert   case ConversionSpecifier::BArg:
1000e5dd7070Spatrick   case ConversionSpecifier::dArg:
1001e5dd7070Spatrick   case ConversionSpecifier::DArg:
1002e5dd7070Spatrick   case ConversionSpecifier::iArg:
1003e5dd7070Spatrick   case ConversionSpecifier::oArg:
1004e5dd7070Spatrick   case ConversionSpecifier::OArg:
1005e5dd7070Spatrick   case ConversionSpecifier::uArg:
1006e5dd7070Spatrick   case ConversionSpecifier::UArg:
1007e5dd7070Spatrick   case ConversionSpecifier::xArg:
1008e5dd7070Spatrick   case ConversionSpecifier::XArg:
1009e5dd7070Spatrick   case ConversionSpecifier::aArg:
1010e5dd7070Spatrick   case ConversionSpecifier::AArg:
1011e5dd7070Spatrick   case ConversionSpecifier::eArg:
1012e5dd7070Spatrick   case ConversionSpecifier::EArg:
1013e5dd7070Spatrick   case ConversionSpecifier::fArg:
1014e5dd7070Spatrick   case ConversionSpecifier::FArg:
1015e5dd7070Spatrick   case ConversionSpecifier::gArg:
1016e5dd7070Spatrick   case ConversionSpecifier::GArg:
1017e5dd7070Spatrick   case ConversionSpecifier::FreeBSDrArg:
1018e5dd7070Spatrick   case ConversionSpecifier::FreeBSDyArg:
1019e5dd7070Spatrick     return true;
1020e5dd7070Spatrick 
1021e5dd7070Spatrick   default:
1022e5dd7070Spatrick     return false;
1023e5dd7070Spatrick   }
1024e5dd7070Spatrick }
1025e5dd7070Spatrick 
hasValidSpacePrefix() const1026e5dd7070Spatrick bool PrintfSpecifier::hasValidSpacePrefix() const {
1027e5dd7070Spatrick   if (!HasSpacePrefix)
1028e5dd7070Spatrick     return true;
1029e5dd7070Spatrick 
1030e5dd7070Spatrick   // The space prefix only makes sense for signed conversions
1031e5dd7070Spatrick   switch (CS.getKind()) {
1032e5dd7070Spatrick   case ConversionSpecifier::dArg:
1033e5dd7070Spatrick   case ConversionSpecifier::DArg:
1034e5dd7070Spatrick   case ConversionSpecifier::iArg:
1035e5dd7070Spatrick   case ConversionSpecifier::fArg:
1036e5dd7070Spatrick   case ConversionSpecifier::FArg:
1037e5dd7070Spatrick   case ConversionSpecifier::eArg:
1038e5dd7070Spatrick   case ConversionSpecifier::EArg:
1039e5dd7070Spatrick   case ConversionSpecifier::gArg:
1040e5dd7070Spatrick   case ConversionSpecifier::GArg:
1041e5dd7070Spatrick   case ConversionSpecifier::aArg:
1042e5dd7070Spatrick   case ConversionSpecifier::AArg:
1043e5dd7070Spatrick   case ConversionSpecifier::FreeBSDrArg:
1044e5dd7070Spatrick   case ConversionSpecifier::FreeBSDyArg:
1045e5dd7070Spatrick     return true;
1046e5dd7070Spatrick 
1047e5dd7070Spatrick   default:
1048e5dd7070Spatrick     return false;
1049e5dd7070Spatrick   }
1050e5dd7070Spatrick }
1051e5dd7070Spatrick 
hasValidLeftJustified() const1052e5dd7070Spatrick bool PrintfSpecifier::hasValidLeftJustified() const {
1053e5dd7070Spatrick   if (!IsLeftJustified)
1054e5dd7070Spatrick     return true;
1055e5dd7070Spatrick 
1056e5dd7070Spatrick   // The left justified flag is valid for all conversions except n
1057e5dd7070Spatrick   switch (CS.getKind()) {
1058e5dd7070Spatrick   case ConversionSpecifier::nArg:
1059e5dd7070Spatrick     return false;
1060e5dd7070Spatrick 
1061e5dd7070Spatrick   default:
1062e5dd7070Spatrick     return true;
1063e5dd7070Spatrick   }
1064e5dd7070Spatrick }
1065e5dd7070Spatrick 
hasValidThousandsGroupingPrefix() const1066e5dd7070Spatrick bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
1067e5dd7070Spatrick   if (!HasThousandsGrouping)
1068e5dd7070Spatrick     return true;
1069e5dd7070Spatrick 
1070e5dd7070Spatrick   switch (CS.getKind()) {
1071e5dd7070Spatrick     case ConversionSpecifier::dArg:
1072e5dd7070Spatrick     case ConversionSpecifier::DArg:
1073e5dd7070Spatrick     case ConversionSpecifier::iArg:
1074e5dd7070Spatrick     case ConversionSpecifier::uArg:
1075e5dd7070Spatrick     case ConversionSpecifier::UArg:
1076e5dd7070Spatrick     case ConversionSpecifier::fArg:
1077e5dd7070Spatrick     case ConversionSpecifier::FArg:
1078e5dd7070Spatrick     case ConversionSpecifier::gArg:
1079e5dd7070Spatrick     case ConversionSpecifier::GArg:
1080e5dd7070Spatrick       return true;
1081e5dd7070Spatrick     default:
1082e5dd7070Spatrick       return false;
1083e5dd7070Spatrick   }
1084e5dd7070Spatrick }
1085e5dd7070Spatrick 
hasValidPrecision() const1086e5dd7070Spatrick bool PrintfSpecifier::hasValidPrecision() const {
1087e5dd7070Spatrick   if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
1088e5dd7070Spatrick     return true;
1089e5dd7070Spatrick 
1090*12c85518Srobert   // Precision is only valid with the bBdiouxXaAeEfFgGsP conversions
1091e5dd7070Spatrick   switch (CS.getKind()) {
1092*12c85518Srobert   case ConversionSpecifier::bArg:
1093*12c85518Srobert   case ConversionSpecifier::BArg:
1094e5dd7070Spatrick   case ConversionSpecifier::dArg:
1095e5dd7070Spatrick   case ConversionSpecifier::DArg:
1096e5dd7070Spatrick   case ConversionSpecifier::iArg:
1097e5dd7070Spatrick   case ConversionSpecifier::oArg:
1098e5dd7070Spatrick   case ConversionSpecifier::OArg:
1099e5dd7070Spatrick   case ConversionSpecifier::uArg:
1100e5dd7070Spatrick   case ConversionSpecifier::UArg:
1101e5dd7070Spatrick   case ConversionSpecifier::xArg:
1102e5dd7070Spatrick   case ConversionSpecifier::XArg:
1103e5dd7070Spatrick   case ConversionSpecifier::aArg:
1104e5dd7070Spatrick   case ConversionSpecifier::AArg:
1105e5dd7070Spatrick   case ConversionSpecifier::eArg:
1106e5dd7070Spatrick   case ConversionSpecifier::EArg:
1107e5dd7070Spatrick   case ConversionSpecifier::fArg:
1108e5dd7070Spatrick   case ConversionSpecifier::FArg:
1109e5dd7070Spatrick   case ConversionSpecifier::gArg:
1110e5dd7070Spatrick   case ConversionSpecifier::GArg:
1111e5dd7070Spatrick   case ConversionSpecifier::sArg:
1112e5dd7070Spatrick   case ConversionSpecifier::FreeBSDrArg:
1113e5dd7070Spatrick   case ConversionSpecifier::FreeBSDyArg:
1114e5dd7070Spatrick   case ConversionSpecifier::PArg:
1115e5dd7070Spatrick     return true;
1116e5dd7070Spatrick 
1117e5dd7070Spatrick   default:
1118e5dd7070Spatrick     return false;
1119e5dd7070Spatrick   }
1120e5dd7070Spatrick }
hasValidFieldWidth() const1121e5dd7070Spatrick bool PrintfSpecifier::hasValidFieldWidth() const {
1122e5dd7070Spatrick   if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
1123e5dd7070Spatrick       return true;
1124e5dd7070Spatrick 
1125e5dd7070Spatrick   // The field width is valid for all conversions except n
1126e5dd7070Spatrick   switch (CS.getKind()) {
1127e5dd7070Spatrick   case ConversionSpecifier::nArg:
1128e5dd7070Spatrick     return false;
1129e5dd7070Spatrick 
1130e5dd7070Spatrick   default:
1131e5dd7070Spatrick     return true;
1132e5dd7070Spatrick   }
1133e5dd7070Spatrick }
1134