| //== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // Handling of format string in printf and friends.  The structure of format | 
 | // strings for fprintf() are described in C99 7.19.6.1. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "clang/Analysis/Analyses/FormatString.h" | 
 | #include "FormatStringParsing.h" | 
 | #include "clang/Basic/TargetInfo.h" | 
 |  | 
 | using clang::analyze_format_string::ArgType; | 
 | using clang::analyze_format_string::FormatStringHandler; | 
 | using clang::analyze_format_string::LengthModifier; | 
 | using clang::analyze_format_string::OptionalAmount; | 
 | using clang::analyze_format_string::ConversionSpecifier; | 
 | using clang::analyze_printf::PrintfSpecifier; | 
 |  | 
 | using namespace clang; | 
 |  | 
 | typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier> | 
 |         PrintfSpecifierResult; | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Methods for parsing format strings. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | using analyze_format_string::ParseNonPositionAmount; | 
 |  | 
 | static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, | 
 |                            const char *Start, const char *&Beg, const char *E, | 
 |                            unsigned *argIndex) { | 
 |   if (argIndex) { | 
 |     FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex)); | 
 |   } else { | 
 |     const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, | 
 |                                            analyze_format_string::PrecisionPos); | 
 |     if (Amt.isInvalid()) | 
 |       return true; | 
 |     FS.setPrecision(Amt); | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS, | 
 |                            const char *FlagBeg, const char *E, bool Warn) { | 
 |    StringRef Flag(FlagBeg, E - FlagBeg); | 
 |    // Currently there is only one flag. | 
 |    if (Flag == "tt") { | 
 |      FS.setHasObjCTechnicalTerm(FlagBeg); | 
 |      return false; | 
 |    } | 
 |    // Handle either the case of no flag or an invalid flag. | 
 |    if (Warn) { | 
 |      if (Flag == "") | 
 |        H.HandleEmptyObjCModifierFlag(FlagBeg, E  - FlagBeg); | 
 |      else | 
 |        H.HandleInvalidObjCModifierFlag(FlagBeg, E  - FlagBeg); | 
 |    } | 
 |    return true; | 
 | } | 
 |  | 
 | static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, | 
 |                                                   const char *&Beg, | 
 |                                                   const char *E, | 
 |                                                   unsigned &argIndex, | 
 |                                                   const LangOptions &LO, | 
 |                                                   const TargetInfo &Target, | 
 |                                                   bool Warn, | 
 |                                                   bool isFreeBSDKPrintf) { | 
 |  | 
 |   using namespace clang::analyze_format_string; | 
 |   using namespace clang::analyze_printf; | 
 |  | 
 |   const char *I = Beg; | 
 |   const char *Start = nullptr; | 
 |   UpdateOnReturn <const char*> UpdateBeg(Beg, I); | 
 |  | 
 |   // Look for a '%' character that indicates the start of a format specifier. | 
 |   for ( ; I != E ; ++I) { | 
 |     char c = *I; | 
 |     if (c == '\0') { | 
 |       // Detect spurious null characters, which are likely errors. | 
 |       H.HandleNullChar(I); | 
 |       return true; | 
 |     } | 
 |     if (c == '%') { | 
 |       Start = I++;  // Record the start of the format specifier. | 
 |       break; | 
 |     } | 
 |   } | 
 |  | 
 |   // No format specifier found? | 
 |   if (!Start) | 
 |     return false; | 
 |  | 
 |   if (I == E) { | 
 |     // No more characters left? | 
 |     if (Warn) | 
 |       H.HandleIncompleteSpecifier(Start, E - Start); | 
 |     return true; | 
 |   } | 
 |  | 
 |   PrintfSpecifier FS; | 
 |   if (ParseArgPosition(H, FS, Start, I, E)) | 
 |     return true; | 
 |  | 
 |   if (I == E) { | 
 |     // No more characters left? | 
 |     if (Warn) | 
 |       H.HandleIncompleteSpecifier(Start, E - Start); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Look for flags (if any). | 
 |   bool hasMore = true; | 
 |   for ( ; I != E; ++I) { | 
 |     switch (*I) { | 
 |       default: hasMore = false; break; | 
 |       case '\'': | 
 |         // FIXME: POSIX specific.  Always accept? | 
 |         FS.setHasThousandsGrouping(I); | 
 |         break; | 
 |       case '-': FS.setIsLeftJustified(I); break; | 
 |       case '+': FS.setHasPlusPrefix(I); break; | 
 |       case ' ': FS.setHasSpacePrefix(I); break; | 
 |       case '#': FS.setHasAlternativeForm(I); break; | 
 |       case '0': FS.setHasLeadingZeros(I); break; | 
 |     } | 
 |     if (!hasMore) | 
 |       break; | 
 |   } | 
 |  | 
 |   if (I == E) { | 
 |     // No more characters left? | 
 |     if (Warn) | 
 |       H.HandleIncompleteSpecifier(Start, E - Start); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Look for the field width (if any). | 
 |   if (ParseFieldWidth(H, FS, Start, I, E, | 
 |                       FS.usesPositionalArg() ? nullptr : &argIndex)) | 
 |     return true; | 
 |  | 
 |   if (I == E) { | 
 |     // No more characters left? | 
 |     if (Warn) | 
 |       H.HandleIncompleteSpecifier(Start, E - Start); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Look for the precision (if any). | 
 |   if (*I == '.') { | 
 |     ++I; | 
 |     if (I == E) { | 
 |       if (Warn) | 
 |         H.HandleIncompleteSpecifier(Start, E - Start); | 
 |       return true; | 
 |     } | 
 |  | 
 |     if (ParsePrecision(H, FS, Start, I, E, | 
 |                        FS.usesPositionalArg() ? nullptr : &argIndex)) | 
 |       return true; | 
 |  | 
 |     if (I == E) { | 
 |       // No more characters left? | 
 |       if (Warn) | 
 |         H.HandleIncompleteSpecifier(Start, E - Start); | 
 |       return true; | 
 |     } | 
 |   } | 
 |  | 
 |   // Look for the length modifier. | 
 |   if (ParseLengthModifier(FS, I, E, LO) && I == E) { | 
 |     // No more characters left? | 
 |     if (Warn) | 
 |       H.HandleIncompleteSpecifier(Start, E - Start); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Look for the Objective-C modifier flags, if any. | 
 |   // We parse these here, even if they don't apply to | 
 |   // the conversion specifier, and then emit an error | 
 |   // later if the conversion specifier isn't '@'.  This | 
 |   // enables better recovery, and we don't know if | 
 |   // these flags are applicable until later. | 
 |   const char *ObjCModifierFlagsStart = nullptr, | 
 |              *ObjCModifierFlagsEnd = nullptr; | 
 |   if (*I == '[') { | 
 |     ObjCModifierFlagsStart = I; | 
 |     ++I; | 
 |     auto flagStart = I; | 
 |     for (;; ++I) { | 
 |       ObjCModifierFlagsEnd = I; | 
 |       if (I == E) { | 
 |         if (Warn) | 
 |           H.HandleIncompleteSpecifier(Start, E - Start); | 
 |         return true; | 
 |       } | 
 |       // Did we find the closing ']'? | 
 |       if (*I == ']') { | 
 |         if (ParseObjCFlags(H, FS, flagStart, I, Warn)) | 
 |           return true; | 
 |         ++I; | 
 |         break; | 
 |       } | 
 |       // There are no separators defined yet for multiple | 
 |       // Objective-C modifier flags.  When those are | 
 |       // defined, this is the place to check. | 
 |     } | 
 |   } | 
 |  | 
 |   if (*I == '\0') { | 
 |     // Detect spurious null characters, which are likely errors. | 
 |     H.HandleNullChar(I); | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Finally, look for the conversion specifier. | 
 |   const char *conversionPosition = I++; | 
 |   ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier; | 
 |   switch (*conversionPosition) { | 
 |     default: | 
 |       break; | 
 |     // C99: 7.19.6.1 (section 8). | 
 |     case '%': k = ConversionSpecifier::PercentArg;   break; | 
 |     case 'A': k = ConversionSpecifier::AArg; break; | 
 |     case 'E': k = ConversionSpecifier::EArg; break; | 
 |     case 'F': k = ConversionSpecifier::FArg; break; | 
 |     case 'G': k = ConversionSpecifier::GArg; break; | 
 |     case 'X': k = ConversionSpecifier::XArg; break; | 
 |     case 'a': k = ConversionSpecifier::aArg; break; | 
 |     case 'c': k = ConversionSpecifier::cArg; break; | 
 |     case 'd': k = ConversionSpecifier::dArg; break; | 
 |     case 'e': k = ConversionSpecifier::eArg; break; | 
 |     case 'f': k = ConversionSpecifier::fArg; break; | 
 |     case 'g': k = ConversionSpecifier::gArg; break; | 
 |     case 'i': k = ConversionSpecifier::iArg; break; | 
 |     case 'n': k = ConversionSpecifier::nArg; break; | 
 |     case 'o': k = ConversionSpecifier::oArg; break; | 
 |     case 'p': k = ConversionSpecifier::pArg; break; | 
 |     case 's': k = ConversionSpecifier::sArg; break; | 
 |     case 'u': k = ConversionSpecifier::uArg; break; | 
 |     case 'x': k = ConversionSpecifier::xArg; break; | 
 |     // POSIX specific. | 
 |     case 'C': k = ConversionSpecifier::CArg; break; | 
 |     case 'S': k = ConversionSpecifier::SArg; break; | 
 |     // Objective-C. | 
 |     case '@': k = ConversionSpecifier::ObjCObjArg; break; | 
 |     // Glibc specific. | 
 |     case 'm': k = ConversionSpecifier::PrintErrno; break; | 
 |     // FreeBSD kernel specific. | 
 |     case 'b': | 
 |       if (isFreeBSDKPrintf) | 
 |         k = ConversionSpecifier::FreeBSDbArg; // int followed by char * | 
 |       break; | 
 |     case 'r': | 
 |       if (isFreeBSDKPrintf) | 
 |         k = ConversionSpecifier::FreeBSDrArg; // int | 
 |       break; | 
 |     case 'y': | 
 |       if (isFreeBSDKPrintf) | 
 |         k = ConversionSpecifier::FreeBSDyArg; // int | 
 |       break; | 
 |     // Apple-specific. | 
 |     case 'D': | 
 |       if (isFreeBSDKPrintf) | 
 |         k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * | 
 |       else if (Target.getTriple().isOSDarwin()) | 
 |         k = ConversionSpecifier::DArg; | 
 |       break; | 
 |     case 'O': | 
 |       if (Target.getTriple().isOSDarwin()) | 
 |         k = ConversionSpecifier::OArg; | 
 |       break; | 
 |     case 'U': | 
 |       if (Target.getTriple().isOSDarwin()) | 
 |         k = ConversionSpecifier::UArg; | 
 |       break; | 
 |     // MS specific. | 
 |     case 'Z': | 
 |       if (Target.getTriple().isOSMSVCRT()) | 
 |         k = ConversionSpecifier::ZArg; | 
 |   } | 
 |    | 
 |   // Check to see if we used the Objective-C modifier flags with | 
 |   // a conversion specifier other than '@'. | 
 |   if (k != ConversionSpecifier::ObjCObjArg && | 
 |       k != ConversionSpecifier::InvalidSpecifier && | 
 |       ObjCModifierFlagsStart) { | 
 |     H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart, | 
 |                                            ObjCModifierFlagsEnd + 1, | 
 |                                            conversionPosition); | 
 |     return true; | 
 |   } | 
 |    | 
 |   PrintfConversionSpecifier CS(conversionPosition, k); | 
 |   FS.setConversionSpecifier(CS); | 
 |   if (CS.consumesDataArgument() && !FS.usesPositionalArg()) | 
 |     FS.setArgIndex(argIndex++); | 
 |   // FreeBSD kernel specific. | 
 |   if (k == ConversionSpecifier::FreeBSDbArg || | 
 |       k == ConversionSpecifier::FreeBSDDArg) | 
 |     argIndex++; | 
 |  | 
 |   if (k == ConversionSpecifier::InvalidSpecifier) { | 
 |     // Assume the conversion takes one argument. | 
 |     return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, I - Start); | 
 |   } | 
 |   return PrintfSpecifierResult(Start, FS); | 
 | } | 
 |  | 
 | bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, | 
 |                                                      const char *I, | 
 |                                                      const char *E, | 
 |                                                      const LangOptions &LO, | 
 |                                                      const TargetInfo &Target, | 
 |                                                      bool isFreeBSDKPrintf) { | 
 |  | 
 |   unsigned argIndex = 0; | 
 |  | 
 |   // Keep looking for a format specifier until we have exhausted the string. | 
 |   while (I != E) { | 
 |     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, | 
 |                                                             LO, Target, true, | 
 |                                                             isFreeBSDKPrintf); | 
 |     // Did a fail-stop error of any kind occur when parsing the specifier? | 
 |     // If so, don't do any more processing. | 
 |     if (FSR.shouldStop()) | 
 |       return true; | 
 |     // Did we exhaust the string or encounter an error that | 
 |     // we can recover from? | 
 |     if (!FSR.hasValue()) | 
 |       continue; | 
 |     // We have a format specifier.  Pass it to the callback. | 
 |     if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), | 
 |                                  I - FSR.getStart())) | 
 |       return true; | 
 |   } | 
 |   assert(I == E && "Format string not exhausted"); | 
 |   return false; | 
 | } | 
 |  | 
 | bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I, | 
 |                                                             const char *E, | 
 |                                                             const LangOptions &LO, | 
 |                                                             const TargetInfo &Target) { | 
 |    | 
 |   unsigned argIndex = 0; | 
 |    | 
 |   // Keep looking for a %s format specifier until we have exhausted the string. | 
 |   FormatStringHandler H; | 
 |   while (I != E) { | 
 |     const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, | 
 |                                                             LO, Target, false, | 
 |                                                             false); | 
 |     // Did a fail-stop error of any kind occur when parsing the specifier? | 
 |     // If so, don't do any more processing. | 
 |     if (FSR.shouldStop()) | 
 |       return false; | 
 |     // Did we exhaust the string or encounter an error that | 
 |     // we can recover from? | 
 |     if (!FSR.hasValue()) | 
 |       continue; | 
 |     const analyze_printf::PrintfSpecifier &FS = FSR.getValue(); | 
 |     // Return true if this a %s format specifier. | 
 |     if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg) | 
 |       return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Methods on PrintfSpecifier. | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, | 
 |                                     bool IsObjCLiteral) const { | 
 |   const PrintfConversionSpecifier &CS = getConversionSpecifier(); | 
 |  | 
 |   if (!CS.consumesDataArgument()) | 
 |     return ArgType::Invalid(); | 
 |  | 
 |   if (CS.getKind() == ConversionSpecifier::cArg) | 
 |     switch (LM.getKind()) { | 
 |       case LengthModifier::None: | 
 |         return Ctx.IntTy; | 
 |       case LengthModifier::AsLong: | 
 |       case LengthModifier::AsWide: | 
 |         return ArgType(ArgType::WIntTy, "wint_t"); | 
 |       case LengthModifier::AsShort: | 
 |         if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) | 
 |           return Ctx.IntTy; | 
 |       default: | 
 |         return ArgType::Invalid(); | 
 |     } | 
 |  | 
 |   if (CS.isIntArg()) | 
 |     switch (LM.getKind()) { | 
 |       case LengthModifier::AsLongDouble: | 
 |         // GNU extension. | 
 |         return Ctx.LongLongTy; | 
 |       case LengthModifier::None: | 
 |         return Ctx.IntTy; | 
 |       case LengthModifier::AsInt32: | 
 |         return ArgType(Ctx.IntTy, "__int32"); | 
 |       case LengthModifier::AsChar: return ArgType::AnyCharTy; | 
 |       case LengthModifier::AsShort: return Ctx.ShortTy; | 
 |       case LengthModifier::AsLong: return Ctx.LongTy; | 
 |       case LengthModifier::AsLongLong: | 
 |       case LengthModifier::AsQuad: | 
 |         return Ctx.LongLongTy; | 
 |       case LengthModifier::AsInt64: | 
 |         return ArgType(Ctx.LongLongTy, "__int64"); | 
 |       case LengthModifier::AsIntMax: | 
 |         return ArgType(Ctx.getIntMaxType(), "intmax_t"); | 
 |       case LengthModifier::AsSizeT: | 
 |         // FIXME: How to get the corresponding signed version of size_t? | 
 |         return ArgType(); | 
 |       case LengthModifier::AsInt3264: | 
 |         return Ctx.getTargetInfo().getTriple().isArch64Bit() | 
 |                    ? ArgType(Ctx.LongLongTy, "__int64") | 
 |                    : ArgType(Ctx.IntTy, "__int32"); | 
 |       case LengthModifier::AsPtrDiff: | 
 |         return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"); | 
 |       case LengthModifier::AsAllocate: | 
 |       case LengthModifier::AsMAllocate: | 
 |       case LengthModifier::AsWide: | 
 |         return ArgType::Invalid(); | 
 |     } | 
 |  | 
 |   if (CS.isUIntArg()) | 
 |     switch (LM.getKind()) { | 
 |       case LengthModifier::AsLongDouble: | 
 |         // GNU extension. | 
 |         return Ctx.UnsignedLongLongTy; | 
 |       case LengthModifier::None: | 
 |         return Ctx.UnsignedIntTy; | 
 |       case LengthModifier::AsInt32: | 
 |         return ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); | 
 |       case LengthModifier::AsChar: return Ctx.UnsignedCharTy; | 
 |       case LengthModifier::AsShort: return Ctx.UnsignedShortTy; | 
 |       case LengthModifier::AsLong: return Ctx.UnsignedLongTy; | 
 |       case LengthModifier::AsLongLong: | 
 |       case LengthModifier::AsQuad: | 
 |         return Ctx.UnsignedLongLongTy; | 
 |       case LengthModifier::AsInt64: | 
 |         return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"); | 
 |       case LengthModifier::AsIntMax: | 
 |         return ArgType(Ctx.getUIntMaxType(), "uintmax_t"); | 
 |       case LengthModifier::AsSizeT: | 
 |         return ArgType(Ctx.getSizeType(), "size_t"); | 
 |       case LengthModifier::AsInt3264: | 
 |         return Ctx.getTargetInfo().getTriple().isArch64Bit() | 
 |                    ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64") | 
 |                    : ArgType(Ctx.UnsignedIntTy, "unsigned __int32"); | 
 |       case LengthModifier::AsPtrDiff: | 
 |         // FIXME: How to get the corresponding unsigned | 
 |         // version of ptrdiff_t? | 
 |         return ArgType(); | 
 |       case LengthModifier::AsAllocate: | 
 |       case LengthModifier::AsMAllocate: | 
 |       case LengthModifier::AsWide: | 
 |         return ArgType::Invalid(); | 
 |     } | 
 |  | 
 |   if (CS.isDoubleArg()) { | 
 |     if (LM.getKind() == LengthModifier::AsLongDouble) | 
 |       return Ctx.LongDoubleTy; | 
 |     return Ctx.DoubleTy; | 
 |   } | 
 |  | 
 |   if (CS.getKind() == ConversionSpecifier::nArg) { | 
 |     switch (LM.getKind()) { | 
 |       case LengthModifier::None: | 
 |         return ArgType::PtrTo(Ctx.IntTy); | 
 |       case LengthModifier::AsChar: | 
 |         return ArgType::PtrTo(Ctx.SignedCharTy); | 
 |       case LengthModifier::AsShort: | 
 |         return ArgType::PtrTo(Ctx.ShortTy); | 
 |       case LengthModifier::AsLong: | 
 |         return ArgType::PtrTo(Ctx.LongTy); | 
 |       case LengthModifier::AsLongLong: | 
 |       case LengthModifier::AsQuad: | 
 |         return ArgType::PtrTo(Ctx.LongLongTy); | 
 |       case LengthModifier::AsIntMax: | 
 |         return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t")); | 
 |       case LengthModifier::AsSizeT: | 
 |         return ArgType(); // FIXME: ssize_t | 
 |       case LengthModifier::AsPtrDiff: | 
 |         return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t")); | 
 |       case LengthModifier::AsLongDouble: | 
 |         return ArgType(); // FIXME: Is this a known extension? | 
 |       case LengthModifier::AsAllocate: | 
 |       case LengthModifier::AsMAllocate: | 
 |       case LengthModifier::AsInt32: | 
 |       case LengthModifier::AsInt3264: | 
 |       case LengthModifier::AsInt64: | 
 |       case LengthModifier::AsWide: | 
 |         return ArgType::Invalid(); | 
 |     } | 
 |   } | 
 |  | 
 |   switch (CS.getKind()) { | 
 |     case ConversionSpecifier::sArg: | 
 |       if (LM.getKind() == LengthModifier::AsWideChar) { | 
 |         if (IsObjCLiteral) | 
 |           return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), | 
 |                          "const unichar *"); | 
 |         return ArgType(ArgType::WCStrTy, "wchar_t *"); | 
 |       } | 
 |       if (LM.getKind() == LengthModifier::AsWide) | 
 |         return ArgType(ArgType::WCStrTy, "wchar_t *"); | 
 |       return ArgType::CStrTy; | 
 |     case ConversionSpecifier::SArg: | 
 |       if (IsObjCLiteral) | 
 |         return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), | 
 |                        "const unichar *"); | 
 |       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && | 
 |           LM.getKind() == LengthModifier::AsShort) | 
 |         return ArgType::CStrTy; | 
 |       return ArgType(ArgType::WCStrTy, "wchar_t *"); | 
 |     case ConversionSpecifier::CArg: | 
 |       if (IsObjCLiteral) | 
 |         return ArgType(Ctx.UnsignedShortTy, "unichar"); | 
 |       if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && | 
 |           LM.getKind() == LengthModifier::AsShort) | 
 |         return Ctx.IntTy; | 
 |       return ArgType(Ctx.WideCharTy, "wchar_t"); | 
 |     case ConversionSpecifier::pArg: | 
 |       return ArgType::CPointerTy; | 
 |     case ConversionSpecifier::ObjCObjArg: | 
 |       return ArgType::ObjCPointerTy; | 
 |     default: | 
 |       break; | 
 |   } | 
 |  | 
 |   // FIXME: Handle other cases. | 
 |   return ArgType(); | 
 | } | 
 |  | 
 | bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, | 
 |                               ASTContext &Ctx, bool IsObjCLiteral) { | 
 |   // %n is different from other conversion specifiers; don't try to fix it. | 
 |   if (CS.getKind() == ConversionSpecifier::nArg) | 
 |     return false; | 
 |  | 
 |   // Handle Objective-C objects first. Note that while the '%@' specifier will | 
 |   // not warn for structure pointer or void pointer arguments (because that's | 
 |   // how CoreFoundation objects are implemented), we only show a fixit for '%@' | 
 |   // if we know it's an object (block, id, class, or __attribute__((NSObject))). | 
 |   if (QT->isObjCRetainableType()) { | 
 |     if (!IsObjCLiteral) | 
 |       return false; | 
 |  | 
 |     CS.setKind(ConversionSpecifier::ObjCObjArg); | 
 |  | 
 |     // Disable irrelevant flags | 
 |     HasThousandsGrouping = false; | 
 |     HasPlusPrefix = false; | 
 |     HasSpacePrefix = false; | 
 |     HasAlternativeForm = false; | 
 |     HasLeadingZeroes = false; | 
 |     Precision.setHowSpecified(OptionalAmount::NotSpecified); | 
 |     LM.setKind(LengthModifier::None); | 
 |  | 
 |     return true; | 
 |   } | 
 |  | 
 |   // Handle strings next (char *, wchar_t *) | 
 |   if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { | 
 |     CS.setKind(ConversionSpecifier::sArg); | 
 |  | 
 |     // Disable irrelevant flags | 
 |     HasAlternativeForm = 0; | 
 |     HasLeadingZeroes = 0; | 
 |  | 
 |     // Set the long length modifier for wide characters | 
 |     if (QT->getPointeeType()->isWideCharType()) | 
 |       LM.setKind(LengthModifier::AsWideChar); | 
 |     else | 
 |       LM.setKind(LengthModifier::None); | 
 |  | 
 |     return true; | 
 |   } | 
 |  | 
 |   // If it's an enum, get its underlying type. | 
 |   if (const EnumType *ETy = QT->getAs<EnumType>()) | 
 |     QT = ETy->getDecl()->getIntegerType(); | 
 |  | 
 |   // We can only work with builtin types. | 
 |   const BuiltinType *BT = QT->getAs<BuiltinType>(); | 
 |   if (!BT) | 
 |     return false; | 
 |  | 
 |   // Set length modifier | 
 |   switch (BT->getKind()) { | 
 |   case BuiltinType::Bool: | 
 |   case BuiltinType::WChar_U: | 
 |   case BuiltinType::WChar_S: | 
 |   case BuiltinType::Char16: | 
 |   case BuiltinType::Char32: | 
 |   case BuiltinType::UInt128: | 
 |   case BuiltinType::Int128: | 
 |   case BuiltinType::Half: | 
 |     // Various types which are non-trivial to correct. | 
 |     return false; | 
 |  | 
 | #define SIGNED_TYPE(Id, SingletonId) | 
 | #define UNSIGNED_TYPE(Id, SingletonId) | 
 | #define FLOATING_TYPE(Id, SingletonId) | 
 | #define BUILTIN_TYPE(Id, SingletonId) \ | 
 |   case BuiltinType::Id: | 
 | #include "clang/AST/BuiltinTypes.def" | 
 |     // Misc other stuff which doesn't make sense here. | 
 |     return false; | 
 |  | 
 |   case BuiltinType::UInt: | 
 |   case BuiltinType::Int: | 
 |   case BuiltinType::Float: | 
 |   case BuiltinType::Double: | 
 |     LM.setKind(LengthModifier::None); | 
 |     break; | 
 |  | 
 |   case BuiltinType::Char_U: | 
 |   case BuiltinType::UChar: | 
 |   case BuiltinType::Char_S: | 
 |   case BuiltinType::SChar: | 
 |     LM.setKind(LengthModifier::AsChar); | 
 |     break; | 
 |  | 
 |   case BuiltinType::Short: | 
 |   case BuiltinType::UShort: | 
 |     LM.setKind(LengthModifier::AsShort); | 
 |     break; | 
 |  | 
 |   case BuiltinType::Long: | 
 |   case BuiltinType::ULong: | 
 |     LM.setKind(LengthModifier::AsLong); | 
 |     break; | 
 |  | 
 |   case BuiltinType::LongLong: | 
 |   case BuiltinType::ULongLong: | 
 |     LM.setKind(LengthModifier::AsLongLong); | 
 |     break; | 
 |  | 
 |   case BuiltinType::LongDouble: | 
 |     LM.setKind(LengthModifier::AsLongDouble); | 
 |     break; | 
 |   } | 
 |  | 
 |   // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99. | 
 |   if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11)) | 
 |     namedTypeToLengthModifier(QT, LM); | 
 |  | 
 |   // If fixing the length modifier was enough, we might be done. | 
 |   if (hasValidLengthModifier(Ctx.getTargetInfo())) { | 
 |     // If we're going to offer a fix anyway, make sure the sign matches. | 
 |     switch (CS.getKind()) { | 
 |     case ConversionSpecifier::uArg: | 
 |     case ConversionSpecifier::UArg: | 
 |       if (QT->isSignedIntegerType()) | 
 |         CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg); | 
 |       break; | 
 |     case ConversionSpecifier::dArg: | 
 |     case ConversionSpecifier::DArg: | 
 |     case ConversionSpecifier::iArg: | 
 |       if (QT->isUnsignedIntegerType() && !HasPlusPrefix) | 
 |         CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg); | 
 |       break; | 
 |     default: | 
 |       // Other specifiers do not have signed/unsigned variants. | 
 |       break; | 
 |     } | 
 |  | 
 |     const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); | 
 |     if (ATR.isValid() && ATR.matchesType(Ctx, QT)) | 
 |       return true; | 
 |   } | 
 |  | 
 |   // Set conversion specifier and disable any flags which do not apply to it. | 
 |   // Let typedefs to char fall through to int, as %c is silly for uint8_t. | 
 |   if (!isa<TypedefType>(QT) && QT->isCharType()) { | 
 |     CS.setKind(ConversionSpecifier::cArg); | 
 |     LM.setKind(LengthModifier::None); | 
 |     Precision.setHowSpecified(OptionalAmount::NotSpecified); | 
 |     HasAlternativeForm = 0; | 
 |     HasLeadingZeroes = 0; | 
 |     HasPlusPrefix = 0; | 
 |   } | 
 |   // Test for Floating type first as LongDouble can pass isUnsignedIntegerType | 
 |   else if (QT->isRealFloatingType()) { | 
 |     CS.setKind(ConversionSpecifier::fArg); | 
 |   } | 
 |   else if (QT->isSignedIntegerType()) { | 
 |     CS.setKind(ConversionSpecifier::dArg); | 
 |     HasAlternativeForm = 0; | 
 |   } | 
 |   else if (QT->isUnsignedIntegerType()) { | 
 |     CS.setKind(ConversionSpecifier::uArg); | 
 |     HasAlternativeForm = 0; | 
 |     HasPlusPrefix = 0; | 
 |   } else { | 
 |     llvm_unreachable("Unexpected type"); | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | void PrintfSpecifier::toString(raw_ostream &os) const { | 
 |   // Whilst some features have no defined order, we are using the order | 
 |   // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1) | 
 |   os << "%"; | 
 |  | 
 |   // Positional args | 
 |   if (usesPositionalArg()) { | 
 |     os << getPositionalArgIndex() << "$"; | 
 |   } | 
 |  | 
 |   // Conversion flags | 
 |   if (IsLeftJustified)    os << "-"; | 
 |   if (HasPlusPrefix)      os << "+"; | 
 |   if (HasSpacePrefix)     os << " "; | 
 |   if (HasAlternativeForm) os << "#"; | 
 |   if (HasLeadingZeroes)   os << "0"; | 
 |  | 
 |   // Minimum field width | 
 |   FieldWidth.toString(os); | 
 |   // Precision | 
 |   Precision.toString(os); | 
 |   // Length modifier | 
 |   os << LM.toString(); | 
 |   // Conversion specifier | 
 |   os << CS.toString(); | 
 | } | 
 |  | 
 | bool PrintfSpecifier::hasValidPlusPrefix() const { | 
 |   if (!HasPlusPrefix) | 
 |     return true; | 
 |  | 
 |   // The plus prefix only makes sense for signed conversions | 
 |   switch (CS.getKind()) { | 
 |   case ConversionSpecifier::dArg: | 
 |   case ConversionSpecifier::DArg: | 
 |   case ConversionSpecifier::iArg: | 
 |   case ConversionSpecifier::fArg: | 
 |   case ConversionSpecifier::FArg: | 
 |   case ConversionSpecifier::eArg: | 
 |   case ConversionSpecifier::EArg: | 
 |   case ConversionSpecifier::gArg: | 
 |   case ConversionSpecifier::GArg: | 
 |   case ConversionSpecifier::aArg: | 
 |   case ConversionSpecifier::AArg: | 
 |   case ConversionSpecifier::FreeBSDrArg: | 
 |   case ConversionSpecifier::FreeBSDyArg: | 
 |     return true; | 
 |  | 
 |   default: | 
 |     return false; | 
 |   } | 
 | } | 
 |  | 
 | bool PrintfSpecifier::hasValidAlternativeForm() const { | 
 |   if (!HasAlternativeForm) | 
 |     return true; | 
 |  | 
 |   // Alternate form flag only valid with the oxXaAeEfFgG conversions | 
 |   switch (CS.getKind()) { | 
 |   case ConversionSpecifier::oArg: | 
 |   case ConversionSpecifier::OArg: | 
 |   case ConversionSpecifier::xArg: | 
 |   case ConversionSpecifier::XArg: | 
 |   case ConversionSpecifier::aArg: | 
 |   case ConversionSpecifier::AArg: | 
 |   case ConversionSpecifier::eArg: | 
 |   case ConversionSpecifier::EArg: | 
 |   case ConversionSpecifier::fArg: | 
 |   case ConversionSpecifier::FArg: | 
 |   case ConversionSpecifier::gArg: | 
 |   case ConversionSpecifier::GArg: | 
 |   case ConversionSpecifier::FreeBSDrArg: | 
 |   case ConversionSpecifier::FreeBSDyArg: | 
 |     return true; | 
 |  | 
 |   default: | 
 |     return false; | 
 |   } | 
 | } | 
 |  | 
 | bool PrintfSpecifier::hasValidLeadingZeros() const { | 
 |   if (!HasLeadingZeroes) | 
 |     return true; | 
 |  | 
 |   // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions | 
 |   switch (CS.getKind()) { | 
 |   case ConversionSpecifier::dArg: | 
 |   case ConversionSpecifier::DArg: | 
 |   case ConversionSpecifier::iArg: | 
 |   case ConversionSpecifier::oArg: | 
 |   case ConversionSpecifier::OArg: | 
 |   case ConversionSpecifier::uArg: | 
 |   case ConversionSpecifier::UArg: | 
 |   case ConversionSpecifier::xArg: | 
 |   case ConversionSpecifier::XArg: | 
 |   case ConversionSpecifier::aArg: | 
 |   case ConversionSpecifier::AArg: | 
 |   case ConversionSpecifier::eArg: | 
 |   case ConversionSpecifier::EArg: | 
 |   case ConversionSpecifier::fArg: | 
 |   case ConversionSpecifier::FArg: | 
 |   case ConversionSpecifier::gArg: | 
 |   case ConversionSpecifier::GArg: | 
 |   case ConversionSpecifier::FreeBSDrArg: | 
 |   case ConversionSpecifier::FreeBSDyArg: | 
 |     return true; | 
 |  | 
 |   default: | 
 |     return false; | 
 |   } | 
 | } | 
 |  | 
 | bool PrintfSpecifier::hasValidSpacePrefix() const { | 
 |   if (!HasSpacePrefix) | 
 |     return true; | 
 |  | 
 |   // The space prefix only makes sense for signed conversions | 
 |   switch (CS.getKind()) { | 
 |   case ConversionSpecifier::dArg: | 
 |   case ConversionSpecifier::DArg: | 
 |   case ConversionSpecifier::iArg: | 
 |   case ConversionSpecifier::fArg: | 
 |   case ConversionSpecifier::FArg: | 
 |   case ConversionSpecifier::eArg: | 
 |   case ConversionSpecifier::EArg: | 
 |   case ConversionSpecifier::gArg: | 
 |   case ConversionSpecifier::GArg: | 
 |   case ConversionSpecifier::aArg: | 
 |   case ConversionSpecifier::AArg: | 
 |   case ConversionSpecifier::FreeBSDrArg: | 
 |   case ConversionSpecifier::FreeBSDyArg: | 
 |     return true; | 
 |  | 
 |   default: | 
 |     return false; | 
 |   } | 
 | } | 
 |  | 
 | bool PrintfSpecifier::hasValidLeftJustified() const { | 
 |   if (!IsLeftJustified) | 
 |     return true; | 
 |  | 
 |   // The left justified flag is valid for all conversions except n | 
 |   switch (CS.getKind()) { | 
 |   case ConversionSpecifier::nArg: | 
 |     return false; | 
 |  | 
 |   default: | 
 |     return true; | 
 |   } | 
 | } | 
 |  | 
 | bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { | 
 |   if (!HasThousandsGrouping) | 
 |     return true; | 
 |  | 
 |   switch (CS.getKind()) { | 
 |     case ConversionSpecifier::dArg: | 
 |     case ConversionSpecifier::DArg: | 
 |     case ConversionSpecifier::iArg: | 
 |     case ConversionSpecifier::uArg: | 
 |     case ConversionSpecifier::UArg: | 
 |     case ConversionSpecifier::fArg: | 
 |     case ConversionSpecifier::FArg: | 
 |     case ConversionSpecifier::gArg: | 
 |     case ConversionSpecifier::GArg: | 
 |       return true; | 
 |     default: | 
 |       return false; | 
 |   } | 
 | } | 
 |  | 
 | bool PrintfSpecifier::hasValidPrecision() const { | 
 |   if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) | 
 |     return true; | 
 |  | 
 |   // Precision is only valid with the diouxXaAeEfFgGs conversions | 
 |   switch (CS.getKind()) { | 
 |   case ConversionSpecifier::dArg: | 
 |   case ConversionSpecifier::DArg: | 
 |   case ConversionSpecifier::iArg: | 
 |   case ConversionSpecifier::oArg: | 
 |   case ConversionSpecifier::OArg: | 
 |   case ConversionSpecifier::uArg: | 
 |   case ConversionSpecifier::UArg: | 
 |   case ConversionSpecifier::xArg: | 
 |   case ConversionSpecifier::XArg: | 
 |   case ConversionSpecifier::aArg: | 
 |   case ConversionSpecifier::AArg: | 
 |   case ConversionSpecifier::eArg: | 
 |   case ConversionSpecifier::EArg: | 
 |   case ConversionSpecifier::fArg: | 
 |   case ConversionSpecifier::FArg: | 
 |   case ConversionSpecifier::gArg: | 
 |   case ConversionSpecifier::GArg: | 
 |   case ConversionSpecifier::sArg: | 
 |   case ConversionSpecifier::FreeBSDrArg: | 
 |   case ConversionSpecifier::FreeBSDyArg: | 
 |     return true; | 
 |  | 
 |   default: | 
 |     return false; | 
 |   } | 
 | } | 
 | bool PrintfSpecifier::hasValidFieldWidth() const { | 
 |   if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) | 
 |       return true; | 
 |  | 
 |   // The field width is valid for all conversions except n | 
 |   switch (CS.getKind()) { | 
 |   case ConversionSpecifier::nArg: | 
 |     return false; | 
 |  | 
 |   default: | 
 |     return true; | 
 |   } | 
 | } |