LCOV - code coverage report
Current view: top level - lib/Support - FormatVariadic.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 73 77 94.8 %
Date: 2017-09-14 15:23:50 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13