/home/arjun/llvm-project/llvm/lib/Support/FormatVariadic.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | //===- FormatVariadic.cpp - Format string parsing and analysis ----*-C++-*-===// | 
| 2 |  | // | 
| 3 |  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
| 4 |  | // See https://llvm.org/LICENSE.txt for license information. | 
| 5 |  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
| 6 |  | //===----------------------------------------------------------------------===// | 
| 7 |  |  | 
| 8 |  | #include "llvm/Support/FormatVariadic.h" | 
| 9 |  | #include <cassert> | 
| 10 |  |  | 
| 11 |  | using namespace llvm; | 
| 12 |  |  | 
| 13 | 0 | static Optional<AlignStyle> translateLocChar(char C) { | 
| 14 | 0 |   switch (C) { | 
| 15 | 0 |   case '-': | 
| 16 | 0 |     return AlignStyle::Left; | 
| 17 | 0 |   case '=': | 
| 18 | 0 |     return AlignStyle::Center; | 
| 19 | 0 |   case '+': | 
| 20 | 0 |     return AlignStyle::Right; | 
| 21 | 0 |   default: | 
| 22 | 0 |     return None; | 
| 23 | 0 |   } | 
| 24 | 0 |   LLVM_BUILTIN_UNREACHABLE; | 
| 25 | 0 | } | 
| 26 |  |  | 
| 27 |  | bool formatv_object_base::consumeFieldLayout(StringRef &Spec, AlignStyle &Where, | 
| 28 | 0 |                                              size_t &Align, char &Pad) { | 
| 29 | 0 |   Where = AlignStyle::Right; | 
| 30 | 0 |   Align = 0; | 
| 31 | 0 |   Pad = ' '; | 
| 32 | 0 |   if (Spec.empty()) | 
| 33 | 0 |     return true; | 
| 34 | 0 |  | 
| 35 | 0 |   if (Spec.size() > 1) { | 
| 36 | 0 |     // A maximum of 2 characters at the beginning can be used for something | 
| 37 | 0 |     // other | 
| 38 | 0 |     // than the width. | 
| 39 | 0 |     // If Spec[1] is a loc char, then Spec[0] is a pad char and Spec[2:...] | 
| 40 | 0 |     // contains the width. | 
| 41 | 0 |     // Otherwise, if Spec[0] is a loc char, then Spec[1:...] contains the width. | 
| 42 | 0 |     // Otherwise, Spec[0:...] contains the width. | 
| 43 | 0 |     if (auto Loc = translateLocChar(Spec[1])) { | 
| 44 | 0 |       Pad = Spec[0]; | 
| 45 | 0 |       Where = *Loc; | 
| 46 | 0 |       Spec = Spec.drop_front(2); | 
| 47 | 0 |     } else if (auto Loc = translateLocChar(Spec[0])) { | 
| 48 | 0 |       Where = *Loc; | 
| 49 | 0 |       Spec = Spec.drop_front(1); | 
| 50 | 0 |     } | 
| 51 | 0 |   } | 
| 52 | 0 | 
 | 
| 53 | 0 |   bool Failed = Spec.consumeInteger(0, Align); | 
| 54 | 0 |   return !Failed; | 
| 55 | 0 | } | 
| 56 |  |  | 
| 57 |  | Optional<ReplacementItem> | 
| 58 | 0 | formatv_object_base::parseReplacementItem(StringRef Spec) { | 
| 59 | 0 |   StringRef RepString = Spec.trim("{}"); | 
| 60 | 0 | 
 | 
| 61 | 0 |   // If the replacement sequence does not start with a non-negative integer, | 
| 62 | 0 |   // this is an error. | 
| 63 | 0 |   char Pad = ' '; | 
| 64 | 0 |   std::size_t Align = 0; | 
| 65 | 0 |   AlignStyle Where = AlignStyle::Right; | 
| 66 | 0 |   StringRef Options; | 
| 67 | 0 |   size_t Index = 0; | 
| 68 | 0 |   RepString = RepString.trim(); | 
| 69 | 0 |   if (RepString.consumeInteger(0, Index)) { | 
| 70 | 0 |     assert(false && "Invalid replacement sequence index!"); | 
| 71 | 0 |     return ReplacementItem{}; | 
| 72 | 0 |   } | 
| 73 | 0 |   RepString = RepString.trim(); | 
| 74 | 0 |   if (!RepString.empty() && RepString.front() == ',') { | 
| 75 | 0 |     RepString = RepString.drop_front(); | 
| 76 | 0 |     if (!consumeFieldLayout(RepString, Where, Align, Pad)) | 
| 77 | 0 |       assert(false && "Invalid replacement field layout specification!"); | 
| 78 | 0 |   } | 
| 79 | 0 |   RepString = RepString.trim(); | 
| 80 | 0 |   if (!RepString.empty() && RepString.front() == ':') { | 
| 81 | 0 |     Options = RepString.drop_front().trim(); | 
| 82 | 0 |     RepString = StringRef(); | 
| 83 | 0 |   } | 
| 84 | 0 |   RepString = RepString.trim(); | 
| 85 | 0 |   if (!RepString.empty()) { | 
| 86 | 0 |     assert(false && "Unexpected characters found in replacement string!"); | 
| 87 | 0 |   } | 
| 88 | 0 | 
 | 
| 89 | 0 |   return ReplacementItem{Spec, Index, Align, Where, Pad, Options}; | 
| 90 | 0 | } | 
| 91 |  |  | 
| 92 |  | std::pair<ReplacementItem, StringRef> | 
| 93 | 0 | formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) { | 
| 94 | 0 |   std::size_t From = 0; | 
| 95 | 0 |   while (From < Fmt.size() && From != StringRef::npos) { | 
| 96 | 0 |     std::size_t BO = Fmt.find_first_of('{', From); | 
| 97 | 0 |     // Everything up until the first brace is a literal. | 
| 98 | 0 |     if (BO != 0) | 
| 99 | 0 |       return std::make_pair(ReplacementItem{Fmt.substr(0, BO)}, Fmt.substr(BO)); | 
| 100 | 0 |  | 
| 101 | 0 |     StringRef Braces = | 
| 102 | 0 |         Fmt.drop_front(BO).take_while([](char C) { return C == '{'; }); | 
| 103 | 0 |     // If there is more than one brace, then some of them are escaped.  Treat | 
| 104 | 0 |     // these as replacements. | 
| 105 | 0 |     if (Braces.size() > 1) { | 
| 106 | 0 |       size_t NumEscapedBraces = Braces.size() / 2; | 
| 107 | 0 |       StringRef Middle = Fmt.substr(BO, NumEscapedBraces); | 
| 108 | 0 |       StringRef Right = Fmt.drop_front(BO + NumEscapedBraces * 2); | 
| 109 | 0 |       return std::make_pair(ReplacementItem{Middle}, Right); | 
| 110 | 0 |     } | 
| 111 | 0 |     // An unterminated open brace is undefined.  We treat the rest of the string | 
| 112 | 0 |     // as a literal replacement, but we assert to indicate that this is | 
| 113 | 0 |     // undefined and that we consider it an error. | 
| 114 | 0 |     std::size_t BC = Fmt.find_first_of('}', BO); | 
| 115 | 0 |     if (BC == StringRef::npos) { | 
| 116 | 0 |       assert( | 
| 117 | 0 |           false && | 
| 118 | 0 |           "Unterminated brace sequence.  Escape with {{ for a literal brace."); | 
| 119 | 0 |       return std::make_pair(ReplacementItem{Fmt}, StringRef()); | 
| 120 | 0 |     } | 
| 121 | 0 |  | 
| 122 | 0 |     // Even if there is a closing brace, if there is another open brace before | 
| 123 | 0 |     // this closing brace, treat this portion as literal, and try again with the | 
| 124 | 0 |     // next one. | 
| 125 | 0 |     std::size_t BO2 = Fmt.find_first_of('{', BO + 1); | 
| 126 | 0 |     if (BO2 < BC) | 
| 127 | 0 |       return std::make_pair(ReplacementItem{Fmt.substr(0, BO2)}, | 
| 128 | 0 |                             Fmt.substr(BO2)); | 
| 129 | 0 |  | 
| 130 | 0 |     StringRef Spec = Fmt.slice(BO + 1, BC); | 
| 131 | 0 |     StringRef Right = Fmt.substr(BC + 1); | 
| 132 | 0 | 
 | 
| 133 | 0 |     auto RI = parseReplacementItem(Spec); | 
| 134 | 0 |     if (RI.hasValue()) | 
| 135 | 0 |       return std::make_pair(*RI, Right); | 
| 136 | 0 |  | 
| 137 | 0 |     // If there was an error parsing the replacement item, treat it as an | 
| 138 | 0 |     // invalid replacement spec, and just continue. | 
| 139 | 0 |     From = BC + 1; | 
| 140 | 0 |   } | 
| 141 | 0 |   return std::make_pair(ReplacementItem{Fmt}, StringRef()); | 
| 142 | 0 | } | 
| 143 |  |  | 
| 144 |  | SmallVector<ReplacementItem, 2> | 
| 145 | 0 | formatv_object_base::parseFormatString(StringRef Fmt) { | 
| 146 | 0 |   SmallVector<ReplacementItem, 2> Replacements; | 
| 147 | 0 |   ReplacementItem I; | 
| 148 | 0 |   while (!Fmt.empty()) { | 
| 149 | 0 |     std::tie(I, Fmt) = splitLiteralAndReplacement(Fmt); | 
| 150 | 0 |     if (I.Type != ReplacementType::Empty) | 
| 151 | 0 |       Replacements.push_back(I); | 
| 152 | 0 |   } | 
| 153 | 0 |   return Replacements; | 
| 154 | 0 | } | 
| 155 |  |  | 
| 156 | 0 | void detail::format_adapter::anchor() { } |