clang  9.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  std::find_if(CaretLine.begin(), CaretLine.end(),
337  [](char c) { return c < ' ' || '~' < c; }));
338 
339  // Find the slice that we need to display the full caret line
340  // correctly.
341  unsigned CaretStart = 0, CaretEnd = CaretLine.size();
342  for (; CaretStart != CaretEnd; ++CaretStart)
343  if (!isWhitespace(CaretLine[CaretStart]))
344  break;
345 
346  for (; CaretEnd != CaretStart; --CaretEnd)
347  if (!isWhitespace(CaretLine[CaretEnd - 1]))
348  break;
349 
350  // caret has already been inserted into CaretLine so the above whitespace
351  // check is guaranteed to include the caret
352 
353  // If we have a fix-it line, make sure the slice includes all of the
354  // fix-it information.
355  if (!FixItInsertionLine.empty()) {
356  unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
357  for (; FixItStart != FixItEnd; ++FixItStart)
358  if (!isWhitespace(FixItInsertionLine[FixItStart]))
359  break;
360 
361  for (; FixItEnd != FixItStart; --FixItEnd)
362  if (!isWhitespace(FixItInsertionLine[FixItEnd - 1]))
363  break;
364 
365  // We can safely use the byte offset FixItStart as the column offset
366  // because the characters up until FixItStart are all ASCII whitespace
367  // characters.
368  unsigned FixItStartCol = FixItStart;
369  unsigned FixItEndCol
370  = llvm::sys::locale::columnWidth(FixItInsertionLine.substr(0, FixItEnd));
371 
372  CaretStart = std::min(FixItStartCol, CaretStart);
373  CaretEnd = std::max(FixItEndCol, CaretEnd);
374  }
375 
376  // CaretEnd may have been set at the middle of a character
377  // If it's not at a character's first column then advance it past the current
378  // character.
379  while (static_cast<int>(CaretEnd) < map.columns() &&
380  -1 == map.columnToByte(CaretEnd))
381  ++CaretEnd;
382 
383  assert((static_cast<int>(CaretStart) > map.columns() ||
384  -1!=map.columnToByte(CaretStart)) &&
385  "CaretStart must not point to a column in the middle of a source"
386  " line character");
387  assert((static_cast<int>(CaretEnd) > map.columns() ||
388  -1!=map.columnToByte(CaretEnd)) &&
389  "CaretEnd must not point to a column in the middle of a source line"
390  " character");
391 
392  // CaretLine[CaretStart, CaretEnd) contains all of the interesting
393  // parts of the caret line. While this slice is smaller than the
394  // number of columns we have, try to grow the slice to encompass
395  // more context.
396 
397  unsigned SourceStart = map.columnToByte(std::min<unsigned>(CaretStart,
398  map.columns()));
399  unsigned SourceEnd = map.columnToByte(std::min<unsigned>(CaretEnd,
400  map.columns()));
401 
402  unsigned CaretColumnsOutsideSource = CaretEnd-CaretStart
403  - (map.byteToColumn(SourceEnd)-map.byteToColumn(SourceStart));
404 
405  char const *front_ellipse = " ...";
406  char const *front_space = " ";
407  char const *back_ellipse = "...";
408  unsigned ellipses_space = strlen(front_ellipse) + strlen(back_ellipse);
409 
410  unsigned TargetColumns = Columns;
411  // Give us extra room for the ellipses
412  // and any of the caret line that extends past the source
413  if (TargetColumns > ellipses_space+CaretColumnsOutsideSource)
414  TargetColumns -= ellipses_space+CaretColumnsOutsideSource;
415 
416  while (SourceStart>0 || SourceEnd<SourceLine.size()) {
417  bool ExpandedRegion = false;
418 
419  if (SourceStart>0) {
420  unsigned NewStart = map.startOfPreviousColumn(SourceStart);
421 
422  // Skip over any whitespace we see here; we're looking for
423  // another bit of interesting text.
424  // FIXME: Detect non-ASCII whitespace characters too.
425  while (NewStart && isWhitespace(SourceLine[NewStart]))
426  NewStart = map.startOfPreviousColumn(NewStart);
427 
428  // Skip over this bit of "interesting" text.
429  while (NewStart) {
430  unsigned Prev = map.startOfPreviousColumn(NewStart);
431  if (isWhitespace(SourceLine[Prev]))
432  break;
433  NewStart = Prev;
434  }
435 
436  assert(map.byteToColumn(NewStart) != -1);
437  unsigned NewColumns = map.byteToColumn(SourceEnd) -
438  map.byteToColumn(NewStart);
439  if (NewColumns <= TargetColumns) {
440  SourceStart = NewStart;
441  ExpandedRegion = true;
442  }
443  }
444 
445  if (SourceEnd<SourceLine.size()) {
446  unsigned NewEnd = map.startOfNextColumn(SourceEnd);
447 
448  // Skip over any whitespace we see here; we're looking for
449  // another bit of interesting text.
450  // FIXME: Detect non-ASCII whitespace characters too.
451  while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
452  NewEnd = map.startOfNextColumn(NewEnd);
453 
454  // Skip over this bit of "interesting" text.
455  while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
456  NewEnd = map.startOfNextColumn(NewEnd);
457 
458  assert(map.byteToColumn(NewEnd) != -1);
459  unsigned NewColumns = map.byteToColumn(NewEnd) -
460  map.byteToColumn(SourceStart);
461  if (NewColumns <= TargetColumns) {
462  SourceEnd = NewEnd;
463  ExpandedRegion = true;
464  }
465  }
466 
467  if (!ExpandedRegion)
468  break;
469  }
470 
471  CaretStart = map.byteToColumn(SourceStart);
472  CaretEnd = map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource;
473 
474  // [CaretStart, CaretEnd) is the slice we want. Update the various
475  // output lines to show only this slice, with two-space padding
476  // before the lines so that it looks nicer.
477 
478  assert(CaretStart!=(unsigned)-1 && CaretEnd!=(unsigned)-1 &&
479  SourceStart!=(unsigned)-1 && SourceEnd!=(unsigned)-1);
480  assert(SourceStart <= SourceEnd);
481  assert(CaretStart <= CaretEnd);
482 
483  unsigned BackColumnsRemoved
484  = map.byteToColumn(SourceLine.size())-map.byteToColumn(SourceEnd);
485  unsigned FrontColumnsRemoved = CaretStart;
486  unsigned ColumnsKept = CaretEnd-CaretStart;
487 
488  // We checked up front that the line needed truncation
489  assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns);
490 
491  // The line needs some truncation, and we'd prefer to keep the front
492  // if possible, so remove the back
493  if (BackColumnsRemoved > strlen(back_ellipse))
494  SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
495 
496  // If that's enough then we're done
497  if (FrontColumnsRemoved+ColumnsKept <= Columns)
498  return;
499 
500  // Otherwise remove the front as well
501  if (FrontColumnsRemoved > strlen(front_ellipse)) {
502  SourceLine.replace(0, SourceStart, front_ellipse);
503  CaretLine.replace(0, CaretStart, front_space);
504  if (!FixItInsertionLine.empty())
505  FixItInsertionLine.replace(0, CaretStart, front_space);
506  }
507 }
508 
509 /// Skip over whitespace in the string, starting at the given
510 /// index.
511 ///
512 /// \returns The index of the first non-whitespace character that is
513 /// greater than or equal to Idx or, if no such character exists,
514 /// returns the end of the string.
515 static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
516  while (Idx < Length && isWhitespace(Str[Idx]))
517  ++Idx;
518  return Idx;
519 }
520 
521 /// If the given character is the start of some kind of
522 /// balanced punctuation (e.g., quotes or parentheses), return the
523 /// character that will terminate the punctuation.
524 ///
525 /// \returns The ending punctuation character, if any, or the NULL
526 /// character if the input character does not start any punctuation.
527 static inline char findMatchingPunctuation(char c) {
528  switch (c) {
529  case '\'': return '\'';
530  case '`': return '\'';
531  case '"': return '"';
532  case '(': return ')';
533  case '[': return ']';
534  case '{': return '}';
535  default: break;
536  }
537 
538  return 0;
539 }
540 
541 /// Find the end of the word starting at the given offset
542 /// within a string.
543 ///
544 /// \returns the index pointing one character past the end of the
545 /// word.
546 static unsigned findEndOfWord(unsigned Start, StringRef Str,
547  unsigned Length, unsigned Column,
548  unsigned Columns) {
549  assert(Start < Str.size() && "Invalid start position!");
550  unsigned End = Start + 1;
551 
552  // If we are already at the end of the string, take that as the word.
553  if (End == Str.size())
554  return End;
555 
556  // Determine if the start of the string is actually opening
557  // punctuation, e.g., a quote or parentheses.
558  char EndPunct = findMatchingPunctuation(Str[Start]);
559  if (!EndPunct) {
560  // This is a normal word. Just find the first space character.
561  while (End < Length && !isWhitespace(Str[End]))
562  ++End;
563  return End;
564  }
565 
566  // We have the start of a balanced punctuation sequence (quotes,
567  // parentheses, etc.). Determine the full sequence is.
568  SmallString<16> PunctuationEndStack;
569  PunctuationEndStack.push_back(EndPunct);
570  while (End < Length && !PunctuationEndStack.empty()) {
571  if (Str[End] == PunctuationEndStack.back())
572  PunctuationEndStack.pop_back();
573  else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
574  PunctuationEndStack.push_back(SubEndPunct);
575 
576  ++End;
577  }
578 
579  // Find the first space character after the punctuation ended.
580  while (End < Length && !isWhitespace(Str[End]))
581  ++End;
582 
583  unsigned PunctWordLength = End - Start;
584  if (// If the word fits on this line
585  Column + PunctWordLength <= Columns ||
586  // ... or the word is "short enough" to take up the next line
587  // without too much ugly white space
588  PunctWordLength < Columns/3)
589  return End; // Take the whole thing as a single "word".
590 
591  // The whole quoted/parenthesized string is too long to print as a
592  // single "word". Instead, find the "word" that starts just after
593  // the punctuation and use that end-point instead. This will recurse
594  // until it finds something small enough to consider a word.
595  return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
596 }
597 
598 /// Print the given string to a stream, word-wrapping it to
599 /// some number of columns in the process.
600 ///
601 /// \param OS the stream to which the word-wrapping string will be
602 /// emitted.
603 /// \param Str the string to word-wrap and output.
604 /// \param Columns the number of columns to word-wrap to.
605 /// \param Column the column number at which the first character of \p
606 /// Str will be printed. This will be non-zero when part of the first
607 /// line has already been printed.
608 /// \param Bold if the current text should be bold
609 /// \param Indentation the number of spaces to indent any lines beyond
610 /// the first line.
611 /// \returns true if word-wrapping was required, or false if the
612 /// string fit on the first line.
613 static bool printWordWrapped(raw_ostream &OS, StringRef Str,
614  unsigned Columns,
615  unsigned Column = 0,
616  bool Bold = false,
617  unsigned Indentation = WordWrapIndentation) {
618  const unsigned Length = std::min(Str.find('\n'), Str.size());
619  bool TextNormal = true;
620 
621  // The string used to indent each line.
622  SmallString<16> IndentStr;
623  IndentStr.assign(Indentation, ' ');
624  bool Wrapped = false;
625  for (unsigned WordStart = 0, WordEnd; WordStart < Length;
626  WordStart = WordEnd) {
627  // Find the beginning of the next word.
628  WordStart = skipWhitespace(WordStart, Str, Length);
629  if (WordStart == Length)
630  break;
631 
632  // Find the end of this word.
633  WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
634 
635  // Does this word fit on the current line?
636  unsigned WordLength = WordEnd - WordStart;
637  if (Column + WordLength < Columns) {
638  // This word fits on the current line; print it there.
639  if (WordStart) {
640  OS << ' ';
641  Column += 1;
642  }
643  applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),
644  TextNormal, Bold);
645  Column += WordLength;
646  continue;
647  }
648 
649  // This word does not fit on the current line, so wrap to the next
650  // line.
651  OS << '\n';
652  OS.write(&IndentStr[0], Indentation);
653  applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),
654  TextNormal, Bold);
655  Column = Indentation + WordLength;
656  Wrapped = true;
657  }
658 
659  // Append any remaning text from the message with its existing formatting.
660  applyTemplateHighlighting(OS, Str.substr(Length), TextNormal, Bold);
661 
662  assert(TextNormal && "Text highlighted at end of diagnostic message.");
663 
664  return Wrapped;
665 }
666 
668  const LangOptions &LangOpts,
669  DiagnosticOptions *DiagOpts)
670  : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS) {}
671 
673 
676  StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
677  DiagOrStoredDiag D) {
678  uint64_t StartOfLocationInfo = OS.tell();
679 
680  // Emit the location of this particular diagnostic.
681  if (Loc.isValid())
682  emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
683 
684  if (DiagOpts->ShowColors)
685  OS.resetColor();
686 
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  const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
767  llvm::sys::path::parent_path(Filename));
768  if (Dir) {
769  StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
770  llvm::sys::path::append(AbsoluteFilename, DirName,
771  llvm::sys::path::filename(Filename));
772  Filename = StringRef(AbsoluteFilename.data(), AbsoluteFilename.size());
773  }
774  }
775 
776  OS << Filename;
777 }
778 
779 /// Print out the file/line/column information and include trace.
780 ///
781 /// This method handlen the emission of the diagnostic location information.
782 /// This includes extracting as much location information as is present for
783 /// the diagnostic and printing it, as well as any include stack or source
784 /// ranges necessary.
787  ArrayRef<CharSourceRange> Ranges) {
788  if (PLoc.isInvalid()) {
789  // At least print the file name if available:
790  FileID FID = Loc.getFileID();
791  if (FID.isValid()) {
792  const FileEntry *FE = Loc.getFileEntry();
793  if (FE && FE->isValid()) {
794  emitFilename(FE->getName(), Loc.getManager());
795  if (FE->isInPCH())
796  OS << " (in PCH)";
797  OS << ": ";
798  }
799  }
800  return;
801  }
802  unsigned LineNo = PLoc.getLine();
803 
804  if (!DiagOpts->ShowLocation)
805  return;
806 
807  if (DiagOpts->ShowColors)
808  OS.changeColor(savedColor, true);
809 
810  emitFilename(PLoc.getFilename(), Loc.getManager());
811  switch (DiagOpts->getFormat()) {
812  case DiagnosticOptions::Clang: OS << ':' << LineNo; break;
813  case DiagnosticOptions::MSVC: OS << '(' << LineNo; break;
814  case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
815  }
816 
817  if (DiagOpts->ShowColumn)
818  // Compute the column number.
819  if (unsigned ColNo = PLoc.getColumn()) {
820  if (DiagOpts->getFormat() == DiagnosticOptions::MSVC) {
821  OS << ',';
822  // Visual Studio 2010 or earlier expects column number to be off by one
823  if (LangOpts.MSCompatibilityVersion &&
825  ColNo--;
826  } else
827  OS << ':';
828  OS << ColNo;
829  }
830  switch (DiagOpts->getFormat()) {
832  case DiagnosticOptions::Vi: OS << ':'; break;
834  // MSVC2013 and before print 'file(4) : error'. MSVC2015 gets rid of the
835  // space and prints 'file(4): error'.
836  OS << ')';
837  if (LangOpts.MSCompatibilityVersion &&
839  OS << ' ';
840  OS << ": ";
841  break;
842  }
843 
844  if (DiagOpts->ShowSourceRanges && !Ranges.empty()) {
845  FileID CaretFileID = Loc.getExpansionLoc().getFileID();
846  bool PrintedRange = false;
847 
848  for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(),
849  RE = Ranges.end();
850  RI != RE; ++RI) {
851  // Ignore invalid ranges.
852  if (!RI->isValid()) continue;
853 
854  auto &SM = Loc.getManager();
855  SourceLocation B = SM.getExpansionLoc(RI->getBegin());
856  CharSourceRange ERange = SM.getExpansionRange(RI->getEnd());
857  SourceLocation E = ERange.getEnd();
858  bool IsTokenRange = ERange.isTokenRange();
859 
860  std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
861  std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
862 
863  // If the start or end of the range is in another file, just discard
864  // it.
865  if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
866  continue;
867 
868  // Add in the length of the token, so that we cover multi-char
869  // tokens.
870  unsigned TokSize = 0;
871  if (IsTokenRange)
872  TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
873 
874  FullSourceLoc BF(B, SM), EF(E, SM);
875  OS << '{'
876  << BF.getLineNumber() << ':' << BF.getColumnNumber() << '-'
877  << EF.getLineNumber() << ':' << (EF.getColumnNumber() + TokSize)
878  << '}';
879  PrintedRange = true;
880  }
881 
882  if (PrintedRange)
883  OS << ':';
884  }
885  OS << ' ';
886 }
887 
889  if (DiagOpts->ShowLocation && PLoc.isValid())
890  OS << "In file included from " << PLoc.getFilename() << ':'
891  << PLoc.getLine() << ":\n";
892  else
893  OS << "In included file:\n";
894 }
895 
897  StringRef ModuleName) {
898  if (DiagOpts->ShowLocation && PLoc.isValid())
899  OS << "In module '" << ModuleName << "' imported from "
900  << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
901  else
902  OS << "In module '" << ModuleName << "':\n";
903 }
904 
906  PresumedLoc PLoc,
907  StringRef ModuleName) {
908  if (DiagOpts->ShowLocation && PLoc.isValid())
909  OS << "While building module '" << ModuleName << "' imported from "
910  << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
911  else
912  OS << "While building module '" << ModuleName << "':\n";
913 }
914 
915 /// Find the suitable set of lines to show to include a set of ranges.
918  const SourceManager &SM) {
919  if (!R.isValid()) return None;
920 
922  SourceLocation End = R.getEnd();
923  if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
924  return None;
925 
926  return std::make_pair(SM.getExpansionLineNumber(Begin),
927  SM.getExpansionLineNumber(End));
928 }
929 
930 /// Add as much of range B into range A as possible without exceeding a maximum
931 /// size of MaxRange. Ranges are inclusive.
932 static std::pair<unsigned, unsigned>
933 maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
934  unsigned MaxRange) {
935  // If A is already the maximum size, we're done.
936  unsigned Slack = MaxRange - (A.second - A.first + 1);
937  if (Slack == 0)
938  return A;
939 
940  // Easy case: merge succeeds within MaxRange.
941  unsigned Min = std::min(A.first, B.first);
942  unsigned Max = std::max(A.second, B.second);
943  if (Max - Min + 1 <= MaxRange)
944  return {Min, Max};
945 
946  // If we can't reach B from A within MaxRange, there's nothing to do.
947  // Don't add lines to the range that contain nothing interesting.
948  if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
949  (B.second < A.second && A.second - B.second + 1 > MaxRange))
950  return A;
951 
952  // Otherwise, expand A towards B to produce a range of size MaxRange. We
953  // attempt to expand by the same amount in both directions if B strictly
954  // contains A.
955 
956  // Expand downwards by up to half the available amount, then upwards as
957  // much as possible, then downwards as much as possible.
958  A.second = std::min(A.second + (Slack + 1) / 2, Max);
959  Slack = MaxRange - (A.second - A.first + 1);
960  A.first = std::max(Min + Slack, A.first) - Slack;
961  A.second = std::min(A.first + MaxRange - 1, Max);
962  return A;
963 }
964 
965 /// Highlight a SourceRange (with ~'s) for any characters on LineNo.
966 static void highlightRange(const CharSourceRange &R,
967  unsigned LineNo, FileID FID,
968  const SourceColumnMap &map,
969  std::string &CaretLine,
970  const SourceManager &SM,
971  const LangOptions &LangOpts) {
972  if (!R.isValid()) return;
973 
975  SourceLocation End = R.getEnd();
976 
977  unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
978  if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
979  return; // No intersection.
980 
981  unsigned EndLineNo = SM.getExpansionLineNumber(End);
982  if (EndLineNo < LineNo || SM.getFileID(End) != FID)
983  return; // No intersection.
984 
985  // Compute the column number of the start.
986  unsigned StartColNo = 0;
987  if (StartLineNo == LineNo) {
988  StartColNo = SM.getExpansionColumnNumber(Begin);
989  if (StartColNo) --StartColNo; // Zero base the col #.
990  }
991 
992  // Compute the column number of the end.
993  unsigned EndColNo = map.getSourceLine().size();
994  if (EndLineNo == LineNo) {
995  EndColNo = SM.getExpansionColumnNumber(End);
996  if (EndColNo) {
997  --EndColNo; // Zero base the col #.
998 
999  // Add in the length of the token, so that we cover multi-char tokens if
1000  // this is a token range.
1001  if (R.isTokenRange())
1002  EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
1003  } else {
1004  EndColNo = CaretLine.size();
1005  }
1006  }
1007 
1008  assert(StartColNo <= EndColNo && "Invalid range!");
1009 
1010  // Check that a token range does not highlight only whitespace.
1011  if (R.isTokenRange()) {
1012  // Pick the first non-whitespace column.
1013  while (StartColNo < map.getSourceLine().size() &&
1014  (map.getSourceLine()[StartColNo] == ' ' ||
1015  map.getSourceLine()[StartColNo] == '\t'))
1016  StartColNo = map.startOfNextColumn(StartColNo);
1017 
1018  // Pick the last non-whitespace column.
1019  if (EndColNo > map.getSourceLine().size())
1020  EndColNo = map.getSourceLine().size();
1021  while (EndColNo &&
1022  (map.getSourceLine()[EndColNo-1] == ' ' ||
1023  map.getSourceLine()[EndColNo-1] == '\t'))
1024  EndColNo = map.startOfPreviousColumn(EndColNo);
1025 
1026  // If the start/end passed each other, then we are trying to highlight a
1027  // range that just exists in whitespace. That most likely means we have
1028  // a multi-line highlighting range that covers a blank line.
1029  if (StartColNo > EndColNo) {
1030  assert(StartLineNo != EndLineNo && "trying to highlight whitespace");
1031  StartColNo = EndColNo;
1032  }
1033  }
1034 
1035  assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
1036  assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
1037 
1038  // Fill the range with ~'s.
1039  StartColNo = map.byteToContainingColumn(StartColNo);
1040  EndColNo = map.byteToContainingColumn(EndColNo);
1041 
1042  assert(StartColNo <= EndColNo && "Invalid range!");
1043  if (CaretLine.size() < EndColNo)
1044  CaretLine.resize(EndColNo,' ');
1045  std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
1046 }
1047 
1048 static std::string buildFixItInsertionLine(FileID FID,
1049  unsigned LineNo,
1050  const SourceColumnMap &map,
1051  ArrayRef<FixItHint> Hints,
1052  const SourceManager &SM,
1053  const DiagnosticOptions *DiagOpts) {
1054  std::string FixItInsertionLine;
1055  if (Hints.empty() || !DiagOpts->ShowFixits)
1056  return FixItInsertionLine;
1057  unsigned PrevHintEndCol = 0;
1058 
1059  for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
1060  I != E; ++I) {
1061  if (!I->CodeToInsert.empty()) {
1062  // We have an insertion hint. Determine whether the inserted
1063  // code contains no newlines and is on the same line as the caret.
1064  std::pair<FileID, unsigned> HintLocInfo
1065  = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
1066  if (FID == HintLocInfo.first &&
1067  LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
1068  StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
1069  // Insert the new code into the line just below the code
1070  // that the user wrote.
1071  // Note: When modifying this function, be very careful about what is a
1072  // "column" (printed width, platform-dependent) and what is a
1073  // "byte offset" (SourceManager "column").
1074  unsigned HintByteOffset
1075  = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
1076 
1077  // The hint must start inside the source or right at the end
1078  assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
1079  unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
1080 
1081  // If we inserted a long previous hint, push this one forwards, and add
1082  // an extra space to show that this is not part of the previous
1083  // completion. This is sort of the best we can do when two hints appear
1084  // to overlap.
1085  //
1086  // Note that if this hint is located immediately after the previous
1087  // hint, no space will be added, since the location is more important.
1088  if (HintCol < PrevHintEndCol)
1089  HintCol = PrevHintEndCol + 1;
1090 
1091  // This should NOT use HintByteOffset, because the source might have
1092  // Unicode characters in earlier columns.
1093  unsigned NewFixItLineSize = FixItInsertionLine.size() +
1094  (HintCol - PrevHintEndCol) + I->CodeToInsert.size();
1095  if (NewFixItLineSize > FixItInsertionLine.size())
1096  FixItInsertionLine.resize(NewFixItLineSize, ' ');
1097 
1098  std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
1099  FixItInsertionLine.end() - I->CodeToInsert.size());
1100 
1101  PrevHintEndCol =
1102  HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert);
1103  }
1104  }
1105  }
1106 
1107  expandTabs(FixItInsertionLine, DiagOpts->TabStop);
1108 
1109  return FixItInsertionLine;
1110 }
1111 
1112 /// Emit a code snippet and caret line.
1113 ///
1114 /// This routine emits a single line's code snippet and caret line..
1115 ///
1116 /// \param Loc The location for the caret.
1117 /// \param Ranges The underlined ranges for this code snippet.
1118 /// \param Hints The FixIt hints active for this diagnostic.
1119 void TextDiagnostic::emitSnippetAndCaret(
1122  assert(Loc.isValid() && "must have a valid source location here");
1123  assert(Loc.isFileID() && "must have a file location here");
1124 
1125  // If caret diagnostics are enabled and we have location, we want to
1126  // emit the caret. However, we only do this if the location moved
1127  // from the last diagnostic, if the last diagnostic was a note that
1128  // was part of a different warning or error diagnostic, or if the
1129  // diagnostic has ranges. We don't want to emit the same caret
1130  // multiple times if one loc has multiple diagnostics.
1131  if (!DiagOpts->ShowCarets)
1132  return;
1133  if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
1135  return;
1136 
1137  // Decompose the location into a FID/Offset pair.
1138  std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc();
1139  FileID FID = LocInfo.first;
1140  const SourceManager &SM = Loc.getManager();
1141 
1142  // Get information about the buffer it points into.
1143  bool Invalid = false;
1144  StringRef BufData = Loc.getBufferData(&Invalid);
1145  if (Invalid)
1146  return;
1147 
1148  unsigned CaretLineNo = Loc.getLineNumber();
1149  unsigned CaretColNo = Loc.getColumnNumber();
1150 
1151  // Arbitrarily stop showing snippets when the line is too long.
1152  static const size_t MaxLineLengthToPrint = 4096;
1153  if (CaretColNo > MaxLineLengthToPrint)
1154  return;
1155 
1156  // Find the set of lines to include.
1157  const unsigned MaxLines = DiagOpts->SnippetLineLimit;
1158  std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
1159  for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
1160  E = Ranges.end();
1161  I != E; ++I)
1162  if (auto OptionalRange = findLinesForRange(*I, FID, SM))
1163  Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
1164 
1165  for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) {
1166  const char *BufStart = BufData.data();
1167  const char *BufEnd = BufStart + BufData.size();
1168 
1169  // Rewind from the current position to the start of the line.
1170  const char *LineStart =
1171  BufStart +
1172  SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
1173  if (LineStart == BufEnd)
1174  break;
1175 
1176  // Compute the line end.
1177  const char *LineEnd = LineStart;
1178  while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
1179  ++LineEnd;
1180 
1181  // Arbitrarily stop showing snippets when the line is too long.
1182  // FIXME: Don't print any lines in this case.
1183  if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
1184  return;
1185 
1186  // Trim trailing null-bytes.
1187  StringRef Line(LineStart, LineEnd - LineStart);
1188  while (!Line.empty() && Line.back() == '\0' &&
1189  (LineNo != CaretLineNo || Line.size() > CaretColNo))
1190  Line = Line.drop_back();
1191 
1192  // Copy the line of code into an std::string for ease of manipulation.
1193  std::string SourceLine(Line.begin(), Line.end());
1194 
1195  // Build the byte to column map.
1196  const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop);
1197 
1198  // Create a line for the caret that is filled with spaces that is the same
1199  // number of columns as the line of source code.
1200  std::string CaretLine(sourceColMap.columns(), ' ');
1201 
1202  // Highlight all of the characters covered by Ranges with ~ characters.
1203  for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
1204  E = Ranges.end();
1205  I != E; ++I)
1206  highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
1207 
1208  // Next, insert the caret itself.
1209  if (CaretLineNo == LineNo) {
1210  CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1);
1211  if (CaretLine.size() < CaretColNo + 1)
1212  CaretLine.resize(CaretColNo + 1, ' ');
1213  CaretLine[CaretColNo] = '^';
1214  }
1215 
1216  std::string FixItInsertionLine = buildFixItInsertionLine(
1217  FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get());
1218 
1219  // If the source line is too long for our terminal, select only the
1220  // "interesting" source region within that line.
1221  unsigned Columns = DiagOpts->MessageLength;
1222  if (Columns)
1223  selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
1224  Columns, sourceColMap);
1225 
1226  // If we are in -fdiagnostics-print-source-range-info mode, we are trying
1227  // to produce easily machine parsable output. Add a space before the
1228  // source line and the caret to make it trivial to tell the main diagnostic
1229  // line from what the user is intended to see.
1230  if (DiagOpts->ShowSourceRanges) {
1231  SourceLine = ' ' + SourceLine;
1232  CaretLine = ' ' + CaretLine;
1233  }
1234 
1235  // Finally, remove any blank spaces from the end of CaretLine.
1236  while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] == ' ')
1237  CaretLine.erase(CaretLine.end() - 1);
1238 
1239  // Emit what we have computed.
1240  emitSnippet(SourceLine);
1241 
1242  if (!CaretLine.empty()) {
1243  if (DiagOpts->ShowColors)
1244  OS.changeColor(caretColor, true);
1245  OS << CaretLine << '\n';
1246  if (DiagOpts->ShowColors)
1247  OS.resetColor();
1248  }
1249 
1250  if (!FixItInsertionLine.empty()) {
1251  if (DiagOpts->ShowColors)
1252  // Print fixit line in color
1253  OS.changeColor(fixitColor, false);
1254  if (DiagOpts->ShowSourceRanges)
1255  OS << ' ';
1256  OS << FixItInsertionLine << '\n';
1257  if (DiagOpts->ShowColors)
1258  OS.resetColor();
1259  }
1260  }
1261 
1262  // Print out any parseable fixit information requested by the options.
1263  emitParseableFixits(Hints, SM);
1264 }
1265 
1266 void TextDiagnostic::emitSnippet(StringRef line) {
1267  if (line.empty())
1268  return;
1269 
1270  size_t i = 0;
1271 
1272  std::string to_print;
1273  bool print_reversed = false;
1274 
1275  while (i<line.size()) {
1276  std::pair<SmallString<16>,bool> res
1277  = printableTextForNextCharacter(line, &i, DiagOpts->TabStop);
1278  bool was_printable = res.second;
1279 
1280  if (DiagOpts->ShowColors && was_printable == print_reversed) {
1281  if (print_reversed)
1282  OS.reverseColor();
1283  OS << to_print;
1284  to_print.clear();
1285  if (DiagOpts->ShowColors)
1286  OS.resetColor();
1287  }
1288 
1289  print_reversed = !was_printable;
1290  to_print += res.first.str();
1291  }
1292 
1293  if (print_reversed && DiagOpts->ShowColors)
1294  OS.reverseColor();
1295  OS << to_print;
1296  if (print_reversed && DiagOpts->ShowColors)
1297  OS.resetColor();
1298 
1299  OS << '\n';
1300 }
1301 
1302 void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
1303  const SourceManager &SM) {
1304  if (!DiagOpts->ShowParseableFixits)
1305  return;
1306 
1307  // We follow FixItRewriter's example in not (yet) handling
1308  // fix-its in macros.
1309  for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
1310  I != E; ++I) {
1311  if (I->RemoveRange.isInvalid() ||
1312  I->RemoveRange.getBegin().isMacroID() ||
1313  I->RemoveRange.getEnd().isMacroID())
1314  return;
1315  }
1316 
1317  for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
1318  I != E; ++I) {
1319  SourceLocation BLoc = I->RemoveRange.getBegin();
1320  SourceLocation ELoc = I->RemoveRange.getEnd();
1321 
1322  std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc);
1323  std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc);
1324 
1325  // Adjust for token ranges.
1326  if (I->RemoveRange.isTokenRange())
1327  EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
1328 
1329  // We specifically do not do word-wrapping or tab-expansion here,
1330  // because this is supposed to be easy to parse.
1331  PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
1332  if (PLoc.isInvalid())
1333  break;
1334 
1335  OS << "fix-it:\"";
1336  OS.write_escaped(PLoc.getFilename());
1337  OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
1338  << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
1339  << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
1340  << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
1341  << "}:\"";
1342  OS.write_escaped(I->CodeToInsert);
1343  OS << "\"\n";
1344  }
1345 }
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const
Definition: LangOptions.h:280
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
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.
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
const DirectoryEntry * getDirectory(StringRef DirName, bool CacheFailure=true)
Lookup, cache, and verify the specified directory (real or virtual).
StringRef Filename
Definition: Format.cpp:1628
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:435
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:1489
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: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:1583
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.
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...
Cached information about one directory (either on disk or in the virtual file system).
Definition: FileManager.h:45
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:151
static enum raw_ostream::Colors remarkColor
A SourceLocation and its associated SourceManager.
__DEVICE__ int max(int __a, int __b)
void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
__DEVICE__ int min(int __a, int __b)
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.