xref: /src/contrib/llvm-project/clang/lib/AST/FormatString.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
13d1dcd9bSDimitry Andric // FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-
23d1dcd9bSDimitry Andric //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63d1dcd9bSDimitry Andric //
73d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
83d1dcd9bSDimitry Andric //
93d1dcd9bSDimitry Andric // Shared details for processing format strings of printf and scanf
103d1dcd9bSDimitry Andric // (and friends).
113d1dcd9bSDimitry Andric //
123d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
133d1dcd9bSDimitry Andric 
143d1dcd9bSDimitry Andric #include "FormatStringParsing.h"
15dbe13110SDimitry Andric #include "clang/Basic/LangOptions.h"
1613cc256eSDimitry Andric #include "clang/Basic/TargetInfo.h"
172b6b257fSDimitry Andric #include "llvm/Support/ConvertUTF.h"
18e3b55780SDimitry Andric #include <optional>
193d1dcd9bSDimitry Andric 
2056d91b49SDimitry Andric using clang::analyze_format_string::ArgType;
213d1dcd9bSDimitry Andric using clang::analyze_format_string::FormatStringHandler;
223d1dcd9bSDimitry Andric using clang::analyze_format_string::FormatSpecifier;
233d1dcd9bSDimitry Andric using clang::analyze_format_string::LengthModifier;
243d1dcd9bSDimitry Andric using clang::analyze_format_string::OptionalAmount;
253d1dcd9bSDimitry Andric using clang::analyze_format_string::ConversionSpecifier;
263d1dcd9bSDimitry Andric using namespace clang;
273d1dcd9bSDimitry Andric 
283d1dcd9bSDimitry Andric // Key function to FormatStringHandler.
~FormatStringHandler()293d1dcd9bSDimitry Andric FormatStringHandler::~FormatStringHandler() {}
303d1dcd9bSDimitry Andric 
313d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
323d1dcd9bSDimitry Andric // Functions for parsing format strings components in both printf and
333d1dcd9bSDimitry Andric // scanf format strings.
343d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
353d1dcd9bSDimitry Andric 
363d1dcd9bSDimitry Andric OptionalAmount
ParseAmount(const char * & Beg,const char * E)373d1dcd9bSDimitry Andric clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {
383d1dcd9bSDimitry Andric   const char *I = Beg;
393d1dcd9bSDimitry Andric   UpdateOnReturn <const char*> UpdateBeg(Beg, I);
403d1dcd9bSDimitry Andric 
413d1dcd9bSDimitry Andric   unsigned accumulator = 0;
423d1dcd9bSDimitry Andric   bool hasDigits = false;
433d1dcd9bSDimitry Andric 
443d1dcd9bSDimitry Andric   for ( ; I != E; ++I) {
453d1dcd9bSDimitry Andric     char c = *I;
463d1dcd9bSDimitry Andric     if (c >= '0' && c <= '9') {
473d1dcd9bSDimitry Andric       hasDigits = true;
483d1dcd9bSDimitry Andric       accumulator = (accumulator * 10) + (c - '0');
493d1dcd9bSDimitry Andric       continue;
503d1dcd9bSDimitry Andric     }
513d1dcd9bSDimitry Andric 
523d1dcd9bSDimitry Andric     if (hasDigits)
533d1dcd9bSDimitry Andric       return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,
543d1dcd9bSDimitry Andric           false);
553d1dcd9bSDimitry Andric 
563d1dcd9bSDimitry Andric     break;
573d1dcd9bSDimitry Andric   }
583d1dcd9bSDimitry Andric 
593d1dcd9bSDimitry Andric   return OptionalAmount();
603d1dcd9bSDimitry Andric }
613d1dcd9bSDimitry Andric 
623d1dcd9bSDimitry Andric OptionalAmount
ParseNonPositionAmount(const char * & Beg,const char * E,unsigned & argIndex)633d1dcd9bSDimitry Andric clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,
643d1dcd9bSDimitry Andric                                                      const char *E,
653d1dcd9bSDimitry Andric                                                      unsigned &argIndex) {
663d1dcd9bSDimitry Andric   if (*Beg == '*') {
673d1dcd9bSDimitry Andric     ++Beg;
683d1dcd9bSDimitry Andric     return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);
693d1dcd9bSDimitry Andric   }
703d1dcd9bSDimitry Andric 
713d1dcd9bSDimitry Andric   return ParseAmount(Beg, E);
723d1dcd9bSDimitry Andric }
733d1dcd9bSDimitry Andric 
743d1dcd9bSDimitry Andric OptionalAmount
ParsePositionAmount(FormatStringHandler & H,const char * Start,const char * & Beg,const char * E,PositionContext p)753d1dcd9bSDimitry Andric clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,
763d1dcd9bSDimitry Andric                                                   const char *Start,
773d1dcd9bSDimitry Andric                                                   const char *&Beg,
783d1dcd9bSDimitry Andric                                                   const char *E,
793d1dcd9bSDimitry Andric                                                   PositionContext p) {
803d1dcd9bSDimitry Andric   if (*Beg == '*') {
813d1dcd9bSDimitry Andric     const char *I = Beg + 1;
823d1dcd9bSDimitry Andric     const OptionalAmount &Amt = ParseAmount(I, E);
833d1dcd9bSDimitry Andric 
843d1dcd9bSDimitry Andric     if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {
853d1dcd9bSDimitry Andric       H.HandleInvalidPosition(Beg, I - Beg, p);
863d1dcd9bSDimitry Andric       return OptionalAmount(false);
873d1dcd9bSDimitry Andric     }
883d1dcd9bSDimitry Andric 
893d1dcd9bSDimitry Andric     if (I == E) {
903d1dcd9bSDimitry Andric       // No more characters left?
913d1dcd9bSDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
923d1dcd9bSDimitry Andric       return OptionalAmount(false);
933d1dcd9bSDimitry Andric     }
943d1dcd9bSDimitry Andric 
953d1dcd9bSDimitry Andric     assert(Amt.getHowSpecified() == OptionalAmount::Constant);
963d1dcd9bSDimitry Andric 
973d1dcd9bSDimitry Andric     if (*I == '$') {
983d1dcd9bSDimitry Andric       // Handle positional arguments
993d1dcd9bSDimitry Andric 
1003d1dcd9bSDimitry Andric       // Special case: '*0$', since this is an easy mistake.
1013d1dcd9bSDimitry Andric       if (Amt.getConstantAmount() == 0) {
1023d1dcd9bSDimitry Andric         H.HandleZeroPosition(Beg, I - Beg + 1);
1033d1dcd9bSDimitry Andric         return OptionalAmount(false);
1043d1dcd9bSDimitry Andric       }
1053d1dcd9bSDimitry Andric 
1063d1dcd9bSDimitry Andric       const char *Tmp = Beg;
1073d1dcd9bSDimitry Andric       Beg = ++I;
1083d1dcd9bSDimitry Andric 
1093d1dcd9bSDimitry Andric       return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,
1103d1dcd9bSDimitry Andric                             Tmp, 0, true);
1113d1dcd9bSDimitry Andric     }
1123d1dcd9bSDimitry Andric 
1133d1dcd9bSDimitry Andric     H.HandleInvalidPosition(Beg, I - Beg, p);
1143d1dcd9bSDimitry Andric     return OptionalAmount(false);
1153d1dcd9bSDimitry Andric   }
1163d1dcd9bSDimitry Andric 
1173d1dcd9bSDimitry Andric   return ParseAmount(Beg, E);
1183d1dcd9bSDimitry Andric }
1193d1dcd9bSDimitry Andric 
1203d1dcd9bSDimitry Andric 
1213d1dcd9bSDimitry Andric bool
ParseFieldWidth(FormatStringHandler & H,FormatSpecifier & CS,const char * Start,const char * & Beg,const char * E,unsigned * argIndex)1223d1dcd9bSDimitry Andric clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,
1233d1dcd9bSDimitry Andric                                               FormatSpecifier &CS,
1243d1dcd9bSDimitry Andric                                               const char *Start,
1253d1dcd9bSDimitry Andric                                               const char *&Beg, const char *E,
1263d1dcd9bSDimitry Andric                                               unsigned *argIndex) {
1273d1dcd9bSDimitry Andric   // FIXME: Support negative field widths.
1283d1dcd9bSDimitry Andric   if (argIndex) {
1293d1dcd9bSDimitry Andric     CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));
1303d1dcd9bSDimitry Andric   }
1313d1dcd9bSDimitry Andric   else {
1323d1dcd9bSDimitry Andric     const OptionalAmount Amt =
1333d1dcd9bSDimitry Andric       ParsePositionAmount(H, Start, Beg, E,
1343d1dcd9bSDimitry Andric                           analyze_format_string::FieldWidthPos);
1353d1dcd9bSDimitry Andric 
1363d1dcd9bSDimitry Andric     if (Amt.isInvalid())
1373d1dcd9bSDimitry Andric       return true;
1383d1dcd9bSDimitry Andric     CS.setFieldWidth(Amt);
1393d1dcd9bSDimitry Andric   }
1403d1dcd9bSDimitry Andric   return false;
1413d1dcd9bSDimitry Andric }
1423d1dcd9bSDimitry Andric 
1433d1dcd9bSDimitry Andric bool
ParseArgPosition(FormatStringHandler & H,FormatSpecifier & FS,const char * Start,const char * & Beg,const char * E)1443d1dcd9bSDimitry Andric clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,
1453d1dcd9bSDimitry Andric                                                FormatSpecifier &FS,
1463d1dcd9bSDimitry Andric                                                const char *Start,
1473d1dcd9bSDimitry Andric                                                const char *&Beg,
1483d1dcd9bSDimitry Andric                                                const char *E) {
1493d1dcd9bSDimitry Andric   const char *I = Beg;
1503d1dcd9bSDimitry Andric 
1513d1dcd9bSDimitry Andric   const OptionalAmount &Amt = ParseAmount(I, E);
1523d1dcd9bSDimitry Andric 
1533d1dcd9bSDimitry Andric   if (I == E) {
1543d1dcd9bSDimitry Andric     // No more characters left?
1553d1dcd9bSDimitry Andric     H.HandleIncompleteSpecifier(Start, E - Start);
1563d1dcd9bSDimitry Andric     return true;
1573d1dcd9bSDimitry Andric   }
1583d1dcd9bSDimitry Andric 
1593d1dcd9bSDimitry Andric   if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {
160dbe13110SDimitry Andric     // Warn that positional arguments are non-standard.
161dbe13110SDimitry Andric     H.HandlePosition(Start, I - Start);
162dbe13110SDimitry Andric 
1633d1dcd9bSDimitry Andric     // Special case: '%0$', since this is an easy mistake.
1643d1dcd9bSDimitry Andric     if (Amt.getConstantAmount() == 0) {
1653d1dcd9bSDimitry Andric       H.HandleZeroPosition(Start, I - Start);
1663d1dcd9bSDimitry Andric       return true;
1673d1dcd9bSDimitry Andric     }
1683d1dcd9bSDimitry Andric 
1693d1dcd9bSDimitry Andric     FS.setArgIndex(Amt.getConstantAmount() - 1);
1703d1dcd9bSDimitry Andric     FS.setUsesPositionalArg();
1713d1dcd9bSDimitry Andric     // Update the caller's pointer if we decided to consume
1723d1dcd9bSDimitry Andric     // these characters.
1733d1dcd9bSDimitry Andric     Beg = I;
1743d1dcd9bSDimitry Andric     return false;
1753d1dcd9bSDimitry Andric   }
1763d1dcd9bSDimitry Andric 
1773d1dcd9bSDimitry Andric   return false;
1783d1dcd9bSDimitry Andric }
1793d1dcd9bSDimitry Andric 
1803d1dcd9bSDimitry Andric bool
ParseVectorModifier(FormatStringHandler & H,FormatSpecifier & FS,const char * & I,const char * E,const LangOptions & LO)181676fbe81SDimitry Andric clang::analyze_format_string::ParseVectorModifier(FormatStringHandler &H,
182676fbe81SDimitry Andric                                                   FormatSpecifier &FS,
183676fbe81SDimitry Andric                                                   const char *&I,
184676fbe81SDimitry Andric                                                   const char *E,
185676fbe81SDimitry Andric                                                   const LangOptions &LO) {
186676fbe81SDimitry Andric   if (!LO.OpenCL)
187676fbe81SDimitry Andric     return false;
188676fbe81SDimitry Andric 
189676fbe81SDimitry Andric   const char *Start = I;
190676fbe81SDimitry Andric   if (*I == 'v') {
191676fbe81SDimitry Andric     ++I;
192676fbe81SDimitry Andric 
193676fbe81SDimitry Andric     if (I == E) {
194676fbe81SDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
195676fbe81SDimitry Andric       return true;
196676fbe81SDimitry Andric     }
197676fbe81SDimitry Andric 
198676fbe81SDimitry Andric     OptionalAmount NumElts = ParseAmount(I, E);
199676fbe81SDimitry Andric     if (NumElts.getHowSpecified() != OptionalAmount::Constant) {
200676fbe81SDimitry Andric       H.HandleIncompleteSpecifier(Start, E - Start);
201676fbe81SDimitry Andric       return true;
202676fbe81SDimitry Andric     }
203676fbe81SDimitry Andric 
204676fbe81SDimitry Andric     FS.setVectorNumElts(NumElts);
205676fbe81SDimitry Andric   }
206676fbe81SDimitry Andric 
207676fbe81SDimitry Andric   return false;
208676fbe81SDimitry Andric }
209676fbe81SDimitry Andric 
210676fbe81SDimitry Andric bool
ParseLengthModifier(FormatSpecifier & FS,const char * & I,const char * E,const LangOptions & LO,bool IsScanf)2113d1dcd9bSDimitry Andric clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
2123d1dcd9bSDimitry Andric                                                   const char *&I,
213dbe13110SDimitry Andric                                                   const char *E,
214dbe13110SDimitry Andric                                                   const LangOptions &LO,
215dbe13110SDimitry Andric                                                   bool IsScanf) {
2163d1dcd9bSDimitry Andric   LengthModifier::Kind lmKind = LengthModifier::None;
2173d1dcd9bSDimitry Andric   const char *lmPosition = I;
2183d1dcd9bSDimitry Andric   switch (*I) {
2193d1dcd9bSDimitry Andric     default:
2203d1dcd9bSDimitry Andric       return false;
2213d1dcd9bSDimitry Andric     case 'h':
2223d1dcd9bSDimitry Andric       ++I;
2232b6b257fSDimitry Andric       if (I != E && *I == 'h') {
2242b6b257fSDimitry Andric         ++I;
2252b6b257fSDimitry Andric         lmKind = LengthModifier::AsChar;
22622989816SDimitry Andric       } else if (I != E && *I == 'l' && LO.OpenCL) {
22722989816SDimitry Andric         ++I;
22822989816SDimitry Andric         lmKind = LengthModifier::AsShortLong;
2292b6b257fSDimitry Andric       } else {
2302b6b257fSDimitry Andric         lmKind = LengthModifier::AsShort;
2312b6b257fSDimitry Andric       }
2323d1dcd9bSDimitry Andric       break;
2333d1dcd9bSDimitry Andric     case 'l':
2343d1dcd9bSDimitry Andric       ++I;
2352b6b257fSDimitry Andric       if (I != E && *I == 'l') {
2362b6b257fSDimitry Andric         ++I;
2372b6b257fSDimitry Andric         lmKind = LengthModifier::AsLongLong;
2382b6b257fSDimitry Andric       } else {
2392b6b257fSDimitry Andric         lmKind = LengthModifier::AsLong;
2402b6b257fSDimitry Andric       }
2413d1dcd9bSDimitry Andric       break;
2423d1dcd9bSDimitry Andric     case 'j': lmKind = LengthModifier::AsIntMax;     ++I; break;
2433d1dcd9bSDimitry Andric     case 'z': lmKind = LengthModifier::AsSizeT;      ++I; break;
2443d1dcd9bSDimitry Andric     case 't': lmKind = LengthModifier::AsPtrDiff;    ++I; break;
2453d1dcd9bSDimitry Andric     case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
246dbe13110SDimitry Andric     case 'q': lmKind = LengthModifier::AsQuad;       ++I; break;
247dbe13110SDimitry Andric     case 'a':
248809500fcSDimitry Andric       if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
249dbe13110SDimitry Andric         // For scanf in C90, look at the next character to see if this should
250dbe13110SDimitry Andric         // be parsed as the GNU extension 'a' length modifier. If not, this
251dbe13110SDimitry Andric         // will be parsed as a conversion specifier.
252dbe13110SDimitry Andric         ++I;
253dbe13110SDimitry Andric         if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {
254dbe13110SDimitry Andric           lmKind = LengthModifier::AsAllocate;
255dbe13110SDimitry Andric           break;
256dbe13110SDimitry Andric         }
257dbe13110SDimitry Andric         --I;
258dbe13110SDimitry Andric       }
259dbe13110SDimitry Andric       return false;
260dbe13110SDimitry Andric     case 'm':
261dbe13110SDimitry Andric       if (IsScanf) {
262dbe13110SDimitry Andric         lmKind = LengthModifier::AsMAllocate;
263dbe13110SDimitry Andric         ++I;
264dbe13110SDimitry Andric         break;
265dbe13110SDimitry Andric       }
266dbe13110SDimitry Andric       return false;
267bfef3995SDimitry Andric     // printf: AsInt64, AsInt32, AsInt3264
268bfef3995SDimitry Andric     // scanf:  AsInt64
269bfef3995SDimitry Andric     case 'I':
270bfef3995SDimitry Andric       if (I + 1 != E && I + 2 != E) {
271bfef3995SDimitry Andric         if (I[1] == '6' && I[2] == '4') {
272bfef3995SDimitry Andric           I += 3;
273bfef3995SDimitry Andric           lmKind = LengthModifier::AsInt64;
274bfef3995SDimitry Andric           break;
275bfef3995SDimitry Andric         }
276bfef3995SDimitry Andric         if (IsScanf)
277bfef3995SDimitry Andric           return false;
278bfef3995SDimitry Andric 
279bfef3995SDimitry Andric         if (I[1] == '3' && I[2] == '2') {
280bfef3995SDimitry Andric           I += 3;
281bfef3995SDimitry Andric           lmKind = LengthModifier::AsInt32;
282bfef3995SDimitry Andric           break;
283bfef3995SDimitry Andric         }
284bfef3995SDimitry Andric       }
285bfef3995SDimitry Andric       ++I;
286bfef3995SDimitry Andric       lmKind = LengthModifier::AsInt3264;
287bfef3995SDimitry Andric       break;
28806d4ba38SDimitry Andric     case 'w':
28906d4ba38SDimitry Andric       lmKind = LengthModifier::AsWide; ++I; break;
2903d1dcd9bSDimitry Andric   }
2913d1dcd9bSDimitry Andric   LengthModifier lm(lmPosition, lmKind);
2923d1dcd9bSDimitry Andric   FS.setLengthModifier(lm);
2933d1dcd9bSDimitry Andric   return true;
2943d1dcd9bSDimitry Andric }
2953d1dcd9bSDimitry Andric 
ParseUTF8InvalidSpecifier(const char * SpecifierBegin,const char * FmtStrEnd,unsigned & Len)2962b6b257fSDimitry Andric bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
2972b6b257fSDimitry Andric     const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {
2982b6b257fSDimitry Andric   if (SpecifierBegin + 1 >= FmtStrEnd)
2992b6b257fSDimitry Andric     return false;
3002b6b257fSDimitry Andric 
301bab175ecSDimitry Andric   const llvm::UTF8 *SB =
302bab175ecSDimitry Andric       reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);
303bab175ecSDimitry Andric   const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);
3042b6b257fSDimitry Andric   const char FirstByte = *SB;
3052b6b257fSDimitry Andric 
3062b6b257fSDimitry Andric   // If the invalid specifier is a multibyte UTF-8 string, return the
3072b6b257fSDimitry Andric   // total length accordingly so that the conversion specifier can be
3082b6b257fSDimitry Andric   // properly updated to reflect a complete UTF-8 specifier.
309bab175ecSDimitry Andric   unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);
3102b6b257fSDimitry Andric   if (NumBytes == 1)
3112b6b257fSDimitry Andric     return false;
3122b6b257fSDimitry Andric   if (SB + NumBytes > SE)
3132b6b257fSDimitry Andric     return false;
3142b6b257fSDimitry Andric 
3152b6b257fSDimitry Andric   Len = NumBytes + 1;
3162b6b257fSDimitry Andric   return true;
3172b6b257fSDimitry Andric }
3182b6b257fSDimitry Andric 
3193d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
32056d91b49SDimitry Andric // Methods on ArgType.
3213d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
3223d1dcd9bSDimitry Andric 
3235e20cdd8SDimitry Andric clang::analyze_format_string::ArgType::MatchKind
matchesType(ASTContext & C,QualType argTy) const3245e20cdd8SDimitry Andric ArgType::matchesType(ASTContext &C, QualType argTy) const {
3251f917f69SDimitry Andric   // When using the format attribute in C++, you can receive a function or an
3261f917f69SDimitry Andric   // array that will necessarily decay to a pointer when passed to the final
3271f917f69SDimitry Andric   // format consumer. Apply decay before type comparison.
3281f917f69SDimitry Andric   if (argTy->canDecayToPointerType())
3291f917f69SDimitry Andric     argTy = C.getDecayedType(argTy);
3301f917f69SDimitry Andric 
33156d91b49SDimitry Andric   if (Ptr) {
33256d91b49SDimitry Andric     // It has to be a pointer.
33356d91b49SDimitry Andric     const PointerType *PT = argTy->getAs<PointerType>();
33456d91b49SDimitry Andric     if (!PT)
3355e20cdd8SDimitry Andric       return NoMatch;
33656d91b49SDimitry Andric 
33756d91b49SDimitry Andric     // We cannot write through a const qualified pointer.
33856d91b49SDimitry Andric     if (PT->getPointeeType().isConstQualified())
3395e20cdd8SDimitry Andric       return NoMatch;
34056d91b49SDimitry Andric 
34156d91b49SDimitry Andric     argTy = PT->getPointeeType();
34256d91b49SDimitry Andric   }
34356d91b49SDimitry Andric 
3443d1dcd9bSDimitry Andric   switch (K) {
3453d1dcd9bSDimitry Andric     case InvalidTy:
34656d91b49SDimitry Andric       llvm_unreachable("ArgType must be valid");
3473d1dcd9bSDimitry Andric 
3483d1dcd9bSDimitry Andric     case UnknownTy:
3495e20cdd8SDimitry Andric       return Match;
3503d1dcd9bSDimitry Andric 
351dbe13110SDimitry Andric     case AnyCharTy: {
352e3b55780SDimitry Andric       if (const auto *ETy = argTy->getAs<EnumType>()) {
353bab175ecSDimitry Andric         // If the enum is incomplete we know nothing about the underlying type.
3547fa27ce4SDimitry Andric         // Assume that it's 'int'. Do not use the underlying type for a scoped
3557fa27ce4SDimitry Andric         // enumeration.
356bab175ecSDimitry Andric         if (!ETy->getDecl()->isComplete())
357bab175ecSDimitry Andric           return NoMatch;
3587fa27ce4SDimitry Andric         if (ETy->isUnscopedEnumerationType())
35956d91b49SDimitry Andric           argTy = ETy->getDecl()->getIntegerType();
360bab175ecSDimitry Andric       }
36156d91b49SDimitry Andric 
362e3b55780SDimitry Andric       if (const auto *BT = argTy->getAs<BuiltinType>()) {
363e3b55780SDimitry Andric         // The types are perfectly matched?
364dbe13110SDimitry Andric         switch (BT->getKind()) {
365dbe13110SDimitry Andric         default:
366dbe13110SDimitry Andric           break;
367dbe13110SDimitry Andric         case BuiltinType::Char_S:
368dbe13110SDimitry Andric         case BuiltinType::SChar:
369dbe13110SDimitry Andric         case BuiltinType::UChar:
370dbe13110SDimitry Andric         case BuiltinType::Char_U:
3715e20cdd8SDimitry Andric             return Match;
372b1c73532SDimitry Andric         case BuiltinType::Bool:
373b1c73532SDimitry Andric           if (!Ptr)
374b1c73532SDimitry Andric             return Match;
375b1c73532SDimitry Andric           break;
376dbe13110SDimitry Andric         }
377e3b55780SDimitry Andric         // "Partially matched" because of promotions?
378e3b55780SDimitry Andric         if (!Ptr) {
379e3b55780SDimitry Andric           switch (BT->getKind()) {
380e3b55780SDimitry Andric           default:
381e3b55780SDimitry Andric             break;
382e3b55780SDimitry Andric           case BuiltinType::Int:
383e3b55780SDimitry Andric           case BuiltinType::UInt:
384e3b55780SDimitry Andric             return MatchPromotion;
385e3b55780SDimitry Andric           case BuiltinType::Short:
386e3b55780SDimitry Andric           case BuiltinType::UShort:
387e3b55780SDimitry Andric           case BuiltinType::WChar_S:
388e3b55780SDimitry Andric           case BuiltinType::WChar_U:
389e3b55780SDimitry Andric             return NoMatchPromotionTypeConfusion;
390e3b55780SDimitry Andric           }
391e3b55780SDimitry Andric         }
392e3b55780SDimitry Andric       }
3935e20cdd8SDimitry Andric       return NoMatch;
394dbe13110SDimitry Andric     }
395dbe13110SDimitry Andric 
3963d1dcd9bSDimitry Andric     case SpecificTy: {
397bab175ecSDimitry Andric       if (const EnumType *ETy = argTy->getAs<EnumType>()) {
398bab175ecSDimitry Andric         // If the enum is incomplete we know nothing about the underlying type.
3997fa27ce4SDimitry Andric         // Assume that it's 'int'. Do not use the underlying type for a scoped
4007fa27ce4SDimitry Andric         // enumeration as that needs an exact match.
401bab175ecSDimitry Andric         if (!ETy->getDecl()->isComplete())
402bab175ecSDimitry Andric           argTy = C.IntTy;
4037fa27ce4SDimitry Andric         else if (ETy->isUnscopedEnumerationType())
40456d91b49SDimitry Andric           argTy = ETy->getDecl()->getIntegerType();
405bab175ecSDimitry Andric       }
406ac9a064cSDimitry Andric 
407ac9a064cSDimitry Andric       if (argTy->isSaturatedFixedPointType())
408ac9a064cSDimitry Andric         argTy = C.getCorrespondingUnsaturatedType(argTy);
409ac9a064cSDimitry Andric 
4103d1dcd9bSDimitry Andric       argTy = C.getCanonicalType(argTy).getUnqualifiedType();
41156d91b49SDimitry Andric 
4123d1dcd9bSDimitry Andric       if (T == argTy)
4135e20cdd8SDimitry Andric         return Match;
414e3b55780SDimitry Andric       if (const auto *BT = argTy->getAs<BuiltinType>()) {
415e3b55780SDimitry Andric         // Check if the only difference between them is signed vs unsigned
416ac9a064cSDimitry Andric         // if true, return match signedness.
4173d1dcd9bSDimitry Andric         switch (BT->getKind()) {
4183d1dcd9bSDimitry Andric           default:
4193d1dcd9bSDimitry Andric             break;
420b1c73532SDimitry Andric           case BuiltinType::Bool:
421b1c73532SDimitry Andric             if (Ptr && (T == C.UnsignedCharTy || T == C.SignedCharTy))
422b1c73532SDimitry Andric               return NoMatch;
423b1c73532SDimitry Andric             [[fallthrough]];
4243d1dcd9bSDimitry Andric           case BuiltinType::Char_S:
4253d1dcd9bSDimitry Andric           case BuiltinType::SChar:
426ac9a064cSDimitry Andric             if (T == C.UnsignedShortTy || T == C.ShortTy)
427ac9a064cSDimitry Andric               return NoMatchTypeConfusion;
428ac9a064cSDimitry Andric             if (T == C.UnsignedCharTy)
429ac9a064cSDimitry Andric               return NoMatchSignedness;
430ac9a064cSDimitry Andric             if (T == C.SignedCharTy)
431ac9a064cSDimitry Andric               return Match;
432ac9a064cSDimitry Andric             break;
4333d1dcd9bSDimitry Andric           case BuiltinType::Char_U:
4343d1dcd9bSDimitry Andric           case BuiltinType::UChar:
435519fc96cSDimitry Andric             if (T == C.UnsignedShortTy || T == C.ShortTy)
436519fc96cSDimitry Andric               return NoMatchTypeConfusion;
437ac9a064cSDimitry Andric             if (T == C.UnsignedCharTy)
438e3b55780SDimitry Andric               return Match;
439ac9a064cSDimitry Andric             if (T == C.SignedCharTy)
440ac9a064cSDimitry Andric               return NoMatchSignedness;
441e3b55780SDimitry Andric             break;
4423d1dcd9bSDimitry Andric           case BuiltinType::Short:
443e3b55780SDimitry Andric             if (T == C.UnsignedShortTy)
444ac9a064cSDimitry Andric               return NoMatchSignedness;
445e3b55780SDimitry Andric             break;
4463d1dcd9bSDimitry Andric           case BuiltinType::UShort:
447e3b55780SDimitry Andric             if (T == C.ShortTy)
448ac9a064cSDimitry Andric               return NoMatchSignedness;
449e3b55780SDimitry Andric             break;
4503d1dcd9bSDimitry Andric           case BuiltinType::Int:
451e3b55780SDimitry Andric             if (T == C.UnsignedIntTy)
452ac9a064cSDimitry Andric               return NoMatchSignedness;
453e3b55780SDimitry Andric             break;
4543d1dcd9bSDimitry Andric           case BuiltinType::UInt:
455e3b55780SDimitry Andric             if (T == C.IntTy)
456ac9a064cSDimitry Andric               return NoMatchSignedness;
457e3b55780SDimitry Andric             break;
4583d1dcd9bSDimitry Andric           case BuiltinType::Long:
459e3b55780SDimitry Andric             if (T == C.UnsignedLongTy)
460ac9a064cSDimitry Andric               return NoMatchSignedness;
461e3b55780SDimitry Andric             break;
4623d1dcd9bSDimitry Andric           case BuiltinType::ULong:
463e3b55780SDimitry Andric             if (T == C.LongTy)
464ac9a064cSDimitry Andric               return NoMatchSignedness;
465e3b55780SDimitry Andric             break;
4663d1dcd9bSDimitry Andric           case BuiltinType::LongLong:
467e3b55780SDimitry Andric             if (T == C.UnsignedLongLongTy)
468ac9a064cSDimitry Andric               return NoMatchSignedness;
469e3b55780SDimitry Andric             break;
4703d1dcd9bSDimitry Andric           case BuiltinType::ULongLong:
471e3b55780SDimitry Andric             if (T == C.LongLongTy)
472ac9a064cSDimitry Andric               return NoMatchSignedness;
473e3b55780SDimitry Andric             break;
474e3b55780SDimitry Andric           }
475e3b55780SDimitry Andric           // "Partially matched" because of promotions?
476e3b55780SDimitry Andric           if (!Ptr) {
477e3b55780SDimitry Andric             switch (BT->getKind()) {
478e3b55780SDimitry Andric             default:
479e3b55780SDimitry Andric               break;
480b1c73532SDimitry Andric             case BuiltinType::Bool:
481b1c73532SDimitry Andric               if (T == C.IntTy || T == C.UnsignedIntTy)
482b1c73532SDimitry Andric                 return MatchPromotion;
483b1c73532SDimitry Andric               break;
484e3b55780SDimitry Andric             case BuiltinType::Int:
485e3b55780SDimitry Andric             case BuiltinType::UInt:
486e3b55780SDimitry Andric               if (T == C.SignedCharTy || T == C.UnsignedCharTy ||
487e3b55780SDimitry Andric                   T == C.ShortTy || T == C.UnsignedShortTy || T == C.WCharTy ||
488e3b55780SDimitry Andric                   T == C.WideCharTy)
489e3b55780SDimitry Andric                 return MatchPromotion;
490e3b55780SDimitry Andric               break;
491b1c73532SDimitry Andric             case BuiltinType::Char_U:
492b1c73532SDimitry Andric               if (T == C.UnsignedIntTy)
493b1c73532SDimitry Andric                 return MatchPromotion;
494b1c73532SDimitry Andric               if (T == C.UnsignedShortTy)
495b1c73532SDimitry Andric                 return NoMatchPromotionTypeConfusion;
496b1c73532SDimitry Andric               break;
497b1c73532SDimitry Andric             case BuiltinType::Char_S:
498b1c73532SDimitry Andric               if (T == C.IntTy)
499b1c73532SDimitry Andric                 return MatchPromotion;
500b1c73532SDimitry Andric               if (T == C.ShortTy)
501b1c73532SDimitry Andric                 return NoMatchPromotionTypeConfusion;
502b1c73532SDimitry Andric               break;
503b1c73532SDimitry Andric             case BuiltinType::Half:
504b1c73532SDimitry Andric             case BuiltinType::Float:
505b1c73532SDimitry Andric               if (T == C.DoubleTy)
506b1c73532SDimitry Andric                 return MatchPromotion;
507b1c73532SDimitry Andric               break;
508e3b55780SDimitry Andric             case BuiltinType::Short:
509e3b55780SDimitry Andric             case BuiltinType::UShort:
510e3b55780SDimitry Andric               if (T == C.SignedCharTy || T == C.UnsignedCharTy)
511e3b55780SDimitry Andric                 return NoMatchPromotionTypeConfusion;
512e3b55780SDimitry Andric               break;
513e3b55780SDimitry Andric             case BuiltinType::WChar_U:
514e3b55780SDimitry Andric             case BuiltinType::WChar_S:
515e3b55780SDimitry Andric               if (T != C.WCharTy && T != C.WideCharTy)
516e3b55780SDimitry Andric                 return NoMatchPromotionTypeConfusion;
517e3b55780SDimitry Andric             }
518e3b55780SDimitry Andric           }
5193d1dcd9bSDimitry Andric       }
5205e20cdd8SDimitry Andric       return NoMatch;
5213d1dcd9bSDimitry Andric     }
5223d1dcd9bSDimitry Andric 
5233d1dcd9bSDimitry Andric     case CStrTy: {
5243d1dcd9bSDimitry Andric       const PointerType *PT = argTy->getAs<PointerType>();
5253d1dcd9bSDimitry Andric       if (!PT)
5265e20cdd8SDimitry Andric         return NoMatch;
5273d1dcd9bSDimitry Andric       QualType pointeeTy = PT->getPointeeType();
5283d1dcd9bSDimitry Andric       if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())
5293d1dcd9bSDimitry Andric         switch (BT->getKind()) {
5303d1dcd9bSDimitry Andric           case BuiltinType::Char_U:
5313d1dcd9bSDimitry Andric           case BuiltinType::UChar:
5323d1dcd9bSDimitry Andric           case BuiltinType::Char_S:
5333d1dcd9bSDimitry Andric           case BuiltinType::SChar:
5345e20cdd8SDimitry Andric             return Match;
5353d1dcd9bSDimitry Andric           default:
5363d1dcd9bSDimitry Andric             break;
5373d1dcd9bSDimitry Andric         }
5383d1dcd9bSDimitry Andric 
5395e20cdd8SDimitry Andric       return NoMatch;
5403d1dcd9bSDimitry Andric     }
5413d1dcd9bSDimitry Andric 
5423d1dcd9bSDimitry Andric     case WCStrTy: {
5433d1dcd9bSDimitry Andric       const PointerType *PT = argTy->getAs<PointerType>();
5443d1dcd9bSDimitry Andric       if (!PT)
5455e20cdd8SDimitry Andric         return NoMatch;
5463d1dcd9bSDimitry Andric       QualType pointeeTy =
5473d1dcd9bSDimitry Andric         C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();
5485e20cdd8SDimitry Andric       return pointeeTy == C.getWideCharType() ? Match : NoMatch;
5493d1dcd9bSDimitry Andric     }
5503d1dcd9bSDimitry Andric 
5513d1dcd9bSDimitry Andric     case WIntTy: {
55256d91b49SDimitry Andric       QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();
553676fbe81SDimitry Andric 
554676fbe81SDimitry Andric       if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
555676fbe81SDimitry Andric         return Match;
556676fbe81SDimitry Andric 
557e3b55780SDimitry Andric       QualType PromoArg = C.isPromotableIntegerType(argTy)
558676fbe81SDimitry Andric                               ? C.getPromotedIntegerType(argTy)
559676fbe81SDimitry Andric                               : argTy;
5603d1dcd9bSDimitry Andric       PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
5613d1dcd9bSDimitry Andric 
56256d91b49SDimitry Andric       // If the promoted argument is the corresponding signed type of the
56356d91b49SDimitry Andric       // wint_t type, then it should match.
56456d91b49SDimitry Andric       if (PromoArg->hasSignedIntegerRepresentation() &&
56556d91b49SDimitry Andric           C.getCorrespondingUnsignedType(PromoArg) == WInt)
5665e20cdd8SDimitry Andric         return Match;
56756d91b49SDimitry Andric 
5685e20cdd8SDimitry Andric       return WInt == PromoArg ? Match : NoMatch;
5693d1dcd9bSDimitry Andric     }
5703d1dcd9bSDimitry Andric 
5713d1dcd9bSDimitry Andric     case CPointerTy:
5725e20cdd8SDimitry Andric       if (argTy->isVoidPointerType()) {
5735e20cdd8SDimitry Andric         return Match;
5745e20cdd8SDimitry Andric       } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||
5755e20cdd8SDimitry Andric             argTy->isBlockPointerType() || argTy->isNullPtrType()) {
5765e20cdd8SDimitry Andric         return NoMatchPedantic;
5775e20cdd8SDimitry Andric       } else {
5785e20cdd8SDimitry Andric         return NoMatch;
5795e20cdd8SDimitry Andric       }
5803d1dcd9bSDimitry Andric 
581dbe13110SDimitry Andric     case ObjCPointerTy: {
582dbe13110SDimitry Andric       if (argTy->getAs<ObjCObjectPointerType>() ||
583dbe13110SDimitry Andric           argTy->getAs<BlockPointerType>())
5845e20cdd8SDimitry Andric         return Match;
585dbe13110SDimitry Andric 
586dbe13110SDimitry Andric       // Handle implicit toll-free bridging.
587dbe13110SDimitry Andric       if (const PointerType *PT = argTy->getAs<PointerType>()) {
588dbe13110SDimitry Andric         // Things such as CFTypeRef are really just opaque pointers
589dbe13110SDimitry Andric         // to C structs representing CF types that can often be bridged
590dbe13110SDimitry Andric         // to Objective-C objects.  Since the compiler doesn't know which
591dbe13110SDimitry Andric         // structs can be toll-free bridged, we just accept them all.
592dbe13110SDimitry Andric         QualType pointee = PT->getPointeeType();
593dbe13110SDimitry Andric         if (pointee->getAsStructureType() || pointee->isVoidType())
5945e20cdd8SDimitry Andric           return Match;
595dbe13110SDimitry Andric       }
5965e20cdd8SDimitry Andric       return NoMatch;
597dbe13110SDimitry Andric     }
5983d1dcd9bSDimitry Andric   }
5993d1dcd9bSDimitry Andric 
60056d91b49SDimitry Andric   llvm_unreachable("Invalid ArgType Kind!");
6013d1dcd9bSDimitry Andric }
6023d1dcd9bSDimitry Andric 
makeVectorType(ASTContext & C,unsigned NumElts) const603676fbe81SDimitry Andric ArgType ArgType::makeVectorType(ASTContext &C, unsigned NumElts) const {
60422989816SDimitry Andric   // Check for valid vector element types.
60522989816SDimitry Andric   if (T.isNull())
606676fbe81SDimitry Andric     return ArgType::Invalid();
607676fbe81SDimitry Andric 
608676fbe81SDimitry Andric   QualType Vec = C.getExtVectorType(T, NumElts);
609676fbe81SDimitry Andric   return ArgType(Vec, Name);
610676fbe81SDimitry Andric }
611676fbe81SDimitry Andric 
getRepresentativeType(ASTContext & C) const61256d91b49SDimitry Andric QualType ArgType::getRepresentativeType(ASTContext &C) const {
61356d91b49SDimitry Andric   QualType Res;
6143d1dcd9bSDimitry Andric   switch (K) {
6153d1dcd9bSDimitry Andric     case InvalidTy:
61656d91b49SDimitry Andric       llvm_unreachable("No representative type for Invalid ArgType");
6173d1dcd9bSDimitry Andric     case UnknownTy:
61856d91b49SDimitry Andric       llvm_unreachable("No representative type for Unknown ArgType");
619dbe13110SDimitry Andric     case AnyCharTy:
62056d91b49SDimitry Andric       Res = C.CharTy;
62156d91b49SDimitry Andric       break;
6223d1dcd9bSDimitry Andric     case SpecificTy:
62356d91b49SDimitry Andric       Res = T;
62456d91b49SDimitry Andric       break;
6253d1dcd9bSDimitry Andric     case CStrTy:
62656d91b49SDimitry Andric       Res = C.getPointerType(C.CharTy);
62756d91b49SDimitry Andric       break;
6283d1dcd9bSDimitry Andric     case WCStrTy:
629bfef3995SDimitry Andric       Res = C.getPointerType(C.getWideCharType());
63056d91b49SDimitry Andric       break;
6313d1dcd9bSDimitry Andric     case ObjCPointerTy:
63256d91b49SDimitry Andric       Res = C.ObjCBuiltinIdTy;
63356d91b49SDimitry Andric       break;
6343d1dcd9bSDimitry Andric     case CPointerTy:
63556d91b49SDimitry Andric       Res = C.VoidPtrTy;
63656d91b49SDimitry Andric       break;
6373d1dcd9bSDimitry Andric     case WIntTy: {
63856d91b49SDimitry Andric       Res = C.getWIntType();
63956d91b49SDimitry Andric       break;
6403d1dcd9bSDimitry Andric     }
6413d1dcd9bSDimitry Andric   }
6423d1dcd9bSDimitry Andric 
64356d91b49SDimitry Andric   if (Ptr)
64456d91b49SDimitry Andric     Res = C.getPointerType(Res);
64556d91b49SDimitry Andric   return Res;
6463d1dcd9bSDimitry Andric }
6473d1dcd9bSDimitry Andric 
getRepresentativeTypeName(ASTContext & C) const64856d91b49SDimitry Andric std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {
649cfca06d7SDimitry Andric   std::string S = getRepresentativeType(C).getAsString(C.getPrintingPolicy());
65056d91b49SDimitry Andric 
65156d91b49SDimitry Andric   std::string Alias;
65256d91b49SDimitry Andric   if (Name) {
65356d91b49SDimitry Andric     // Use a specific name for this type, e.g. "size_t".
65456d91b49SDimitry Andric     Alias = Name;
65556d91b49SDimitry Andric     if (Ptr) {
65656d91b49SDimitry Andric       // If ArgType is actually a pointer to T, append an asterisk.
65756d91b49SDimitry Andric       Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";
65856d91b49SDimitry Andric     }
65956d91b49SDimitry Andric     // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.
66056d91b49SDimitry Andric     if (S == Alias)
66156d91b49SDimitry Andric       Alias.clear();
66256d91b49SDimitry Andric   }
66356d91b49SDimitry Andric 
66456d91b49SDimitry Andric   if (!Alias.empty())
66556d91b49SDimitry Andric     return std::string("'") + Alias + "' (aka '" + S + "')";
666dbe13110SDimitry Andric   return std::string("'") + S + "'";
667dbe13110SDimitry Andric }
668dbe13110SDimitry Andric 
669dbe13110SDimitry Andric 
6703d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
6713d1dcd9bSDimitry Andric // Methods on OptionalAmount.
6723d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
6733d1dcd9bSDimitry Andric 
67456d91b49SDimitry Andric ArgType
getArgType(ASTContext & Ctx) const6753d1dcd9bSDimitry Andric analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {
6763d1dcd9bSDimitry Andric   return Ctx.IntTy;
6773d1dcd9bSDimitry Andric }
6783d1dcd9bSDimitry Andric 
6793d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
6803d1dcd9bSDimitry Andric // Methods on LengthModifier.
6813d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
6823d1dcd9bSDimitry Andric 
6833d1dcd9bSDimitry Andric const char *
toString() const6843d1dcd9bSDimitry Andric analyze_format_string::LengthModifier::toString() const {
6853d1dcd9bSDimitry Andric   switch (kind) {
6863d1dcd9bSDimitry Andric   case AsChar:
6873d1dcd9bSDimitry Andric     return "hh";
6883d1dcd9bSDimitry Andric   case AsShort:
6893d1dcd9bSDimitry Andric     return "h";
69022989816SDimitry Andric   case AsShortLong:
69122989816SDimitry Andric     return "hl";
6923d1dcd9bSDimitry Andric   case AsLong: // or AsWideChar
6933d1dcd9bSDimitry Andric     return "l";
6943d1dcd9bSDimitry Andric   case AsLongLong:
6953d1dcd9bSDimitry Andric     return "ll";
696dbe13110SDimitry Andric   case AsQuad:
697dbe13110SDimitry Andric     return "q";
6983d1dcd9bSDimitry Andric   case AsIntMax:
6993d1dcd9bSDimitry Andric     return "j";
7003d1dcd9bSDimitry Andric   case AsSizeT:
7013d1dcd9bSDimitry Andric     return "z";
7023d1dcd9bSDimitry Andric   case AsPtrDiff:
7033d1dcd9bSDimitry Andric     return "t";
704bfef3995SDimitry Andric   case AsInt32:
705bfef3995SDimitry Andric     return "I32";
706bfef3995SDimitry Andric   case AsInt3264:
707bfef3995SDimitry Andric     return "I";
708bfef3995SDimitry Andric   case AsInt64:
709bfef3995SDimitry Andric     return "I64";
7103d1dcd9bSDimitry Andric   case AsLongDouble:
7113d1dcd9bSDimitry Andric     return "L";
712dbe13110SDimitry Andric   case AsAllocate:
713dbe13110SDimitry Andric     return "a";
714dbe13110SDimitry Andric   case AsMAllocate:
715dbe13110SDimitry Andric     return "m";
71606d4ba38SDimitry Andric   case AsWide:
71706d4ba38SDimitry Andric     return "w";
7183d1dcd9bSDimitry Andric   case None:
7193d1dcd9bSDimitry Andric     return "";
7203d1dcd9bSDimitry Andric   }
7219f4dbff6SDimitry Andric   return nullptr;
7223d1dcd9bSDimitry Andric }
7233d1dcd9bSDimitry Andric 
7243d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
725dbe13110SDimitry Andric // Methods on ConversionSpecifier.
726dbe13110SDimitry Andric //===----------------------------------------------------------------------===//
727dbe13110SDimitry Andric 
toString() const728dbe13110SDimitry Andric const char *ConversionSpecifier::toString() const {
729dbe13110SDimitry Andric   switch (kind) {
730e3b55780SDimitry Andric   case bArg: return "b";
731e3b55780SDimitry Andric   case BArg: return "B";
732dbe13110SDimitry Andric   case dArg: return "d";
73313cc256eSDimitry Andric   case DArg: return "D";
734dbe13110SDimitry Andric   case iArg: return "i";
735dbe13110SDimitry Andric   case oArg: return "o";
73613cc256eSDimitry Andric   case OArg: return "O";
737dbe13110SDimitry Andric   case uArg: return "u";
73813cc256eSDimitry Andric   case UArg: return "U";
739dbe13110SDimitry Andric   case xArg: return "x";
740dbe13110SDimitry Andric   case XArg: return "X";
741dbe13110SDimitry Andric   case fArg: return "f";
742dbe13110SDimitry Andric   case FArg: return "F";
743dbe13110SDimitry Andric   case eArg: return "e";
744dbe13110SDimitry Andric   case EArg: return "E";
745dbe13110SDimitry Andric   case gArg: return "g";
746dbe13110SDimitry Andric   case GArg: return "G";
747dbe13110SDimitry Andric   case aArg: return "a";
748dbe13110SDimitry Andric   case AArg: return "A";
749dbe13110SDimitry Andric   case cArg: return "c";
750dbe13110SDimitry Andric   case sArg: return "s";
751dbe13110SDimitry Andric   case pArg: return "p";
752bab175ecSDimitry Andric   case PArg:
753bab175ecSDimitry Andric     return "P";
754dbe13110SDimitry Andric   case nArg: return "n";
755dbe13110SDimitry Andric   case PercentArg:  return "%";
756dbe13110SDimitry Andric   case ScanListArg: return "[";
7579f4dbff6SDimitry Andric   case InvalidSpecifier: return nullptr;
758dbe13110SDimitry Andric 
759bfef3995SDimitry Andric   // POSIX unicode extensions.
760dbe13110SDimitry Andric   case CArg: return "C";
761dbe13110SDimitry Andric   case SArg: return "S";
762dbe13110SDimitry Andric 
763dbe13110SDimitry Andric   // Objective-C specific specifiers.
764dbe13110SDimitry Andric   case ObjCObjArg: return "@";
765dbe13110SDimitry Andric 
7665e20cdd8SDimitry Andric   // FreeBSD kernel specific specifiers.
7675e20cdd8SDimitry Andric   case FreeBSDbArg: return "b";
7685e20cdd8SDimitry Andric   case FreeBSDDArg: return "D";
7695e20cdd8SDimitry Andric   case FreeBSDrArg: return "r";
7705e20cdd8SDimitry Andric   case FreeBSDyArg: return "y";
7715e20cdd8SDimitry Andric 
772dbe13110SDimitry Andric   // GlibC specific specifiers.
773dbe13110SDimitry Andric   case PrintErrno: return "m";
77406d4ba38SDimitry Andric 
77506d4ba38SDimitry Andric   // MS specific specifiers.
77606d4ba38SDimitry Andric   case ZArg: return "Z";
777ac9a064cSDimitry Andric 
778ac9a064cSDimitry Andric   // ISO/IEC TR 18037 (fixed-point) specific specifiers.
779ac9a064cSDimitry Andric   case rArg:
780ac9a064cSDimitry Andric     return "r";
781ac9a064cSDimitry Andric   case RArg:
782ac9a064cSDimitry Andric     return "R";
783ac9a064cSDimitry Andric   case kArg:
784ac9a064cSDimitry Andric     return "k";
785ac9a064cSDimitry Andric   case KArg:
786ac9a064cSDimitry Andric     return "K";
787dbe13110SDimitry Andric   }
7889f4dbff6SDimitry Andric   return nullptr;
789dbe13110SDimitry Andric }
790dbe13110SDimitry Andric 
791e3b55780SDimitry Andric std::optional<ConversionSpecifier>
getStandardSpecifier() const79213cc256eSDimitry Andric ConversionSpecifier::getStandardSpecifier() const {
79313cc256eSDimitry Andric   ConversionSpecifier::Kind NewKind;
79413cc256eSDimitry Andric 
79513cc256eSDimitry Andric   switch (getKind()) {
79613cc256eSDimitry Andric   default:
797e3b55780SDimitry Andric     return std::nullopt;
79813cc256eSDimitry Andric   case DArg:
79913cc256eSDimitry Andric     NewKind = dArg;
80013cc256eSDimitry Andric     break;
80113cc256eSDimitry Andric   case UArg:
80213cc256eSDimitry Andric     NewKind = uArg;
80313cc256eSDimitry Andric     break;
80413cc256eSDimitry Andric   case OArg:
80513cc256eSDimitry Andric     NewKind = oArg;
80613cc256eSDimitry Andric     break;
80713cc256eSDimitry Andric   }
80813cc256eSDimitry Andric 
80913cc256eSDimitry Andric   ConversionSpecifier FixedCS(*this);
81013cc256eSDimitry Andric   FixedCS.setKind(NewKind);
81113cc256eSDimitry Andric   return FixedCS;
81213cc256eSDimitry Andric }
81313cc256eSDimitry Andric 
814dbe13110SDimitry Andric //===----------------------------------------------------------------------===//
8153d1dcd9bSDimitry Andric // Methods on OptionalAmount.
8163d1dcd9bSDimitry Andric //===----------------------------------------------------------------------===//
8173d1dcd9bSDimitry Andric 
toString(raw_ostream & os) const81836981b17SDimitry Andric void OptionalAmount::toString(raw_ostream &os) const {
8193d1dcd9bSDimitry Andric   switch (hs) {
8203d1dcd9bSDimitry Andric   case Invalid:
8213d1dcd9bSDimitry Andric   case NotSpecified:
8223d1dcd9bSDimitry Andric     return;
8233d1dcd9bSDimitry Andric   case Arg:
8243d1dcd9bSDimitry Andric     if (UsesDotPrefix)
8253d1dcd9bSDimitry Andric         os << ".";
8263d1dcd9bSDimitry Andric     if (usesPositionalArg())
8273d1dcd9bSDimitry Andric       os << "*" << getPositionalArgIndex() << "$";
8283d1dcd9bSDimitry Andric     else
8293d1dcd9bSDimitry Andric       os << "*";
8303d1dcd9bSDimitry Andric     break;
8313d1dcd9bSDimitry Andric   case Constant:
8323d1dcd9bSDimitry Andric     if (UsesDotPrefix)
8333d1dcd9bSDimitry Andric         os << ".";
8343d1dcd9bSDimitry Andric     os << amt;
8353d1dcd9bSDimitry Andric     break;
8363d1dcd9bSDimitry Andric   }
8373d1dcd9bSDimitry Andric }
8383d1dcd9bSDimitry Andric 
hasValidLengthModifier(const TargetInfo & Target,const LangOptions & LO) const83922989816SDimitry Andric bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
84022989816SDimitry Andric                                              const LangOptions &LO) const {
8413d1dcd9bSDimitry Andric   switch (LM.getKind()) {
8423d1dcd9bSDimitry Andric     case LengthModifier::None:
8433d1dcd9bSDimitry Andric       return true;
8443d1dcd9bSDimitry Andric 
8453d1dcd9bSDimitry Andric     // Handle most integer flags
8463d1dcd9bSDimitry Andric     case LengthModifier::AsShort:
84722989816SDimitry Andric       // Length modifier only applies to FP vectors.
84822989816SDimitry Andric       if (LO.OpenCL && CS.isDoubleArg())
84922989816SDimitry Andric         return !VectorNumElts.isInvalid();
85022989816SDimitry Andric 
851ac9a064cSDimitry Andric       if (CS.isFixedPointArg())
852ac9a064cSDimitry Andric         return true;
853ac9a064cSDimitry Andric 
85406d4ba38SDimitry Andric       if (Target.getTriple().isOSMSVCRT()) {
85506d4ba38SDimitry Andric         switch (CS.getKind()) {
85606d4ba38SDimitry Andric           case ConversionSpecifier::cArg:
85706d4ba38SDimitry Andric           case ConversionSpecifier::CArg:
85806d4ba38SDimitry Andric           case ConversionSpecifier::sArg:
85906d4ba38SDimitry Andric           case ConversionSpecifier::SArg:
86006d4ba38SDimitry Andric           case ConversionSpecifier::ZArg:
86106d4ba38SDimitry Andric             return true;
86206d4ba38SDimitry Andric           default:
86306d4ba38SDimitry Andric             break;
86406d4ba38SDimitry Andric         }
86506d4ba38SDimitry Andric       }
866e3b55780SDimitry Andric       [[fallthrough]];
86706d4ba38SDimitry Andric     case LengthModifier::AsChar:
8683d1dcd9bSDimitry Andric     case LengthModifier::AsLongLong:
869dbe13110SDimitry Andric     case LengthModifier::AsQuad:
8703d1dcd9bSDimitry Andric     case LengthModifier::AsIntMax:
8713d1dcd9bSDimitry Andric     case LengthModifier::AsSizeT:
8723d1dcd9bSDimitry Andric     case LengthModifier::AsPtrDiff:
8733d1dcd9bSDimitry Andric       switch (CS.getKind()) {
874e3b55780SDimitry Andric         case ConversionSpecifier::bArg:
875e3b55780SDimitry Andric         case ConversionSpecifier::BArg:
8763d1dcd9bSDimitry Andric         case ConversionSpecifier::dArg:
87713cc256eSDimitry Andric         case ConversionSpecifier::DArg:
8783d1dcd9bSDimitry Andric         case ConversionSpecifier::iArg:
8793d1dcd9bSDimitry Andric         case ConversionSpecifier::oArg:
88013cc256eSDimitry Andric         case ConversionSpecifier::OArg:
8813d1dcd9bSDimitry Andric         case ConversionSpecifier::uArg:
88213cc256eSDimitry Andric         case ConversionSpecifier::UArg:
8833d1dcd9bSDimitry Andric         case ConversionSpecifier::xArg:
8843d1dcd9bSDimitry Andric         case ConversionSpecifier::XArg:
8853d1dcd9bSDimitry Andric         case ConversionSpecifier::nArg:
8863d1dcd9bSDimitry Andric           return true;
8875e20cdd8SDimitry Andric         case ConversionSpecifier::FreeBSDrArg:
8885e20cdd8SDimitry Andric         case ConversionSpecifier::FreeBSDyArg:
889145449b1SDimitry Andric           return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();
8903d1dcd9bSDimitry Andric         default:
8913d1dcd9bSDimitry Andric           return false;
8923d1dcd9bSDimitry Andric       }
8933d1dcd9bSDimitry Andric 
89422989816SDimitry Andric     case LengthModifier::AsShortLong:
89522989816SDimitry Andric       return LO.OpenCL && !VectorNumElts.isInvalid();
89622989816SDimitry Andric 
8973d1dcd9bSDimitry Andric     // Handle 'l' flag
89806d4ba38SDimitry Andric     case LengthModifier::AsLong: // or AsWideChar
89922989816SDimitry Andric       if (CS.isDoubleArg()) {
90022989816SDimitry Andric         // Invalid for OpenCL FP scalars.
90122989816SDimitry Andric         if (LO.OpenCL && VectorNumElts.isInvalid())
90222989816SDimitry Andric           return false;
90322989816SDimitry Andric         return true;
90422989816SDimitry Andric       }
90522989816SDimitry Andric 
906ac9a064cSDimitry Andric       if (CS.isFixedPointArg())
907ac9a064cSDimitry Andric         return true;
908ac9a064cSDimitry Andric 
9093d1dcd9bSDimitry Andric       switch (CS.getKind()) {
9107fa27ce4SDimitry Andric         case ConversionSpecifier::bArg:
9117fa27ce4SDimitry Andric         case ConversionSpecifier::BArg:
9123d1dcd9bSDimitry Andric         case ConversionSpecifier::dArg:
91313cc256eSDimitry Andric         case ConversionSpecifier::DArg:
9143d1dcd9bSDimitry Andric         case ConversionSpecifier::iArg:
9153d1dcd9bSDimitry Andric         case ConversionSpecifier::oArg:
91613cc256eSDimitry Andric         case ConversionSpecifier::OArg:
9173d1dcd9bSDimitry Andric         case ConversionSpecifier::uArg:
91813cc256eSDimitry Andric         case ConversionSpecifier::UArg:
9193d1dcd9bSDimitry Andric         case ConversionSpecifier::xArg:
9203d1dcd9bSDimitry Andric         case ConversionSpecifier::XArg:
9213d1dcd9bSDimitry Andric         case ConversionSpecifier::nArg:
9223d1dcd9bSDimitry Andric         case ConversionSpecifier::cArg:
9233d1dcd9bSDimitry Andric         case ConversionSpecifier::sArg:
924dbe13110SDimitry Andric         case ConversionSpecifier::ScanListArg:
92506d4ba38SDimitry Andric         case ConversionSpecifier::ZArg:
9263d1dcd9bSDimitry Andric           return true;
9275e20cdd8SDimitry Andric         case ConversionSpecifier::FreeBSDrArg:
9285e20cdd8SDimitry Andric         case ConversionSpecifier::FreeBSDyArg:
929145449b1SDimitry Andric           return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS();
9303d1dcd9bSDimitry Andric         default:
9313d1dcd9bSDimitry Andric           return false;
9323d1dcd9bSDimitry Andric       }
9333d1dcd9bSDimitry Andric 
9343d1dcd9bSDimitry Andric     case LengthModifier::AsLongDouble:
9353d1dcd9bSDimitry Andric       switch (CS.getKind()) {
9363d1dcd9bSDimitry Andric         case ConversionSpecifier::aArg:
9373d1dcd9bSDimitry Andric         case ConversionSpecifier::AArg:
9383d1dcd9bSDimitry Andric         case ConversionSpecifier::fArg:
9393d1dcd9bSDimitry Andric         case ConversionSpecifier::FArg:
9403d1dcd9bSDimitry Andric         case ConversionSpecifier::eArg:
9413d1dcd9bSDimitry Andric         case ConversionSpecifier::EArg:
9423d1dcd9bSDimitry Andric         case ConversionSpecifier::gArg:
9433d1dcd9bSDimitry Andric         case ConversionSpecifier::GArg:
9443d1dcd9bSDimitry Andric           return true;
94513cc256eSDimitry Andric         // GNU libc extension.
946dbe13110SDimitry Andric         case ConversionSpecifier::dArg:
947dbe13110SDimitry Andric         case ConversionSpecifier::iArg:
948dbe13110SDimitry Andric         case ConversionSpecifier::oArg:
949dbe13110SDimitry Andric         case ConversionSpecifier::uArg:
950dbe13110SDimitry Andric         case ConversionSpecifier::xArg:
951dbe13110SDimitry Andric         case ConversionSpecifier::XArg:
95213cc256eSDimitry Andric           return !Target.getTriple().isOSDarwin() &&
95313cc256eSDimitry Andric                  !Target.getTriple().isOSWindows();
954dbe13110SDimitry Andric         default:
955dbe13110SDimitry Andric           return false;
956dbe13110SDimitry Andric       }
957dbe13110SDimitry Andric 
958dbe13110SDimitry Andric     case LengthModifier::AsAllocate:
959dbe13110SDimitry Andric       switch (CS.getKind()) {
960dbe13110SDimitry Andric         case ConversionSpecifier::sArg:
961dbe13110SDimitry Andric         case ConversionSpecifier::SArg:
962dbe13110SDimitry Andric         case ConversionSpecifier::ScanListArg:
963dbe13110SDimitry Andric           return true;
964dbe13110SDimitry Andric         default:
965dbe13110SDimitry Andric           return false;
966dbe13110SDimitry Andric       }
967dbe13110SDimitry Andric 
968dbe13110SDimitry Andric     case LengthModifier::AsMAllocate:
969dbe13110SDimitry Andric       switch (CS.getKind()) {
970dbe13110SDimitry Andric         case ConversionSpecifier::cArg:
971dbe13110SDimitry Andric         case ConversionSpecifier::CArg:
972dbe13110SDimitry Andric         case ConversionSpecifier::sArg:
973dbe13110SDimitry Andric         case ConversionSpecifier::SArg:
974dbe13110SDimitry Andric         case ConversionSpecifier::ScanListArg:
975dbe13110SDimitry Andric           return true;
9763d1dcd9bSDimitry Andric         default:
9773d1dcd9bSDimitry Andric           return false;
9783d1dcd9bSDimitry Andric       }
979bfef3995SDimitry Andric     case LengthModifier::AsInt32:
980bfef3995SDimitry Andric     case LengthModifier::AsInt3264:
981bfef3995SDimitry Andric     case LengthModifier::AsInt64:
982bfef3995SDimitry Andric       switch (CS.getKind()) {
983bfef3995SDimitry Andric         case ConversionSpecifier::dArg:
984bfef3995SDimitry Andric         case ConversionSpecifier::iArg:
985bfef3995SDimitry Andric         case ConversionSpecifier::oArg:
986bfef3995SDimitry Andric         case ConversionSpecifier::uArg:
987bfef3995SDimitry Andric         case ConversionSpecifier::xArg:
988bfef3995SDimitry Andric         case ConversionSpecifier::XArg:
989bfef3995SDimitry Andric           return Target.getTriple().isOSMSVCRT();
990bfef3995SDimitry Andric         default:
991bfef3995SDimitry Andric           return false;
992bfef3995SDimitry Andric       }
99306d4ba38SDimitry Andric     case LengthModifier::AsWide:
99406d4ba38SDimitry Andric       switch (CS.getKind()) {
99506d4ba38SDimitry Andric         case ConversionSpecifier::cArg:
99606d4ba38SDimitry Andric         case ConversionSpecifier::CArg:
99706d4ba38SDimitry Andric         case ConversionSpecifier::sArg:
99806d4ba38SDimitry Andric         case ConversionSpecifier::SArg:
99906d4ba38SDimitry Andric         case ConversionSpecifier::ZArg:
100006d4ba38SDimitry Andric           return Target.getTriple().isOSMSVCRT();
100106d4ba38SDimitry Andric         default:
100206d4ba38SDimitry Andric           return false;
100306d4ba38SDimitry Andric       }
10043d1dcd9bSDimitry Andric   }
1005dbe13110SDimitry Andric   llvm_unreachable("Invalid LengthModifier Kind!");
10063d1dcd9bSDimitry Andric }
10073d1dcd9bSDimitry Andric 
hasStandardLengthModifier() const1008dbe13110SDimitry Andric bool FormatSpecifier::hasStandardLengthModifier() const {
1009dbe13110SDimitry Andric   switch (LM.getKind()) {
1010dbe13110SDimitry Andric     case LengthModifier::None:
1011dbe13110SDimitry Andric     case LengthModifier::AsChar:
1012dbe13110SDimitry Andric     case LengthModifier::AsShort:
1013dbe13110SDimitry Andric     case LengthModifier::AsLong:
1014dbe13110SDimitry Andric     case LengthModifier::AsLongLong:
1015dbe13110SDimitry Andric     case LengthModifier::AsIntMax:
1016dbe13110SDimitry Andric     case LengthModifier::AsSizeT:
1017dbe13110SDimitry Andric     case LengthModifier::AsPtrDiff:
1018dbe13110SDimitry Andric     case LengthModifier::AsLongDouble:
1019dbe13110SDimitry Andric       return true;
1020dbe13110SDimitry Andric     case LengthModifier::AsAllocate:
1021dbe13110SDimitry Andric     case LengthModifier::AsMAllocate:
1022dbe13110SDimitry Andric     case LengthModifier::AsQuad:
1023bfef3995SDimitry Andric     case LengthModifier::AsInt32:
1024bfef3995SDimitry Andric     case LengthModifier::AsInt3264:
1025bfef3995SDimitry Andric     case LengthModifier::AsInt64:
102606d4ba38SDimitry Andric     case LengthModifier::AsWide:
102722989816SDimitry Andric     case LengthModifier::AsShortLong: // ???
1028dbe13110SDimitry Andric       return false;
1029dbe13110SDimitry Andric   }
1030dbe13110SDimitry Andric   llvm_unreachable("Invalid LengthModifier Kind!");
1031dbe13110SDimitry Andric }
10323d1dcd9bSDimitry Andric 
hasStandardConversionSpecifier(const LangOptions & LangOpt) const10335e20cdd8SDimitry Andric bool FormatSpecifier::hasStandardConversionSpecifier(
10345e20cdd8SDimitry Andric     const LangOptions &LangOpt) const {
1035dbe13110SDimitry Andric   switch (CS.getKind()) {
1036e3b55780SDimitry Andric     case ConversionSpecifier::bArg:
1037e3b55780SDimitry Andric     case ConversionSpecifier::BArg:
1038dbe13110SDimitry Andric     case ConversionSpecifier::cArg:
1039dbe13110SDimitry Andric     case ConversionSpecifier::dArg:
1040dbe13110SDimitry Andric     case ConversionSpecifier::iArg:
1041dbe13110SDimitry Andric     case ConversionSpecifier::oArg:
1042dbe13110SDimitry Andric     case ConversionSpecifier::uArg:
1043dbe13110SDimitry Andric     case ConversionSpecifier::xArg:
1044dbe13110SDimitry Andric     case ConversionSpecifier::XArg:
1045dbe13110SDimitry Andric     case ConversionSpecifier::fArg:
1046dbe13110SDimitry Andric     case ConversionSpecifier::FArg:
1047dbe13110SDimitry Andric     case ConversionSpecifier::eArg:
1048dbe13110SDimitry Andric     case ConversionSpecifier::EArg:
1049dbe13110SDimitry Andric     case ConversionSpecifier::gArg:
1050dbe13110SDimitry Andric     case ConversionSpecifier::GArg:
1051dbe13110SDimitry Andric     case ConversionSpecifier::aArg:
1052dbe13110SDimitry Andric     case ConversionSpecifier::AArg:
1053dbe13110SDimitry Andric     case ConversionSpecifier::sArg:
1054dbe13110SDimitry Andric     case ConversionSpecifier::pArg:
1055dbe13110SDimitry Andric     case ConversionSpecifier::nArg:
1056dbe13110SDimitry Andric     case ConversionSpecifier::ObjCObjArg:
1057dbe13110SDimitry Andric     case ConversionSpecifier::ScanListArg:
1058dbe13110SDimitry Andric     case ConversionSpecifier::PercentArg:
1059bab175ecSDimitry Andric     case ConversionSpecifier::PArg:
1060dbe13110SDimitry Andric       return true;
1061dbe13110SDimitry Andric     case ConversionSpecifier::CArg:
1062dbe13110SDimitry Andric     case ConversionSpecifier::SArg:
1063676fbe81SDimitry Andric       return LangOpt.ObjC;
1064dbe13110SDimitry Andric     case ConversionSpecifier::InvalidSpecifier:
10655e20cdd8SDimitry Andric     case ConversionSpecifier::FreeBSDbArg:
10665e20cdd8SDimitry Andric     case ConversionSpecifier::FreeBSDDArg:
10675e20cdd8SDimitry Andric     case ConversionSpecifier::FreeBSDrArg:
10685e20cdd8SDimitry Andric     case ConversionSpecifier::FreeBSDyArg:
1069dbe13110SDimitry Andric     case ConversionSpecifier::PrintErrno:
107013cc256eSDimitry Andric     case ConversionSpecifier::DArg:
107113cc256eSDimitry Andric     case ConversionSpecifier::OArg:
107213cc256eSDimitry Andric     case ConversionSpecifier::UArg:
107306d4ba38SDimitry Andric     case ConversionSpecifier::ZArg:
1074dbe13110SDimitry Andric       return false;
1075ac9a064cSDimitry Andric     case ConversionSpecifier::rArg:
1076ac9a064cSDimitry Andric     case ConversionSpecifier::RArg:
1077ac9a064cSDimitry Andric     case ConversionSpecifier::kArg:
1078ac9a064cSDimitry Andric     case ConversionSpecifier::KArg:
1079ac9a064cSDimitry Andric       return LangOpt.FixedPoint;
1080dbe13110SDimitry Andric   }
1081dbe13110SDimitry Andric   llvm_unreachable("Invalid ConversionSpecifier Kind!");
1082dbe13110SDimitry Andric }
1083dbe13110SDimitry Andric 
hasStandardLengthConversionCombination() const1084dbe13110SDimitry Andric bool FormatSpecifier::hasStandardLengthConversionCombination() const {
1085dbe13110SDimitry Andric   if (LM.getKind() == LengthModifier::AsLongDouble) {
1086dbe13110SDimitry Andric     switch(CS.getKind()) {
1087dbe13110SDimitry Andric         case ConversionSpecifier::dArg:
1088dbe13110SDimitry Andric         case ConversionSpecifier::iArg:
1089dbe13110SDimitry Andric         case ConversionSpecifier::oArg:
1090dbe13110SDimitry Andric         case ConversionSpecifier::uArg:
1091dbe13110SDimitry Andric         case ConversionSpecifier::xArg:
1092dbe13110SDimitry Andric         case ConversionSpecifier::XArg:
1093dbe13110SDimitry Andric           return false;
1094dbe13110SDimitry Andric         default:
1095dbe13110SDimitry Andric           return true;
1096dbe13110SDimitry Andric     }
1097dbe13110SDimitry Andric   }
1098dbe13110SDimitry Andric   return true;
1099dbe13110SDimitry Andric }
110056d91b49SDimitry Andric 
1101e3b55780SDimitry Andric std::optional<LengthModifier>
getCorrectedLengthModifier() const1102e3b55780SDimitry Andric FormatSpecifier::getCorrectedLengthModifier() const {
110313cc256eSDimitry Andric   if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
110413cc256eSDimitry Andric     if (LM.getKind() == LengthModifier::AsLongDouble ||
110513cc256eSDimitry Andric         LM.getKind() == LengthModifier::AsQuad) {
110613cc256eSDimitry Andric       LengthModifier FixedLM(LM);
110713cc256eSDimitry Andric       FixedLM.setKind(LengthModifier::AsLongLong);
110813cc256eSDimitry Andric       return FixedLM;
110913cc256eSDimitry Andric     }
111013cc256eSDimitry Andric   }
111113cc256eSDimitry Andric 
1112e3b55780SDimitry Andric   return std::nullopt;
111313cc256eSDimitry Andric }
111413cc256eSDimitry Andric 
namedTypeToLengthModifier(QualType QT,LengthModifier & LM)111556d91b49SDimitry Andric bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
111656d91b49SDimitry Andric                                                 LengthModifier &LM) {
1117e3b55780SDimitry Andric   for (/**/; const auto *TT = QT->getAs<TypedefType>();
1118e3b55780SDimitry Andric        QT = TT->getDecl()->getUnderlyingType()) {
1119e3b55780SDimitry Andric     const TypedefNameDecl *Typedef = TT->getDecl();
112056d91b49SDimitry Andric     const IdentifierInfo *Identifier = Typedef->getIdentifier();
112156d91b49SDimitry Andric     if (Identifier->getName() == "size_t") {
112256d91b49SDimitry Andric       LM.setKind(LengthModifier::AsSizeT);
112356d91b49SDimitry Andric       return true;
112456d91b49SDimitry Andric     } else if (Identifier->getName() == "ssize_t") {
112556d91b49SDimitry Andric       // Not C99, but common in Unix.
112656d91b49SDimitry Andric       LM.setKind(LengthModifier::AsSizeT);
112756d91b49SDimitry Andric       return true;
112856d91b49SDimitry Andric     } else if (Identifier->getName() == "intmax_t") {
112956d91b49SDimitry Andric       LM.setKind(LengthModifier::AsIntMax);
113056d91b49SDimitry Andric       return true;
113156d91b49SDimitry Andric     } else if (Identifier->getName() == "uintmax_t") {
113256d91b49SDimitry Andric       LM.setKind(LengthModifier::AsIntMax);
113356d91b49SDimitry Andric       return true;
113456d91b49SDimitry Andric     } else if (Identifier->getName() == "ptrdiff_t") {
113556d91b49SDimitry Andric       LM.setKind(LengthModifier::AsPtrDiff);
113656d91b49SDimitry Andric       return true;
113756d91b49SDimitry Andric     }
113856d91b49SDimitry Andric   }
113956d91b49SDimitry Andric   return false;
114056d91b49SDimitry Andric }
1141