Home | History | Annotate | Line # | Download | only in Frontend
TextDiagnostic.cpp revision 1.1
      1  1.1  joerg //===--- TextDiagnostic.cpp - Text Diagnostic Pretty-Printing -------------===//
      2  1.1  joerg //
      3  1.1  joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  1.1  joerg // See https://llvm.org/LICENSE.txt for license information.
      5  1.1  joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  1.1  joerg //
      7  1.1  joerg //===----------------------------------------------------------------------===//
      8  1.1  joerg 
      9  1.1  joerg #include "clang/Frontend/TextDiagnostic.h"
     10  1.1  joerg #include "clang/Basic/CharInfo.h"
     11  1.1  joerg #include "clang/Basic/DiagnosticOptions.h"
     12  1.1  joerg #include "clang/Basic/FileManager.h"
     13  1.1  joerg #include "clang/Basic/SourceManager.h"
     14  1.1  joerg #include "clang/Lex/Lexer.h"
     15  1.1  joerg #include "llvm/ADT/SmallString.h"
     16  1.1  joerg #include "llvm/ADT/StringExtras.h"
     17  1.1  joerg #include "llvm/Support/ConvertUTF.h"
     18  1.1  joerg #include "llvm/Support/ErrorHandling.h"
     19  1.1  joerg #include "llvm/Support/Locale.h"
     20  1.1  joerg #include "llvm/Support/Path.h"
     21  1.1  joerg #include "llvm/Support/raw_ostream.h"
     22  1.1  joerg #include <algorithm>
     23  1.1  joerg 
     24  1.1  joerg using namespace clang;
     25  1.1  joerg 
     26  1.1  joerg static const enum raw_ostream::Colors noteColor =
     27  1.1  joerg   raw_ostream::BLACK;
     28  1.1  joerg static const enum raw_ostream::Colors remarkColor =
     29  1.1  joerg   raw_ostream::BLUE;
     30  1.1  joerg static const enum raw_ostream::Colors fixitColor =
     31  1.1  joerg   raw_ostream::GREEN;
     32  1.1  joerg static const enum raw_ostream::Colors caretColor =
     33  1.1  joerg   raw_ostream::GREEN;
     34  1.1  joerg static const enum raw_ostream::Colors warningColor =
     35  1.1  joerg   raw_ostream::MAGENTA;
     36  1.1  joerg static const enum raw_ostream::Colors templateColor =
     37  1.1  joerg   raw_ostream::CYAN;
     38  1.1  joerg static const enum raw_ostream::Colors errorColor = raw_ostream::RED;
     39  1.1  joerg static const enum raw_ostream::Colors fatalColor = raw_ostream::RED;
     40  1.1  joerg // Used for changing only the bold attribute.
     41  1.1  joerg static const enum raw_ostream::Colors savedColor =
     42  1.1  joerg   raw_ostream::SAVEDCOLOR;
     43  1.1  joerg 
     44  1.1  joerg /// Add highlights to differences in template strings.
     45  1.1  joerg static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str,
     46  1.1  joerg                                       bool &Normal, bool Bold) {
     47  1.1  joerg   while (1) {
     48  1.1  joerg     size_t Pos = Str.find(ToggleHighlight);
     49  1.1  joerg     OS << Str.slice(0, Pos);
     50  1.1  joerg     if (Pos == StringRef::npos)
     51  1.1  joerg       break;
     52  1.1  joerg 
     53  1.1  joerg     Str = Str.substr(Pos + 1);
     54  1.1  joerg     if (Normal)
     55  1.1  joerg       OS.changeColor(templateColor, true);
     56  1.1  joerg     else {
     57  1.1  joerg       OS.resetColor();
     58  1.1  joerg       if (Bold)
     59  1.1  joerg         OS.changeColor(savedColor, true);
     60  1.1  joerg     }
     61  1.1  joerg     Normal = !Normal;
     62  1.1  joerg   }
     63  1.1  joerg }
     64  1.1  joerg 
     65  1.1  joerg /// Number of spaces to indent when word-wrapping.
     66  1.1  joerg const unsigned WordWrapIndentation = 6;
     67  1.1  joerg 
     68  1.1  joerg static int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) {
     69  1.1  joerg   int bytes = 0;
     70  1.1  joerg   while (0<i) {
     71  1.1  joerg     if (SourceLine[--i]=='\t')
     72  1.1  joerg       break;
     73  1.1  joerg     ++bytes;
     74  1.1  joerg   }
     75  1.1  joerg   return bytes;
     76  1.1  joerg }
     77  1.1  joerg 
     78  1.1  joerg /// returns a printable representation of first item from input range
     79  1.1  joerg ///
     80  1.1  joerg /// This function returns a printable representation of the next item in a line
     81  1.1  joerg ///  of source. If the next byte begins a valid and printable character, that
     82  1.1  joerg ///  character is returned along with 'true'.
     83  1.1  joerg ///
     84  1.1  joerg /// Otherwise, if the next byte begins a valid, but unprintable character, a
     85  1.1  joerg ///  printable, escaped representation of the character is returned, along with
     86  1.1  joerg ///  'false'. Otherwise a printable, escaped representation of the next byte
     87  1.1  joerg ///  is returned along with 'false'.
     88  1.1  joerg ///
     89  1.1  joerg /// \note The index is updated to be used with a subsequent call to
     90  1.1  joerg ///        printableTextForNextCharacter.
     91  1.1  joerg ///
     92  1.1  joerg /// \param SourceLine The line of source
     93  1.1  joerg /// \param i Pointer to byte index,
     94  1.1  joerg /// \param TabStop used to expand tabs
     95  1.1  joerg /// \return pair(printable text, 'true' iff original text was printable)
     96  1.1  joerg ///
     97  1.1  joerg static std::pair<SmallString<16>, bool>
     98  1.1  joerg printableTextForNextCharacter(StringRef SourceLine, size_t *i,
     99  1.1  joerg                               unsigned TabStop) {
    100  1.1  joerg   assert(i && "i must not be null");
    101  1.1  joerg   assert(*i<SourceLine.size() && "must point to a valid index");
    102  1.1  joerg 
    103  1.1  joerg   if (SourceLine[*i]=='\t') {
    104  1.1  joerg     assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
    105  1.1  joerg            "Invalid -ftabstop value");
    106  1.1  joerg     unsigned col = bytesSincePreviousTabOrLineBegin(SourceLine, *i);
    107  1.1  joerg     unsigned NumSpaces = TabStop - col%TabStop;
    108  1.1  joerg     assert(0 < NumSpaces && NumSpaces <= TabStop
    109  1.1  joerg            && "Invalid computation of space amt");
    110  1.1  joerg     ++(*i);
    111  1.1  joerg 
    112  1.1  joerg     SmallString<16> expandedTab;
    113  1.1  joerg     expandedTab.assign(NumSpaces, ' ');
    114  1.1  joerg     return std::make_pair(expandedTab, true);
    115  1.1  joerg   }
    116  1.1  joerg 
    117  1.1  joerg   unsigned char const *begin, *end;
    118  1.1  joerg   begin = reinterpret_cast<unsigned char const *>(&*(SourceLine.begin() + *i));
    119  1.1  joerg   end = begin + (SourceLine.size() - *i);
    120  1.1  joerg 
    121  1.1  joerg   if (llvm::isLegalUTF8Sequence(begin, end)) {
    122  1.1  joerg     llvm::UTF32 c;
    123  1.1  joerg     llvm::UTF32 *cptr = &c;
    124  1.1  joerg     unsigned char const *original_begin = begin;
    125  1.1  joerg     unsigned char const *cp_end =
    126  1.1  joerg         begin + llvm::getNumBytesForUTF8(SourceLine[*i]);
    127  1.1  joerg 
    128  1.1  joerg     llvm::ConversionResult res = llvm::ConvertUTF8toUTF32(
    129  1.1  joerg         &begin, cp_end, &cptr, cptr + 1, llvm::strictConversion);
    130  1.1  joerg     (void)res;
    131  1.1  joerg     assert(llvm::conversionOK == res);
    132  1.1  joerg     assert(0 < begin-original_begin
    133  1.1  joerg            && "we must be further along in the string now");
    134  1.1  joerg     *i += begin-original_begin;
    135  1.1  joerg 
    136  1.1  joerg     if (!llvm::sys::locale::isPrint(c)) {
    137  1.1  joerg       // If next character is valid UTF-8, but not printable
    138  1.1  joerg       SmallString<16> expandedCP("<U+>");
    139  1.1  joerg       while (c) {
    140  1.1  joerg         expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(c%16));
    141  1.1  joerg         c/=16;
    142  1.1  joerg       }
    143  1.1  joerg       while (expandedCP.size() < 8)
    144  1.1  joerg         expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(0));
    145  1.1  joerg       return std::make_pair(expandedCP, false);
    146  1.1  joerg     }
    147  1.1  joerg 
    148  1.1  joerg     // If next character is valid UTF-8, and printable
    149  1.1  joerg     return std::make_pair(SmallString<16>(original_begin, cp_end), true);
    150  1.1  joerg 
    151  1.1  joerg   }
    152  1.1  joerg 
    153  1.1  joerg   // If next byte is not valid UTF-8 (and therefore not printable)
    154  1.1  joerg   SmallString<16> expandedByte("<XX>");
    155  1.1  joerg   unsigned char byte = SourceLine[*i];
    156  1.1  joerg   expandedByte[1] = llvm::hexdigit(byte / 16);
    157  1.1  joerg   expandedByte[2] = llvm::hexdigit(byte % 16);
    158  1.1  joerg   ++(*i);
    159  1.1  joerg   return std::make_pair(expandedByte, false);
    160  1.1  joerg }
    161  1.1  joerg 
    162  1.1  joerg static void expandTabs(std::string &SourceLine, unsigned TabStop) {
    163  1.1  joerg   size_t i = SourceLine.size();
    164  1.1  joerg   while (i>0) {
    165  1.1  joerg     i--;
    166  1.1  joerg     if (SourceLine[i]!='\t')
    167  1.1  joerg       continue;
    168  1.1  joerg     size_t tmp_i = i;
    169  1.1  joerg     std::pair<SmallString<16>,bool> res
    170  1.1  joerg       = printableTextForNextCharacter(SourceLine, &tmp_i, TabStop);
    171  1.1  joerg     SourceLine.replace(i, 1, res.first.c_str());
    172  1.1  joerg   }
    173  1.1  joerg }
    174  1.1  joerg 
    175  1.1  joerg /// This function takes a raw source line and produces a mapping from the bytes
    176  1.1  joerg ///  of the printable representation of the line to the columns those printable
    177  1.1  joerg ///  characters will appear at (numbering the first column as 0).
    178  1.1  joerg ///
    179  1.1  joerg /// If a byte 'i' corresponds to multiple columns (e.g. the byte contains a tab
    180  1.1  joerg ///  character) then the array will map that byte to the first column the
    181  1.1  joerg ///  tab appears at and the next value in the map will have been incremented
    182  1.1  joerg ///  more than once.
    183  1.1  joerg ///
    184  1.1  joerg /// If a byte is the first in a sequence of bytes that together map to a single
    185  1.1  joerg ///  entity in the output, then the array will map that byte to the appropriate
    186  1.1  joerg ///  column while the subsequent bytes will be -1.
    187  1.1  joerg ///
    188  1.1  joerg /// The last element in the array does not correspond to any byte in the input
    189  1.1  joerg ///  and instead is the number of columns needed to display the source
    190  1.1  joerg ///
    191  1.1  joerg /// example: (given a tabstop of 8)
    192  1.1  joerg ///
    193  1.1  joerg ///    "a \t \u3042" -> {0,1,2,8,9,-1,-1,11}
    194  1.1  joerg ///
    195  1.1  joerg ///  (\\u3042 is represented in UTF-8 by three bytes and takes two columns to
    196  1.1  joerg ///   display)
    197  1.1  joerg static void byteToColumn(StringRef SourceLine, unsigned TabStop,
    198  1.1  joerg                          SmallVectorImpl<int> &out) {
    199  1.1  joerg   out.clear();
    200  1.1  joerg 
    201  1.1  joerg   if (SourceLine.empty()) {
    202  1.1  joerg     out.resize(1u,0);
    203  1.1  joerg     return;
    204  1.1  joerg   }
    205  1.1  joerg 
    206  1.1  joerg   out.resize(SourceLine.size()+1, -1);
    207  1.1  joerg 
    208  1.1  joerg   int columns = 0;
    209  1.1  joerg   size_t i = 0;
    210  1.1  joerg   while (i<SourceLine.size()) {
    211  1.1  joerg     out[i] = columns;
    212  1.1  joerg     std::pair<SmallString<16>,bool> res
    213  1.1  joerg       = printableTextForNextCharacter(SourceLine, &i, TabStop);
    214  1.1  joerg     columns += llvm::sys::locale::columnWidth(res.first);
    215  1.1  joerg   }
    216  1.1  joerg   out.back() = columns;
    217  1.1  joerg }
    218  1.1  joerg 
    219  1.1  joerg /// This function takes a raw source line and produces a mapping from columns
    220  1.1  joerg ///  to the byte of the source line that produced the character displaying at
    221  1.1  joerg ///  that column. This is the inverse of the mapping produced by byteToColumn()
    222  1.1  joerg ///
    223  1.1  joerg /// The last element in the array is the number of bytes in the source string
    224  1.1  joerg ///
    225  1.1  joerg /// example: (given a tabstop of 8)
    226  1.1  joerg ///
    227  1.1  joerg ///    "a \t \u3042" -> {0,1,2,-1,-1,-1,-1,-1,3,4,-1,7}
    228  1.1  joerg ///
    229  1.1  joerg ///  (\\u3042 is represented in UTF-8 by three bytes and takes two columns to
    230  1.1  joerg ///   display)
    231  1.1  joerg static void columnToByte(StringRef SourceLine, unsigned TabStop,
    232  1.1  joerg                          SmallVectorImpl<int> &out) {
    233  1.1  joerg   out.clear();
    234  1.1  joerg 
    235  1.1  joerg   if (SourceLine.empty()) {
    236  1.1  joerg     out.resize(1u, 0);
    237  1.1  joerg     return;
    238  1.1  joerg   }
    239  1.1  joerg 
    240  1.1  joerg   int columns = 0;
    241  1.1  joerg   size_t i = 0;
    242  1.1  joerg   while (i<SourceLine.size()) {
    243  1.1  joerg     out.resize(columns+1, -1);
    244  1.1  joerg     out.back() = i;
    245  1.1  joerg     std::pair<SmallString<16>,bool> res
    246  1.1  joerg       = printableTextForNextCharacter(SourceLine, &i, TabStop);
    247  1.1  joerg     columns += llvm::sys::locale::columnWidth(res.first);
    248  1.1  joerg   }
    249  1.1  joerg   out.resize(columns+1, -1);
    250  1.1  joerg   out.back() = i;
    251  1.1  joerg }
    252  1.1  joerg 
    253  1.1  joerg namespace {
    254  1.1  joerg struct SourceColumnMap {
    255  1.1  joerg   SourceColumnMap(StringRef SourceLine, unsigned TabStop)
    256  1.1  joerg   : m_SourceLine(SourceLine) {
    257  1.1  joerg 
    258  1.1  joerg     ::byteToColumn(SourceLine, TabStop, m_byteToColumn);
    259  1.1  joerg     ::columnToByte(SourceLine, TabStop, m_columnToByte);
    260  1.1  joerg 
    261  1.1  joerg     assert(m_byteToColumn.size()==SourceLine.size()+1);
    262  1.1  joerg     assert(0 < m_byteToColumn.size() && 0 < m_columnToByte.size());
    263  1.1  joerg     assert(m_byteToColumn.size()
    264  1.1  joerg            == static_cast<unsigned>(m_columnToByte.back()+1));
    265  1.1  joerg     assert(static_cast<unsigned>(m_byteToColumn.back()+1)
    266  1.1  joerg            == m_columnToByte.size());
    267  1.1  joerg   }
    268  1.1  joerg   int columns() const { return m_byteToColumn.back(); }
    269  1.1  joerg   int bytes() const { return m_columnToByte.back(); }
    270  1.1  joerg 
    271  1.1  joerg   /// Map a byte to the column which it is at the start of, or return -1
    272  1.1  joerg   /// if it is not at the start of a column (for a UTF-8 trailing byte).
    273  1.1  joerg   int byteToColumn(int n) const {
    274  1.1  joerg     assert(0<=n && n<static_cast<int>(m_byteToColumn.size()));
    275  1.1  joerg     return m_byteToColumn[n];
    276  1.1  joerg   }
    277  1.1  joerg 
    278  1.1  joerg   /// Map a byte to the first column which contains it.
    279  1.1  joerg   int byteToContainingColumn(int N) const {
    280  1.1  joerg     assert(0 <= N && N < static_cast<int>(m_byteToColumn.size()));
    281  1.1  joerg     while (m_byteToColumn[N] == -1)
    282  1.1  joerg       --N;
    283  1.1  joerg     return m_byteToColumn[N];
    284  1.1  joerg   }
    285  1.1  joerg 
    286  1.1  joerg   /// Map a column to the byte which starts the column, or return -1 if
    287  1.1  joerg   /// the column the second or subsequent column of an expanded tab or similar
    288  1.1  joerg   /// multi-column entity.
    289  1.1  joerg   int columnToByte(int n) const {
    290  1.1  joerg     assert(0<=n && n<static_cast<int>(m_columnToByte.size()));
    291  1.1  joerg     return m_columnToByte[n];
    292  1.1  joerg   }
    293  1.1  joerg 
    294  1.1  joerg   /// Map from a byte index to the next byte which starts a column.
    295  1.1  joerg   int startOfNextColumn(int N) const {
    296  1.1  joerg     assert(0 <= N && N < static_cast<int>(m_byteToColumn.size() - 1));
    297  1.1  joerg     while (byteToColumn(++N) == -1) {}
    298  1.1  joerg     return N;
    299  1.1  joerg   }
    300  1.1  joerg 
    301  1.1  joerg   /// Map from a byte index to the previous byte which starts a column.
    302  1.1  joerg   int startOfPreviousColumn(int N) const {
    303  1.1  joerg     assert(0 < N && N < static_cast<int>(m_byteToColumn.size()));
    304  1.1  joerg     while (byteToColumn(--N) == -1) {}
    305  1.1  joerg     return N;
    306  1.1  joerg   }
    307  1.1  joerg 
    308  1.1  joerg   StringRef getSourceLine() const {
    309  1.1  joerg     return m_SourceLine;
    310  1.1  joerg   }
    311  1.1  joerg 
    312  1.1  joerg private:
    313  1.1  joerg   const std::string m_SourceLine;
    314  1.1  joerg   SmallVector<int,200> m_byteToColumn;
    315  1.1  joerg   SmallVector<int,200> m_columnToByte;
    316  1.1  joerg };
    317  1.1  joerg } // end anonymous namespace
    318  1.1  joerg 
    319  1.1  joerg /// When the source code line we want to print is too long for
    320  1.1  joerg /// the terminal, select the "interesting" region.
    321  1.1  joerg static void selectInterestingSourceRegion(std::string &SourceLine,
    322  1.1  joerg                                           std::string &CaretLine,
    323  1.1  joerg                                           std::string &FixItInsertionLine,
    324  1.1  joerg                                           unsigned Columns,
    325  1.1  joerg                                           const SourceColumnMap &map) {
    326  1.1  joerg   unsigned CaretColumns = CaretLine.size();
    327  1.1  joerg   unsigned FixItColumns = llvm::sys::locale::columnWidth(FixItInsertionLine);
    328  1.1  joerg   unsigned MaxColumns = std::max(static_cast<unsigned>(map.columns()),
    329  1.1  joerg                                  std::max(CaretColumns, FixItColumns));
    330  1.1  joerg   // if the number of columns is less than the desired number we're done
    331  1.1  joerg   if (MaxColumns <= Columns)
    332  1.1  joerg     return;
    333  1.1  joerg 
    334  1.1  joerg   // No special characters are allowed in CaretLine.
    335  1.1  joerg   assert(CaretLine.end() ==
    336  1.1  joerg          llvm::find_if(CaretLine, [](char c) { return c < ' ' || '~' < c; }));
    337  1.1  joerg 
    338  1.1  joerg   // Find the slice that we need to display the full caret line
    339  1.1  joerg   // correctly.
    340  1.1  joerg   unsigned CaretStart = 0, CaretEnd = CaretLine.size();
    341  1.1  joerg   for (; CaretStart != CaretEnd; ++CaretStart)
    342  1.1  joerg     if (!isWhitespace(CaretLine[CaretStart]))
    343  1.1  joerg       break;
    344  1.1  joerg 
    345  1.1  joerg   for (; CaretEnd != CaretStart; --CaretEnd)
    346  1.1  joerg     if (!isWhitespace(CaretLine[CaretEnd - 1]))
    347  1.1  joerg       break;
    348  1.1  joerg 
    349  1.1  joerg   // caret has already been inserted into CaretLine so the above whitespace
    350  1.1  joerg   // check is guaranteed to include the caret
    351  1.1  joerg 
    352  1.1  joerg   // If we have a fix-it line, make sure the slice includes all of the
    353  1.1  joerg   // fix-it information.
    354  1.1  joerg   if (!FixItInsertionLine.empty()) {
    355  1.1  joerg     unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
    356  1.1  joerg     for (; FixItStart != FixItEnd; ++FixItStart)
    357  1.1  joerg       if (!isWhitespace(FixItInsertionLine[FixItStart]))
    358  1.1  joerg         break;
    359  1.1  joerg 
    360  1.1  joerg     for (; FixItEnd != FixItStart; --FixItEnd)
    361  1.1  joerg       if (!isWhitespace(FixItInsertionLine[FixItEnd - 1]))
    362  1.1  joerg         break;
    363  1.1  joerg 
    364  1.1  joerg     // We can safely use the byte offset FixItStart as the column offset
    365  1.1  joerg     // because the characters up until FixItStart are all ASCII whitespace
    366  1.1  joerg     // characters.
    367  1.1  joerg     unsigned FixItStartCol = FixItStart;
    368  1.1  joerg     unsigned FixItEndCol
    369  1.1  joerg       = llvm::sys::locale::columnWidth(FixItInsertionLine.substr(0, FixItEnd));
    370  1.1  joerg 
    371  1.1  joerg     CaretStart = std::min(FixItStartCol, CaretStart);
    372  1.1  joerg     CaretEnd = std::max(FixItEndCol, CaretEnd);
    373  1.1  joerg   }
    374  1.1  joerg 
    375  1.1  joerg   // CaretEnd may have been set at the middle of a character
    376  1.1  joerg   // If it's not at a character's first column then advance it past the current
    377  1.1  joerg   //   character.
    378  1.1  joerg   while (static_cast<int>(CaretEnd) < map.columns() &&
    379  1.1  joerg          -1 == map.columnToByte(CaretEnd))
    380  1.1  joerg     ++CaretEnd;
    381  1.1  joerg 
    382  1.1  joerg   assert((static_cast<int>(CaretStart) > map.columns() ||
    383  1.1  joerg           -1!=map.columnToByte(CaretStart)) &&
    384  1.1  joerg          "CaretStart must not point to a column in the middle of a source"
    385  1.1  joerg          " line character");
    386  1.1  joerg   assert((static_cast<int>(CaretEnd) > map.columns() ||
    387  1.1  joerg           -1!=map.columnToByte(CaretEnd)) &&
    388  1.1  joerg          "CaretEnd must not point to a column in the middle of a source line"
    389  1.1  joerg          " character");
    390  1.1  joerg 
    391  1.1  joerg   // CaretLine[CaretStart, CaretEnd) contains all of the interesting
    392  1.1  joerg   // parts of the caret line. While this slice is smaller than the
    393  1.1  joerg   // number of columns we have, try to grow the slice to encompass
    394  1.1  joerg   // more context.
    395  1.1  joerg 
    396  1.1  joerg   unsigned SourceStart = map.columnToByte(std::min<unsigned>(CaretStart,
    397  1.1  joerg                                                              map.columns()));
    398  1.1  joerg   unsigned SourceEnd = map.columnToByte(std::min<unsigned>(CaretEnd,
    399  1.1  joerg                                                            map.columns()));
    400  1.1  joerg 
    401  1.1  joerg   unsigned CaretColumnsOutsideSource = CaretEnd-CaretStart
    402  1.1  joerg     - (map.byteToColumn(SourceEnd)-map.byteToColumn(SourceStart));
    403  1.1  joerg 
    404  1.1  joerg   char const *front_ellipse = "  ...";
    405  1.1  joerg   char const *front_space   = "     ";
    406  1.1  joerg   char const *back_ellipse = "...";
    407  1.1  joerg   unsigned ellipses_space = strlen(front_ellipse) + strlen(back_ellipse);
    408  1.1  joerg 
    409  1.1  joerg   unsigned TargetColumns = Columns;
    410  1.1  joerg   // Give us extra room for the ellipses
    411  1.1  joerg   //  and any of the caret line that extends past the source
    412  1.1  joerg   if (TargetColumns > ellipses_space+CaretColumnsOutsideSource)
    413  1.1  joerg     TargetColumns -= ellipses_space+CaretColumnsOutsideSource;
    414  1.1  joerg 
    415  1.1  joerg   while (SourceStart>0 || SourceEnd<SourceLine.size()) {
    416  1.1  joerg     bool ExpandedRegion = false;
    417  1.1  joerg 
    418  1.1  joerg     if (SourceStart>0) {
    419  1.1  joerg       unsigned NewStart = map.startOfPreviousColumn(SourceStart);
    420  1.1  joerg 
    421  1.1  joerg       // Skip over any whitespace we see here; we're looking for
    422  1.1  joerg       // another bit of interesting text.
    423  1.1  joerg       // FIXME: Detect non-ASCII whitespace characters too.
    424  1.1  joerg       while (NewStart && isWhitespace(SourceLine[NewStart]))
    425  1.1  joerg         NewStart = map.startOfPreviousColumn(NewStart);
    426  1.1  joerg 
    427  1.1  joerg       // Skip over this bit of "interesting" text.
    428  1.1  joerg       while (NewStart) {
    429  1.1  joerg         unsigned Prev = map.startOfPreviousColumn(NewStart);
    430  1.1  joerg         if (isWhitespace(SourceLine[Prev]))
    431  1.1  joerg           break;
    432  1.1  joerg         NewStart = Prev;
    433  1.1  joerg       }
    434  1.1  joerg 
    435  1.1  joerg       assert(map.byteToColumn(NewStart) != -1);
    436  1.1  joerg       unsigned NewColumns = map.byteToColumn(SourceEnd) -
    437  1.1  joerg                               map.byteToColumn(NewStart);
    438  1.1  joerg       if (NewColumns <= TargetColumns) {
    439  1.1  joerg         SourceStart = NewStart;
    440  1.1  joerg         ExpandedRegion = true;
    441  1.1  joerg       }
    442  1.1  joerg     }
    443  1.1  joerg 
    444  1.1  joerg     if (SourceEnd<SourceLine.size()) {
    445  1.1  joerg       unsigned NewEnd = map.startOfNextColumn(SourceEnd);
    446  1.1  joerg 
    447  1.1  joerg       // Skip over any whitespace we see here; we're looking for
    448  1.1  joerg       // another bit of interesting text.
    449  1.1  joerg       // FIXME: Detect non-ASCII whitespace characters too.
    450  1.1  joerg       while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
    451  1.1  joerg         NewEnd = map.startOfNextColumn(NewEnd);
    452  1.1  joerg 
    453  1.1  joerg       // Skip over this bit of "interesting" text.
    454  1.1  joerg       while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
    455  1.1  joerg         NewEnd = map.startOfNextColumn(NewEnd);
    456  1.1  joerg 
    457  1.1  joerg       assert(map.byteToColumn(NewEnd) != -1);
    458  1.1  joerg       unsigned NewColumns = map.byteToColumn(NewEnd) -
    459  1.1  joerg                               map.byteToColumn(SourceStart);
    460  1.1  joerg       if (NewColumns <= TargetColumns) {
    461  1.1  joerg         SourceEnd = NewEnd;
    462  1.1  joerg         ExpandedRegion = true;
    463  1.1  joerg       }
    464  1.1  joerg     }
    465  1.1  joerg 
    466  1.1  joerg     if (!ExpandedRegion)
    467  1.1  joerg       break;
    468  1.1  joerg   }
    469  1.1  joerg 
    470  1.1  joerg   CaretStart = map.byteToColumn(SourceStart);
    471  1.1  joerg   CaretEnd = map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource;
    472  1.1  joerg 
    473  1.1  joerg   // [CaretStart, CaretEnd) is the slice we want. Update the various
    474  1.1  joerg   // output lines to show only this slice, with two-space padding
    475  1.1  joerg   // before the lines so that it looks nicer.
    476  1.1  joerg 
    477  1.1  joerg   assert(CaretStart!=(unsigned)-1 && CaretEnd!=(unsigned)-1 &&
    478  1.1  joerg          SourceStart!=(unsigned)-1 && SourceEnd!=(unsigned)-1);
    479  1.1  joerg   assert(SourceStart <= SourceEnd);
    480  1.1  joerg   assert(CaretStart <= CaretEnd);
    481  1.1  joerg 
    482  1.1  joerg   unsigned BackColumnsRemoved
    483  1.1  joerg     = map.byteToColumn(SourceLine.size())-map.byteToColumn(SourceEnd);
    484  1.1  joerg   unsigned FrontColumnsRemoved = CaretStart;
    485  1.1  joerg   unsigned ColumnsKept = CaretEnd-CaretStart;
    486  1.1  joerg 
    487  1.1  joerg   // We checked up front that the line needed truncation
    488  1.1  joerg   assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns);
    489  1.1  joerg 
    490  1.1  joerg   // The line needs some truncation, and we'd prefer to keep the front
    491  1.1  joerg   //  if possible, so remove the back
    492  1.1  joerg   if (BackColumnsRemoved > strlen(back_ellipse))
    493  1.1  joerg     SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
    494  1.1  joerg 
    495  1.1  joerg   // If that's enough then we're done
    496  1.1  joerg   if (FrontColumnsRemoved+ColumnsKept <= Columns)
    497  1.1  joerg     return;
    498  1.1  joerg 
    499  1.1  joerg   // Otherwise remove the front as well
    500  1.1  joerg   if (FrontColumnsRemoved > strlen(front_ellipse)) {
    501  1.1  joerg     SourceLine.replace(0, SourceStart, front_ellipse);
    502  1.1  joerg     CaretLine.replace(0, CaretStart, front_space);
    503  1.1  joerg     if (!FixItInsertionLine.empty())
    504  1.1  joerg       FixItInsertionLine.replace(0, CaretStart, front_space);
    505  1.1  joerg   }
    506  1.1  joerg }
    507  1.1  joerg 
    508  1.1  joerg /// Skip over whitespace in the string, starting at the given
    509  1.1  joerg /// index.
    510  1.1  joerg ///
    511  1.1  joerg /// \returns The index of the first non-whitespace character that is
    512  1.1  joerg /// greater than or equal to Idx or, if no such character exists,
    513  1.1  joerg /// returns the end of the string.
    514  1.1  joerg static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
    515  1.1  joerg   while (Idx < Length && isWhitespace(Str[Idx]))
    516  1.1  joerg     ++Idx;
    517  1.1  joerg   return Idx;
    518  1.1  joerg }
    519  1.1  joerg 
    520  1.1  joerg /// If the given character is the start of some kind of
    521  1.1  joerg /// balanced punctuation (e.g., quotes or parentheses), return the
    522  1.1  joerg /// character that will terminate the punctuation.
    523  1.1  joerg ///
    524  1.1  joerg /// \returns The ending punctuation character, if any, or the NULL
    525  1.1  joerg /// character if the input character does not start any punctuation.
    526  1.1  joerg static inline char findMatchingPunctuation(char c) {
    527  1.1  joerg   switch (c) {
    528  1.1  joerg   case '\'': return '\'';
    529  1.1  joerg   case '`': return '\'';
    530  1.1  joerg   case '"':  return '"';
    531  1.1  joerg   case '(':  return ')';
    532  1.1  joerg   case '[': return ']';
    533  1.1  joerg   case '{': return '}';
    534  1.1  joerg   default: break;
    535  1.1  joerg   }
    536  1.1  joerg 
    537  1.1  joerg   return 0;
    538  1.1  joerg }
    539  1.1  joerg 
    540  1.1  joerg /// Find the end of the word starting at the given offset
    541  1.1  joerg /// within a string.
    542  1.1  joerg ///
    543  1.1  joerg /// \returns the index pointing one character past the end of the
    544  1.1  joerg /// word.
    545  1.1  joerg static unsigned findEndOfWord(unsigned Start, StringRef Str,
    546  1.1  joerg                               unsigned Length, unsigned Column,
    547  1.1  joerg                               unsigned Columns) {
    548  1.1  joerg   assert(Start < Str.size() && "Invalid start position!");
    549  1.1  joerg   unsigned End = Start + 1;
    550  1.1  joerg 
    551  1.1  joerg   // If we are already at the end of the string, take that as the word.
    552  1.1  joerg   if (End == Str.size())
    553  1.1  joerg     return End;
    554  1.1  joerg 
    555  1.1  joerg   // Determine if the start of the string is actually opening
    556  1.1  joerg   // punctuation, e.g., a quote or parentheses.
    557  1.1  joerg   char EndPunct = findMatchingPunctuation(Str[Start]);
    558  1.1  joerg   if (!EndPunct) {
    559  1.1  joerg     // This is a normal word. Just find the first space character.
    560  1.1  joerg     while (End < Length && !isWhitespace(Str[End]))
    561  1.1  joerg       ++End;
    562  1.1  joerg     return End;
    563  1.1  joerg   }
    564  1.1  joerg 
    565  1.1  joerg   // We have the start of a balanced punctuation sequence (quotes,
    566  1.1  joerg   // parentheses, etc.). Determine the full sequence is.
    567  1.1  joerg   SmallString<16> PunctuationEndStack;
    568  1.1  joerg   PunctuationEndStack.push_back(EndPunct);
    569  1.1  joerg   while (End < Length && !PunctuationEndStack.empty()) {
    570  1.1  joerg     if (Str[End] == PunctuationEndStack.back())
    571  1.1  joerg       PunctuationEndStack.pop_back();
    572  1.1  joerg     else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
    573  1.1  joerg       PunctuationEndStack.push_back(SubEndPunct);
    574  1.1  joerg 
    575  1.1  joerg     ++End;
    576  1.1  joerg   }
    577  1.1  joerg 
    578  1.1  joerg   // Find the first space character after the punctuation ended.
    579  1.1  joerg   while (End < Length && !isWhitespace(Str[End]))
    580  1.1  joerg     ++End;
    581  1.1  joerg 
    582  1.1  joerg   unsigned PunctWordLength = End - Start;
    583  1.1  joerg   if (// If the word fits on this line
    584  1.1  joerg       Column + PunctWordLength <= Columns ||
    585  1.1  joerg       // ... or the word is "short enough" to take up the next line
    586  1.1  joerg       // without too much ugly white space
    587  1.1  joerg       PunctWordLength < Columns/3)
    588  1.1  joerg     return End; // Take the whole thing as a single "word".
    589  1.1  joerg 
    590  1.1  joerg   // The whole quoted/parenthesized string is too long to print as a
    591  1.1  joerg   // single "word". Instead, find the "word" that starts just after
    592  1.1  joerg   // the punctuation and use that end-point instead. This will recurse
    593  1.1  joerg   // until it finds something small enough to consider a word.
    594  1.1  joerg   return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
    595  1.1  joerg }
    596  1.1  joerg 
    597  1.1  joerg /// Print the given string to a stream, word-wrapping it to
    598  1.1  joerg /// some number of columns in the process.
    599  1.1  joerg ///
    600  1.1  joerg /// \param OS the stream to which the word-wrapping string will be
    601  1.1  joerg /// emitted.
    602  1.1  joerg /// \param Str the string to word-wrap and output.
    603  1.1  joerg /// \param Columns the number of columns to word-wrap to.
    604  1.1  joerg /// \param Column the column number at which the first character of \p
    605  1.1  joerg /// Str will be printed. This will be non-zero when part of the first
    606  1.1  joerg /// line has already been printed.
    607  1.1  joerg /// \param Bold if the current text should be bold
    608  1.1  joerg /// \param Indentation the number of spaces to indent any lines beyond
    609  1.1  joerg /// the first line.
    610  1.1  joerg /// \returns true if word-wrapping was required, or false if the
    611  1.1  joerg /// string fit on the first line.
    612  1.1  joerg static bool printWordWrapped(raw_ostream &OS, StringRef Str,
    613  1.1  joerg                              unsigned Columns,
    614  1.1  joerg                              unsigned Column = 0,
    615  1.1  joerg                              bool Bold = false,
    616  1.1  joerg                              unsigned Indentation = WordWrapIndentation) {
    617  1.1  joerg   const unsigned Length = std::min(Str.find('\n'), Str.size());
    618  1.1  joerg   bool TextNormal = true;
    619  1.1  joerg 
    620  1.1  joerg   // The string used to indent each line.
    621  1.1  joerg   SmallString<16> IndentStr;
    622  1.1  joerg   IndentStr.assign(Indentation, ' ');
    623  1.1  joerg   bool Wrapped = false;
    624  1.1  joerg   for (unsigned WordStart = 0, WordEnd; WordStart < Length;
    625  1.1  joerg        WordStart = WordEnd) {
    626  1.1  joerg     // Find the beginning of the next word.
    627  1.1  joerg     WordStart = skipWhitespace(WordStart, Str, Length);
    628  1.1  joerg     if (WordStart == Length)
    629  1.1  joerg       break;
    630  1.1  joerg 
    631  1.1  joerg     // Find the end of this word.
    632  1.1  joerg     WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
    633  1.1  joerg 
    634  1.1  joerg     // Does this word fit on the current line?
    635  1.1  joerg     unsigned WordLength = WordEnd - WordStart;
    636  1.1  joerg     if (Column + WordLength < Columns) {
    637  1.1  joerg       // This word fits on the current line; print it there.
    638  1.1  joerg       if (WordStart) {
    639  1.1  joerg         OS << ' ';
    640  1.1  joerg         Column += 1;
    641  1.1  joerg       }
    642  1.1  joerg       applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),
    643  1.1  joerg                                 TextNormal, Bold);
    644  1.1  joerg       Column += WordLength;
    645  1.1  joerg       continue;
    646  1.1  joerg     }
    647  1.1  joerg 
    648  1.1  joerg     // This word does not fit on the current line, so wrap to the next
    649  1.1  joerg     // line.
    650  1.1  joerg     OS << '\n';
    651  1.1  joerg     OS.write(&IndentStr[0], Indentation);
    652  1.1  joerg     applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),
    653  1.1  joerg                               TextNormal, Bold);
    654  1.1  joerg     Column = Indentation + WordLength;
    655  1.1  joerg     Wrapped = true;
    656  1.1  joerg   }
    657  1.1  joerg 
    658  1.1  joerg   // Append any remaning text from the message with its existing formatting.
    659  1.1  joerg   applyTemplateHighlighting(OS, Str.substr(Length), TextNormal, Bold);
    660  1.1  joerg 
    661  1.1  joerg   assert(TextNormal && "Text highlighted at end of diagnostic message.");
    662  1.1  joerg 
    663  1.1  joerg   return Wrapped;
    664  1.1  joerg }
    665  1.1  joerg 
    666  1.1  joerg TextDiagnostic::TextDiagnostic(raw_ostream &OS,
    667  1.1  joerg                                const LangOptions &LangOpts,
    668  1.1  joerg                                DiagnosticOptions *DiagOpts)
    669  1.1  joerg   : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS) {}
    670  1.1  joerg 
    671  1.1  joerg TextDiagnostic::~TextDiagnostic() {}
    672  1.1  joerg 
    673  1.1  joerg void TextDiagnostic::emitDiagnosticMessage(
    674  1.1  joerg     FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level,
    675  1.1  joerg     StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
    676  1.1  joerg     DiagOrStoredDiag D) {
    677  1.1  joerg   uint64_t StartOfLocationInfo = OS.tell();
    678  1.1  joerg 
    679  1.1  joerg   // Emit the location of this particular diagnostic.
    680  1.1  joerg   if (Loc.isValid())
    681  1.1  joerg     emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
    682  1.1  joerg 
    683  1.1  joerg   if (DiagOpts->ShowColors)
    684  1.1  joerg     OS.resetColor();
    685  1.1  joerg 
    686  1.1  joerg   if (DiagOpts->ShowLevel)
    687  1.1  joerg     printDiagnosticLevel(OS, Level, DiagOpts->ShowColors,
    688  1.1  joerg                          DiagOpts->CLFallbackMode);
    689  1.1  joerg   printDiagnosticMessage(OS,
    690  1.1  joerg                          /*IsSupplemental*/ Level == DiagnosticsEngine::Note,
    691  1.1  joerg                          Message, OS.tell() - StartOfLocationInfo,
    692  1.1  joerg                          DiagOpts->MessageLength, DiagOpts->ShowColors);
    693  1.1  joerg }
    694  1.1  joerg 
    695  1.1  joerg /*static*/ void
    696  1.1  joerg TextDiagnostic::printDiagnosticLevel(raw_ostream &OS,
    697  1.1  joerg                                      DiagnosticsEngine::Level Level,
    698  1.1  joerg                                      bool ShowColors,
    699  1.1  joerg                                      bool CLFallbackMode) {
    700  1.1  joerg   if (ShowColors) {
    701  1.1  joerg     // Print diagnostic category in bold and color
    702  1.1  joerg     switch (Level) {
    703  1.1  joerg     case DiagnosticsEngine::Ignored:
    704  1.1  joerg       llvm_unreachable("Invalid diagnostic type");
    705  1.1  joerg     case DiagnosticsEngine::Note:    OS.changeColor(noteColor, true); break;
    706  1.1  joerg     case DiagnosticsEngine::Remark:  OS.changeColor(remarkColor, true); break;
    707  1.1  joerg     case DiagnosticsEngine::Warning: OS.changeColor(warningColor, true); break;
    708  1.1  joerg     case DiagnosticsEngine::Error:   OS.changeColor(errorColor, true); break;
    709  1.1  joerg     case DiagnosticsEngine::Fatal:   OS.changeColor(fatalColor, true); break;
    710  1.1  joerg     }
    711  1.1  joerg   }
    712  1.1  joerg 
    713  1.1  joerg   switch (Level) {
    714  1.1  joerg   case DiagnosticsEngine::Ignored:
    715  1.1  joerg     llvm_unreachable("Invalid diagnostic type");
    716  1.1  joerg   case DiagnosticsEngine::Note:    OS << "note"; break;
    717  1.1  joerg   case DiagnosticsEngine::Remark:  OS << "remark"; break;
    718  1.1  joerg   case DiagnosticsEngine::Warning: OS << "warning"; break;
    719  1.1  joerg   case DiagnosticsEngine::Error:   OS << "error"; break;
    720  1.1  joerg   case DiagnosticsEngine::Fatal:   OS << "fatal error"; break;
    721  1.1  joerg   }
    722  1.1  joerg 
    723  1.1  joerg   // In clang-cl /fallback mode, print diagnostics as "error(clang):". This
    724  1.1  joerg   // makes it more clear whether a message is coming from clang or cl.exe,
    725  1.1  joerg   // and it prevents MSBuild from concluding that the build failed just because
    726  1.1  joerg   // there is an "error:" in the output.
    727  1.1  joerg   if (CLFallbackMode)
    728  1.1  joerg     OS << "(clang)";
    729  1.1  joerg 
    730  1.1  joerg   OS << ": ";
    731  1.1  joerg 
    732  1.1  joerg   if (ShowColors)
    733  1.1  joerg     OS.resetColor();
    734  1.1  joerg }
    735  1.1  joerg 
    736  1.1  joerg /*static*/
    737  1.1  joerg void TextDiagnostic::printDiagnosticMessage(raw_ostream &OS,
    738  1.1  joerg                                             bool IsSupplemental,
    739  1.1  joerg                                             StringRef Message,
    740  1.1  joerg                                             unsigned CurrentColumn,
    741  1.1  joerg                                             unsigned Columns, bool ShowColors) {
    742  1.1  joerg   bool Bold = false;
    743  1.1  joerg   if (ShowColors && !IsSupplemental) {
    744  1.1  joerg     // Print primary diagnostic messages in bold and without color, to visually
    745  1.1  joerg     // indicate the transition from continuation notes and other output.
    746  1.1  joerg     OS.changeColor(savedColor, true);
    747  1.1  joerg     Bold = true;
    748  1.1  joerg   }
    749  1.1  joerg 
    750  1.1  joerg   if (Columns)
    751  1.1  joerg     printWordWrapped(OS, Message, Columns, CurrentColumn, Bold);
    752  1.1  joerg   else {
    753  1.1  joerg     bool Normal = true;
    754  1.1  joerg     applyTemplateHighlighting(OS, Message, Normal, Bold);
    755  1.1  joerg     assert(Normal && "Formatting should have returned to normal");
    756  1.1  joerg   }
    757  1.1  joerg 
    758  1.1  joerg   if (ShowColors)
    759  1.1  joerg     OS.resetColor();
    760  1.1  joerg   OS << '\n';
    761  1.1  joerg }
    762  1.1  joerg 
    763  1.1  joerg void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
    764  1.1  joerg   SmallVector<char, 128> AbsoluteFilename;
    765  1.1  joerg   if (DiagOpts->AbsolutePath) {
    766  1.1  joerg     auto Dir = SM.getFileManager().getDirectory(
    767  1.1  joerg         llvm::sys::path::parent_path(Filename));
    768  1.1  joerg     if (Dir) {
    769  1.1  joerg       // We want to print a simplified absolute path, i. e. without "dots".
    770  1.1  joerg       //
    771  1.1  joerg       // The hardest part here are the paths like "<part1>/<link>/../<part2>".
    772  1.1  joerg       // On Unix-like systems, we cannot just collapse "<link>/..", because
    773  1.1  joerg       // paths are resolved sequentially, and, thereby, the path
    774  1.1  joerg       // "<part1>/<part2>" may point to a different location. That is why
    775  1.1  joerg       // we use FileManager::getCanonicalName(), which expands all indirections
    776  1.1  joerg       // with llvm::sys::fs::real_path() and caches the result.
    777  1.1  joerg       //
    778  1.1  joerg       // On the other hand, it would be better to preserve as much of the
    779  1.1  joerg       // original path as possible, because that helps a user to recognize it.
    780  1.1  joerg       // real_path() expands all links, which sometimes too much. Luckily,
    781  1.1  joerg       // on Windows we can just use llvm::sys::path::remove_dots(), because,
    782  1.1  joerg       // on that system, both aforementioned paths point to the same place.
    783  1.1  joerg #ifdef _WIN32
    784  1.1  joerg       SmallString<4096> DirName = (*Dir)->getName();
    785  1.1  joerg       llvm::sys::fs::make_absolute(DirName);
    786  1.1  joerg       llvm::sys::path::native(DirName);
    787  1.1  joerg       llvm::sys::path::remove_dots(DirName, /* remove_dot_dot */ true);
    788  1.1  joerg #else
    789  1.1  joerg       StringRef DirName = SM.getFileManager().getCanonicalName(*Dir);
    790  1.1  joerg #endif
    791  1.1  joerg       llvm::sys::path::append(AbsoluteFilename, DirName,
    792  1.1  joerg                               llvm::sys::path::filename(Filename));
    793  1.1  joerg       Filename = StringRef(AbsoluteFilename.data(), AbsoluteFilename.size());
    794  1.1  joerg     }
    795  1.1  joerg   }
    796  1.1  joerg 
    797  1.1  joerg   OS << Filename;
    798  1.1  joerg }
    799  1.1  joerg 
    800  1.1  joerg /// Print out the file/line/column information and include trace.
    801  1.1  joerg ///
    802  1.1  joerg /// This method handlen the emission of the diagnostic location information.
    803  1.1  joerg /// This includes extracting as much location information as is present for
    804  1.1  joerg /// the diagnostic and printing it, as well as any include stack or source
    805  1.1  joerg /// ranges necessary.
    806  1.1  joerg void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
    807  1.1  joerg                                        DiagnosticsEngine::Level Level,
    808  1.1  joerg                                        ArrayRef<CharSourceRange> Ranges) {
    809  1.1  joerg   if (PLoc.isInvalid()) {
    810  1.1  joerg     // At least print the file name if available:
    811  1.1  joerg     FileID FID = Loc.getFileID();
    812  1.1  joerg     if (FID.isValid()) {
    813  1.1  joerg       const FileEntry *FE = Loc.getFileEntry();
    814  1.1  joerg       if (FE && FE->isValid()) {
    815  1.1  joerg         emitFilename(FE->getName(), Loc.getManager());
    816  1.1  joerg         OS << ": ";
    817  1.1  joerg       }
    818  1.1  joerg     }
    819  1.1  joerg     return;
    820  1.1  joerg   }
    821  1.1  joerg   unsigned LineNo = PLoc.getLine();
    822  1.1  joerg 
    823  1.1  joerg   if (!DiagOpts->ShowLocation)
    824  1.1  joerg     return;
    825  1.1  joerg 
    826  1.1  joerg   if (DiagOpts->ShowColors)
    827  1.1  joerg     OS.changeColor(savedColor, true);
    828  1.1  joerg 
    829  1.1  joerg   emitFilename(PLoc.getFilename(), Loc.getManager());
    830  1.1  joerg   switch (DiagOpts->getFormat()) {
    831  1.1  joerg   case DiagnosticOptions::Clang: OS << ':'  << LineNo; break;
    832  1.1  joerg   case DiagnosticOptions::MSVC:  OS << '('  << LineNo; break;
    833  1.1  joerg   case DiagnosticOptions::Vi:    OS << " +" << LineNo; break;
    834  1.1  joerg   }
    835  1.1  joerg 
    836  1.1  joerg   if (DiagOpts->ShowColumn)
    837  1.1  joerg     // Compute the column number.
    838  1.1  joerg     if (unsigned ColNo = PLoc.getColumn()) {
    839  1.1  joerg       if (DiagOpts->getFormat() == DiagnosticOptions::MSVC) {
    840  1.1  joerg         OS << ',';
    841  1.1  joerg         // Visual Studio 2010 or earlier expects column number to be off by one
    842  1.1  joerg         if (LangOpts.MSCompatibilityVersion &&
    843  1.1  joerg             !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
    844  1.1  joerg           ColNo--;
    845  1.1  joerg       } else
    846  1.1  joerg         OS << ':';
    847  1.1  joerg       OS << ColNo;
    848  1.1  joerg     }
    849  1.1  joerg   switch (DiagOpts->getFormat()) {
    850  1.1  joerg   case DiagnosticOptions::Clang:
    851  1.1  joerg   case DiagnosticOptions::Vi:    OS << ':';    break;
    852  1.1  joerg   case DiagnosticOptions::MSVC:
    853  1.1  joerg     // MSVC2013 and before print 'file(4) : error'. MSVC2015 gets rid of the
    854  1.1  joerg     // space and prints 'file(4): error'.
    855  1.1  joerg     OS << ')';
    856  1.1  joerg     if (LangOpts.MSCompatibilityVersion &&
    857  1.1  joerg         !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
    858  1.1  joerg       OS << ' ';
    859  1.1  joerg     OS << ':';
    860  1.1  joerg     break;
    861  1.1  joerg   }
    862  1.1  joerg 
    863  1.1  joerg   if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
    864  1.1  joerg     FileID CaretFileID = Loc.getExpansionLoc().getFileID();
    865  1.1  joerg     bool PrintedRange = false;
    866  1.1  joerg 
    867  1.1  joerg     for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(),
    868  1.1  joerg          RE = Ranges.end();
    869  1.1  joerg          RI != RE; ++RI) {
    870  1.1  joerg       // Ignore invalid ranges.
    871  1.1  joerg       if (!RI->isValid()) continue;
    872  1.1  joerg 
    873  1.1  joerg       auto &SM = Loc.getManager();
    874  1.1  joerg       SourceLocation B = SM.getExpansionLoc(RI->getBegin());
    875  1.1  joerg       CharSourceRange ERange = SM.getExpansionRange(RI->getEnd());
    876  1.1  joerg       SourceLocation E = ERange.getEnd();
    877  1.1  joerg       bool IsTokenRange = ERange.isTokenRange();
    878  1.1  joerg 
    879  1.1  joerg       std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
    880  1.1  joerg       std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
    881  1.1  joerg 
    882  1.1  joerg       // If the start or end of the range is in another file, just discard
    883  1.1  joerg       // it.
    884  1.1  joerg       if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
    885  1.1  joerg         continue;
    886  1.1  joerg 
    887  1.1  joerg       // Add in the length of the token, so that we cover multi-char
    888  1.1  joerg       // tokens.
    889  1.1  joerg       unsigned TokSize = 0;
    890  1.1  joerg       if (IsTokenRange)
    891  1.1  joerg         TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
    892  1.1  joerg 
    893  1.1  joerg       FullSourceLoc BF(B, SM), EF(E, SM);
    894  1.1  joerg       OS << '{'
    895  1.1  joerg          << BF.getLineNumber() << ':' << BF.getColumnNumber() << '-'
    896  1.1  joerg          << EF.getLineNumber() << ':' << (EF.getColumnNumber() + TokSize)
    897  1.1  joerg          << '}';
    898  1.1  joerg       PrintedRange = true;
    899  1.1  joerg     }
    900  1.1  joerg 
    901  1.1  joerg     if (PrintedRange)
    902  1.1  joerg       OS << ':';
    903  1.1  joerg   }
    904  1.1  joerg   OS << ' ';
    905  1.1  joerg }
    906  1.1  joerg 
    907  1.1  joerg void TextDiagnostic::emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) {
    908  1.1  joerg   if (DiagOpts->ShowLocation && PLoc.isValid())
    909  1.1  joerg     OS << "In file included from " << PLoc.getFilename() << ':'
    910  1.1  joerg        << PLoc.getLine() << ":\n";
    911  1.1  joerg   else
    912  1.1  joerg     OS << "In included file:\n";
    913  1.1  joerg }
    914  1.1  joerg 
    915  1.1  joerg void TextDiagnostic::emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc,
    916  1.1  joerg                                         StringRef ModuleName) {
    917  1.1  joerg   if (DiagOpts->ShowLocation && PLoc.isValid())
    918  1.1  joerg     OS << "In module '" << ModuleName << "' imported from "
    919  1.1  joerg        << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
    920  1.1  joerg   else
    921  1.1  joerg     OS << "In module '" << ModuleName << "':\n";
    922  1.1  joerg }
    923  1.1  joerg 
    924  1.1  joerg void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc,
    925  1.1  joerg                                                 PresumedLoc PLoc,
    926  1.1  joerg                                                 StringRef ModuleName) {
    927  1.1  joerg   if (DiagOpts->ShowLocation && PLoc.isValid())
    928  1.1  joerg     OS << "While building module '" << ModuleName << "' imported from "
    929  1.1  joerg       << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
    930  1.1  joerg   else
    931  1.1  joerg     OS << "While building module '" << ModuleName << "':\n";
    932  1.1  joerg }
    933  1.1  joerg 
    934  1.1  joerg /// Find the suitable set of lines to show to include a set of ranges.
    935  1.1  joerg static llvm::Optional<std::pair<unsigned, unsigned>>
    936  1.1  joerg findLinesForRange(const CharSourceRange &R, FileID FID,
    937  1.1  joerg                   const SourceManager &SM) {
    938  1.1  joerg   if (!R.isValid()) return None;
    939  1.1  joerg 
    940  1.1  joerg   SourceLocation Begin = R.getBegin();
    941  1.1  joerg   SourceLocation End = R.getEnd();
    942  1.1  joerg   if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
    943  1.1  joerg     return None;
    944  1.1  joerg 
    945  1.1  joerg   return std::make_pair(SM.getExpansionLineNumber(Begin),
    946  1.1  joerg                         SM.getExpansionLineNumber(End));
    947  1.1  joerg }
    948  1.1  joerg 
    949  1.1  joerg /// Add as much of range B into range A as possible without exceeding a maximum
    950  1.1  joerg /// size of MaxRange. Ranges are inclusive.
    951  1.1  joerg static std::pair<unsigned, unsigned>
    952  1.1  joerg maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
    953  1.1  joerg               unsigned MaxRange) {
    954  1.1  joerg   // If A is already the maximum size, we're done.
    955  1.1  joerg   unsigned Slack = MaxRange - (A.second - A.first + 1);
    956  1.1  joerg   if (Slack == 0)
    957  1.1  joerg     return A;
    958  1.1  joerg 
    959  1.1  joerg   // Easy case: merge succeeds within MaxRange.
    960  1.1  joerg   unsigned Min = std::min(A.first, B.first);
    961  1.1  joerg   unsigned Max = std::max(A.second, B.second);
    962  1.1  joerg   if (Max - Min + 1 <= MaxRange)
    963  1.1  joerg     return {Min, Max};
    964  1.1  joerg 
    965  1.1  joerg   // If we can't reach B from A within MaxRange, there's nothing to do.
    966  1.1  joerg   // Don't add lines to the range that contain nothing interesting.
    967  1.1  joerg   if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
    968  1.1  joerg       (B.second < A.second && A.second - B.second + 1 > MaxRange))
    969  1.1  joerg     return A;
    970  1.1  joerg 
    971  1.1  joerg   // Otherwise, expand A towards B to produce a range of size MaxRange. We
    972  1.1  joerg   // attempt to expand by the same amount in both directions if B strictly
    973  1.1  joerg   // contains A.
    974  1.1  joerg 
    975  1.1  joerg   // Expand downwards by up to half the available amount, then upwards as
    976  1.1  joerg   // much as possible, then downwards as much as possible.
    977  1.1  joerg   A.second = std::min(A.second + (Slack + 1) / 2, Max);
    978  1.1  joerg   Slack = MaxRange - (A.second - A.first + 1);
    979  1.1  joerg   A.first = std::max(Min + Slack, A.first) - Slack;
    980  1.1  joerg   A.second = std::min(A.first + MaxRange - 1, Max);
    981  1.1  joerg   return A;
    982  1.1  joerg }
    983  1.1  joerg 
    984  1.1  joerg /// Highlight a SourceRange (with ~'s) for any characters on LineNo.
    985  1.1  joerg static void highlightRange(const CharSourceRange &R,
    986  1.1  joerg                            unsigned LineNo, FileID FID,
    987  1.1  joerg                            const SourceColumnMap &map,
    988  1.1  joerg                            std::string &CaretLine,
    989  1.1  joerg                            const SourceManager &SM,
    990  1.1  joerg                            const LangOptions &LangOpts) {
    991  1.1  joerg   if (!R.isValid()) return;
    992  1.1  joerg 
    993  1.1  joerg   SourceLocation Begin = R.getBegin();
    994  1.1  joerg   SourceLocation End = R.getEnd();
    995  1.1  joerg 
    996  1.1  joerg   unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
    997  1.1  joerg   if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
    998  1.1  joerg     return;  // No intersection.
    999  1.1  joerg 
   1000  1.1  joerg   unsigned EndLineNo = SM.getExpansionLineNumber(End);
   1001  1.1  joerg   if (EndLineNo < LineNo || SM.getFileID(End) != FID)
   1002  1.1  joerg     return;  // No intersection.
   1003  1.1  joerg 
   1004  1.1  joerg   // Compute the column number of the start.
   1005  1.1  joerg   unsigned StartColNo = 0;
   1006  1.1  joerg   if (StartLineNo == LineNo) {
   1007  1.1  joerg     StartColNo = SM.getExpansionColumnNumber(Begin);
   1008  1.1  joerg     if (StartColNo) --StartColNo;  // Zero base the col #.
   1009  1.1  joerg   }
   1010  1.1  joerg 
   1011  1.1  joerg   // Compute the column number of the end.
   1012  1.1  joerg   unsigned EndColNo = map.getSourceLine().size();
   1013  1.1  joerg   if (EndLineNo == LineNo) {
   1014  1.1  joerg     EndColNo = SM.getExpansionColumnNumber(End);
   1015  1.1  joerg     if (EndColNo) {
   1016  1.1  joerg       --EndColNo;  // Zero base the col #.
   1017  1.1  joerg 
   1018  1.1  joerg       // Add in the length of the token, so that we cover multi-char tokens if
   1019  1.1  joerg       // this is a token range.
   1020  1.1  joerg       if (R.isTokenRange())
   1021  1.1  joerg         EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
   1022  1.1  joerg     } else {
   1023  1.1  joerg       EndColNo = CaretLine.size();
   1024  1.1  joerg     }
   1025  1.1  joerg   }
   1026  1.1  joerg 
   1027  1.1  joerg   assert(StartColNo <= EndColNo && "Invalid range!");
   1028  1.1  joerg 
   1029  1.1  joerg   // Check that a token range does not highlight only whitespace.
   1030  1.1  joerg   if (R.isTokenRange()) {
   1031  1.1  joerg     // Pick the first non-whitespace column.
   1032  1.1  joerg     while (StartColNo < map.getSourceLine().size() &&
   1033  1.1  joerg            (map.getSourceLine()[StartColNo] == ' ' ||
   1034  1.1  joerg             map.getSourceLine()[StartColNo] == '\t'))
   1035  1.1  joerg       StartColNo = map.startOfNextColumn(StartColNo);
   1036  1.1  joerg 
   1037  1.1  joerg     // Pick the last non-whitespace column.
   1038  1.1  joerg     if (EndColNo > map.getSourceLine().size())
   1039  1.1  joerg       EndColNo = map.getSourceLine().size();
   1040  1.1  joerg     while (EndColNo &&
   1041  1.1  joerg            (map.getSourceLine()[EndColNo-1] == ' ' ||
   1042  1.1  joerg             map.getSourceLine()[EndColNo-1] == '\t'))
   1043  1.1  joerg       EndColNo = map.startOfPreviousColumn(EndColNo);
   1044  1.1  joerg 
   1045  1.1  joerg     // If the start/end passed each other, then we are trying to highlight a
   1046  1.1  joerg     // range that just exists in whitespace. That most likely means we have
   1047  1.1  joerg     // a multi-line highlighting range that covers a blank line.
   1048  1.1  joerg     if (StartColNo > EndColNo) {
   1049  1.1  joerg       assert(StartLineNo != EndLineNo && "trying to highlight whitespace");
   1050  1.1  joerg       StartColNo = EndColNo;
   1051  1.1  joerg     }
   1052  1.1  joerg   }
   1053  1.1  joerg 
   1054  1.1  joerg   assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
   1055  1.1  joerg   assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
   1056  1.1  joerg 
   1057  1.1  joerg   // Fill the range with ~'s.
   1058  1.1  joerg   StartColNo = map.byteToContainingColumn(StartColNo);
   1059  1.1  joerg   EndColNo = map.byteToContainingColumn(EndColNo);
   1060  1.1  joerg 
   1061  1.1  joerg   assert(StartColNo <= EndColNo && "Invalid range!");
   1062  1.1  joerg   if (CaretLine.size() < EndColNo)
   1063  1.1  joerg     CaretLine.resize(EndColNo,' ');
   1064  1.1  joerg   std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
   1065  1.1  joerg }
   1066  1.1  joerg 
   1067  1.1  joerg static std::string buildFixItInsertionLine(FileID FID,
   1068  1.1  joerg                                            unsigned LineNo,
   1069  1.1  joerg                                            const SourceColumnMap &map,
   1070  1.1  joerg                                            ArrayRef<FixItHint> Hints,
   1071  1.1  joerg                                            const SourceManager &SM,
   1072  1.1  joerg                                            const DiagnosticOptions *DiagOpts) {
   1073  1.1  joerg   std::string FixItInsertionLine;
   1074  1.1  joerg   if (Hints.empty() || !DiagOpts->ShowFixits)
   1075  1.1  joerg     return FixItInsertionLine;
   1076  1.1  joerg   unsigned PrevHintEndCol = 0;
   1077  1.1  joerg 
   1078  1.1  joerg   for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
   1079  1.1  joerg        I != E; ++I) {
   1080  1.1  joerg     if (!I->CodeToInsert.empty()) {
   1081  1.1  joerg       // We have an insertion hint. Determine whether the inserted
   1082  1.1  joerg       // code contains no newlines and is on the same line as the caret.
   1083  1.1  joerg       std::pair<FileID, unsigned> HintLocInfo
   1084  1.1  joerg         = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
   1085  1.1  joerg       if (FID == HintLocInfo.first &&
   1086  1.1  joerg           LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
   1087  1.1  joerg           StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
   1088  1.1  joerg         // Insert the new code into the line just below the code
   1089  1.1  joerg         // that the user wrote.
   1090  1.1  joerg         // Note: When modifying this function, be very careful about what is a
   1091  1.1  joerg         // "column" (printed width, platform-dependent) and what is a
   1092  1.1  joerg         // "byte offset" (SourceManager "column").
   1093  1.1  joerg         unsigned HintByteOffset
   1094  1.1  joerg           = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
   1095  1.1  joerg 
   1096  1.1  joerg         // The hint must start inside the source or right at the end
   1097  1.1  joerg         assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
   1098  1.1  joerg         unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
   1099  1.1  joerg 
   1100  1.1  joerg         // If we inserted a long previous hint, push this one forwards, and add
   1101  1.1  joerg         // an extra space to show that this is not part of the previous
   1102  1.1  joerg         // completion. This is sort of the best we can do when two hints appear
   1103  1.1  joerg         // to overlap.
   1104  1.1  joerg         //
   1105  1.1  joerg         // Note that if this hint is located immediately after the previous
   1106  1.1  joerg         // hint, no space will be added, since the location is more important.
   1107  1.1  joerg         if (HintCol < PrevHintEndCol)
   1108  1.1  joerg           HintCol = PrevHintEndCol + 1;
   1109  1.1  joerg 
   1110  1.1  joerg         // This should NOT use HintByteOffset, because the source might have
   1111  1.1  joerg         // Unicode characters in earlier columns.
   1112  1.1  joerg         unsigned NewFixItLineSize = FixItInsertionLine.size() +
   1113  1.1  joerg           (HintCol - PrevHintEndCol) + I->CodeToInsert.size();
   1114  1.1  joerg         if (NewFixItLineSize > FixItInsertionLine.size())
   1115  1.1  joerg           FixItInsertionLine.resize(NewFixItLineSize, ' ');
   1116  1.1  joerg 
   1117  1.1  joerg         std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
   1118  1.1  joerg                   FixItInsertionLine.end() - I->CodeToInsert.size());
   1119  1.1  joerg 
   1120  1.1  joerg         PrevHintEndCol =
   1121  1.1  joerg           HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert);
   1122  1.1  joerg       }
   1123  1.1  joerg     }
   1124  1.1  joerg   }
   1125  1.1  joerg 
   1126  1.1  joerg   expandTabs(FixItInsertionLine, DiagOpts->TabStop);
   1127  1.1  joerg 
   1128  1.1  joerg   return FixItInsertionLine;
   1129  1.1  joerg }
   1130  1.1  joerg 
   1131  1.1  joerg /// Emit a code snippet and caret line.
   1132  1.1  joerg ///
   1133  1.1  joerg /// This routine emits a single line's code snippet and caret line..
   1134  1.1  joerg ///
   1135  1.1  joerg /// \param Loc The location for the caret.
   1136  1.1  joerg /// \param Ranges The underlined ranges for this code snippet.
   1137  1.1  joerg /// \param Hints The FixIt hints active for this diagnostic.
   1138  1.1  joerg void TextDiagnostic::emitSnippetAndCaret(
   1139  1.1  joerg     FullSourceLoc Loc, DiagnosticsEngine::Level Level,
   1140  1.1  joerg     SmallVectorImpl<CharSourceRange> &Ranges, ArrayRef<FixItHint> Hints) {
   1141  1.1  joerg   assert(Loc.isValid() && "must have a valid source location here");
   1142  1.1  joerg   assert(Loc.isFileID() && "must have a file location here");
   1143  1.1  joerg 
   1144  1.1  joerg   // If caret diagnostics are enabled and we have location, we want to
   1145  1.1  joerg   // emit the caret.  However, we only do this if the location moved
   1146  1.1  joerg   // from the last diagnostic, if the last diagnostic was a note that
   1147  1.1  joerg   // was part of a different warning or error diagnostic, or if the
   1148  1.1  joerg   // diagnostic has ranges.  We don't want to emit the same caret
   1149  1.1  joerg   // multiple times if one loc has multiple diagnostics.
   1150  1.1  joerg   if (!DiagOpts->ShowCarets)
   1151  1.1  joerg     return;
   1152  1.1  joerg   if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
   1153  1.1  joerg       (LastLevel != DiagnosticsEngine::Note || Level == LastLevel))
   1154  1.1  joerg     return;
   1155  1.1  joerg 
   1156  1.1  joerg   // Decompose the location into a FID/Offset pair.
   1157  1.1  joerg   std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc();
   1158  1.1  joerg   FileID FID = LocInfo.first;
   1159  1.1  joerg   const SourceManager &SM = Loc.getManager();
   1160  1.1  joerg 
   1161  1.1  joerg   // Get information about the buffer it points into.
   1162  1.1  joerg   bool Invalid = false;
   1163  1.1  joerg   StringRef BufData = Loc.getBufferData(&Invalid);
   1164  1.1  joerg   if (Invalid)
   1165  1.1  joerg     return;
   1166  1.1  joerg 
   1167  1.1  joerg   unsigned CaretLineNo = Loc.getLineNumber();
   1168  1.1  joerg   unsigned CaretColNo = Loc.getColumnNumber();
   1169  1.1  joerg 
   1170  1.1  joerg   // Arbitrarily stop showing snippets when the line is too long.
   1171  1.1  joerg   static const size_t MaxLineLengthToPrint = 4096;
   1172  1.1  joerg   if (CaretColNo > MaxLineLengthToPrint)
   1173  1.1  joerg     return;
   1174  1.1  joerg 
   1175  1.1  joerg   // Find the set of lines to include.
   1176  1.1  joerg   const unsigned MaxLines = DiagOpts->SnippetLineLimit;
   1177  1.1  joerg   std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
   1178  1.1  joerg   for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
   1179  1.1  joerg                                                   E = Ranges.end();
   1180  1.1  joerg        I != E; ++I)
   1181  1.1  joerg     if (auto OptionalRange = findLinesForRange(*I, FID, SM))
   1182  1.1  joerg       Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
   1183  1.1  joerg 
   1184  1.1  joerg   for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) {
   1185  1.1  joerg     const char *BufStart = BufData.data();
   1186  1.1  joerg     const char *BufEnd = BufStart + BufData.size();
   1187  1.1  joerg 
   1188  1.1  joerg     // Rewind from the current position to the start of the line.
   1189  1.1  joerg     const char *LineStart =
   1190  1.1  joerg         BufStart +
   1191  1.1  joerg         SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
   1192  1.1  joerg     if (LineStart == BufEnd)
   1193  1.1  joerg       break;
   1194  1.1  joerg 
   1195  1.1  joerg     // Compute the line end.
   1196  1.1  joerg     const char *LineEnd = LineStart;
   1197  1.1  joerg     while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
   1198  1.1  joerg       ++LineEnd;
   1199  1.1  joerg 
   1200  1.1  joerg     // Arbitrarily stop showing snippets when the line is too long.
   1201  1.1  joerg     // FIXME: Don't print any lines in this case.
   1202  1.1  joerg     if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
   1203  1.1  joerg       return;
   1204  1.1  joerg 
   1205  1.1  joerg     // Trim trailing null-bytes.
   1206  1.1  joerg     StringRef Line(LineStart, LineEnd - LineStart);
   1207  1.1  joerg     while (!Line.empty() && Line.back() == '\0' &&
   1208  1.1  joerg            (LineNo != CaretLineNo || Line.size() > CaretColNo))
   1209  1.1  joerg       Line = Line.drop_back();
   1210  1.1  joerg 
   1211  1.1  joerg     // Copy the line of code into an std::string for ease of manipulation.
   1212  1.1  joerg     std::string SourceLine(Line.begin(), Line.end());
   1213  1.1  joerg 
   1214  1.1  joerg     // Build the byte to column map.
   1215  1.1  joerg     const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
   1216  1.1  joerg 
   1217  1.1  joerg     // Create a line for the caret that is filled with spaces that is the same
   1218  1.1  joerg     // number of columns as the line of source code.
   1219  1.1  joerg     std::string CaretLine(sourceColMap.columns(), ' ');
   1220  1.1  joerg 
   1221  1.1  joerg     // Highlight all of the characters covered by Ranges with ~ characters.
   1222  1.1  joerg     for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
   1223  1.1  joerg                                                     E = Ranges.end();
   1224  1.1  joerg          I != E; ++I)
   1225  1.1  joerg       highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
   1226  1.1  joerg 
   1227  1.1  joerg     // Next, insert the caret itself.
   1228  1.1  joerg     if (CaretLineNo == LineNo) {
   1229  1.1  joerg       CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1);
   1230  1.1  joerg       if (CaretLine.size() < CaretColNo + 1)
   1231  1.1  joerg         CaretLine.resize(CaretColNo + 1, ' ');
   1232  1.1  joerg       CaretLine[CaretColNo] = '^';
   1233  1.1  joerg     }
   1234  1.1  joerg 
   1235  1.1  joerg     std::string FixItInsertionLine = buildFixItInsertionLine(
   1236  1.1  joerg         FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get());
   1237  1.1  joerg 
   1238  1.1  joerg     // If the source line is too long for our terminal, select only the
   1239  1.1  joerg     // "interesting" source region within that line.
   1240  1.1  joerg     unsigned Columns = DiagOpts->MessageLength;
   1241  1.1  joerg     if (Columns)
   1242  1.1  joerg       selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
   1243  1.1  joerg                                     Columns, sourceColMap);
   1244  1.1  joerg 
   1245  1.1  joerg     // If we are in -fdiagnostics-print-source-range-info mode, we are trying
   1246  1.1  joerg     // to produce easily machine parsable output.  Add a space before the
   1247  1.1  joerg     // source line and the caret to make it trivial to tell the main diagnostic
   1248  1.1  joerg     // line from what the user is intended to see.
   1249  1.1  joerg     if (DiagOpts->ShowSourceRanges) {
   1250  1.1  joerg       SourceLine = ' ' + SourceLine;
   1251  1.1  joerg       CaretLine = ' ' + CaretLine;
   1252  1.1  joerg     }
   1253  1.1  joerg 
   1254  1.1  joerg     // Finally, remove any blank spaces from the end of CaretLine.
   1255  1.1  joerg     while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ')
   1256  1.1  joerg       CaretLine.erase(CaretLine.end() - 1);
   1257  1.1  joerg 
   1258  1.1  joerg     // Emit what we have computed.
   1259  1.1  joerg     emitSnippet(SourceLine);
   1260  1.1  joerg 
   1261  1.1  joerg     if (!CaretLine.empty()) {
   1262  1.1  joerg       if (DiagOpts->ShowColors)
   1263  1.1  joerg         OS.changeColor(caretColor, true);
   1264  1.1  joerg       OS << CaretLine << '\n';
   1265  1.1  joerg       if (DiagOpts->ShowColors)
   1266  1.1  joerg         OS.resetColor();
   1267  1.1  joerg     }
   1268  1.1  joerg 
   1269  1.1  joerg     if (!FixItInsertionLine.empty()) {
   1270  1.1  joerg       if (DiagOpts->ShowColors)
   1271  1.1  joerg         // Print fixit line in color
   1272  1.1  joerg         OS.changeColor(fixitColor, false);
   1273  1.1  joerg       if (DiagOpts->ShowSourceRanges)
   1274  1.1  joerg         OS << ' ';
   1275  1.1  joerg       OS << FixItInsertionLine << '\n';
   1276  1.1  joerg       if (DiagOpts->ShowColors)
   1277  1.1  joerg         OS.resetColor();
   1278  1.1  joerg     }
   1279  1.1  joerg   }
   1280  1.1  joerg 
   1281  1.1  joerg   // Print out any parseable fixit information requested by the options.
   1282  1.1  joerg   emitParseableFixits(Hints, SM);
   1283  1.1  joerg }
   1284  1.1  joerg 
   1285  1.1  joerg void TextDiagnostic::emitSnippet(StringRef line) {
   1286  1.1  joerg   if (line.empty())
   1287  1.1  joerg     return;
   1288  1.1  joerg 
   1289  1.1  joerg   size_t i = 0;
   1290  1.1  joerg 
   1291  1.1  joerg   std::string to_print;
   1292  1.1  joerg   bool print_reversed = false;
   1293  1.1  joerg 
   1294  1.1  joerg   while (i<line.size()) {
   1295  1.1  joerg     std::pair<SmallString<16>,bool> res
   1296  1.1  joerg         = printableTextForNextCharacter(line, &i, DiagOpts->TabStop);
   1297  1.1  joerg     bool was_printable = res.second;
   1298  1.1  joerg 
   1299  1.1  joerg     if (DiagOpts->ShowColors && was_printable == print_reversed) {
   1300  1.1  joerg       if (print_reversed)
   1301  1.1  joerg         OS.reverseColor();
   1302  1.1  joerg       OS << to_print;
   1303  1.1  joerg       to_print.clear();
   1304  1.1  joerg       if (DiagOpts->ShowColors)
   1305  1.1  joerg         OS.resetColor();
   1306  1.1  joerg     }
   1307  1.1  joerg 
   1308  1.1  joerg     print_reversed = !was_printable;
   1309  1.1  joerg     to_print += res.first.str();
   1310  1.1  joerg   }
   1311  1.1  joerg 
   1312  1.1  joerg   if (print_reversed && DiagOpts->ShowColors)
   1313  1.1  joerg     OS.reverseColor();
   1314  1.1  joerg   OS << to_print;
   1315  1.1  joerg   if (print_reversed && DiagOpts->ShowColors)
   1316  1.1  joerg     OS.resetColor();
   1317  1.1  joerg 
   1318  1.1  joerg   OS << '\n';
   1319  1.1  joerg }
   1320  1.1  joerg 
   1321  1.1  joerg void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
   1322  1.1  joerg                                          const SourceManager &SM) {
   1323  1.1  joerg   if (!DiagOpts->ShowParseableFixits)
   1324  1.1  joerg     return;
   1325  1.1  joerg 
   1326  1.1  joerg   // We follow FixItRewriter's example in not (yet) handling
   1327  1.1  joerg   // fix-its in macros.
   1328  1.1  joerg   for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
   1329  1.1  joerg        I != E; ++I) {
   1330  1.1  joerg     if (I->RemoveRange.isInvalid() ||
   1331  1.1  joerg         I->RemoveRange.getBegin().isMacroID() ||
   1332  1.1  joerg         I->RemoveRange.getEnd().isMacroID())
   1333  1.1  joerg       return;
   1334  1.1  joerg   }
   1335  1.1  joerg 
   1336  1.1  joerg   for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
   1337  1.1  joerg        I != E; ++I) {
   1338  1.1  joerg     SourceLocation BLoc = I->RemoveRange.getBegin();
   1339  1.1  joerg     SourceLocation ELoc = I->RemoveRange.getEnd();
   1340  1.1  joerg 
   1341  1.1  joerg     std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
   1342  1.1  joerg     std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
   1343  1.1  joerg 
   1344  1.1  joerg     // Adjust for token ranges.
   1345  1.1  joerg     if (I->RemoveRange.isTokenRange())
   1346  1.1  joerg       EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
   1347  1.1  joerg 
   1348  1.1  joerg     // We specifically do not do word-wrapping or tab-expansion here,
   1349  1.1  joerg     // because this is supposed to be easy to parse.
   1350  1.1  joerg     PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
   1351  1.1  joerg     if (PLoc.isInvalid())
   1352  1.1  joerg       break;
   1353  1.1  joerg 
   1354  1.1  joerg     OS << "fix-it:\"";
   1355  1.1  joerg     OS.write_escaped(PLoc.getFilename());
   1356  1.1  joerg     OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
   1357  1.1  joerg       << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
   1358  1.1  joerg       << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
   1359  1.1  joerg       << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
   1360  1.1  joerg       << "}:\"";
   1361  1.1  joerg     OS.write_escaped(I->CodeToInsert);
   1362  1.1  joerg     OS << "\"\n";
   1363  1.1  joerg   }
   1364  1.1  joerg }
   1365