LCOV - code coverage report
Current view: top level - lib/Support - FormatVariadic.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 60 61 98.4 %
Date: 2018-09-23 13:06:45 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        2412 :   switch (C) {
      15             :   case '-':
      16             :     return AlignStyle::Left;
      17         145 :   case '=':
      18             :     return AlignStyle::Center;
      19         454 :   case '+':
      20             :     return AlignStyle::Right;
      21             :   default:
      22             :     return None;
      23             :   }
      24             :   LLVM_BUILTIN_UNREACHABLE;
      25             : }
      26             : 
      27        1523 : bool formatv_object_base::consumeFieldLayout(StringRef &Spec, AlignStyle &Where,
      28             :                                              size_t &Align, char &Pad) {
      29        1523 :   Where = AlignStyle::Right;
      30        1523 :   Align = 0;
      31        1523 :   Pad = ' ';
      32        1523 :   if (Spec.empty())
      33             :     return true;
      34             : 
      35        1523 :   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        2429 :     if (auto Loc = translateLocChar(Spec[1])) {
      44          20 :       Pad = Spec[0];
      45          20 :       Where = *Loc;
      46          20 :       Spec = Spec.drop_front(2);
      47        1196 :     } else if (auto Loc = translateLocChar(Spec[0])) {
      48         905 :       Where = *Loc;
      49         905 :       Spec = Spec.drop_front(1);
      50             :     }
      51             :   }
      52             : 
      53             :   bool Failed = Spec.consumeInteger(0, Align);
      54        1523 :   return !Failed;
      55             : }
      56             : 
      57             : Optional<ReplacementItem>
      58      481737 : formatv_object_base::parseReplacementItem(StringRef Spec) {
      59      481737 :   StringRef RepString = Spec.trim("{}");
      60             : 
      61             :   // If the replacement sequence does not start with a non-negative integer,
      62             :   // this is an error.
      63      481737 :   char Pad = ' ';
      64      481737 :   std::size_t Align = 0;
      65      481737 :   AlignStyle Where = AlignStyle::Right;
      66             :   StringRef Options;
      67             :   size_t Index = 0;
      68      481737 :   RepString = RepString.trim();
      69             :   if (RepString.consumeInteger(0, Index)) {
      70             :     assert(false && "Invalid replacement sequence index!");
      71           0 :     return ReplacementItem{};
      72             :   }
      73      481737 :   RepString = RepString.trim();
      74      481737 :   if (!RepString.empty() && RepString.front() == ',') {
      75        1523 :     RepString = RepString.drop_front();
      76        1523 :     if (!consumeFieldLayout(RepString, Where, Align, Pad))
      77             :       assert(false && "Invalid replacement field layout specification!");
      78             :   }
      79      481737 :   RepString = RepString.trim();
      80      481737 :   if (!RepString.empty() && RepString.front() == ':') {
      81        8646 :     Options = RepString.drop_front().trim();
      82        8646 :     RepString = StringRef();
      83             :   }
      84      481737 :   RepString = RepString.trim();
      85             :   if (!RepString.empty()) {
      86             :     assert(false && "Unexpected characters found in replacement string!");
      87             :   }
      88             : 
      89      963474 :   return ReplacementItem{Spec, Index, Align, Where, Pad, Options};
      90             : }
      91             : 
      92             : std::pair<ReplacementItem, StringRef>
      93      943156 : formatv_object_base::splitLiteralAndReplacement(StringRef Fmt) {
      94             :   std::size_t From = 0;
      95      943156 :   while (From < Fmt.size() && From != StringRef::npos) {
      96      943156 :     std::size_t BO = Fmt.find_first_of('{', From);
      97             :     // Everything up until the first brace is a literal.
      98      943156 :     if (BO != 0)
      99      491101 :       return std::make_pair(ReplacementItem{Fmt.substr(0, BO)}, Fmt.substr(BO));
     100             : 
     101             :     StringRef Braces =
     102      481873 :         Fmt.drop_front(BO).take_while([](char C) { return C == '{'; });
     103             :     // If there is more than one brace, then some of them are escaped.  Treat
     104             :     // these as replacements.
     105      481873 :     if (Braces.size() > 1) {
     106         133 :       size_t NumEscapedBraces = Braces.size() / 2;
     107         133 :       StringRef Middle = Fmt.substr(BO, NumEscapedBraces);
     108         133 :       StringRef Right = Fmt.drop_front(BO + NumEscapedBraces * 2);
     109             :       return std::make_pair(ReplacementItem{Middle}, Right);
     110             :     }
     111             :     // An unterminated open brace is undefined.  We treat the rest of the string
     112             :     // as a literal replacement, but we assert to indicate that this is
     113             :     // undefined and that we consider it an error.
     114      481740 :     std::size_t BC = Fmt.find_first_of('}', BO);
     115      481740 :     if (BC == StringRef::npos) {
     116             :       assert(
     117             :           false &&
     118             :           "Unterminated brace sequence.  Escape with {{ for a literal brace.");
     119             :       return std::make_pair(ReplacementItem{Fmt}, StringRef());
     120             :     }
     121             : 
     122             :     // Even if there is a closing brace, if there is another open brace before
     123             :     // this closing brace, treat this portion as literal, and try again with the
     124             :     // next one.
     125      481740 :     std::size_t BO2 = Fmt.find_first_of('{', BO + 1);
     126      481740 :     if (BO2 < BC)
     127           3 :       return std::make_pair(ReplacementItem{Fmt.substr(0, BO2)},
     128           3 :                             Fmt.substr(BO2));
     129             : 
     130      481737 :     StringRef Spec = Fmt.slice(BO + 1, BC);
     131      481737 :     StringRef Right = Fmt.substr(BC + 1);
     132             : 
     133      481737 :     auto RI = parseReplacementItem(Spec);
     134      481737 :     if (RI.hasValue())
     135      481737 :       return std::make_pair(*RI, Right);
     136             : 
     137             :     // If there was an error parsing the replacement item, treat it as an
     138             :     // invalid replacement spec, and just continue.
     139             :     From = BC + 1;
     140             :   }
     141             :   return std::make_pair(ReplacementItem{Fmt}, StringRef());
     142             : }
     143             : 
     144             : std::vector<ReplacementItem>
     145      453568 : formatv_object_base::parseFormatString(StringRef Fmt) {
     146             :   std::vector<ReplacementItem> Replacements;
     147             :   ReplacementItem I;
     148     1396724 :   while (!Fmt.empty()) {
     149      943156 :     std::tie(I, Fmt) = splitLiteralAndReplacement(Fmt);
     150      943156 :     if (I.Type != ReplacementType::Empty)
     151      943156 :       Replacements.push_back(I);
     152             :   }
     153      453568 :   return Replacements;
     154             : }

Generated by: LCOV version 1.13