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