FormatString.cpp revision 826a3457f737f1fc45a22954fd1bfde38160c165
1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*- 2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// 3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// The LLVM Compiler Infrastructure 4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// 5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// This file is distributed under the University of Illinois Open Source 6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// License. See LICENSE.TXT for details. 7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// 8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//===----------------------------------------------------------------------===// 9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// 10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Shared details for processing format strings of printf and scanf 11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// (and friends). 12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// 13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//===----------------------------------------------------------------------===// 14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "FormatStringParsing.h" 16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::ArgTypeResult; 18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::FormatStringHandler; 19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::FormatSpecifier; 20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::LengthModifier; 21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::OptionalAmount; 22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing clang::analyze_format_string::PositionContext; 23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgusing namespace clang; 24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Key function to FormatStringHandler. 26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgFormatStringHandler::~FormatStringHandler() {} 27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//===----------------------------------------------------------------------===// 29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// Functions for parsing format strings components in both printf and 30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org// scanf format strings. 31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org//===----------------------------------------------------------------------===// 32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgOptionalAmount 34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) { 35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *I = Beg; 36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org UpdateOnReturn <const char*> UpdateBeg(Beg, I); 37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned accumulator = 0; 39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org bool hasDigits = false; 40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for ( ; I != E; ++I) { 42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org char c = *I; 43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (c >= '0' && c <= '9') { 44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org hasDigits = true; 45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org accumulator = (accumulator * 10) + (c - '0'); 46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org continue; 47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (hasDigits) 50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg, 51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org false); 52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org break; 54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return OptionalAmount(); 57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgOptionalAmount 60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParseNonPositionAmount(const char *&Beg, 61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *E, 62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned &argIndex) { 63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (*Beg == '*') { 64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org ++Beg; 65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false); 66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return ParseAmount(Beg, E); 69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgOptionalAmount 72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H, 73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *Start, 74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *&Beg, 75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *E, 76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org PositionContext p) { 77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (*Beg == '*') { 78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *I = Beg + 1; 79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const OptionalAmount &Amt = ParseAmount(I, E); 80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) { 82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org H.HandleInvalidPosition(Beg, I - Beg, p); 83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return OptionalAmount(false); 84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (I == E) { 87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // No more characters left? 88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org H.HandleIncompleteSpecifier(Start, E - Start); 89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return OptionalAmount(false); 90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(Amt.getHowSpecified() == OptionalAmount::Constant); 93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (*I == '$') { 95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Handle positional arguments 96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Special case: '*0$', since this is an easy mistake. 98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (Amt.getConstantAmount() == 0) { 99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org H.HandleZeroPosition(Beg, I - Beg + 1); 100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return OptionalAmount(false); 101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *Tmp = Beg; 104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org Beg = ++I; 105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1, 107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org Tmp, 0, true); 108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org H.HandleInvalidPosition(Beg, I - Beg, p); 111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return OptionalAmount(false); 112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return ParseAmount(Beg, E); 115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool 119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H, 120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org FormatSpecifier &CS, 121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *Start, 122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *&Beg, const char *E, 123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned *argIndex) { 124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // FIXME: Support negative field widths. 125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (argIndex) { 126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex)); 127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org else { 129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const OptionalAmount Amt = 130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org ParsePositionAmount(H, Start, Beg, E, 131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org analyze_format_string::FieldWidthPos); 132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (Amt.isInvalid()) 134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return true; 135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org CS.setFieldWidth(Amt); 136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return false; 138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgbool 141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgclang::analyze_format_string::ParseArgPosition(FormatStringHandler &H, 142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org FormatSpecifier &FS, 143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *Start, 144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *&Beg, 145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *E) { 146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const char *I = Beg; 147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const OptionalAmount &Amt = ParseAmount(I, E); 149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (I == E) { 151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // No more characters left? 152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org H.HandleIncompleteSpecifier(Start, E - Start); 153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return true; 154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') { 157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Special case: '%0$', since this is an easy mistake. 158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (Amt.getConstantAmount() == 0) { 159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org H.HandleZeroPosition(Start, I - Start); 160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return true; 161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org FS.setArgIndex(Amt.getConstantAmount() - 1); 164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org FS.setUsesPositionalArg(); 165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // Update the caller's pointer if we decided to consume 166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // these characters. 167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org Beg = I; 168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return false; 169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 171 return false; 172} 173 174bool 175clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, 176 const char *&I, 177 const char *E) { 178 LengthModifier::Kind lmKind = LengthModifier::None; 179 const char *lmPosition = I; 180 switch (*I) { 181 default: 182 return false; 183 case 'h': 184 ++I; 185 lmKind = (I != E && *I == 'h') ? 186 ++I, LengthModifier::AsChar : LengthModifier::AsShort; 187 break; 188 case 'l': 189 ++I; 190 lmKind = (I != E && *I == 'l') ? 191 ++I, LengthModifier::AsLongLong : LengthModifier::AsLong; 192 break; 193 case 'j': lmKind = LengthModifier::AsIntMax; ++I; break; 194 case 'z': lmKind = LengthModifier::AsSizeT; ++I; break; 195 case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break; 196 case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break; 197 case 'q': lmKind = LengthModifier::AsLongLong; ++I; break; 198 } 199 LengthModifier lm(lmPosition, lmKind); 200 FS.setLengthModifier(lm); 201 return true; 202} 203 204//===----------------------------------------------------------------------===// 205// Methods on ArgTypeResult. 206//===----------------------------------------------------------------------===// 207 208bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { 209 switch (K) { 210 case InvalidTy: 211 assert(false && "ArgTypeResult must be valid"); 212 return true; 213 214 case UnknownTy: 215 return true; 216 217 case SpecificTy: { 218 argTy = C.getCanonicalType(argTy).getUnqualifiedType(); 219 if (T == argTy) 220 return true; 221 if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) 222 switch (BT->getKind()) { 223 default: 224 break; 225 case BuiltinType::Char_S: 226 case BuiltinType::SChar: 227 return T == C.UnsignedCharTy; 228 case BuiltinType::Char_U: 229 case BuiltinType::UChar: 230 return T == C.SignedCharTy; 231 case BuiltinType::Short: 232 return T == C.UnsignedShortTy; 233 case BuiltinType::UShort: 234 return T == C.ShortTy; 235 case BuiltinType::Int: 236 return T == C.UnsignedIntTy; 237 case BuiltinType::UInt: 238 return T == C.IntTy; 239 case BuiltinType::Long: 240 return T == C.UnsignedLongTy; 241 case BuiltinType::ULong: 242 return T == C.LongTy; 243 case BuiltinType::LongLong: 244 return T == C.UnsignedLongLongTy; 245 case BuiltinType::ULongLong: 246 return T == C.LongLongTy; 247 } 248 return false; 249 } 250 251 case CStrTy: { 252 const PointerType *PT = argTy->getAs<PointerType>(); 253 if (!PT) 254 return false; 255 QualType pointeeTy = PT->getPointeeType(); 256 if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) 257 switch (BT->getKind()) { 258 case BuiltinType::Void: 259 case BuiltinType::Char_U: 260 case BuiltinType::UChar: 261 case BuiltinType::Char_S: 262 case BuiltinType::SChar: 263 return true; 264 default: 265 break; 266 } 267 268 return false; 269 } 270 271 case WCStrTy: { 272 const PointerType *PT = argTy->getAs<PointerType>(); 273 if (!PT) 274 return false; 275 QualType pointeeTy = 276 C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); 277 return pointeeTy == C.getWCharType(); 278 } 279 280 case CPointerTy: 281 return argTy->getAs<PointerType>() != NULL || 282 argTy->getAs<ObjCObjectPointerType>() != NULL; 283 284 case ObjCPointerTy: 285 return argTy->getAs<ObjCObjectPointerType>() != NULL; 286 } 287 288 // FIXME: Should be unreachable, but Clang is currently emitting 289 // a warning. 290 return false; 291} 292 293QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { 294 switch (K) { 295 case InvalidTy: 296 assert(false && "No representative type for Invalid ArgTypeResult"); 297 // Fall-through. 298 case UnknownTy: 299 return QualType(); 300 case SpecificTy: 301 return T; 302 case CStrTy: 303 return C.getPointerType(C.CharTy); 304 case WCStrTy: 305 return C.getPointerType(C.getWCharType()); 306 case ObjCPointerTy: 307 return C.ObjCBuiltinIdTy; 308 case CPointerTy: 309 return C.VoidPtrTy; 310 } 311 312 // FIXME: Should be unreachable, but Clang is currently emitting 313 // a warning. 314 return QualType(); 315} 316 317//===----------------------------------------------------------------------===// 318// Methods on OptionalAmount. 319//===----------------------------------------------------------------------===// 320 321ArgTypeResult 322analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const { 323 return Ctx.IntTy; 324} 325 326//===----------------------------------------------------------------------===// 327// Methods on LengthModifier. 328//===----------------------------------------------------------------------===// 329 330const char * 331analyze_format_string::LengthModifier::toString() const { 332 switch (kind) { 333 case AsChar: 334 return "hh"; 335 case AsShort: 336 return "h"; 337 case AsLong: // or AsWideChar 338 return "l"; 339 case AsLongLong: 340 return "ll"; 341 case AsIntMax: 342 return "j"; 343 case AsSizeT: 344 return "z"; 345 case AsPtrDiff: 346 return "t"; 347 case AsLongDouble: 348 return "L"; 349 case None: 350 return ""; 351 } 352 return NULL; 353} 354 355//===----------------------------------------------------------------------===// 356// Methods on OptionalAmount. 357//===----------------------------------------------------------------------===// 358 359void 360analyze_format_string::OptionalAmount::toString(llvm::raw_ostream &os) const { 361 switch (hs) { 362 case Invalid: 363 case NotSpecified: 364 return; 365 case Arg: 366 if (UsesDotPrefix) 367 os << "."; 368 if (usesPositionalArg()) 369 os << "*" << getPositionalArgIndex() << "$"; 370 else 371 os << "*"; 372 break; 373 case Constant: 374 if (UsesDotPrefix) 375 os << "."; 376 os << amt; 377 break; 378 } 379} 380 381