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