xref: /minix3/external/bsd/llvm/dist/clang/lib/Analysis/PrintfFormatString.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // Handling of format string in printf and friends.  The structure of format
11f4a2713aSLionel Sambuc // strings for fprintf() are described in C99 7.19.6.1.
12f4a2713aSLionel Sambuc //
13f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
14f4a2713aSLionel Sambuc 
15f4a2713aSLionel Sambuc #include "clang/Analysis/Analyses/FormatString.h"
16f4a2713aSLionel Sambuc #include "FormatStringParsing.h"
17f4a2713aSLionel Sambuc #include "clang/Basic/TargetInfo.h"
18f4a2713aSLionel Sambuc 
19f4a2713aSLionel Sambuc using clang::analyze_format_string::ArgType;
20f4a2713aSLionel Sambuc using clang::analyze_format_string::FormatStringHandler;
21f4a2713aSLionel Sambuc using clang::analyze_format_string::LengthModifier;
22f4a2713aSLionel Sambuc using clang::analyze_format_string::OptionalAmount;
23f4a2713aSLionel Sambuc using clang::analyze_format_string::ConversionSpecifier;
24f4a2713aSLionel Sambuc using clang::analyze_printf::PrintfSpecifier;
25f4a2713aSLionel Sambuc 
26f4a2713aSLionel Sambuc using namespace clang;
27f4a2713aSLionel Sambuc 
28f4a2713aSLionel Sambuc typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier>
29f4a2713aSLionel Sambuc         PrintfSpecifierResult;
30f4a2713aSLionel Sambuc 
31f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
32f4a2713aSLionel Sambuc // Methods for parsing format strings.
33f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
34f4a2713aSLionel Sambuc 
35f4a2713aSLionel Sambuc using analyze_format_string::ParseNonPositionAmount;
36f4a2713aSLionel Sambuc 
ParsePrecision(FormatStringHandler & H,PrintfSpecifier & FS,const char * Start,const char * & Beg,const char * E,unsigned * argIndex)37f4a2713aSLionel Sambuc static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,
38f4a2713aSLionel Sambuc                            const char *Start, const char *&Beg, const char *E,
39f4a2713aSLionel Sambuc                            unsigned *argIndex) {
40f4a2713aSLionel Sambuc   if (argIndex) {
41f4a2713aSLionel Sambuc     FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));
42f4a2713aSLionel Sambuc   } else {
43f4a2713aSLionel Sambuc     const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,
44f4a2713aSLionel Sambuc                                            analyze_format_string::PrecisionPos);
45f4a2713aSLionel Sambuc     if (Amt.isInvalid())
46f4a2713aSLionel Sambuc       return true;
47f4a2713aSLionel Sambuc     FS.setPrecision(Amt);
48f4a2713aSLionel Sambuc   }
49f4a2713aSLionel Sambuc   return false;
50f4a2713aSLionel Sambuc }
51f4a2713aSLionel Sambuc 
ParsePrintfSpecifier(FormatStringHandler & H,const char * & Beg,const char * E,unsigned & argIndex,const LangOptions & LO,const TargetInfo & Target,bool Warn)52f4a2713aSLionel Sambuc static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
53f4a2713aSLionel Sambuc                                                   const char *&Beg,
54f4a2713aSLionel Sambuc                                                   const char *E,
55f4a2713aSLionel Sambuc                                                   unsigned &argIndex,
56f4a2713aSLionel Sambuc                                                   const LangOptions &LO,
57*0a6a1f1dSLionel Sambuc                                                   const TargetInfo &Target,
58*0a6a1f1dSLionel Sambuc                                                   bool Warn) {
59f4a2713aSLionel Sambuc 
60f4a2713aSLionel Sambuc   using namespace clang::analyze_format_string;
61f4a2713aSLionel Sambuc   using namespace clang::analyze_printf;
62f4a2713aSLionel Sambuc 
63f4a2713aSLionel Sambuc   const char *I = Beg;
64*0a6a1f1dSLionel Sambuc   const char *Start = nullptr;
65f4a2713aSLionel Sambuc   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
66f4a2713aSLionel Sambuc 
67f4a2713aSLionel Sambuc   // Look for a '%' character that indicates the start of a format specifier.
68f4a2713aSLionel Sambuc   for ( ; I != E ; ++I) {
69f4a2713aSLionel Sambuc     char c = *I;
70f4a2713aSLionel Sambuc     if (c == '\0') {
71f4a2713aSLionel Sambuc       // Detect spurious null characters, which are likely errors.
72f4a2713aSLionel Sambuc       H.HandleNullChar(I);
73f4a2713aSLionel Sambuc       return true;
74f4a2713aSLionel Sambuc     }
75f4a2713aSLionel Sambuc     if (c == '%') {
76f4a2713aSLionel Sambuc       Start = I++;  // Record the start of the format specifier.
77f4a2713aSLionel Sambuc       break;
78f4a2713aSLionel Sambuc     }
79f4a2713aSLionel Sambuc   }
80f4a2713aSLionel Sambuc 
81f4a2713aSLionel Sambuc   // No format specifier found?
82f4a2713aSLionel Sambuc   if (!Start)
83f4a2713aSLionel Sambuc     return false;
84f4a2713aSLionel Sambuc 
85f4a2713aSLionel Sambuc   if (I == E) {
86f4a2713aSLionel Sambuc     // No more characters left?
87*0a6a1f1dSLionel Sambuc     if (Warn)
88f4a2713aSLionel Sambuc       H.HandleIncompleteSpecifier(Start, E - Start);
89f4a2713aSLionel Sambuc     return true;
90f4a2713aSLionel Sambuc   }
91f4a2713aSLionel Sambuc 
92f4a2713aSLionel Sambuc   PrintfSpecifier FS;
93f4a2713aSLionel Sambuc   if (ParseArgPosition(H, FS, Start, I, E))
94f4a2713aSLionel Sambuc     return true;
95f4a2713aSLionel Sambuc 
96f4a2713aSLionel Sambuc   if (I == E) {
97f4a2713aSLionel Sambuc     // No more characters left?
98*0a6a1f1dSLionel Sambuc     if (Warn)
99f4a2713aSLionel Sambuc       H.HandleIncompleteSpecifier(Start, E - Start);
100f4a2713aSLionel Sambuc     return true;
101f4a2713aSLionel Sambuc   }
102f4a2713aSLionel Sambuc 
103f4a2713aSLionel Sambuc   // Look for flags (if any).
104f4a2713aSLionel Sambuc   bool hasMore = true;
105f4a2713aSLionel Sambuc   for ( ; I != E; ++I) {
106f4a2713aSLionel Sambuc     switch (*I) {
107f4a2713aSLionel Sambuc       default: hasMore = false; break;
108f4a2713aSLionel Sambuc       case '\'':
109f4a2713aSLionel Sambuc         // FIXME: POSIX specific.  Always accept?
110f4a2713aSLionel Sambuc         FS.setHasThousandsGrouping(I);
111f4a2713aSLionel Sambuc         break;
112f4a2713aSLionel Sambuc       case '-': FS.setIsLeftJustified(I); break;
113f4a2713aSLionel Sambuc       case '+': FS.setHasPlusPrefix(I); break;
114f4a2713aSLionel Sambuc       case ' ': FS.setHasSpacePrefix(I); break;
115f4a2713aSLionel Sambuc       case '#': FS.setHasAlternativeForm(I); break;
116f4a2713aSLionel Sambuc       case '0': FS.setHasLeadingZeros(I); break;
117f4a2713aSLionel Sambuc     }
118f4a2713aSLionel Sambuc     if (!hasMore)
119f4a2713aSLionel Sambuc       break;
120f4a2713aSLionel Sambuc   }
121f4a2713aSLionel Sambuc 
122f4a2713aSLionel Sambuc   if (I == E) {
123f4a2713aSLionel Sambuc     // No more characters left?
124*0a6a1f1dSLionel Sambuc     if (Warn)
125f4a2713aSLionel Sambuc       H.HandleIncompleteSpecifier(Start, E - Start);
126f4a2713aSLionel Sambuc     return true;
127f4a2713aSLionel Sambuc   }
128f4a2713aSLionel Sambuc 
129f4a2713aSLionel Sambuc   // Look for the field width (if any).
130f4a2713aSLionel Sambuc   if (ParseFieldWidth(H, FS, Start, I, E,
131*0a6a1f1dSLionel Sambuc                       FS.usesPositionalArg() ? nullptr : &argIndex))
132f4a2713aSLionel Sambuc     return true;
133f4a2713aSLionel Sambuc 
134f4a2713aSLionel Sambuc   if (I == E) {
135f4a2713aSLionel Sambuc     // No more characters left?
136*0a6a1f1dSLionel Sambuc     if (Warn)
137f4a2713aSLionel Sambuc       H.HandleIncompleteSpecifier(Start, E - Start);
138f4a2713aSLionel Sambuc     return true;
139f4a2713aSLionel Sambuc   }
140f4a2713aSLionel Sambuc 
141f4a2713aSLionel Sambuc   // Look for the precision (if any).
142f4a2713aSLionel Sambuc   if (*I == '.') {
143f4a2713aSLionel Sambuc     ++I;
144f4a2713aSLionel Sambuc     if (I == E) {
145*0a6a1f1dSLionel Sambuc       if (Warn)
146f4a2713aSLionel Sambuc         H.HandleIncompleteSpecifier(Start, E - Start);
147f4a2713aSLionel Sambuc       return true;
148f4a2713aSLionel Sambuc     }
149f4a2713aSLionel Sambuc 
150f4a2713aSLionel Sambuc     if (ParsePrecision(H, FS, Start, I, E,
151*0a6a1f1dSLionel Sambuc                        FS.usesPositionalArg() ? nullptr : &argIndex))
152f4a2713aSLionel Sambuc       return true;
153f4a2713aSLionel Sambuc 
154f4a2713aSLionel Sambuc     if (I == E) {
155f4a2713aSLionel Sambuc       // No more characters left?
156*0a6a1f1dSLionel Sambuc       if (Warn)
157f4a2713aSLionel Sambuc         H.HandleIncompleteSpecifier(Start, E - Start);
158f4a2713aSLionel Sambuc       return true;
159f4a2713aSLionel Sambuc     }
160f4a2713aSLionel Sambuc   }
161f4a2713aSLionel Sambuc 
162f4a2713aSLionel Sambuc   // Look for the length modifier.
163f4a2713aSLionel Sambuc   if (ParseLengthModifier(FS, I, E, LO) && I == E) {
164f4a2713aSLionel Sambuc     // No more characters left?
165*0a6a1f1dSLionel Sambuc     if (Warn)
166f4a2713aSLionel Sambuc       H.HandleIncompleteSpecifier(Start, E - Start);
167f4a2713aSLionel Sambuc     return true;
168f4a2713aSLionel Sambuc   }
169f4a2713aSLionel Sambuc 
170f4a2713aSLionel Sambuc   if (*I == '\0') {
171f4a2713aSLionel Sambuc     // Detect spurious null characters, which are likely errors.
172f4a2713aSLionel Sambuc     H.HandleNullChar(I);
173f4a2713aSLionel Sambuc     return true;
174f4a2713aSLionel Sambuc   }
175f4a2713aSLionel Sambuc 
176f4a2713aSLionel Sambuc   // Finally, look for the conversion specifier.
177f4a2713aSLionel Sambuc   const char *conversionPosition = I++;
178f4a2713aSLionel Sambuc   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;
179f4a2713aSLionel Sambuc   switch (*conversionPosition) {
180f4a2713aSLionel Sambuc     default:
181f4a2713aSLionel Sambuc       break;
182f4a2713aSLionel Sambuc     // C99: 7.19.6.1 (section 8).
183f4a2713aSLionel Sambuc     case '%': k = ConversionSpecifier::PercentArg;   break;
184f4a2713aSLionel Sambuc     case 'A': k = ConversionSpecifier::AArg; break;
185f4a2713aSLionel Sambuc     case 'E': k = ConversionSpecifier::EArg; break;
186f4a2713aSLionel Sambuc     case 'F': k = ConversionSpecifier::FArg; break;
187f4a2713aSLionel Sambuc     case 'G': k = ConversionSpecifier::GArg; break;
188f4a2713aSLionel Sambuc     case 'X': k = ConversionSpecifier::XArg; break;
189f4a2713aSLionel Sambuc     case 'a': k = ConversionSpecifier::aArg; break;
190f4a2713aSLionel Sambuc     case 'c': k = ConversionSpecifier::cArg; break;
191f4a2713aSLionel Sambuc     case 'd': k = ConversionSpecifier::dArg; break;
192f4a2713aSLionel Sambuc     case 'e': k = ConversionSpecifier::eArg; break;
193f4a2713aSLionel Sambuc     case 'f': k = ConversionSpecifier::fArg; break;
194f4a2713aSLionel Sambuc     case 'g': k = ConversionSpecifier::gArg; break;
195f4a2713aSLionel Sambuc     case 'i': k = ConversionSpecifier::iArg; break;
196f4a2713aSLionel Sambuc     case 'n': k = ConversionSpecifier::nArg; break;
197f4a2713aSLionel Sambuc     case 'o': k = ConversionSpecifier::oArg; break;
198f4a2713aSLionel Sambuc     case 'p': k = ConversionSpecifier::pArg; break;
199f4a2713aSLionel Sambuc     case 's': k = ConversionSpecifier::sArg; break;
200f4a2713aSLionel Sambuc     case 'u': k = ConversionSpecifier::uArg; break;
201f4a2713aSLionel Sambuc     case 'x': k = ConversionSpecifier::xArg; break;
202f4a2713aSLionel Sambuc     // POSIX specific.
203f4a2713aSLionel Sambuc     case 'C': k = ConversionSpecifier::CArg; break;
204f4a2713aSLionel Sambuc     case 'S': k = ConversionSpecifier::SArg; break;
205f4a2713aSLionel Sambuc     // Objective-C.
206f4a2713aSLionel Sambuc     case '@': k = ConversionSpecifier::ObjCObjArg; break;
207f4a2713aSLionel Sambuc     // Glibc specific.
208f4a2713aSLionel Sambuc     case 'm': k = ConversionSpecifier::PrintErrno; break;
209*0a6a1f1dSLionel Sambuc     // Apple-specific.
210f4a2713aSLionel Sambuc     case 'D':
211f4a2713aSLionel Sambuc       if (Target.getTriple().isOSDarwin())
212f4a2713aSLionel Sambuc         k = ConversionSpecifier::DArg;
213f4a2713aSLionel Sambuc       break;
214f4a2713aSLionel Sambuc     case 'O':
215f4a2713aSLionel Sambuc       if (Target.getTriple().isOSDarwin())
216f4a2713aSLionel Sambuc         k = ConversionSpecifier::OArg;
217f4a2713aSLionel Sambuc       break;
218f4a2713aSLionel Sambuc     case 'U':
219f4a2713aSLionel Sambuc       if (Target.getTriple().isOSDarwin())
220f4a2713aSLionel Sambuc         k = ConversionSpecifier::UArg;
221f4a2713aSLionel Sambuc       break;
222*0a6a1f1dSLionel Sambuc     // MS specific.
223*0a6a1f1dSLionel Sambuc     case 'Z':
224*0a6a1f1dSLionel Sambuc       if (Target.getTriple().isOSMSVCRT())
225*0a6a1f1dSLionel Sambuc         k = ConversionSpecifier::ZArg;
226f4a2713aSLionel Sambuc   }
227f4a2713aSLionel Sambuc   PrintfConversionSpecifier CS(conversionPosition, k);
228f4a2713aSLionel Sambuc   FS.setConversionSpecifier(CS);
229f4a2713aSLionel Sambuc   if (CS.consumesDataArgument() && !FS.usesPositionalArg())
230f4a2713aSLionel Sambuc     FS.setArgIndex(argIndex++);
231f4a2713aSLionel Sambuc 
232f4a2713aSLionel Sambuc   if (k == ConversionSpecifier::InvalidSpecifier) {
233f4a2713aSLionel Sambuc     // Assume the conversion takes one argument.
234f4a2713aSLionel Sambuc     return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start);
235f4a2713aSLionel Sambuc   }
236f4a2713aSLionel Sambuc   return PrintfSpecifierResult(Start, FS);
237f4a2713aSLionel Sambuc }
238f4a2713aSLionel Sambuc 
ParsePrintfString(FormatStringHandler & H,const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)239f4a2713aSLionel Sambuc bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
240f4a2713aSLionel Sambuc                                                      const char *I,
241f4a2713aSLionel Sambuc                                                      const char *E,
242f4a2713aSLionel Sambuc                                                      const LangOptions &LO,
243f4a2713aSLionel Sambuc                                                      const TargetInfo &Target) {
244f4a2713aSLionel Sambuc 
245f4a2713aSLionel Sambuc   unsigned argIndex = 0;
246f4a2713aSLionel Sambuc 
247f4a2713aSLionel Sambuc   // Keep looking for a format specifier until we have exhausted the string.
248f4a2713aSLionel Sambuc   while (I != E) {
249f4a2713aSLionel Sambuc     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
250*0a6a1f1dSLionel Sambuc                                                             LO, Target, true);
251f4a2713aSLionel Sambuc     // Did a fail-stop error of any kind occur when parsing the specifier?
252f4a2713aSLionel Sambuc     // If so, don't do any more processing.
253f4a2713aSLionel Sambuc     if (FSR.shouldStop())
254f4a2713aSLionel Sambuc       return true;
255f4a2713aSLionel Sambuc     // Did we exhaust the string or encounter an error that
256f4a2713aSLionel Sambuc     // we can recover from?
257f4a2713aSLionel Sambuc     if (!FSR.hasValue())
258f4a2713aSLionel Sambuc       continue;
259f4a2713aSLionel Sambuc     // We have a format specifier.  Pass it to the callback.
260f4a2713aSLionel Sambuc     if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),
261f4a2713aSLionel Sambuc                                  I - FSR.getStart()))
262f4a2713aSLionel Sambuc       return true;
263f4a2713aSLionel Sambuc   }
264f4a2713aSLionel Sambuc   assert(I == E && "Format string not exhausted");
265f4a2713aSLionel Sambuc   return false;
266f4a2713aSLionel Sambuc }
267f4a2713aSLionel Sambuc 
ParseFormatStringHasSArg(const char * I,const char * E,const LangOptions & LO,const TargetInfo & Target)268*0a6a1f1dSLionel Sambuc bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
269*0a6a1f1dSLionel Sambuc                                                             const char *E,
270*0a6a1f1dSLionel Sambuc                                                             const LangOptions &LO,
271*0a6a1f1dSLionel Sambuc                                                             const TargetInfo &Target) {
272*0a6a1f1dSLionel Sambuc 
273*0a6a1f1dSLionel Sambuc   unsigned argIndex = 0;
274*0a6a1f1dSLionel Sambuc 
275*0a6a1f1dSLionel Sambuc   // Keep looking for a %s format specifier until we have exhausted the string.
276*0a6a1f1dSLionel Sambuc   FormatStringHandler H;
277*0a6a1f1dSLionel Sambuc   while (I != E) {
278*0a6a1f1dSLionel Sambuc     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,
279*0a6a1f1dSLionel Sambuc                                                             LO, Target, false);
280*0a6a1f1dSLionel Sambuc     // Did a fail-stop error of any kind occur when parsing the specifier?
281*0a6a1f1dSLionel Sambuc     // If so, don't do any more processing.
282*0a6a1f1dSLionel Sambuc     if (FSR.shouldStop())
283*0a6a1f1dSLionel Sambuc       return false;
284*0a6a1f1dSLionel Sambuc     // Did we exhaust the string or encounter an error that
285*0a6a1f1dSLionel Sambuc     // we can recover from?
286*0a6a1f1dSLionel Sambuc     if (!FSR.hasValue())
287*0a6a1f1dSLionel Sambuc       continue;
288*0a6a1f1dSLionel Sambuc     const analyze_printf::PrintfSpecifier &FS = FSR.getValue();
289*0a6a1f1dSLionel Sambuc     // Return true if this a %s format specifier.
290*0a6a1f1dSLionel Sambuc     if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)
291*0a6a1f1dSLionel Sambuc       return true;
292*0a6a1f1dSLionel Sambuc   }
293*0a6a1f1dSLionel Sambuc   return false;
294*0a6a1f1dSLionel Sambuc }
295*0a6a1f1dSLionel Sambuc 
296f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
297f4a2713aSLionel Sambuc // Methods on PrintfSpecifier.
298f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
299f4a2713aSLionel Sambuc 
getArgType(ASTContext & Ctx,bool IsObjCLiteral) const300f4a2713aSLionel Sambuc ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
301f4a2713aSLionel Sambuc                                     bool IsObjCLiteral) const {
302f4a2713aSLionel Sambuc   const PrintfConversionSpecifier &CS = getConversionSpecifier();
303f4a2713aSLionel Sambuc 
304f4a2713aSLionel Sambuc   if (!CS.consumesDataArgument())
305f4a2713aSLionel Sambuc     return ArgType::Invalid();
306f4a2713aSLionel Sambuc 
307f4a2713aSLionel Sambuc   if (CS.getKind() == ConversionSpecifier::cArg)
308f4a2713aSLionel Sambuc     switch (LM.getKind()) {
309*0a6a1f1dSLionel Sambuc       case LengthModifier::None:
310*0a6a1f1dSLionel Sambuc         return Ctx.IntTy;
311f4a2713aSLionel Sambuc       case LengthModifier::AsLong:
312*0a6a1f1dSLionel Sambuc       case LengthModifier::AsWide:
313f4a2713aSLionel Sambuc         return ArgType(ArgType::WIntTy, "wint_t");
314*0a6a1f1dSLionel Sambuc       case LengthModifier::AsShort:
315*0a6a1f1dSLionel Sambuc         if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
316*0a6a1f1dSLionel Sambuc           return Ctx.IntTy;
317f4a2713aSLionel Sambuc       default:
318f4a2713aSLionel Sambuc         return ArgType::Invalid();
319f4a2713aSLionel Sambuc     }
320f4a2713aSLionel Sambuc 
321f4a2713aSLionel Sambuc   if (CS.isIntArg())
322f4a2713aSLionel Sambuc     switch (LM.getKind()) {
323f4a2713aSLionel Sambuc       case LengthModifier::AsLongDouble:
324f4a2713aSLionel Sambuc         // GNU extension.
325f4a2713aSLionel Sambuc         return Ctx.LongLongTy;
326f4a2713aSLionel Sambuc       case LengthModifier::None:
327f4a2713aSLionel Sambuc         return Ctx.IntTy;
328f4a2713aSLionel Sambuc       case LengthModifier::AsInt32:
329f4a2713aSLionel Sambuc         return ArgType(Ctx.IntTy, "__int32");
330f4a2713aSLionel Sambuc       case LengthModifier::AsChar: return ArgType::AnyCharTy;
331f4a2713aSLionel Sambuc       case LengthModifier::AsShort: return Ctx.ShortTy;
332f4a2713aSLionel Sambuc       case LengthModifier::AsLong: return Ctx.LongTy;
333f4a2713aSLionel Sambuc       case LengthModifier::AsLongLong:
334f4a2713aSLionel Sambuc       case LengthModifier::AsQuad:
335f4a2713aSLionel Sambuc         return Ctx.LongLongTy;
336f4a2713aSLionel Sambuc       case LengthModifier::AsInt64:
337f4a2713aSLionel Sambuc         return ArgType(Ctx.LongLongTy, "__int64");
338f4a2713aSLionel Sambuc       case LengthModifier::AsIntMax:
339f4a2713aSLionel Sambuc         return ArgType(Ctx.getIntMaxType(), "intmax_t");
340f4a2713aSLionel Sambuc       case LengthModifier::AsSizeT:
341f4a2713aSLionel Sambuc         // FIXME: How to get the corresponding signed version of size_t?
342f4a2713aSLionel Sambuc         return ArgType();
343f4a2713aSLionel Sambuc       case LengthModifier::AsInt3264:
344f4a2713aSLionel Sambuc         return Ctx.getTargetInfo().getTriple().isArch64Bit()
345f4a2713aSLionel Sambuc                    ? ArgType(Ctx.LongLongTy, "__int64")
346f4a2713aSLionel Sambuc                    : ArgType(Ctx.IntTy, "__int32");
347f4a2713aSLionel Sambuc       case LengthModifier::AsPtrDiff:
348f4a2713aSLionel Sambuc         return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t");
349f4a2713aSLionel Sambuc       case LengthModifier::AsAllocate:
350f4a2713aSLionel Sambuc       case LengthModifier::AsMAllocate:
351*0a6a1f1dSLionel Sambuc       case LengthModifier::AsWide:
352f4a2713aSLionel Sambuc         return ArgType::Invalid();
353f4a2713aSLionel Sambuc     }
354f4a2713aSLionel Sambuc 
355f4a2713aSLionel Sambuc   if (CS.isUIntArg())
356f4a2713aSLionel Sambuc     switch (LM.getKind()) {
357f4a2713aSLionel Sambuc       case LengthModifier::AsLongDouble:
358f4a2713aSLionel Sambuc         // GNU extension.
359f4a2713aSLionel Sambuc         return Ctx.UnsignedLongLongTy;
360f4a2713aSLionel Sambuc       case LengthModifier::None:
361f4a2713aSLionel Sambuc         return Ctx.UnsignedIntTy;
362f4a2713aSLionel Sambuc       case LengthModifier::AsInt32:
363f4a2713aSLionel Sambuc         return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
364f4a2713aSLionel Sambuc       case LengthModifier::AsChar: return Ctx.UnsignedCharTy;
365f4a2713aSLionel Sambuc       case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
366f4a2713aSLionel Sambuc       case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
367f4a2713aSLionel Sambuc       case LengthModifier::AsLongLong:
368f4a2713aSLionel Sambuc       case LengthModifier::AsQuad:
369f4a2713aSLionel Sambuc         return Ctx.UnsignedLongLongTy;
370f4a2713aSLionel Sambuc       case LengthModifier::AsInt64:
371f4a2713aSLionel Sambuc         return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");
372f4a2713aSLionel Sambuc       case LengthModifier::AsIntMax:
373f4a2713aSLionel Sambuc         return ArgType(Ctx.getUIntMaxType(), "uintmax_t");
374f4a2713aSLionel Sambuc       case LengthModifier::AsSizeT:
375f4a2713aSLionel Sambuc         return ArgType(Ctx.getSizeType(), "size_t");
376f4a2713aSLionel Sambuc       case LengthModifier::AsInt3264:
377f4a2713aSLionel Sambuc         return Ctx.getTargetInfo().getTriple().isArch64Bit()
378f4a2713aSLionel Sambuc                    ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")
379f4a2713aSLionel Sambuc                    : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");
380f4a2713aSLionel Sambuc       case LengthModifier::AsPtrDiff:
381f4a2713aSLionel Sambuc         // FIXME: How to get the corresponding unsigned
382f4a2713aSLionel Sambuc         // version of ptrdiff_t?
383f4a2713aSLionel Sambuc         return ArgType();
384f4a2713aSLionel Sambuc       case LengthModifier::AsAllocate:
385f4a2713aSLionel Sambuc       case LengthModifier::AsMAllocate:
386*0a6a1f1dSLionel Sambuc       case LengthModifier::AsWide:
387f4a2713aSLionel Sambuc         return ArgType::Invalid();
388f4a2713aSLionel Sambuc     }
389f4a2713aSLionel Sambuc 
390f4a2713aSLionel Sambuc   if (CS.isDoubleArg()) {
391f4a2713aSLionel Sambuc     if (LM.getKind() == LengthModifier::AsLongDouble)
392f4a2713aSLionel Sambuc       return Ctx.LongDoubleTy;
393f4a2713aSLionel Sambuc     return Ctx.DoubleTy;
394f4a2713aSLionel Sambuc   }
395f4a2713aSLionel Sambuc 
396f4a2713aSLionel Sambuc   if (CS.getKind() == ConversionSpecifier::nArg) {
397f4a2713aSLionel Sambuc     switch (LM.getKind()) {
398f4a2713aSLionel Sambuc       case LengthModifier::None:
399f4a2713aSLionel Sambuc         return ArgType::PtrTo(Ctx.IntTy);
400f4a2713aSLionel Sambuc       case LengthModifier::AsChar:
401f4a2713aSLionel Sambuc         return ArgType::PtrTo(Ctx.SignedCharTy);
402f4a2713aSLionel Sambuc       case LengthModifier::AsShort:
403f4a2713aSLionel Sambuc         return ArgType::PtrTo(Ctx.ShortTy);
404f4a2713aSLionel Sambuc       case LengthModifier::AsLong:
405f4a2713aSLionel Sambuc         return ArgType::PtrTo(Ctx.LongTy);
406f4a2713aSLionel Sambuc       case LengthModifier::AsLongLong:
407f4a2713aSLionel Sambuc       case LengthModifier::AsQuad:
408f4a2713aSLionel Sambuc         return ArgType::PtrTo(Ctx.LongLongTy);
409f4a2713aSLionel Sambuc       case LengthModifier::AsIntMax:
410f4a2713aSLionel Sambuc         return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));
411f4a2713aSLionel Sambuc       case LengthModifier::AsSizeT:
412f4a2713aSLionel Sambuc         return ArgType(); // FIXME: ssize_t
413f4a2713aSLionel Sambuc       case LengthModifier::AsPtrDiff:
414f4a2713aSLionel Sambuc         return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));
415f4a2713aSLionel Sambuc       case LengthModifier::AsLongDouble:
416f4a2713aSLionel Sambuc         return ArgType(); // FIXME: Is this a known extension?
417f4a2713aSLionel Sambuc       case LengthModifier::AsAllocate:
418f4a2713aSLionel Sambuc       case LengthModifier::AsMAllocate:
419f4a2713aSLionel Sambuc       case LengthModifier::AsInt32:
420f4a2713aSLionel Sambuc       case LengthModifier::AsInt3264:
421f4a2713aSLionel Sambuc       case LengthModifier::AsInt64:
422*0a6a1f1dSLionel Sambuc       case LengthModifier::AsWide:
423f4a2713aSLionel Sambuc         return ArgType::Invalid();
424f4a2713aSLionel Sambuc     }
425f4a2713aSLionel Sambuc   }
426f4a2713aSLionel Sambuc 
427f4a2713aSLionel Sambuc   switch (CS.getKind()) {
428f4a2713aSLionel Sambuc     case ConversionSpecifier::sArg:
429f4a2713aSLionel Sambuc       if (LM.getKind() == LengthModifier::AsWideChar) {
430f4a2713aSLionel Sambuc         if (IsObjCLiteral)
431f4a2713aSLionel Sambuc           return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
432f4a2713aSLionel Sambuc                          "const unichar *");
433f4a2713aSLionel Sambuc         return ArgType(ArgType::WCStrTy, "wchar_t *");
434f4a2713aSLionel Sambuc       }
435*0a6a1f1dSLionel Sambuc       if (LM.getKind() == LengthModifier::AsWide)
436*0a6a1f1dSLionel Sambuc         return ArgType(ArgType::WCStrTy, "wchar_t *");
437f4a2713aSLionel Sambuc       return ArgType::CStrTy;
438f4a2713aSLionel Sambuc     case ConversionSpecifier::SArg:
439f4a2713aSLionel Sambuc       if (IsObjCLiteral)
440f4a2713aSLionel Sambuc         return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
441f4a2713aSLionel Sambuc                        "const unichar *");
442*0a6a1f1dSLionel Sambuc       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
443*0a6a1f1dSLionel Sambuc           LM.getKind() == LengthModifier::AsShort)
444*0a6a1f1dSLionel Sambuc         return ArgType::CStrTy;
445f4a2713aSLionel Sambuc       return ArgType(ArgType::WCStrTy, "wchar_t *");
446f4a2713aSLionel Sambuc     case ConversionSpecifier::CArg:
447f4a2713aSLionel Sambuc       if (IsObjCLiteral)
448f4a2713aSLionel Sambuc         return ArgType(Ctx.UnsignedShortTy, "unichar");
449*0a6a1f1dSLionel Sambuc       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&
450*0a6a1f1dSLionel Sambuc           LM.getKind() == LengthModifier::AsShort)
451*0a6a1f1dSLionel Sambuc         return Ctx.IntTy;
452f4a2713aSLionel Sambuc       return ArgType(Ctx.WideCharTy, "wchar_t");
453f4a2713aSLionel Sambuc     case ConversionSpecifier::pArg:
454f4a2713aSLionel Sambuc       return ArgType::CPointerTy;
455f4a2713aSLionel Sambuc     case ConversionSpecifier::ObjCObjArg:
456f4a2713aSLionel Sambuc       return ArgType::ObjCPointerTy;
457f4a2713aSLionel Sambuc     default:
458f4a2713aSLionel Sambuc       break;
459f4a2713aSLionel Sambuc   }
460f4a2713aSLionel Sambuc 
461f4a2713aSLionel Sambuc   // FIXME: Handle other cases.
462f4a2713aSLionel Sambuc   return ArgType();
463f4a2713aSLionel Sambuc }
464f4a2713aSLionel Sambuc 
fixType(QualType QT,const LangOptions & LangOpt,ASTContext & Ctx,bool IsObjCLiteral)465f4a2713aSLionel Sambuc bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
466f4a2713aSLionel Sambuc                               ASTContext &Ctx, bool IsObjCLiteral) {
467f4a2713aSLionel Sambuc   // %n is different from other conversion specifiers; don't try to fix it.
468f4a2713aSLionel Sambuc   if (CS.getKind() == ConversionSpecifier::nArg)
469f4a2713aSLionel Sambuc     return false;
470f4a2713aSLionel Sambuc 
471f4a2713aSLionel Sambuc   // Handle Objective-C objects first. Note that while the '%@' specifier will
472f4a2713aSLionel Sambuc   // not warn for structure pointer or void pointer arguments (because that's
473f4a2713aSLionel Sambuc   // how CoreFoundation objects are implemented), we only show a fixit for '%@'
474f4a2713aSLionel Sambuc   // if we know it's an object (block, id, class, or __attribute__((NSObject))).
475f4a2713aSLionel Sambuc   if (QT->isObjCRetainableType()) {
476f4a2713aSLionel Sambuc     if (!IsObjCLiteral)
477f4a2713aSLionel Sambuc       return false;
478f4a2713aSLionel Sambuc 
479f4a2713aSLionel Sambuc     CS.setKind(ConversionSpecifier::ObjCObjArg);
480f4a2713aSLionel Sambuc 
481f4a2713aSLionel Sambuc     // Disable irrelevant flags
482f4a2713aSLionel Sambuc     HasThousandsGrouping = false;
483f4a2713aSLionel Sambuc     HasPlusPrefix = false;
484f4a2713aSLionel Sambuc     HasSpacePrefix = false;
485f4a2713aSLionel Sambuc     HasAlternativeForm = false;
486f4a2713aSLionel Sambuc     HasLeadingZeroes = false;
487f4a2713aSLionel Sambuc     Precision.setHowSpecified(OptionalAmount::NotSpecified);
488f4a2713aSLionel Sambuc     LM.setKind(LengthModifier::None);
489f4a2713aSLionel Sambuc 
490f4a2713aSLionel Sambuc     return true;
491f4a2713aSLionel Sambuc   }
492f4a2713aSLionel Sambuc 
493f4a2713aSLionel Sambuc   // Handle strings next (char *, wchar_t *)
494f4a2713aSLionel Sambuc   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {
495f4a2713aSLionel Sambuc     CS.setKind(ConversionSpecifier::sArg);
496f4a2713aSLionel Sambuc 
497f4a2713aSLionel Sambuc     // Disable irrelevant flags
498f4a2713aSLionel Sambuc     HasAlternativeForm = 0;
499f4a2713aSLionel Sambuc     HasLeadingZeroes = 0;
500f4a2713aSLionel Sambuc 
501f4a2713aSLionel Sambuc     // Set the long length modifier for wide characters
502f4a2713aSLionel Sambuc     if (QT->getPointeeType()->isWideCharType())
503f4a2713aSLionel Sambuc       LM.setKind(LengthModifier::AsWideChar);
504f4a2713aSLionel Sambuc     else
505f4a2713aSLionel Sambuc       LM.setKind(LengthModifier::None);
506f4a2713aSLionel Sambuc 
507f4a2713aSLionel Sambuc     return true;
508f4a2713aSLionel Sambuc   }
509f4a2713aSLionel Sambuc 
510f4a2713aSLionel Sambuc   // If it's an enum, get its underlying type.
511f4a2713aSLionel Sambuc   if (const EnumType *ETy = QT->getAs<EnumType>())
512f4a2713aSLionel Sambuc     QT = ETy->getDecl()->getIntegerType();
513f4a2713aSLionel Sambuc 
514f4a2713aSLionel Sambuc   // We can only work with builtin types.
515f4a2713aSLionel Sambuc   const BuiltinType *BT = QT->getAs<BuiltinType>();
516f4a2713aSLionel Sambuc   if (!BT)
517f4a2713aSLionel Sambuc     return false;
518f4a2713aSLionel Sambuc 
519f4a2713aSLionel Sambuc   // Set length modifier
520f4a2713aSLionel Sambuc   switch (BT->getKind()) {
521f4a2713aSLionel Sambuc   case BuiltinType::Bool:
522f4a2713aSLionel Sambuc   case BuiltinType::WChar_U:
523f4a2713aSLionel Sambuc   case BuiltinType::WChar_S:
524f4a2713aSLionel Sambuc   case BuiltinType::Char16:
525f4a2713aSLionel Sambuc   case BuiltinType::Char32:
526f4a2713aSLionel Sambuc   case BuiltinType::UInt128:
527f4a2713aSLionel Sambuc   case BuiltinType::Int128:
528f4a2713aSLionel Sambuc   case BuiltinType::Half:
529f4a2713aSLionel Sambuc     // Various types which are non-trivial to correct.
530f4a2713aSLionel Sambuc     return false;
531f4a2713aSLionel Sambuc 
532f4a2713aSLionel Sambuc #define SIGNED_TYPE(Id, SingletonId)
533f4a2713aSLionel Sambuc #define UNSIGNED_TYPE(Id, SingletonId)
534f4a2713aSLionel Sambuc #define FLOATING_TYPE(Id, SingletonId)
535f4a2713aSLionel Sambuc #define BUILTIN_TYPE(Id, SingletonId) \
536f4a2713aSLionel Sambuc   case BuiltinType::Id:
537f4a2713aSLionel Sambuc #include "clang/AST/BuiltinTypes.def"
538f4a2713aSLionel Sambuc     // Misc other stuff which doesn't make sense here.
539f4a2713aSLionel Sambuc     return false;
540f4a2713aSLionel Sambuc 
541f4a2713aSLionel Sambuc   case BuiltinType::UInt:
542f4a2713aSLionel Sambuc   case BuiltinType::Int:
543f4a2713aSLionel Sambuc   case BuiltinType::Float:
544f4a2713aSLionel Sambuc   case BuiltinType::Double:
545f4a2713aSLionel Sambuc     LM.setKind(LengthModifier::None);
546f4a2713aSLionel Sambuc     break;
547f4a2713aSLionel Sambuc 
548f4a2713aSLionel Sambuc   case BuiltinType::Char_U:
549f4a2713aSLionel Sambuc   case BuiltinType::UChar:
550f4a2713aSLionel Sambuc   case BuiltinType::Char_S:
551f4a2713aSLionel Sambuc   case BuiltinType::SChar:
552f4a2713aSLionel Sambuc     LM.setKind(LengthModifier::AsChar);
553f4a2713aSLionel Sambuc     break;
554f4a2713aSLionel Sambuc 
555f4a2713aSLionel Sambuc   case BuiltinType::Short:
556f4a2713aSLionel Sambuc   case BuiltinType::UShort:
557f4a2713aSLionel Sambuc     LM.setKind(LengthModifier::AsShort);
558f4a2713aSLionel Sambuc     break;
559f4a2713aSLionel Sambuc 
560f4a2713aSLionel Sambuc   case BuiltinType::Long:
561f4a2713aSLionel Sambuc   case BuiltinType::ULong:
562f4a2713aSLionel Sambuc     LM.setKind(LengthModifier::AsLong);
563f4a2713aSLionel Sambuc     break;
564f4a2713aSLionel Sambuc 
565f4a2713aSLionel Sambuc   case BuiltinType::LongLong:
566f4a2713aSLionel Sambuc   case BuiltinType::ULongLong:
567f4a2713aSLionel Sambuc     LM.setKind(LengthModifier::AsLongLong);
568f4a2713aSLionel Sambuc     break;
569f4a2713aSLionel Sambuc 
570f4a2713aSLionel Sambuc   case BuiltinType::LongDouble:
571f4a2713aSLionel Sambuc     LM.setKind(LengthModifier::AsLongDouble);
572f4a2713aSLionel Sambuc     break;
573f4a2713aSLionel Sambuc   }
574f4a2713aSLionel Sambuc 
575f4a2713aSLionel Sambuc   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
576f4a2713aSLionel Sambuc   if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
577f4a2713aSLionel Sambuc     namedTypeToLengthModifier(QT, LM);
578f4a2713aSLionel Sambuc 
579f4a2713aSLionel Sambuc   // If fixing the length modifier was enough, we might be done.
580f4a2713aSLionel Sambuc   if (hasValidLengthModifier(Ctx.getTargetInfo())) {
581f4a2713aSLionel Sambuc     // If we're going to offer a fix anyway, make sure the sign matches.
582f4a2713aSLionel Sambuc     switch (CS.getKind()) {
583f4a2713aSLionel Sambuc     case ConversionSpecifier::uArg:
584f4a2713aSLionel Sambuc     case ConversionSpecifier::UArg:
585f4a2713aSLionel Sambuc       if (QT->isSignedIntegerType())
586f4a2713aSLionel Sambuc         CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
587f4a2713aSLionel Sambuc       break;
588f4a2713aSLionel Sambuc     case ConversionSpecifier::dArg:
589f4a2713aSLionel Sambuc     case ConversionSpecifier::DArg:
590f4a2713aSLionel Sambuc     case ConversionSpecifier::iArg:
591f4a2713aSLionel Sambuc       if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
592f4a2713aSLionel Sambuc         CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
593f4a2713aSLionel Sambuc       break;
594f4a2713aSLionel Sambuc     default:
595f4a2713aSLionel Sambuc       // Other specifiers do not have signed/unsigned variants.
596f4a2713aSLionel Sambuc       break;
597f4a2713aSLionel Sambuc     }
598f4a2713aSLionel Sambuc 
599f4a2713aSLionel Sambuc     const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
600f4a2713aSLionel Sambuc     if (ATR.isValid() && ATR.matchesType(Ctx, QT))
601f4a2713aSLionel Sambuc       return true;
602f4a2713aSLionel Sambuc   }
603f4a2713aSLionel Sambuc 
604f4a2713aSLionel Sambuc   // Set conversion specifier and disable any flags which do not apply to it.
605f4a2713aSLionel Sambuc   // Let typedefs to char fall through to int, as %c is silly for uint8_t.
606f4a2713aSLionel Sambuc   if (!isa<TypedefType>(QT) && QT->isCharType()) {
607f4a2713aSLionel Sambuc     CS.setKind(ConversionSpecifier::cArg);
608f4a2713aSLionel Sambuc     LM.setKind(LengthModifier::None);
609f4a2713aSLionel Sambuc     Precision.setHowSpecified(OptionalAmount::NotSpecified);
610f4a2713aSLionel Sambuc     HasAlternativeForm = 0;
611f4a2713aSLionel Sambuc     HasLeadingZeroes = 0;
612f4a2713aSLionel Sambuc     HasPlusPrefix = 0;
613f4a2713aSLionel Sambuc   }
614f4a2713aSLionel Sambuc   // Test for Floating type first as LongDouble can pass isUnsignedIntegerType
615f4a2713aSLionel Sambuc   else if (QT->isRealFloatingType()) {
616f4a2713aSLionel Sambuc     CS.setKind(ConversionSpecifier::fArg);
617f4a2713aSLionel Sambuc   }
618f4a2713aSLionel Sambuc   else if (QT->isSignedIntegerType()) {
619f4a2713aSLionel Sambuc     CS.setKind(ConversionSpecifier::dArg);
620f4a2713aSLionel Sambuc     HasAlternativeForm = 0;
621f4a2713aSLionel Sambuc   }
622f4a2713aSLionel Sambuc   else if (QT->isUnsignedIntegerType()) {
623f4a2713aSLionel Sambuc     CS.setKind(ConversionSpecifier::uArg);
624f4a2713aSLionel Sambuc     HasAlternativeForm = 0;
625f4a2713aSLionel Sambuc     HasPlusPrefix = 0;
626f4a2713aSLionel Sambuc   } else {
627f4a2713aSLionel Sambuc     llvm_unreachable("Unexpected type");
628f4a2713aSLionel Sambuc   }
629f4a2713aSLionel Sambuc 
630f4a2713aSLionel Sambuc   return true;
631f4a2713aSLionel Sambuc }
632f4a2713aSLionel Sambuc 
toString(raw_ostream & os) const633f4a2713aSLionel Sambuc void PrintfSpecifier::toString(raw_ostream &os) const {
634f4a2713aSLionel Sambuc   // Whilst some features have no defined order, we are using the order
635f4a2713aSLionel Sambuc   // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)
636f4a2713aSLionel Sambuc   os << "%";
637f4a2713aSLionel Sambuc 
638f4a2713aSLionel Sambuc   // Positional args
639f4a2713aSLionel Sambuc   if (usesPositionalArg()) {
640f4a2713aSLionel Sambuc     os << getPositionalArgIndex() << "$";
641f4a2713aSLionel Sambuc   }
642f4a2713aSLionel Sambuc 
643f4a2713aSLionel Sambuc   // Conversion flags
644f4a2713aSLionel Sambuc   if (IsLeftJustified)    os << "-";
645f4a2713aSLionel Sambuc   if (HasPlusPrefix)      os << "+";
646f4a2713aSLionel Sambuc   if (HasSpacePrefix)     os << " ";
647f4a2713aSLionel Sambuc   if (HasAlternativeForm) os << "#";
648f4a2713aSLionel Sambuc   if (HasLeadingZeroes)   os << "0";
649f4a2713aSLionel Sambuc 
650f4a2713aSLionel Sambuc   // Minimum field width
651f4a2713aSLionel Sambuc   FieldWidth.toString(os);
652f4a2713aSLionel Sambuc   // Precision
653f4a2713aSLionel Sambuc   Precision.toString(os);
654f4a2713aSLionel Sambuc   // Length modifier
655f4a2713aSLionel Sambuc   os << LM.toString();
656f4a2713aSLionel Sambuc   // Conversion specifier
657f4a2713aSLionel Sambuc   os << CS.toString();
658f4a2713aSLionel Sambuc }
659f4a2713aSLionel Sambuc 
hasValidPlusPrefix() const660f4a2713aSLionel Sambuc bool PrintfSpecifier::hasValidPlusPrefix() const {
661f4a2713aSLionel Sambuc   if (!HasPlusPrefix)
662f4a2713aSLionel Sambuc     return true;
663f4a2713aSLionel Sambuc 
664f4a2713aSLionel Sambuc   // The plus prefix only makes sense for signed conversions
665f4a2713aSLionel Sambuc   switch (CS.getKind()) {
666f4a2713aSLionel Sambuc   case ConversionSpecifier::dArg:
667f4a2713aSLionel Sambuc   case ConversionSpecifier::DArg:
668f4a2713aSLionel Sambuc   case ConversionSpecifier::iArg:
669f4a2713aSLionel Sambuc   case ConversionSpecifier::fArg:
670f4a2713aSLionel Sambuc   case ConversionSpecifier::FArg:
671f4a2713aSLionel Sambuc   case ConversionSpecifier::eArg:
672f4a2713aSLionel Sambuc   case ConversionSpecifier::EArg:
673f4a2713aSLionel Sambuc   case ConversionSpecifier::gArg:
674f4a2713aSLionel Sambuc   case ConversionSpecifier::GArg:
675f4a2713aSLionel Sambuc   case ConversionSpecifier::aArg:
676f4a2713aSLionel Sambuc   case ConversionSpecifier::AArg:
677f4a2713aSLionel Sambuc     return true;
678f4a2713aSLionel Sambuc 
679f4a2713aSLionel Sambuc   default:
680f4a2713aSLionel Sambuc     return false;
681f4a2713aSLionel Sambuc   }
682f4a2713aSLionel Sambuc }
683f4a2713aSLionel Sambuc 
hasValidAlternativeForm() const684f4a2713aSLionel Sambuc bool PrintfSpecifier::hasValidAlternativeForm() const {
685f4a2713aSLionel Sambuc   if (!HasAlternativeForm)
686f4a2713aSLionel Sambuc     return true;
687f4a2713aSLionel Sambuc 
688f4a2713aSLionel Sambuc   // Alternate form flag only valid with the oxXaAeEfFgG conversions
689f4a2713aSLionel Sambuc   switch (CS.getKind()) {
690f4a2713aSLionel Sambuc   case ConversionSpecifier::oArg:
691f4a2713aSLionel Sambuc   case ConversionSpecifier::OArg:
692f4a2713aSLionel Sambuc   case ConversionSpecifier::xArg:
693f4a2713aSLionel Sambuc   case ConversionSpecifier::XArg:
694f4a2713aSLionel Sambuc   case ConversionSpecifier::aArg:
695f4a2713aSLionel Sambuc   case ConversionSpecifier::AArg:
696f4a2713aSLionel Sambuc   case ConversionSpecifier::eArg:
697f4a2713aSLionel Sambuc   case ConversionSpecifier::EArg:
698f4a2713aSLionel Sambuc   case ConversionSpecifier::fArg:
699f4a2713aSLionel Sambuc   case ConversionSpecifier::FArg:
700f4a2713aSLionel Sambuc   case ConversionSpecifier::gArg:
701f4a2713aSLionel Sambuc   case ConversionSpecifier::GArg:
702f4a2713aSLionel Sambuc     return true;
703f4a2713aSLionel Sambuc 
704f4a2713aSLionel Sambuc   default:
705f4a2713aSLionel Sambuc     return false;
706f4a2713aSLionel Sambuc   }
707f4a2713aSLionel Sambuc }
708f4a2713aSLionel Sambuc 
hasValidLeadingZeros() const709f4a2713aSLionel Sambuc bool PrintfSpecifier::hasValidLeadingZeros() const {
710f4a2713aSLionel Sambuc   if (!HasLeadingZeroes)
711f4a2713aSLionel Sambuc     return true;
712f4a2713aSLionel Sambuc 
713f4a2713aSLionel Sambuc   // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
714f4a2713aSLionel Sambuc   switch (CS.getKind()) {
715f4a2713aSLionel Sambuc   case ConversionSpecifier::dArg:
716f4a2713aSLionel Sambuc   case ConversionSpecifier::DArg:
717f4a2713aSLionel Sambuc   case ConversionSpecifier::iArg:
718f4a2713aSLionel Sambuc   case ConversionSpecifier::oArg:
719f4a2713aSLionel Sambuc   case ConversionSpecifier::OArg:
720f4a2713aSLionel Sambuc   case ConversionSpecifier::uArg:
721f4a2713aSLionel Sambuc   case ConversionSpecifier::UArg:
722f4a2713aSLionel Sambuc   case ConversionSpecifier::xArg:
723f4a2713aSLionel Sambuc   case ConversionSpecifier::XArg:
724f4a2713aSLionel Sambuc   case ConversionSpecifier::aArg:
725f4a2713aSLionel Sambuc   case ConversionSpecifier::AArg:
726f4a2713aSLionel Sambuc   case ConversionSpecifier::eArg:
727f4a2713aSLionel Sambuc   case ConversionSpecifier::EArg:
728f4a2713aSLionel Sambuc   case ConversionSpecifier::fArg:
729f4a2713aSLionel Sambuc   case ConversionSpecifier::FArg:
730f4a2713aSLionel Sambuc   case ConversionSpecifier::gArg:
731f4a2713aSLionel Sambuc   case ConversionSpecifier::GArg:
732f4a2713aSLionel Sambuc     return true;
733f4a2713aSLionel Sambuc 
734f4a2713aSLionel Sambuc   default:
735f4a2713aSLionel Sambuc     return false;
736f4a2713aSLionel Sambuc   }
737f4a2713aSLionel Sambuc }
738f4a2713aSLionel Sambuc 
hasValidSpacePrefix() const739f4a2713aSLionel Sambuc bool PrintfSpecifier::hasValidSpacePrefix() const {
740f4a2713aSLionel Sambuc   if (!HasSpacePrefix)
741f4a2713aSLionel Sambuc     return true;
742f4a2713aSLionel Sambuc 
743f4a2713aSLionel Sambuc   // The space prefix only makes sense for signed conversions
744f4a2713aSLionel Sambuc   switch (CS.getKind()) {
745f4a2713aSLionel Sambuc   case ConversionSpecifier::dArg:
746f4a2713aSLionel Sambuc   case ConversionSpecifier::DArg:
747f4a2713aSLionel Sambuc   case ConversionSpecifier::iArg:
748f4a2713aSLionel Sambuc   case ConversionSpecifier::fArg:
749f4a2713aSLionel Sambuc   case ConversionSpecifier::FArg:
750f4a2713aSLionel Sambuc   case ConversionSpecifier::eArg:
751f4a2713aSLionel Sambuc   case ConversionSpecifier::EArg:
752f4a2713aSLionel Sambuc   case ConversionSpecifier::gArg:
753f4a2713aSLionel Sambuc   case ConversionSpecifier::GArg:
754f4a2713aSLionel Sambuc   case ConversionSpecifier::aArg:
755f4a2713aSLionel Sambuc   case ConversionSpecifier::AArg:
756f4a2713aSLionel Sambuc     return true;
757f4a2713aSLionel Sambuc 
758f4a2713aSLionel Sambuc   default:
759f4a2713aSLionel Sambuc     return false;
760f4a2713aSLionel Sambuc   }
761f4a2713aSLionel Sambuc }
762f4a2713aSLionel Sambuc 
hasValidLeftJustified() const763f4a2713aSLionel Sambuc bool PrintfSpecifier::hasValidLeftJustified() const {
764f4a2713aSLionel Sambuc   if (!IsLeftJustified)
765f4a2713aSLionel Sambuc     return true;
766f4a2713aSLionel Sambuc 
767f4a2713aSLionel Sambuc   // The left justified flag is valid for all conversions except n
768f4a2713aSLionel Sambuc   switch (CS.getKind()) {
769f4a2713aSLionel Sambuc   case ConversionSpecifier::nArg:
770f4a2713aSLionel Sambuc     return false;
771f4a2713aSLionel Sambuc 
772f4a2713aSLionel Sambuc   default:
773f4a2713aSLionel Sambuc     return true;
774f4a2713aSLionel Sambuc   }
775f4a2713aSLionel Sambuc }
776f4a2713aSLionel Sambuc 
hasValidThousandsGroupingPrefix() const777f4a2713aSLionel Sambuc bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {
778f4a2713aSLionel Sambuc   if (!HasThousandsGrouping)
779f4a2713aSLionel Sambuc     return true;
780f4a2713aSLionel Sambuc 
781f4a2713aSLionel Sambuc   switch (CS.getKind()) {
782f4a2713aSLionel Sambuc     case ConversionSpecifier::dArg:
783f4a2713aSLionel Sambuc     case ConversionSpecifier::DArg:
784f4a2713aSLionel Sambuc     case ConversionSpecifier::iArg:
785f4a2713aSLionel Sambuc     case ConversionSpecifier::uArg:
786f4a2713aSLionel Sambuc     case ConversionSpecifier::UArg:
787f4a2713aSLionel Sambuc     case ConversionSpecifier::fArg:
788f4a2713aSLionel Sambuc     case ConversionSpecifier::FArg:
789f4a2713aSLionel Sambuc     case ConversionSpecifier::gArg:
790f4a2713aSLionel Sambuc     case ConversionSpecifier::GArg:
791f4a2713aSLionel Sambuc       return true;
792f4a2713aSLionel Sambuc     default:
793f4a2713aSLionel Sambuc       return false;
794f4a2713aSLionel Sambuc   }
795f4a2713aSLionel Sambuc }
796f4a2713aSLionel Sambuc 
hasValidPrecision() const797f4a2713aSLionel Sambuc bool PrintfSpecifier::hasValidPrecision() const {
798f4a2713aSLionel Sambuc   if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
799f4a2713aSLionel Sambuc     return true;
800f4a2713aSLionel Sambuc 
801f4a2713aSLionel Sambuc   // Precision is only valid with the diouxXaAeEfFgGs conversions
802f4a2713aSLionel Sambuc   switch (CS.getKind()) {
803f4a2713aSLionel Sambuc   case ConversionSpecifier::dArg:
804f4a2713aSLionel Sambuc   case ConversionSpecifier::DArg:
805f4a2713aSLionel Sambuc   case ConversionSpecifier::iArg:
806f4a2713aSLionel Sambuc   case ConversionSpecifier::oArg:
807f4a2713aSLionel Sambuc   case ConversionSpecifier::OArg:
808f4a2713aSLionel Sambuc   case ConversionSpecifier::uArg:
809f4a2713aSLionel Sambuc   case ConversionSpecifier::UArg:
810f4a2713aSLionel Sambuc   case ConversionSpecifier::xArg:
811f4a2713aSLionel Sambuc   case ConversionSpecifier::XArg:
812f4a2713aSLionel Sambuc   case ConversionSpecifier::aArg:
813f4a2713aSLionel Sambuc   case ConversionSpecifier::AArg:
814f4a2713aSLionel Sambuc   case ConversionSpecifier::eArg:
815f4a2713aSLionel Sambuc   case ConversionSpecifier::EArg:
816f4a2713aSLionel Sambuc   case ConversionSpecifier::fArg:
817f4a2713aSLionel Sambuc   case ConversionSpecifier::FArg:
818f4a2713aSLionel Sambuc   case ConversionSpecifier::gArg:
819f4a2713aSLionel Sambuc   case ConversionSpecifier::GArg:
820f4a2713aSLionel Sambuc   case ConversionSpecifier::sArg:
821f4a2713aSLionel Sambuc     return true;
822f4a2713aSLionel Sambuc 
823f4a2713aSLionel Sambuc   default:
824f4a2713aSLionel Sambuc     return false;
825f4a2713aSLionel Sambuc   }
826f4a2713aSLionel Sambuc }
hasValidFieldWidth() const827f4a2713aSLionel Sambuc bool PrintfSpecifier::hasValidFieldWidth() const {
828f4a2713aSLionel Sambuc   if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)
829f4a2713aSLionel Sambuc       return true;
830f4a2713aSLionel Sambuc 
831f4a2713aSLionel Sambuc   // The field width is valid for all conversions except n
832f4a2713aSLionel Sambuc   switch (CS.getKind()) {
833f4a2713aSLionel Sambuc   case ConversionSpecifier::nArg:
834f4a2713aSLionel Sambuc     return false;
835f4a2713aSLionel Sambuc 
836f4a2713aSLionel Sambuc   default:
837f4a2713aSLionel Sambuc     return true;
838f4a2713aSLionel Sambuc   }
839f4a2713aSLionel Sambuc }
840