clang 23.0.0git
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
14#include "clang/Lex/Lexer.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 <algorithm>
21#include <optional>
22
23using namespace clang;
24
25static constexpr raw_ostream::Colors NoteColor = raw_ostream::CYAN;
26static constexpr raw_ostream::Colors RemarkColor = raw_ostream::BLUE;
27static constexpr raw_ostream::Colors FixitColor = raw_ostream::GREEN;
28static constexpr raw_ostream::Colors CaretColor = raw_ostream::GREEN;
29static constexpr raw_ostream::Colors WarningColor = raw_ostream::MAGENTA;
30static constexpr raw_ostream::Colors TemplateColor = raw_ostream::CYAN;
31static constexpr raw_ostream::Colors ErrorColor = raw_ostream::RED;
32static constexpr raw_ostream::Colors FatalColor = raw_ostream::RED;
33// Used for changing only the bold attribute.
34static constexpr raw_ostream::Colors SavedColor = raw_ostream::SAVEDCOLOR;
35
36// Magenta is taken for 'warning'. Red is already 'error' and 'cyan'
37// is already taken for 'note'. Green is already used to underline
38// source ranges. White and black are bad because of the usual
39// terminal backgrounds. Which leaves us only with TWO options.
40static constexpr raw_ostream::Colors CommentColor = raw_ostream::YELLOW;
41static constexpr raw_ostream::Colors LiteralColor = raw_ostream::GREEN;
42static constexpr raw_ostream::Colors KeywordColor = raw_ostream::BLUE;
43
44namespace {
45template <typename Sub> class ColumnsOrBytes {
46public:
47 int V = 0;
48 ColumnsOrBytes(int V) : V(V) {}
49 bool isValid() const { return V != -1; }
50 Sub next() const { return Sub(V + 1); }
51 Sub prev() const { return Sub(V - 1); }
52
53 bool operator>(Sub O) const { return V > O.V; }
54 bool operator<(Sub O) const { return V < O.V; }
55 bool operator<=(Sub B) const { return V <= B.V; }
56 bool operator!=(Sub C) const { return C.V != V; }
57
58 Sub operator+(Sub B) const { return Sub(V + B.V); }
59 Sub &operator+=(Sub B) {
60 V += B.V;
61 return *static_cast<Sub *>(this);
62 }
63 Sub operator-(Sub B) const { return Sub(V - B.V); }
64 Sub &operator-=(Sub B) {
65 V -= B.V;
66 return *static_cast<Sub *>(this);
67 }
68};
69
70class Bytes final : public ColumnsOrBytes<Bytes> {
71public:
72 Bytes(int V) : ColumnsOrBytes(V) {}
73};
74
75class Columns final : public ColumnsOrBytes<Columns> {
76public:
77 Columns(int V) : ColumnsOrBytes(V) {}
78};
79} // namespace
80
81/// Add highlights to differences in template strings.
82static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str,
83 bool &Normal, bool Bold) {
84 while (true) {
85 size_t Pos = Str.find(ToggleHighlight);
86 OS << Str.slice(0, Pos);
87 if (Pos == StringRef::npos)
88 break;
89
90 Str = Str.substr(Pos + 1);
91 if (Normal)
92 OS.changeColor(TemplateColor, true);
93 else {
94 OS.resetColor();
95 if (Bold)
96 OS.changeColor(SavedColor, true);
97 }
98 Normal = !Normal;
99 }
100}
101
102/// Number of spaces to indent when word-wrapping.
103const unsigned WordWrapIndentation = 6;
104
105static int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) {
106 int bytes = 0;
107 while (0<i) {
108 if (SourceLine[--i]=='\t')
109 break;
110 ++bytes;
111 }
112 return bytes;
113}
114
115/// returns a printable representation of first item from input range
116///
117/// This function returns a printable representation of the next item in a line
118/// of source. If the next byte begins a valid and printable character, that
119/// character is returned along with 'true'.
120///
121/// Otherwise, if the next byte begins a valid, but unprintable character, a
122/// printable, escaped representation of the character is returned, along with
123/// 'false'. Otherwise a printable, escaped representation of the next byte
124/// is returned along with 'false'.
125///
126/// \note The index is updated to be used with a subsequent call to
127/// printableTextForNextCharacter.
128///
129/// \param SourceLine The line of source
130/// \param I Pointer to byte index,
131/// \param TabStop used to expand tabs
132/// \return pair(printable text, 'true' iff original text was printable)
133///
134static std::pair<SmallString<16>, bool>
135printableTextForNextCharacter(StringRef SourceLine, size_t *I,
136 unsigned TabStop) {
137 assert(I && "I must not be null");
138 assert(*I < SourceLine.size() && "must point to a valid index");
139
140 if (SourceLine[*I] == '\t') {
141 assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
142 "Invalid -ftabstop value");
143 unsigned LineBytes = bytesSincePreviousTabOrLineBegin(SourceLine, *I);
144 unsigned NumSpaces = TabStop - (LineBytes % TabStop);
145 assert(0 < NumSpaces && NumSpaces <= TabStop
146 && "Invalid computation of space amt");
147 ++(*I);
148
149 SmallString<16> ExpandedTab;
150 ExpandedTab.assign(NumSpaces, ' ');
151 return std::make_pair(ExpandedTab, true);
152 }
153
154 const unsigned char *Begin = SourceLine.bytes_begin() + *I;
155
156 // Fast path for the common ASCII case.
157 if (*Begin < 0x80 && llvm::sys::locale::isPrint(*Begin)) {
158 ++(*I);
159 return std::make_pair(SmallString<16>(Begin, Begin + 1), true);
160 }
161 unsigned CharSize = llvm::getNumBytesForUTF8(*Begin);
162 const unsigned char *End = Begin + CharSize;
163
164 // Convert it to UTF32 and check if it's printable.
165 if (End <= SourceLine.bytes_end() && llvm::isLegalUTF8Sequence(Begin, End)) {
166 llvm::UTF32 C;
167 llvm::UTF32 *CPtr = &C;
168
169 // Begin and end before conversion.
170 unsigned char const *OriginalBegin = Begin;
171 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
172 &Begin, End, &CPtr, CPtr + 1, llvm::strictConversion);
173 (void)Res;
174 assert(Res == llvm::conversionOK);
175 assert(OriginalBegin < Begin);
176 assert(unsigned(Begin - OriginalBegin) == CharSize);
177
178 (*I) += (Begin - OriginalBegin);
179
180 // Valid, multi-byte, printable UTF8 character.
181 if (llvm::sys::locale::isPrint(C))
182 return std::make_pair(SmallString<16>(OriginalBegin, End), true);
183
184 // Valid but not printable.
185 SmallString<16> Str("<U+>");
186 while (C) {
187 Str.insert(Str.begin() + 3, llvm::hexdigit(C % 16));
188 C /= 16;
189 }
190 while (Str.size() < 8)
191 Str.insert(Str.begin() + 3, llvm::hexdigit(0));
192 return std::make_pair(Str, false);
193 }
194
195 // Otherwise, not printable since it's not valid UTF8.
196 SmallString<16> ExpandedByte("<XX>");
197 unsigned char Byte = SourceLine[*I];
198 ExpandedByte[1] = llvm::hexdigit(Byte / 16);
199 ExpandedByte[2] = llvm::hexdigit(Byte % 16);
200 ++(*I);
201 return std::make_pair(ExpandedByte, false);
202}
203
204static void expandTabs(std::string &SourceLine, unsigned TabStop) {
205 size_t I = SourceLine.size();
206 while (I > 0) {
207 I--;
208 if (SourceLine[I] != '\t')
209 continue;
210 size_t TmpI = I;
211 auto [Str, Printable] =
212 printableTextForNextCharacter(SourceLine, &TmpI, TabStop);
213 SourceLine.replace(I, 1, Str.c_str());
214 }
215}
216
217/// \p BytesOut:
218/// A mapping from columns to the byte of the source line that produced the
219/// character displaying at that column. This is the inverse of \p ColumnsOut.
220///
221/// The last element in the array is the number of bytes in the source string.
222///
223/// example: (given a tabstop of 8)
224///
225/// "a \t \u3042" -> {0,1,2,-1,-1,-1,-1,-1,3,4,-1,7}
226///
227/// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to
228/// display)
229///
230/// \p ColumnsOut:
231/// A mapping from the bytes
232/// of the printable representation of the line to the columns those printable
233/// characters will appear at (numbering the first column as 0).
234///
235/// If a byte 'i' corresponds to multiple columns (e.g. the byte contains a tab
236/// character) then the array will map that byte to the first column the
237/// tab appears at and the next value in the map will have been incremented
238/// more than once.
239///
240/// If a byte is the first in a sequence of bytes that together map to a single
241/// entity in the output, then the array will map that byte to the appropriate
242/// column while the subsequent bytes will be -1.
243///
244/// The last element in the array does not correspond to any byte in the input
245/// and instead is the number of columns needed to display the source
246///
247/// example: (given a tabstop of 8)
248///
249/// "a \t \u3042" -> {0,1,2,8,9,-1,-1,11}
250///
251/// (\\u3042 is represented in UTF-8 by three bytes and takes two columns to
252/// display)
253static void genColumnByteMapping(StringRef SourceLine, unsigned TabStop,
254 SmallVectorImpl<Bytes> &BytesOut,
255 SmallVectorImpl<Columns> &ColumnsOut) {
256 assert(BytesOut.empty());
257 assert(ColumnsOut.empty());
258
259 if (SourceLine.empty()) {
260 BytesOut.resize(1u, Bytes(0));
261 ColumnsOut.resize(1u, Columns(0));
262 return;
263 }
264
265 ColumnsOut.resize(SourceLine.size() + 1, -1);
266
267 Columns NumColumns = 0;
268 size_t I = 0;
269 while (I < SourceLine.size()) {
270 ColumnsOut[I] = NumColumns;
271 BytesOut.resize(NumColumns.V + 1, -1);
272 BytesOut.back() = Bytes(I);
273 auto [Str, Printable] =
274 printableTextForNextCharacter(SourceLine, &I, TabStop);
275 NumColumns += Columns(llvm::sys::locale::columnWidth(Str));
276 }
277
278 ColumnsOut.back() = NumColumns;
279 BytesOut.resize(NumColumns.V + 1, -1);
280 BytesOut.back() = Bytes(I);
281}
282
283namespace {
284struct SourceColumnMap {
285 SourceColumnMap(StringRef SourceLine, unsigned TabStop)
286 : SourceLine(SourceLine) {
287
288 genColumnByteMapping(SourceLine, TabStop, ColumnToByte, ByteToColumn);
289
290 assert(ByteToColumn.size() == SourceLine.size() + 1);
291 assert(0 < ByteToColumn.size() && 0 < ColumnToByte.size());
292 assert(ByteToColumn.size() ==
293 static_cast<unsigned>(ColumnToByte.back().V + 1));
294 assert(static_cast<unsigned>(ByteToColumn.back().V + 1) ==
295 ColumnToByte.size());
296 }
297 Columns columns() const { return ByteToColumn.back(); }
298 Bytes bytes() const { return ColumnToByte.back(); }
299
300 /// Map a byte to the column which it is at the start of, or return -1
301 /// if it is not at the start of a column (for a UTF-8 trailing byte).
302 Columns byteToColumn(Bytes N) const {
303 assert(0 <= N.V && N.V < static_cast<int>(ByteToColumn.size()));
304 return ByteToColumn[N.V];
305 }
306
307 /// Map a byte to the first column which contains it.
308 Columns byteToContainingColumn(Bytes N) const {
309 assert(0 <= N.V && N.V < static_cast<int>(ByteToColumn.size()));
310 while (!ByteToColumn[N.V].isValid())
311 --N.V;
312 return ByteToColumn[N.V];
313 }
314
315 /// Map a column to the byte which starts the column, or return -1 if
316 /// the column the second or subsequent column of an expanded tab or similar
317 /// multi-column entity.
318 Bytes columnToByte(Columns N) const {
319 assert(0 <= N.V && N.V < static_cast<int>(ColumnToByte.size()));
320 return ColumnToByte[N.V];
321 }
322
323 /// Map from a byte index to the next byte which starts a column.
324 Bytes startOfNextColumn(Bytes N) const {
325 assert(0 <= N.V && N.V < static_cast<int>(ByteToColumn.size() - 1));
326 N = N.next();
327 while (!byteToColumn(N).isValid())
328 N = N.next();
329 return N;
330 }
331
332 /// Map from a byte index to the previous byte which starts a column.
333 Bytes startOfPreviousColumn(Bytes N) const {
334 assert(0 < N.V && N.V < static_cast<int>(ByteToColumn.size()));
335 N = N.prev();
336 while (!byteToColumn(N).isValid())
337 N = N.prev();
338 return N;
339 }
340
341 StringRef getSourceLine() const { return SourceLine; }
342
343private:
344 StringRef SourceLine;
345 SmallVector<Columns, 200> ByteToColumn;
346 SmallVector<Bytes, 200> ColumnToByte;
347};
348} // end anonymous namespace
349
350/// When the source code line we want to print is too long for
351/// the terminal, select the "interesting" region.
353 std::string &SourceLine, std::string &CaretLine,
354 std::string &FixItInsertionLine, Columns NonGutterColumns,
355 const SourceColumnMap &Map,
357 Columns CaretColumns = CaretLine.size();
358 Columns FixItColumns = llvm::sys::locale::columnWidth(FixItInsertionLine);
359 Columns MaxColumns =
360 std::max({Map.columns().V, CaretColumns.V, FixItColumns.V});
361 // if the number of columns is less than the desired number we're done
362 if (MaxColumns <= NonGutterColumns)
363 return;
364
365 // No special characters are allowed in CaretLine.
366 assert(llvm::none_of(CaretLine, [](char c) { return c < ' ' || '~' < c; }));
367
368 // Find the slice that we need to display the full caret line
369 // correctly.
370 Columns CaretStart = 0, CaretEnd = CaretLine.size();
371 while (CaretStart != CaretEnd && isWhitespace(CaretLine[CaretStart.V]))
372 CaretStart = CaretStart.next();
373
374 while (CaretEnd != CaretStart && isWhitespace(CaretLine[CaretEnd.V]))
375 CaretEnd = CaretEnd.prev();
376
377 // caret has already been inserted into CaretLine so the above whitespace
378 // check is guaranteed to include the caret
379
380 // If we have a fix-it line, make sure the slice includes all of the
381 // fix-it information.
382 if (!FixItInsertionLine.empty()) {
383 // We can safely use the byte offset FixItStart as the column offset
384 // because the characters up until FixItStart are all ASCII whitespace
385 // characters.
386 Bytes FixItStart = 0;
387 Bytes FixItEnd = Bytes(FixItInsertionLine.size());
388 while (FixItStart != FixItEnd &&
389 isWhitespace(FixItInsertionLine[FixItStart.V]))
390 FixItStart = FixItStart.next();
391
392 while (FixItEnd != FixItStart &&
393 isWhitespace(FixItInsertionLine[FixItEnd.V - 1]))
394 FixItEnd = FixItEnd.prev();
395
396 Columns FixItStartCol = Columns(FixItStart.V);
397 Columns FixItEndCol = Columns(llvm::sys::locale::columnWidth(
398 FixItInsertionLine.substr(0, FixItEnd.V)));
399
400 CaretStart = std::min(FixItStartCol.V, CaretStart.V);
401 CaretEnd = std::max(FixItEndCol.V, CaretEnd.V);
402 }
403
404 // CaretEnd may have been set at the middle of a character
405 // If it's not at a character's first column then advance it past the current
406 // character.
407 while (CaretEnd < Map.columns() && !Map.columnToByte(CaretEnd).isValid())
408 CaretEnd = CaretEnd.next();
409
410 assert(
411 (CaretStart > Map.columns() || Map.columnToByte(CaretStart).isValid()) &&
412 "CaretStart must not point to a column in the middle of a source"
413 " line character");
414 assert((CaretEnd > Map.columns() || Map.columnToByte(CaretEnd).isValid()) &&
415 "CaretEnd must not point to a column in the middle of a source line"
416 " character");
417
418 // CaretLine[CaretStart, CaretEnd) contains all of the interesting
419 // parts of the caret line. While this slice is smaller than the
420 // number of columns we have, try to grow the slice to encompass
421 // more context.
422
423 Bytes SourceStart = Map.columnToByte(std::min(CaretStart.V, Map.columns().V));
424 Bytes SourceEnd = Map.columnToByte(std::min(CaretEnd.V, Map.columns().V));
425
426 Columns CaretColumnsOutsideSource =
427 CaretEnd - CaretStart -
428 (Map.byteToColumn(SourceEnd) - Map.byteToColumn(SourceStart));
429
430 constexpr StringRef FrontEllipse = " ...";
431 constexpr StringRef FrontSpace = " ";
432 constexpr StringRef BackEllipse = "...";
433 Columns EllipsesColumns = Columns(FrontEllipse.size() + BackEllipse.size());
434
435 Columns TargetColumns = NonGutterColumns;
436 // Give us extra room for the ellipses
437 // and any of the caret line that extends past the source
438 if (TargetColumns > EllipsesColumns + CaretColumnsOutsideSource)
439 TargetColumns -= EllipsesColumns + CaretColumnsOutsideSource;
440
441 while (SourceStart > 0 || SourceEnd < SourceLine.size()) {
442 bool ExpandedRegion = false;
443
444 if (SourceStart > 0) {
445 Bytes NewStart = Map.startOfPreviousColumn(SourceStart);
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 (NewStart > 0 && isWhitespace(SourceLine[NewStart.V]))
451 NewStart = Map.startOfPreviousColumn(NewStart);
452
453 // Skip over this bit of "interesting" text.
454 while (NewStart > 0) {
455 Bytes Prev = Map.startOfPreviousColumn(NewStart);
456 if (isWhitespace(SourceLine[Prev.V]))
457 break;
458 NewStart = Prev;
459 }
460
461 assert(Map.byteToColumn(NewStart).isValid());
462 Columns NewColumns =
463 Map.byteToColumn(SourceEnd) - Map.byteToColumn(NewStart);
464 if (NewColumns <= TargetColumns) {
465 SourceStart = NewStart;
466 ExpandedRegion = true;
467 }
468 }
469
470 if (SourceEnd < SourceLine.size()) {
471 Bytes NewEnd = Map.startOfNextColumn(SourceEnd);
472
473 // Skip over any whitespace we see here; we're looking for
474 // another bit of interesting text.
475 // FIXME: Detect non-ASCII whitespace characters too.
476 while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd.V]))
477 NewEnd = Map.startOfNextColumn(NewEnd);
478
479 // Skip over this bit of "interesting" text.
480 while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd.V]))
481 NewEnd = Map.startOfNextColumn(NewEnd);
482
483 assert(Map.byteToColumn(NewEnd).isValid());
484 Columns NewColumns =
485 Map.byteToColumn(NewEnd) - Map.byteToColumn(SourceStart);
486 if (NewColumns <= TargetColumns) {
487 SourceEnd = NewEnd;
488 ExpandedRegion = true;
489 }
490 }
491
492 if (!ExpandedRegion)
493 break;
494 }
495
496 CaretStart = Map.byteToColumn(SourceStart);
497 CaretEnd = Map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource;
498
499 // [CaretStart, CaretEnd) is the slice we want. Update the various
500 // output lines to show only this slice.
501 assert(CaretStart.isValid() && CaretEnd.isValid() && SourceStart.isValid() &&
502 SourceEnd.isValid());
503 assert(SourceStart <= SourceEnd);
504 assert(CaretStart <= CaretEnd);
505
506 Columns BackColumnsRemoved =
507 Map.byteToColumn(Bytes{static_cast<int>(SourceLine.size())}) -
508 Map.byteToColumn(SourceEnd);
509 Columns FrontColumnsRemoved = CaretStart;
510 Columns ColumnsKept = CaretEnd - CaretStart;
511
512 // We checked up front that the line needed truncation
513 assert(FrontColumnsRemoved + ColumnsKept + BackColumnsRemoved >
514 NonGutterColumns);
515
516 // Since we've modified the SourceLine, we also need to adjust the line's
517 // highlighting information. In particular, if we've removed
518 // from the front of the line, we need to move the style ranges to the
519 // left and remove unneeded ranges.
520 // Note in particular that variables like CaretEnd are defined in the
521 // CaretLine, which only contains ASCII, while the style ranges are defined in
522 // the source line, where we have to care for the byte-index != column-index
523 // case.
524 Bytes BytesRemoved =
525 FrontColumnsRemoved > FrontEllipse.size()
526 ? (Map.columnToByte(FrontColumnsRemoved) - Bytes(FrontEllipse.size()))
527 : 0;
528 Bytes CodeEnd =
529 CaretEnd < Map.columns() ? Map.columnToByte(CaretEnd.V) : CaretEnd.V;
530 for (TextDiagnostic::StyleRange &R : Styles) {
531 // Remove style ranges before and after the new truncated snippet.
532 if (R.Start >= static_cast<unsigned>(CodeEnd.V) ||
533 R.End < static_cast<unsigned>(BytesRemoved.V)) {
534 R.Start = R.End = std::numeric_limits<int>::max();
535 continue;
536 }
537 // Move them left. (Note that this can wrap R.Start, but that doesn't
538 // matter).
539 R.Start -= BytesRemoved.V;
540 R.End -= BytesRemoved.V;
541
542 // Don't leak into the ellipse at the end.
543 if (R.Start < static_cast<unsigned>(CodeEnd.V) &&
544 R.End > static_cast<unsigned>(CodeEnd.V))
545 R.End = CodeEnd.V + 1; // R.End is inclusive.
546 }
547
548 // The line needs some truncation, and we'd prefer to keep the front
549 // if possible, so remove the back
550 if (BackColumnsRemoved > Columns(BackEllipse.size()))
551 SourceLine.replace(SourceEnd.V, std::string::npos, BackEllipse);
552
553 // If that's enough then we're done
554 if (FrontColumnsRemoved + ColumnsKept <= NonGutterColumns)
555 return;
556
557 // Otherwise remove the front as well
558 if (FrontColumnsRemoved > Columns(FrontEllipse.size())) {
559 SourceLine.replace(0, SourceStart.V, FrontEllipse);
560 CaretLine.replace(0, CaretStart.V, FrontSpace);
561 if (!FixItInsertionLine.empty())
562 FixItInsertionLine.replace(0, CaretStart.V, FrontSpace);
563 }
564}
565
566/// Skip over whitespace in the string, starting at the given
567/// index.
568///
569/// \returns The index of the first non-whitespace character that is
570/// greater than or equal to Idx or, if no such character exists,
571/// returns the end of the string.
572static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
573 while (Idx < Length && isWhitespace(Str[Idx]))
574 ++Idx;
575 return Idx;
576}
577
578/// If the given character is the start of some kind of
579/// balanced punctuation (e.g., quotes or parentheses), return the
580/// character that will terminate the punctuation.
581///
582/// \returns The ending punctuation character, if any, or the NULL
583/// character if the input character does not start any punctuation.
584static inline char findMatchingPunctuation(char c) {
585 switch (c) {
586 case '\'': return '\'';
587 case '`': return '\'';
588 case '"': return '"';
589 case '(': return ')';
590 case '[': return ']';
591 case '{': return '}';
592 default: break;
593 }
594
595 return 0;
596}
597
598/// Find the end of the word starting at the given offset
599/// within a string.
600///
601/// \returns the index pointing one character past the end of the
602/// word.
603static unsigned findEndOfWord(unsigned Start, StringRef Str,
604 unsigned Length, unsigned Column,
605 unsigned Columns) {
606 assert(Start < Str.size() && "Invalid start position!");
607 unsigned End = Start + 1;
608
609 // If we are already at the end of the string, take that as the word.
610 if (End == Str.size())
611 return End;
612
613 // Determine if the start of the string is actually opening
614 // punctuation, e.g., a quote or parentheses.
615 char EndPunct = findMatchingPunctuation(Str[Start]);
616 if (!EndPunct) {
617 // This is a normal word. Just find the first space character.
618 while (End < Length && !isWhitespace(Str[End]))
619 ++End;
620 return End;
621 }
622
623 // We have the start of a balanced punctuation sequence (quotes,
624 // parentheses, etc.). Determine the full sequence is.
625 SmallString<16> PunctuationEndStack;
626 PunctuationEndStack.push_back(EndPunct);
627 while (End < Length && !PunctuationEndStack.empty()) {
628 if (Str[End] == PunctuationEndStack.back())
629 PunctuationEndStack.pop_back();
630 else if (char SubEndPunct = findMatchingPunctuation(Str[End]))
631 PunctuationEndStack.push_back(SubEndPunct);
632
633 ++End;
634 }
635
636 // Find the first space character after the punctuation ended.
637 while (End < Length && !isWhitespace(Str[End]))
638 ++End;
639
640 unsigned PunctWordLength = End - Start;
641 if (// If the word fits on this line
642 Column + PunctWordLength <= Columns ||
643 // ... or the word is "short enough" to take up the next line
644 // without too much ugly white space
645 PunctWordLength < Columns/3)
646 return End; // Take the whole thing as a single "word".
647
648 // The whole quoted/parenthesized string is too long to print as a
649 // single "word". Instead, find the "word" that starts just after
650 // the punctuation and use that end-point instead. This will recurse
651 // until it finds something small enough to consider a word.
652 return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
653}
654
655/// Print the given string to a stream, word-wrapping it to
656/// some number of columns in the process.
657///
658/// \param OS the stream to which the word-wrapping string will be
659/// emitted.
660/// \param Str the string to word-wrap and output.
661/// \param Columns the number of columns to word-wrap to.
662/// \param Column the column number at which the first character of \p
663/// Str will be printed. This will be non-zero when part of the first
664/// line has already been printed.
665/// \param Bold if the current text should be bold
666/// \returns true if word-wrapping was required, or false if the
667/// string fit on the first line.
668static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns,
669 unsigned Column, bool Bold) {
670 const unsigned Length = std::min(Str.find('\n'), Str.size());
671 bool TextNormal = true;
672
673 bool Wrapped = false;
674 for (unsigned WordStart = 0, WordEnd; WordStart < Length;
675 WordStart = WordEnd) {
676 // Find the beginning of the next word.
677 WordStart = skipWhitespace(WordStart, Str, Length);
678 if (WordStart == Length)
679 break;
680
681 // Find the end of this word.
682 WordEnd = findEndOfWord(WordStart, Str, Length, Column, Columns);
683
684 // Does this word fit on the current line?
685 unsigned WordLength = WordEnd - WordStart;
686 if (Column + WordLength < Columns) {
687 // This word fits on the current line; print it there.
688 if (WordStart) {
689 OS << ' ';
690 Column += 1;
691 }
692 applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),
693 TextNormal, Bold);
694 Column += WordLength;
695 continue;
696 }
697
698 // This word does not fit on the current line, so wrap to the next
699 // line.
700 OS << '\n';
701 OS.indent(WordWrapIndentation);
702 applyTemplateHighlighting(OS, Str.substr(WordStart, WordLength),
703 TextNormal, Bold);
704 Column = WordWrapIndentation + WordLength;
705 Wrapped = true;
706 }
707
708 // Append any remaning text from the message with its existing formatting.
709 applyTemplateHighlighting(OS, Str.substr(Length), TextNormal, Bold);
710
711 assert(TextNormal && "Text highlighted at end of diagnostic message.");
712
713 return Wrapped;
714}
715
720
722
725 StringRef Message, ArrayRef<clang::CharSourceRange> Ranges,
727 uint64_t StartOfLocationInfo = OS.getColumn();
728
729 // Emit the location of this particular diagnostic.
730 if (Loc.isValid())
731 emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
732
733 if (DiagOpts.showColors(OS.has_colors()))
734 OS.resetColor();
735
736 if (DiagOpts.ShowLevel)
737 printDiagnosticLevel(OS, Level, DiagOpts.showColors(OS.has_colors()));
739 /*IsSupplemental*/ Level == DiagnosticsEngine::Note,
740 Message, OS.getColumn() - StartOfLocationInfo,
741 DiagOpts.MessageLength,
742 DiagOpts.showColors(OS.has_colors()));
743 // We use a formatted ostream, which does its own buffering. Flush here
744 // so we keep the proper order of output.
745 OS.flush();
746}
747
748/*static*/ void
751 bool ShowColors) {
752 if (ShowColors) {
753 // Print diagnostic category in bold and color
754 switch (Level) {
756 llvm_unreachable("Invalid diagnostic type");
758 OS.changeColor(NoteColor, true);
759 break;
761 OS.changeColor(RemarkColor, true);
762 break;
764 OS.changeColor(WarningColor, true);
765 break;
767 OS.changeColor(ErrorColor, true);
768 break;
770 OS.changeColor(FatalColor, true);
771 break;
772 }
773 }
774
775 switch (Level) {
777 llvm_unreachable("Invalid diagnostic type");
778 case DiagnosticsEngine::Note: OS << "note: "; break;
779 case DiagnosticsEngine::Remark: OS << "remark: "; break;
780 case DiagnosticsEngine::Warning: OS << "warning: "; break;
781 case DiagnosticsEngine::Error: OS << "error: "; break;
782 case DiagnosticsEngine::Fatal: OS << "fatal error: "; break;
783 }
784
785 if (ShowColors)
786 OS.resetColor();
787}
788
789/*static*/
791 bool IsSupplemental,
792 StringRef Message,
793 unsigned CurrentColumn,
794 unsigned Columns, bool ShowColors) {
795 bool Bold = false;
796 if (ShowColors && !IsSupplemental) {
797 // Print primary diagnostic messages in bold and without color, to visually
798 // indicate the transition from continuation notes and other output.
799 OS.changeColor(SavedColor, true);
800 Bold = true;
801 }
802
803 if (Columns)
804 printWordWrapped(OS, Message, Columns, CurrentColumn, Bold);
805 else {
806 bool Normal = true;
807 applyTemplateHighlighting(OS, Message, Normal, Bold);
808 assert(Normal && "Formatting should have returned to normal");
809 }
810
811 if (ShowColors)
812 OS.resetColor();
813 OS << '\n';
814}
815
816void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
817#ifdef _WIN32
818 SmallString<4096> TmpFilename;
819#endif
820 if (DiagOpts.AbsolutePath) {
821 auto File = SM.getFileManager().getOptionalFileRef(Filename);
822 if (File) {
823 // We want to print a simplified absolute path, i. e. without "dots".
824 //
825 // The hardest part here are the paths like "<part1>/<link>/../<part2>".
826 // On Unix-like systems, we cannot just collapse "<link>/..", because
827 // paths are resolved sequentially, and, thereby, the path
828 // "<part1>/<part2>" may point to a different location. That is why
829 // we use FileManager::getCanonicalName(), which expands all indirections
830 // with llvm::sys::fs::real_path() and caches the result.
831 //
832 // On the other hand, it would be better to preserve as much of the
833 // original path as possible, because that helps a user to recognize it.
834 // real_path() expands all links, which sometimes too much. Luckily,
835 // on Windows we can just use llvm::sys::path::remove_dots(), because,
836 // on that system, both aforementioned paths point to the same place.
837#ifdef _WIN32
838 TmpFilename = File->getName();
839 SM.getFileManager().makeAbsolutePath(TmpFilename);
840 llvm::sys::path::native(TmpFilename);
841 llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
842 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
843#else
844 Filename = SM.getFileManager().getCanonicalName(*File);
845#endif
846 }
847 }
848
849 OS << Filename;
850}
851
852/// Print out the file/line/column information and include trace.
853///
854/// This method handles the emission of the diagnostic location information.
855/// This includes extracting as much location information as is present for
856/// the diagnostic and printing it, as well as any include stack or source
857/// ranges necessary.
861 if (PLoc.isInvalid()) {
862 // At least print the file name if available:
863 if (FileID FID = Loc.getFileID(); FID.isValid()) {
864 if (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {
865 emitFilename(FE->getName(), Loc.getManager());
866 OS << ": ";
867 }
868 }
869 return;
870 }
871 unsigned LineNo = PLoc.getLine();
872
873 if (!DiagOpts.ShowLocation)
874 return;
875
876 if (DiagOpts.showColors(OS.has_colors()))
877 OS.changeColor(SavedColor, true);
878
879 emitFilename(PLoc.getFilename(), Loc.getManager());
880 switch (DiagOpts.getFormat()) {
883 if (DiagOpts.ShowLine)
884 OS << ':' << LineNo;
885 break;
886 case DiagnosticOptions::MSVC: OS << '(' << LineNo; break;
887 case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
888 }
889
890 if (DiagOpts.ShowColumn)
891 // Compute the column number.
892 if (unsigned ColNo = PLoc.getColumn()) {
893 if (DiagOpts.getFormat() == DiagnosticOptions::MSVC) {
894 OS << ',';
895 // Visual Studio 2010 or earlier expects column number to be off by one
896 if (LangOpts.MSCompatibilityVersion &&
897 !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
898 ColNo--;
899 } else
900 OS << ':';
901 OS << ColNo;
902 }
903 switch (DiagOpts.getFormat()) {
906 case DiagnosticOptions::Vi: OS << ':'; break;
908 // MSVC2013 and before print 'file(4) : error'. MSVC2015 gets rid of the
909 // space and prints 'file(4): error'.
910 OS << ')';
911 if (LangOpts.MSCompatibilityVersion &&
912 !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
913 OS << ' ';
914 OS << ':';
915 break;
916 }
917
918 if (DiagOpts.ShowSourceRanges && !Ranges.empty()) {
919 FileID CaretFileID = Loc.getExpansionLoc().getFileID();
920 bool PrintedRange = false;
921 const SourceManager &SM = Loc.getManager();
922
923 for (const auto &R : Ranges) {
924 // Ignore invalid ranges.
925 if (!R.isValid())
926 continue;
927
928 SourceLocation B = SM.getExpansionLoc(R.getBegin());
929 CharSourceRange ERange = SM.getExpansionRange(R.getEnd());
930 SourceLocation E = ERange.getEnd();
931
932 // If the start or end of the range is in another file, just
933 // discard it.
934 if (SM.getFileID(B) != CaretFileID || SM.getFileID(E) != CaretFileID)
935 continue;
936
937 // Add in the length of the token, so that we cover multi-char
938 // tokens.
939 unsigned TokSize = 0;
940 if (ERange.isTokenRange())
942
943 FullSourceLoc BF(B, SM), EF(E, SM);
944 OS << '{'
945 << BF.getLineNumber() << ':' << BF.getColumnNumber() << '-'
946 << EF.getLineNumber() << ':' << (EF.getColumnNumber() + TokSize)
947 << '}';
948 PrintedRange = true;
949 }
950
951 if (PrintedRange)
952 OS << ':';
953 }
954 OS << ' ';
955}
956
958 if (DiagOpts.ShowLocation && PLoc.isValid()) {
959 OS << "In file included from ";
960 emitFilename(PLoc.getFilename(), Loc.getManager());
961 OS << ':' << PLoc.getLine() << ":\n";
962 } else
963 OS << "In included file:\n";
964}
965
967 StringRef ModuleName) {
968 if (DiagOpts.ShowLocation && PLoc.isValid())
969 OS << "In module '" << ModuleName << "' imported from "
970 << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
971 else
972 OS << "In module '" << ModuleName << "':\n";
973}
974
976 PresumedLoc PLoc,
977 StringRef ModuleName) {
978 if (DiagOpts.ShowLocation && PLoc.isValid())
979 OS << "While building module '" << ModuleName << "' imported from "
980 << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
981 else
982 OS << "While building module '" << ModuleName << "':\n";
983}
984
985/// Find the suitable set of lines to show to include a set of ranges.
986static std::optional<std::pair<unsigned, unsigned>>
988 const SourceManager &SM) {
989 if (!R.isValid())
990 return std::nullopt;
991
992 SourceLocation Begin = R.getBegin();
993 SourceLocation End = R.getEnd();
994 if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
995 return std::nullopt;
996
997 return std::make_pair(SM.getExpansionLineNumber(Begin),
998 SM.getExpansionLineNumber(End));
999}
1000
1001/// Add as much of range B into range A as possible without exceeding a maximum
1002/// size of MaxRange. Ranges are inclusive.
1003static std::pair<unsigned, unsigned>
1004maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
1005 unsigned MaxRange) {
1006 // If A is already the maximum size, we're done.
1007 unsigned Slack = MaxRange - (A.second - A.first + 1);
1008 if (Slack == 0)
1009 return A;
1010
1011 // Easy case: merge succeeds within MaxRange.
1012 unsigned Min = std::min(A.first, B.first);
1013 unsigned Max = std::max(A.second, B.second);
1014 if (Max - Min + 1 <= MaxRange)
1015 return {Min, Max};
1016
1017 // If we can't reach B from A within MaxRange, there's nothing to do.
1018 // Don't add lines to the range that contain nothing interesting.
1019 if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
1020 (B.second < A.second && A.second - B.second + 1 > MaxRange))
1021 return A;
1022
1023 // Otherwise, expand A towards B to produce a range of size MaxRange. We
1024 // attempt to expand by the same amount in both directions if B strictly
1025 // contains A.
1026
1027 // Expand downwards by up to half the available amount, then upwards as
1028 // much as possible, then downwards as much as possible.
1029 A.second = std::min(A.second + (Slack + 1) / 2, Max);
1030 Slack = MaxRange - (A.second - A.first + 1);
1031 A.first = std::max(Min + Slack, A.first) - Slack;
1032 A.second = std::min(A.first + MaxRange - 1, Max);
1033 return A;
1034}
1035
1037 unsigned LineNo;
1039 Bytes EndByte;
1040};
1041
1042/// Highlight \p R (with ~'s) on the current source line.
1043static void highlightRange(const LineRange &R, const SourceColumnMap &Map,
1044 std::string &CaretLine) {
1045 // Pick the first non-whitespace column.
1046 Bytes StartByte = R.StartByte;
1047 while (StartByte < Map.bytes() && (Map.getSourceLine()[StartByte.V] == ' ' ||
1048 Map.getSourceLine()[StartByte.V] == '\t'))
1049 StartByte = Map.startOfNextColumn(StartByte);
1050
1051 // Pick the last non-whitespace column.
1052 Bytes EndByte = std::min(R.EndByte.V, Map.bytes().V);
1053 while (EndByte.V != 0 && (Map.getSourceLine()[EndByte.V - 1] == ' ' ||
1054 Map.getSourceLine()[EndByte.V - 1] == '\t'))
1055 EndByte = Map.startOfPreviousColumn(EndByte);
1056
1057 // If the start/end passed each other, then we are trying to highlight a
1058 // range that just exists in whitespace. That most likely means we have
1059 // a multi-line highlighting range that covers a blank line.
1060 if (StartByte > EndByte)
1061 return;
1062
1063 assert(StartByte <= EndByte && "Invalid range!");
1064 // Fill the range with ~'s.
1065 Columns StartCol = Map.byteToContainingColumn(StartByte);
1066 Columns EndCol = Map.byteToContainingColumn(EndByte);
1067
1068 if (CaretLine.size() < static_cast<size_t>(EndCol.V))
1069 CaretLine.resize(EndCol.V, ' ');
1070
1071 std::fill(CaretLine.begin() + StartCol.V, CaretLine.begin() + EndCol.V, '~');
1072}
1073
1074static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo,
1075 const SourceColumnMap &map,
1076 ArrayRef<FixItHint> Hints,
1077 const SourceManager &SM,
1078 const DiagnosticOptions &DiagOpts) {
1079 std::string FixItInsertionLine;
1080 if (Hints.empty() || !DiagOpts.ShowFixits)
1081 return FixItInsertionLine;
1082 Columns PrevHintEndCol = 0;
1083
1084 for (const auto &H : Hints) {
1085 if (H.CodeToInsert.empty())
1086 continue;
1087
1088 // We have an insertion hint. Determine whether the inserted
1089 // code contains no newlines and is on the same line as the caret.
1090 FileIDAndOffset HintLocInfo =
1091 SM.getDecomposedExpansionLoc(H.RemoveRange.getBegin());
1092 if (FID == HintLocInfo.first &&
1093 LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
1094 StringRef(H.CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
1095 // Insert the new code into the line just below the code
1096 // that the user wrote.
1097 // Note: When modifying this function, be very careful about what is a
1098 // "column" (printed width, platform-dependent) and what is a
1099 // "byte offset" (SourceManager "column").
1100 Bytes HintByteOffset =
1101 Bytes(SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second))
1102 .prev();
1103
1104 // The hint must start inside the source or right at the end
1105 assert(HintByteOffset < map.bytes().next());
1106 Columns HintCol = map.byteToContainingColumn(HintByteOffset);
1107
1108 // If we inserted a long previous hint, push this one forwards, and add
1109 // an extra space to show that this is not part of the previous
1110 // completion. This is sort of the best we can do when two hints appear
1111 // to overlap.
1112 //
1113 // Note that if this hint is located immediately after the previous
1114 // hint, no space will be added, since the location is more important.
1115 if (HintCol < PrevHintEndCol)
1116 HintCol = PrevHintEndCol + 1;
1117
1118 // This should NOT use HintByteOffset, because the source might have
1119 // Unicode characters in earlier columns.
1120 Columns NewFixItLineSize = Columns(FixItInsertionLine.size()) +
1121 (HintCol - PrevHintEndCol) +
1122 Columns(H.CodeToInsert.size());
1123 if (NewFixItLineSize > FixItInsertionLine.size())
1124 FixItInsertionLine.resize(NewFixItLineSize.V, ' ');
1125
1126 std::copy(H.CodeToInsert.begin(), H.CodeToInsert.end(),
1127 FixItInsertionLine.end() - H.CodeToInsert.size());
1128
1129 PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(H.CodeToInsert);
1130 }
1131 }
1132
1133 expandTabs(FixItInsertionLine, DiagOpts.TabStop);
1134
1135 return FixItInsertionLine;
1136}
1137
1138static unsigned getNumDisplayWidth(unsigned N) {
1139 unsigned L = 1u, M = 10u;
1140 while (M <= N && ++L != std::numeric_limits<unsigned>::digits10 + 1)
1141 M *= 10u;
1142
1143 return L;
1144}
1145
1146/// Filter out invalid ranges, ranges that don't fit into the window of
1147/// source lines we will print, and ranges from other files.
1148///
1149/// For the remaining ranges, convert them to simple LineRange structs,
1150/// which only cover one line at a time.
1153 const SourceManager &SM,
1154 const std::pair<unsigned, unsigned> &Lines, FileID FID,
1155 const LangOptions &LangOpts) {
1156 SmallVector<LineRange> LineRanges;
1157
1158 for (const CharSourceRange &R : Ranges) {
1159 if (R.isInvalid())
1160 continue;
1161 SourceLocation Begin = R.getBegin();
1162 SourceLocation End = R.getEnd();
1163
1164 unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
1165 if (StartLineNo > Lines.second || SM.getFileID(Begin) != FID)
1166 continue;
1167
1168 unsigned EndLineNo = SM.getExpansionLineNumber(End);
1169 if (EndLineNo < Lines.first || SM.getFileID(End) != FID)
1170 continue;
1171
1172 Bytes StartByte = SM.getExpansionColumnNumber(Begin);
1173 Bytes EndByte = SM.getExpansionColumnNumber(End);
1174 assert(StartByte.V != 0 && "StartByte must be valid, 0 is invalid");
1175 assert(EndByte.V != 0 && "EndByte must be valid, 0 is invalid");
1176 if (R.isTokenRange())
1177 EndByte += Bytes(Lexer::MeasureTokenLength(End, SM, LangOpts));
1178
1179 // Only a single line.
1180 if (StartLineNo == EndLineNo) {
1181 LineRanges.push_back({StartLineNo, StartByte.prev(), EndByte.prev()});
1182 continue;
1183 }
1184
1185 // Start line.
1186 LineRanges.push_back(
1187 {StartLineNo, StartByte.prev(), std::numeric_limits<int>::max()});
1188
1189 // Middle lines.
1190 for (unsigned S = StartLineNo + 1; S != EndLineNo; ++S)
1191 LineRanges.push_back({S, 0, std::numeric_limits<int>::max()});
1192
1193 // End line.
1194 LineRanges.push_back({EndLineNo, 0, EndByte.prev()});
1195 }
1196
1197 return LineRanges;
1198}
1199
1200/// Creates syntax highlighting information in form of StyleRanges.
1201///
1202/// The returned unique ptr has always exactly size
1203/// (\p EndLineNumber - \p StartLineNumber + 1). Each SmallVector in there
1204/// corresponds to syntax highlighting information in one line. In each line,
1205/// the StyleRanges are non-overlapping and sorted from start to end of the
1206/// line.
1207static std::unique_ptr<llvm::SmallVector<TextDiagnostic::StyleRange>[]>
1208highlightLines(StringRef FileData, unsigned StartLineNumber,
1209 unsigned EndLineNumber, const Preprocessor *PP,
1210 const LangOptions &LangOpts, bool ShowColors, FileID FID,
1211 const SourceManager &SM) {
1212 assert(StartLineNumber <= EndLineNumber);
1213 auto SnippetRanges =
1214 std::make_unique<SmallVector<TextDiagnostic::StyleRange>[]>(
1215 EndLineNumber - StartLineNumber + 1);
1216
1217 if (!PP || !ShowColors)
1218 return SnippetRanges;
1219
1220 // Might cause emission of another diagnostic.
1222 return SnippetRanges;
1223
1224 auto Buff = llvm::MemoryBuffer::getMemBuffer(FileData);
1225 Lexer L{FID, *Buff, SM, LangOpts};
1226 L.SetKeepWhitespaceMode(true);
1227
1228 const char *FirstLineStart =
1229 FileData.data() +
1230 SM.getDecomposedLoc(SM.translateLineCol(FID, StartLineNumber, 1)).second;
1231 if (const char *CheckPoint = PP->getCheckPoint(FID, FirstLineStart)) {
1232 assert(CheckPoint >= Buff->getBufferStart() &&
1233 CheckPoint <= Buff->getBufferEnd());
1234 assert(CheckPoint <= FirstLineStart);
1235 size_t Offset = CheckPoint - Buff->getBufferStart();
1236 L.seek(Offset, /*IsAtStartOfLine=*/false);
1237 }
1238
1239 // Classify the given token and append it to the given vector.
1240 auto appendStyle =
1241 [PP, &LangOpts](SmallVector<TextDiagnostic::StyleRange> &Vec,
1242 const Token &T, unsigned Start, unsigned Length) -> void {
1243 if (T.is(tok::raw_identifier)) {
1244 StringRef RawIdent = T.getRawIdentifier();
1245 // Special case true/false/nullptr/... literals, since they will otherwise
1246 // be treated as keywords.
1247 // FIXME: It would be good to have a programmatic way of getting this
1248 // list.
1249 if (llvm::StringSwitch<bool>(RawIdent)
1250 .Case("true", true)
1251 .Case("false", true)
1252 .Case("nullptr", true)
1253 .Case("__func__", true)
1254 .Case("__objc_yes__", true)
1255 .Case("__objc_no__", true)
1256 .Case("__null", true)
1257 .Case("__FUNCDNAME__", true)
1258 .Case("__FUNCSIG__", true)
1259 .Case("__FUNCTION__", true)
1260 .Case("__FUNCSIG__", true)
1261 .Default(false)) {
1262 Vec.emplace_back(Start, Start + Length, LiteralColor);
1263 } else {
1264 const IdentifierInfo *II = PP->getIdentifierInfo(RawIdent);
1265 assert(II);
1266 if (II->isKeyword(LangOpts))
1267 Vec.emplace_back(Start, Start + Length, KeywordColor);
1268 }
1269 } else if (tok::isLiteral(T.getKind())) {
1270 Vec.emplace_back(Start, Start + Length, LiteralColor);
1271 } else {
1272 assert(T.is(tok::comment));
1273 Vec.emplace_back(Start, Start + Length, CommentColor);
1274 }
1275 };
1276
1277 bool Stop = false;
1278 while (!Stop) {
1279 Token T;
1280 Stop = L.LexFromRawLexer(T);
1281 if (T.is(tok::unknown))
1282 continue;
1283
1284 // We are only interested in identifiers, literals and comments.
1285 if (!T.is(tok::raw_identifier) && !T.is(tok::comment) &&
1286 !tok::isLiteral(T.getKind()))
1287 continue;
1288
1289 bool Invalid = false;
1290 unsigned TokenEndLine = SM.getSpellingLineNumber(T.getEndLoc(), &Invalid);
1291 if (Invalid || TokenEndLine < StartLineNumber)
1292 continue;
1293
1294 assert(TokenEndLine >= StartLineNumber);
1295
1296 unsigned TokenStartLine =
1297 SM.getSpellingLineNumber(T.getLocation(), &Invalid);
1298 if (Invalid)
1299 continue;
1300 // If this happens, we're done.
1301 if (TokenStartLine > EndLineNumber)
1302 break;
1303
1304 Bytes StartCol = SM.getSpellingColumnNumber(T.getLocation(), &Invalid) - 1;
1305 if (Invalid)
1306 continue;
1307
1308 // Simple tokens.
1309 if (TokenStartLine == TokenEndLine) {
1311 SnippetRanges[TokenStartLine - StartLineNumber];
1312 appendStyle(LineRanges, T, StartCol.V, T.getLength());
1313 continue;
1314 }
1315 assert((TokenEndLine - TokenStartLine) >= 1);
1316
1317 // For tokens that span multiple lines (think multiline comments), we
1318 // divide them into multiple StyleRanges.
1319 Bytes EndCol = SM.getSpellingColumnNumber(T.getEndLoc(), &Invalid) - 1;
1320 if (Invalid)
1321 continue;
1322
1323 std::string Spelling = Lexer::getSpelling(T, SM, LangOpts);
1324
1325 unsigned L = TokenStartLine;
1326 unsigned LineLength = 0;
1327 for (unsigned I = 0; I <= Spelling.size(); ++I) {
1328 // This line is done.
1329 if (I == Spelling.size() || isVerticalWhitespace(Spelling[I])) {
1330 if (L >= StartLineNumber) {
1332 SnippetRanges[L - StartLineNumber];
1333
1334 if (L == TokenStartLine) // First line
1335 appendStyle(LineRanges, T, StartCol.V, LineLength);
1336 else if (L == TokenEndLine) // Last line
1337 appendStyle(LineRanges, T, 0, EndCol.V);
1338 else
1339 appendStyle(LineRanges, T, 0, LineLength);
1340 }
1341
1342 ++L;
1343 if (L > EndLineNumber)
1344 break;
1345 LineLength = 0;
1346 continue;
1347 }
1348 ++LineLength;
1349 }
1350 }
1351
1352 return SnippetRanges;
1353}
1354
1355/// Emit a code snippet and caret line.
1356///
1357/// This routine emits a single line's code snippet and caret line..
1358///
1359/// \param Loc The location for the caret.
1360/// \param Ranges The underlined ranges for this code snippet.
1361/// \param Hints The FixIt hints active for this diagnostic.
1362void TextDiagnostic::emitSnippetAndCaret(
1365 assert(Loc.isValid() && "must have a valid source location here");
1366 assert(Loc.isFileID() && "must have a file location here");
1367
1368 // If caret diagnostics are enabled and we have location, we want to
1369 // emit the caret. However, we only do this if the location moved
1370 // from the last diagnostic, if the last diagnostic was a note that
1371 // was part of a different warning or error diagnostic, or if the
1372 // diagnostic has ranges. We don't want to emit the same caret
1373 // multiple times if one loc has multiple diagnostics.
1374 if (!DiagOpts.ShowCarets)
1375 return;
1376 if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
1378 return;
1379
1380 FileID FID = Loc.getFileID();
1381 const SourceManager &SM = Loc.getManager();
1382
1383 // Get information about the buffer it points into.
1384 bool Invalid = false;
1385 StringRef BufData = Loc.getBufferData(&Invalid);
1386 if (Invalid)
1387 return;
1388 const char *BufStart = BufData.data();
1389 const char *BufEnd = BufStart + BufData.size();
1390
1391 unsigned CaretLineNo = Loc.getLineNumber();
1392 Bytes CaretByte = Loc.getColumnNumber();
1393
1394 // Arbitrarily stop showing snippets when the line is too long.
1395 static const size_t MaxLineLengthToPrint = 4096;
1396 if (CaretByte > MaxLineLengthToPrint)
1397 return;
1398
1399 // Find the set of lines to include.
1400 const unsigned MaxLines = DiagOpts.SnippetLineLimit;
1401 std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
1402 unsigned DisplayLineNo = Loc.getPresumedLoc().getLine();
1403 for (const auto &I : Ranges) {
1404 if (auto OptionalRange = findLinesForRange(I, FID, SM))
1405 Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
1406
1407 DisplayLineNo =
1408 std::min(DisplayLineNo, SM.getPresumedLineNumber(I.getBegin()));
1409 }
1410
1411 // Our line numbers look like:
1412 // " [number] | "
1413 // Where [number] is MaxLineNoDisplayWidth columns
1414 // and the full thing is therefore MaxLineNoDisplayWidth + 4 columns.
1415 unsigned MaxLineNoDisplayWidth =
1416 DiagOpts.ShowLineNumbers
1417 ? std::max(4u, getNumDisplayWidth(DisplayLineNo + MaxLines))
1418 : 0;
1419 auto indentForLineNumbers = [&] {
1420 if (MaxLineNoDisplayWidth > 0)
1421 OS.indent(MaxLineNoDisplayWidth + 2) << "| ";
1422 };
1423
1424 Columns MessageLength = DiagOpts.MessageLength;
1425 // If we don't have enough columns available, just abort now.
1426 if (MessageLength != 0 && MessageLength <= Columns(MaxLineNoDisplayWidth + 4))
1427 return;
1428
1429 // Prepare source highlighting information for the lines we're about to
1430 // emit, starting from the first line.
1431 std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles =
1432 highlightLines(BufData, Lines.first, Lines.second, PP, LangOpts,
1433 DiagOpts.showColors(OS.has_colors()), FID, SM);
1434
1435 SmallVector<LineRange> LineRanges =
1436 prepareAndFilterRanges(Ranges, SM, Lines, FID, LangOpts);
1437
1438 for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1;
1439 ++LineNo, ++DisplayLineNo) {
1440 // Rewind from the current position to the start of the line.
1441 const char *LineStart =
1442 BufStart +
1443 SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
1444 if (LineStart == BufEnd)
1445 break;
1446
1447 // Compute the line end.
1448 const char *LineEnd = LineStart;
1449 while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
1450 ++LineEnd;
1451
1452 // Arbitrarily stop showing snippets when the line is too long.
1453 // FIXME: Don't print any lines in this case.
1454 if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
1455 return;
1456
1457 // Copy the line of code into an std::string for ease of manipulation.
1458 std::string SourceLine(LineStart, LineEnd);
1459 // Remove trailing null bytes.
1460 while (!SourceLine.empty() && SourceLine.back() == '\0' &&
1461 (LineNo != CaretLineNo ||
1462 SourceLine.size() > static_cast<size_t>(CaretByte.V)))
1463 SourceLine.pop_back();
1464
1465 // Build the byte to column map.
1466 const SourceColumnMap SourceColMap(SourceLine, DiagOpts.TabStop);
1467
1468 std::string CaretLine;
1469 // Highlight all of the characters covered by Ranges with ~ characters.
1470 for (const auto &LR : LineRanges) {
1471 if (LR.LineNo == LineNo)
1472 highlightRange(LR, SourceColMap, CaretLine);
1473 }
1474
1475 // Next, insert the caret itself.
1476 if (CaretLineNo == LineNo) {
1477 Columns Col = SourceColMap.byteToContainingColumn(CaretByte.prev());
1478 CaretLine.resize(
1479 std::max(static_cast<size_t>(Col.V) + 1, CaretLine.size()), ' ');
1480 CaretLine[Col.V] = '^';
1481 }
1482
1483 std::string FixItInsertionLine =
1484 buildFixItInsertionLine(FID, LineNo, SourceColMap, Hints, SM, DiagOpts);
1485
1486 // If the source line is too long for our terminal, select only the
1487 // "interesting" source region within that line.
1488 if (MessageLength != 0) {
1489 Columns NonGutterColumns = MessageLength;
1490 if (MaxLineNoDisplayWidth != 0)
1491 NonGutterColumns -= Columns(MaxLineNoDisplayWidth + 4);
1492 selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
1493 NonGutterColumns, SourceColMap,
1494 SourceStyles[LineNo - Lines.first]);
1495 }
1496
1497 // If we are in -fdiagnostics-print-source-range-info mode, we are trying
1498 // to produce easily machine parsable output. Add a space before the
1499 // source line and the caret to make it trivial to tell the main diagnostic
1500 // line from what the user is intended to see.
1501 if (DiagOpts.ShowSourceRanges && !SourceLine.empty()) {
1502 SourceLine = ' ' + SourceLine;
1503 CaretLine = ' ' + CaretLine;
1504 }
1505
1506 // Emit what we have computed.
1507 emitSnippet(SourceLine, MaxLineNoDisplayWidth, LineNo, DisplayLineNo,
1508 SourceStyles[LineNo - Lines.first]);
1509
1510 if (!CaretLine.empty()) {
1511 indentForLineNumbers();
1512 if (DiagOpts.showColors(OS.has_colors()))
1513 OS.changeColor(CaretColor, true);
1514 OS << CaretLine << '\n';
1515 if (DiagOpts.showColors(OS.has_colors()))
1516 OS.resetColor();
1517 }
1518
1519 if (!FixItInsertionLine.empty()) {
1520 indentForLineNumbers();
1521 if (DiagOpts.showColors(OS.has_colors()))
1522 // Print fixit line in color
1523 OS.changeColor(FixitColor, false);
1524 if (DiagOpts.ShowSourceRanges)
1525 OS << ' ';
1526 OS << FixItInsertionLine << '\n';
1527 if (DiagOpts.showColors(OS.has_colors()))
1528 OS.resetColor();
1529 }
1530 }
1531
1532 // Print out any parseable fixit information requested by the options.
1533 emitParseableFixits(Hints, SM);
1534}
1535
1536void TextDiagnostic::emitSnippet(StringRef SourceLine,
1537 unsigned MaxLineNoDisplayWidth,
1538 unsigned LineNo, unsigned DisplayLineNo,
1539 ArrayRef<StyleRange> Styles) {
1540 // Emit line number.
1541 if (MaxLineNoDisplayWidth > 0) {
1542 unsigned LineNoDisplayWidth = getNumDisplayWidth(DisplayLineNo);
1543 OS.indent(MaxLineNoDisplayWidth - LineNoDisplayWidth + 1)
1544 << DisplayLineNo << " | ";
1545 }
1546
1547 // Print the source line one character at a time.
1548 bool PrintReversed = false;
1549 std::optional<llvm::raw_ostream::Colors> CurrentColor;
1550 size_t I = 0; // Bytes.
1551 while (I < SourceLine.size()) {
1552 auto [Str, WasPrintable] =
1553 printableTextForNextCharacter(SourceLine, &I, DiagOpts.TabStop);
1554
1555 // Toggle inverted colors on or off for this character.
1556 if (DiagOpts.showColors(OS.has_colors())) {
1557 if (WasPrintable == PrintReversed) {
1558 PrintReversed = !PrintReversed;
1559 if (PrintReversed)
1560 OS.reverseColor();
1561 else {
1562 OS.resetColor();
1563 CurrentColor = std::nullopt;
1564 }
1565 }
1566
1567 // Apply syntax highlighting information.
1568 const auto *CharStyle = llvm::find_if(Styles, [I](const StyleRange &R) {
1569 return (R.Start < I && R.End >= I);
1570 });
1571
1572 if (CharStyle != Styles.end()) {
1573 if (!CurrentColor ||
1574 (CurrentColor && *CurrentColor != CharStyle->Color)) {
1575 OS.changeColor(CharStyle->Color);
1576 CurrentColor = CharStyle->Color;
1577 }
1578 } else if (CurrentColor) {
1579 OS.resetColor();
1580 CurrentColor = std::nullopt;
1581 }
1582 }
1583
1584 OS << Str;
1585 }
1586
1587 if (DiagOpts.showColors(OS.has_colors()))
1588 OS.resetColor();
1589
1590 OS << '\n';
1591}
1592
1593void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
1594 const SourceManager &SM) {
1595 if (!DiagOpts.ShowParseableFixits)
1596 return;
1597
1598 // We follow FixItRewriter's example in not (yet) handling
1599 // fix-its in macros.
1600 for (const auto &H : Hints) {
1601 if (H.RemoveRange.isInvalid() || H.RemoveRange.getBegin().isMacroID() ||
1602 H.RemoveRange.getEnd().isMacroID())
1603 return;
1604 }
1605
1606 for (const auto &H : Hints) {
1607 SourceLocation BLoc = H.RemoveRange.getBegin();
1608 SourceLocation ELoc = H.RemoveRange.getEnd();
1609
1610 FileIDAndOffset BInfo = SM.getDecomposedLoc(BLoc);
1611 FileIDAndOffset EInfo = SM.getDecomposedLoc(ELoc);
1612
1613 // Adjust for token ranges.
1614 if (H.RemoveRange.isTokenRange())
1615 EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
1616
1617 // We specifically do not do word-wrapping or tab-expansion here,
1618 // because this is supposed to be easy to parse.
1619 PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
1620 if (PLoc.isInvalid())
1621 break;
1622
1623 OS << "fix-it:\"";
1624 OS.write_escaped(PLoc.getFilename());
1625 OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
1626 << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
1627 << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
1628 << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
1629 << "}:\"";
1630 OS.write_escaped(H.CodeToInsert);
1631 OS << "\"\n";
1632 }
1633}
#define V(N, I)
static StringRef bytes(const std::vector< T, Allocator > &v)
static size_t getNumDisplayWidth(size_t N)
Definition Disasm.cpp:134
Defines the clang::FileManager interface and associated types.
static SmallVectorImpl< char > & operator+=(SmallVectorImpl< char > &Includes, StringRef RHS)
#define SM(sm)
Defines the clang::Preprocessor interface.
Defines the SourceManager interface.
static int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i)
static constexpr raw_ostream::Colors SavedColor
static std::pair< unsigned, unsigned > maybeAddRange(std::pair< unsigned, unsigned > A, std::pair< unsigned, unsigned > B, unsigned MaxRange)
Add as much of range B into range A as possible without exceeding a maximum size of MaxRange.
static void genColumnByteMapping(StringRef SourceLine, unsigned TabStop, SmallVectorImpl< Bytes > &BytesOut, SmallVectorImpl< Columns > &ColumnsOut)
BytesOut: A mapping from columns to the byte of the source line that produced the character displayin...
static void selectInterestingSourceRegion(std::string &SourceLine, std::string &CaretLine, std::string &FixItInsertionLine, Columns NonGutterColumns, const SourceColumnMap &Map, SmallVectorImpl< clang::TextDiagnostic::StyleRange > &Styles)
When the source code line we want to print is too long for the terminal, select the "interesting" reg...
static constexpr raw_ostream::Colors CommentColor
static constexpr raw_ostream::Colors LiteralColor
static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str, bool &Normal, bool Bold)
Add highlights to differences in template strings.
static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length)
Skip over whitespace in the string, starting at the given index.
static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns, unsigned Column, bool Bold)
Print the given string to a stream, word-wrapping it to some number of columns in the process.
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 std::pair< SmallString< 16 >, bool > printableTextForNextCharacter(StringRef SourceLine, size_t *I, unsigned TabStop)
returns a printable representation of first item from input range
static constexpr raw_ostream::Colors TemplateColor
static constexpr raw_ostream::Colors ErrorColor
static std::unique_ptr< llvm::SmallVector< TextDiagnostic::StyleRange >[]> highlightLines(StringRef FileData, unsigned StartLineNumber, unsigned EndLineNumber, const Preprocessor *PP, const LangOptions &LangOpts, bool ShowColors, FileID FID, const SourceManager &SM)
Creates syntax highlighting information in form of StyleRanges.
static constexpr raw_ostream::Colors FatalColor
static constexpr raw_ostream::Colors KeywordColor
static std::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.
static char findMatchingPunctuation(char c)
If the given character is the start of some kind of balanced punctuation (e.g., quotes or parentheses...
static constexpr raw_ostream::Colors CaretColor
static constexpr raw_ostream::Colors FixitColor
static void expandTabs(std::string &SourceLine, unsigned TabStop)
static constexpr raw_ostream::Colors WarningColor
static void highlightRange(const LineRange &R, const SourceColumnMap &Map, std::string &CaretLine)
Highlight R (with ~'s) on the current source line.
const unsigned WordWrapIndentation
Number of spaces to indent when word-wrapping.
static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo, const SourceColumnMap &map, ArrayRef< FixItHint > Hints, const SourceManager &SM, const DiagnosticOptions &DiagOpts)
static constexpr raw_ostream::Colors RemarkColor
static constexpr raw_ostream::Colors NoteColor
static SmallVector< LineRange > prepareAndFilterRanges(const SmallVectorImpl< CharSourceRange > &Ranges, const SourceManager &SM, const std::pair< unsigned, unsigned > &Lines, FileID FID, const LangOptions &LangOpts)
Filter out invalid ranges, ranges that don't fit into the window of source lines we will print,...
Represents a byte-granular source range.
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
SourceLocation getEnd() const
Options for controlling the compiler diagnostics engine.
const LangOptions & LangOpts
SourceLocation LastLoc
The location of the previous diagnostic if known.
DiagnosticOptions & DiagOpts
DiagnosticsEngine::Level LastLevel
The level of the last diagnostic emitted.
DiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts)
Level
The level of the diagnostic, after it has been through mapping.
Definition Diagnostic.h:239
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isValid() const
A SourceLocation and its associated SourceManager.
unsigned getColumnNumber(bool *Invalid=nullptr) const
FullSourceLoc getExpansionLoc() const
unsigned getLineNumber(bool *Invalid=nullptr) const
OptionalFileEntryRef getFileEntryRef() const
StringRef getBufferData(bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
PresumedLoc getPresumedLoc(bool UseLineDirectives=true) const
const SourceManager & getManager() const
One of these records is kept for each identifier that is lexed.
bool isKeyword(const LangOptions &LangOpts) const
Return true if this token is a keyword in the specified language.
IdentifierInfoLookup * getExternalIdentifierLookup() const
Retrieve the external identifier lookup object, if any.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
Definition Lexer.h:79
void SetKeepWhitespaceMode(bool Val)
SetKeepWhitespaceMode - This method lets clients enable or disable whitespace retention mode.
Definition Lexer.h:254
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
Definition Lexer.h:236
void seek(unsigned Offset, bool IsAtStartOfLine)
Set the lexer's buffer pointer to Offset.
Definition Lexer.cpp:287
static unsigned getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid=nullptr)
getSpelling - This method is used to get the spelling of a token into a preallocated buffer,...
Definition Lexer.cpp:461
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:508
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
const char * getCheckPoint(FileID FID, const char *Start) const
Returns a pointer into the given file's buffer that's guaranteed to be between tokens.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
IdentifierTable & getIdentifierTable()
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
const char * getFilename() const
Return the presumed filename of this location.
unsigned getLine() const
Return the presumed line number of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
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.
void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override
TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts, DiagnosticOptions &DiagOpts, const Preprocessor *PP=nullptr)
static void printDiagnosticLevel(raw_ostream &OS, DiagnosticsEngine::Level Level, bool ShowColors)
Print the diagonstic level to a raw_ostream.
void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef< CharSourceRange > Ranges) override
Print out the file/line/column information and include trace.
void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, DiagOrStoredDiag D) override
void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
Token - This structure provides full information about a lexed token.
Definition Token.h:36
bool isLiteral(TokenKind K)
Return true if this is a "literal" kind, like a numeric constant, string, etc.
Definition TokenKinds.h:103
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY bool isVerticalWhitespace(unsigned char c)
Returns true if this character is vertical ASCII whitespace: '\n', '\r'.
Definition CharInfo.h:99
CustomizableOptional< FileEntryRef > OptionalFileEntryRef
Definition FileEntry.h:196
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
std::pair< FileID, unsigned > FileIDAndOffset
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
@ Default
Set to the current date and time.
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
Definition CharInfo.h:108
const char ToggleHighlight
Special character that the diagnostic printer will use to toggle the bold attribute.
bool operator!=(CanQual< T > x, CanQual< U > y)
bool operator<=(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
bool operator>(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.