clang 22.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)
734 OS.resetColor();
735
736 if (DiagOpts.ShowLevel)
737 printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
739 /*IsSupplemental*/ Level == DiagnosticsEngine::Note,
740 Message, OS.getColumn() - StartOfLocationInfo,
741 DiagOpts.MessageLength, DiagOpts.ShowColors);
742 // We use a formatted ostream, which does its own buffering. Flush here
743 // so we keep the proper order of output.
744 OS.flush();
745}
746
747/*static*/ void
750 bool ShowColors) {
751 if (ShowColors) {
752 // Print diagnostic category in bold and color
753 switch (Level) {
755 llvm_unreachable("Invalid diagnostic type");
757 OS.changeColor(NoteColor, true);
758 break;
760 OS.changeColor(RemarkColor, true);
761 break;
763 OS.changeColor(WarningColor, true);
764 break;
766 OS.changeColor(ErrorColor, true);
767 break;
769 OS.changeColor(FatalColor, true);
770 break;
771 }
772 }
773
774 switch (Level) {
776 llvm_unreachable("Invalid diagnostic type");
777 case DiagnosticsEngine::Note: OS << "note: "; break;
778 case DiagnosticsEngine::Remark: OS << "remark: "; break;
779 case DiagnosticsEngine::Warning: OS << "warning: "; break;
780 case DiagnosticsEngine::Error: OS << "error: "; break;
781 case DiagnosticsEngine::Fatal: OS << "fatal error: "; break;
782 }
783
784 if (ShowColors)
785 OS.resetColor();
786}
787
788/*static*/
790 bool IsSupplemental,
791 StringRef Message,
792 unsigned CurrentColumn,
793 unsigned Columns, bool ShowColors) {
794 bool Bold = false;
795 if (ShowColors && !IsSupplemental) {
796 // Print primary diagnostic messages in bold and without color, to visually
797 // indicate the transition from continuation notes and other output.
798 OS.changeColor(SavedColor, true);
799 Bold = true;
800 }
801
802 if (Columns)
803 printWordWrapped(OS, Message, Columns, CurrentColumn, Bold);
804 else {
805 bool Normal = true;
806 applyTemplateHighlighting(OS, Message, Normal, Bold);
807 assert(Normal && "Formatting should have returned to normal");
808 }
809
810 if (ShowColors)
811 OS.resetColor();
812 OS << '\n';
813}
814
815void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
816#ifdef _WIN32
817 SmallString<4096> TmpFilename;
818#endif
819 if (DiagOpts.AbsolutePath) {
820 auto File = SM.getFileManager().getOptionalFileRef(Filename);
821 if (File) {
822 // We want to print a simplified absolute path, i. e. without "dots".
823 //
824 // The hardest part here are the paths like "<part1>/<link>/../<part2>".
825 // On Unix-like systems, we cannot just collapse "<link>/..", because
826 // paths are resolved sequentially, and, thereby, the path
827 // "<part1>/<part2>" may point to a different location. That is why
828 // we use FileManager::getCanonicalName(), which expands all indirections
829 // with llvm::sys::fs::real_path() and caches the result.
830 //
831 // On the other hand, it would be better to preserve as much of the
832 // original path as possible, because that helps a user to recognize it.
833 // real_path() expands all links, which sometimes too much. Luckily,
834 // on Windows we can just use llvm::sys::path::remove_dots(), because,
835 // on that system, both aforementioned paths point to the same place.
836#ifdef _WIN32
837 TmpFilename = File->getName();
838 llvm::sys::fs::make_absolute(TmpFilename);
839 llvm::sys::path::native(TmpFilename);
840 llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true);
841 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
842#else
843 Filename = SM.getFileManager().getCanonicalName(*File);
844#endif
845 }
846 }
847
848 OS << Filename;
849}
850
851/// Print out the file/line/column information and include trace.
852///
853/// This method handles the emission of the diagnostic location information.
854/// This includes extracting as much location information as is present for
855/// the diagnostic and printing it, as well as any include stack or source
856/// ranges necessary.
860 if (PLoc.isInvalid()) {
861 // At least print the file name if available:
862 if (FileID FID = Loc.getFileID(); FID.isValid()) {
863 if (OptionalFileEntryRef FE = Loc.getFileEntryRef()) {
864 emitFilename(FE->getName(), Loc.getManager());
865 OS << ": ";
866 }
867 }
868 return;
869 }
870 unsigned LineNo = PLoc.getLine();
871
872 if (!DiagOpts.ShowLocation)
873 return;
874
875 if (DiagOpts.ShowColors)
876 OS.changeColor(SavedColor, true);
877
878 emitFilename(PLoc.getFilename(), Loc.getManager());
879 switch (DiagOpts.getFormat()) {
882 if (DiagOpts.ShowLine)
883 OS << ':' << LineNo;
884 break;
885 case DiagnosticOptions::MSVC: OS << '(' << LineNo; break;
886 case DiagnosticOptions::Vi: OS << " +" << LineNo; break;
887 }
888
889 if (DiagOpts.ShowColumn)
890 // Compute the column number.
891 if (unsigned ColNo = PLoc.getColumn()) {
892 if (DiagOpts.getFormat() == DiagnosticOptions::MSVC) {
893 OS << ',';
894 // Visual Studio 2010 or earlier expects column number to be off by one
895 if (LangOpts.MSCompatibilityVersion &&
896 !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2012))
897 ColNo--;
898 } else
899 OS << ':';
900 OS << ColNo;
901 }
902 switch (DiagOpts.getFormat()) {
905 case DiagnosticOptions::Vi: OS << ':'; break;
907 // MSVC2013 and before print 'file(4) : error'. MSVC2015 gets rid of the
908 // space and prints 'file(4): error'.
909 OS << ')';
910 if (LangOpts.MSCompatibilityVersion &&
911 !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015))
912 OS << ' ';
913 OS << ':';
914 break;
915 }
916
917 if (DiagOpts.ShowSourceRanges && !Ranges.empty()) {
918 FileID CaretFileID = Loc.getExpansionLoc().getFileID();
919 bool PrintedRange = false;
920 const SourceManager &SM = Loc.getManager();
921
922 for (const auto &R : Ranges) {
923 // Ignore invalid ranges.
924 if (!R.isValid())
925 continue;
926
927 SourceLocation B = SM.getExpansionLoc(R.getBegin());
928 CharSourceRange ERange = SM.getExpansionRange(R.getEnd());
929 SourceLocation E = ERange.getEnd();
930
931 // If the start or end of the range is in another file, just
932 // discard it.
933 if (SM.getFileID(B) != CaretFileID || SM.getFileID(E) != CaretFileID)
934 continue;
935
936 // Add in the length of the token, so that we cover multi-char
937 // tokens.
938 unsigned TokSize = 0;
939 if (ERange.isTokenRange())
941
942 FullSourceLoc BF(B, SM), EF(E, SM);
943 OS << '{'
944 << BF.getLineNumber() << ':' << BF.getColumnNumber() << '-'
945 << EF.getLineNumber() << ':' << (EF.getColumnNumber() + TokSize)
946 << '}';
947 PrintedRange = true;
948 }
949
950 if (PrintedRange)
951 OS << ':';
952 }
953 OS << ' ';
954}
955
957 if (DiagOpts.ShowLocation && PLoc.isValid()) {
958 OS << "In file included from ";
959 emitFilename(PLoc.getFilename(), Loc.getManager());
960 OS << ':' << PLoc.getLine() << ":\n";
961 } else
962 OS << "In included file:\n";
963}
964
966 StringRef ModuleName) {
967 if (DiagOpts.ShowLocation && PLoc.isValid())
968 OS << "In module '" << ModuleName << "' imported from "
969 << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
970 else
971 OS << "In module '" << ModuleName << "':\n";
972}
973
975 PresumedLoc PLoc,
976 StringRef ModuleName) {
977 if (DiagOpts.ShowLocation && PLoc.isValid())
978 OS << "While building module '" << ModuleName << "' imported from "
979 << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
980 else
981 OS << "While building module '" << ModuleName << "':\n";
982}
983
984/// Find the suitable set of lines to show to include a set of ranges.
985static std::optional<std::pair<unsigned, unsigned>>
987 const SourceManager &SM) {
988 if (!R.isValid())
989 return std::nullopt;
990
991 SourceLocation Begin = R.getBegin();
992 SourceLocation End = R.getEnd();
993 if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
994 return std::nullopt;
995
996 return std::make_pair(SM.getExpansionLineNumber(Begin),
997 SM.getExpansionLineNumber(End));
998}
999
1000/// Add as much of range B into range A as possible without exceeding a maximum
1001/// size of MaxRange. Ranges are inclusive.
1002static std::pair<unsigned, unsigned>
1003maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
1004 unsigned MaxRange) {
1005 // If A is already the maximum size, we're done.
1006 unsigned Slack = MaxRange - (A.second - A.first + 1);
1007 if (Slack == 0)
1008 return A;
1009
1010 // Easy case: merge succeeds within MaxRange.
1011 unsigned Min = std::min(A.first, B.first);
1012 unsigned Max = std::max(A.second, B.second);
1013 if (Max - Min + 1 <= MaxRange)
1014 return {Min, Max};
1015
1016 // If we can't reach B from A within MaxRange, there's nothing to do.
1017 // Don't add lines to the range that contain nothing interesting.
1018 if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
1019 (B.second < A.second && A.second - B.second + 1 > MaxRange))
1020 return A;
1021
1022 // Otherwise, expand A towards B to produce a range of size MaxRange. We
1023 // attempt to expand by the same amount in both directions if B strictly
1024 // contains A.
1025
1026 // Expand downwards by up to half the available amount, then upwards as
1027 // much as possible, then downwards as much as possible.
1028 A.second = std::min(A.second + (Slack + 1) / 2, Max);
1029 Slack = MaxRange - (A.second - A.first + 1);
1030 A.first = std::max(Min + Slack, A.first) - Slack;
1031 A.second = std::min(A.first + MaxRange - 1, Max);
1032 return A;
1033}
1034
1036 unsigned LineNo;
1038 Bytes EndByte;
1039};
1040
1041/// Highlight \p R (with ~'s) on the current source line.
1042static void highlightRange(const LineRange &R, const SourceColumnMap &Map,
1043 std::string &CaretLine) {
1044 // Pick the first non-whitespace column.
1045 Bytes StartByte = R.StartByte;
1046 while (StartByte < Map.bytes() && (Map.getSourceLine()[StartByte.V] == ' ' ||
1047 Map.getSourceLine()[StartByte.V] == '\t'))
1048 StartByte = Map.startOfNextColumn(StartByte);
1049
1050 // Pick the last non-whitespace column.
1051 Bytes EndByte = std::min(R.EndByte.V, Map.bytes().V);
1052 while (EndByte.V != 0 && (Map.getSourceLine()[EndByte.V - 1] == ' ' ||
1053 Map.getSourceLine()[EndByte.V - 1] == '\t'))
1054 EndByte = Map.startOfPreviousColumn(EndByte);
1055
1056 // If the start/end passed each other, then we are trying to highlight a
1057 // range that just exists in whitespace. That most likely means we have
1058 // a multi-line highlighting range that covers a blank line.
1059 if (StartByte > EndByte)
1060 return;
1061
1062 assert(StartByte <= EndByte && "Invalid range!");
1063 // Fill the range with ~'s.
1064 Columns StartCol = Map.byteToContainingColumn(StartByte);
1065 Columns EndCol = Map.byteToContainingColumn(EndByte);
1066
1067 if (CaretLine.size() < static_cast<size_t>(EndCol.V))
1068 CaretLine.resize(EndCol.V, ' ');
1069
1070 std::fill(CaretLine.begin() + StartCol.V, CaretLine.begin() + EndCol.V, '~');
1071}
1072
1073static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo,
1074 const SourceColumnMap &map,
1075 ArrayRef<FixItHint> Hints,
1076 const SourceManager &SM,
1077 const DiagnosticOptions &DiagOpts) {
1078 std::string FixItInsertionLine;
1079 if (Hints.empty() || !DiagOpts.ShowFixits)
1080 return FixItInsertionLine;
1081 Columns PrevHintEndCol = 0;
1082
1083 for (const auto &H : Hints) {
1084 if (H.CodeToInsert.empty())
1085 continue;
1086
1087 // We have an insertion hint. Determine whether the inserted
1088 // code contains no newlines and is on the same line as the caret.
1089 FileIDAndOffset HintLocInfo =
1090 SM.getDecomposedExpansionLoc(H.RemoveRange.getBegin());
1091 if (FID == HintLocInfo.first &&
1092 LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
1093 StringRef(H.CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
1094 // Insert the new code into the line just below the code
1095 // that the user wrote.
1096 // Note: When modifying this function, be very careful about what is a
1097 // "column" (printed width, platform-dependent) and what is a
1098 // "byte offset" (SourceManager "column").
1099 Bytes HintByteOffset =
1100 Bytes(SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second))
1101 .prev();
1102
1103 // The hint must start inside the source or right at the end
1104 assert(HintByteOffset < map.bytes().next());
1105 Columns HintCol = map.byteToContainingColumn(HintByteOffset);
1106
1107 // If we inserted a long previous hint, push this one forwards, and add
1108 // an extra space to show that this is not part of the previous
1109 // completion. This is sort of the best we can do when two hints appear
1110 // to overlap.
1111 //
1112 // Note that if this hint is located immediately after the previous
1113 // hint, no space will be added, since the location is more important.
1114 if (HintCol < PrevHintEndCol)
1115 HintCol = PrevHintEndCol + 1;
1116
1117 // This should NOT use HintByteOffset, because the source might have
1118 // Unicode characters in earlier columns.
1119 Columns NewFixItLineSize = Columns(FixItInsertionLine.size()) +
1120 (HintCol - PrevHintEndCol) +
1121 Columns(H.CodeToInsert.size());
1122 if (NewFixItLineSize > FixItInsertionLine.size())
1123 FixItInsertionLine.resize(NewFixItLineSize.V, ' ');
1124
1125 std::copy(H.CodeToInsert.begin(), H.CodeToInsert.end(),
1126 FixItInsertionLine.end() - H.CodeToInsert.size());
1127
1128 PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(H.CodeToInsert);
1129 }
1130 }
1131
1132 expandTabs(FixItInsertionLine, DiagOpts.TabStop);
1133
1134 return FixItInsertionLine;
1135}
1136
1137static unsigned getNumDisplayWidth(unsigned N) {
1138 unsigned L = 1u, M = 10u;
1139 while (M <= N && ++L != std::numeric_limits<unsigned>::digits10 + 1)
1140 M *= 10u;
1141
1142 return L;
1143}
1144
1145/// Filter out invalid ranges, ranges that don't fit into the window of
1146/// source lines we will print, and ranges from other files.
1147///
1148/// For the remaining ranges, convert them to simple LineRange structs,
1149/// which only cover one line at a time.
1152 const SourceManager &SM,
1153 const std::pair<unsigned, unsigned> &Lines, FileID FID,
1154 const LangOptions &LangOpts) {
1155 SmallVector<LineRange> LineRanges;
1156
1157 for (const CharSourceRange &R : Ranges) {
1158 if (R.isInvalid())
1159 continue;
1160 SourceLocation Begin = R.getBegin();
1161 SourceLocation End = R.getEnd();
1162
1163 unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
1164 if (StartLineNo > Lines.second || SM.getFileID(Begin) != FID)
1165 continue;
1166
1167 unsigned EndLineNo = SM.getExpansionLineNumber(End);
1168 if (EndLineNo < Lines.first || SM.getFileID(End) != FID)
1169 continue;
1170
1171 Bytes StartByte = SM.getExpansionColumnNumber(Begin);
1172 Bytes EndByte = SM.getExpansionColumnNumber(End);
1173 assert(StartByte.V != 0 && "StartByte must be valid, 0 is invalid");
1174 assert(EndByte.V != 0 && "EndByte must be valid, 0 is invalid");
1175 if (R.isTokenRange())
1176 EndByte += Bytes(Lexer::MeasureTokenLength(End, SM, LangOpts));
1177
1178 // Only a single line.
1179 if (StartLineNo == EndLineNo) {
1180 LineRanges.push_back({StartLineNo, StartByte.prev(), EndByte.prev()});
1181 continue;
1182 }
1183
1184 // Start line.
1185 LineRanges.push_back(
1186 {StartLineNo, StartByte.prev(), std::numeric_limits<int>::max()});
1187
1188 // Middle lines.
1189 for (unsigned S = StartLineNo + 1; S != EndLineNo; ++S)
1190 LineRanges.push_back({S, 0, std::numeric_limits<int>::max()});
1191
1192 // End line.
1193 LineRanges.push_back({EndLineNo, 0, EndByte.prev()});
1194 }
1195
1196 return LineRanges;
1197}
1198
1199/// Creates syntax highlighting information in form of StyleRanges.
1200///
1201/// The returned unique ptr has always exactly size
1202/// (\p EndLineNumber - \p StartLineNumber + 1). Each SmallVector in there
1203/// corresponds to syntax highlighting information in one line. In each line,
1204/// the StyleRanges are non-overlapping and sorted from start to end of the
1205/// line.
1206static std::unique_ptr<llvm::SmallVector<TextDiagnostic::StyleRange>[]>
1207highlightLines(StringRef FileData, unsigned StartLineNumber,
1208 unsigned EndLineNumber, const Preprocessor *PP,
1209 const LangOptions &LangOpts, bool ShowColors, FileID FID,
1210 const SourceManager &SM) {
1211 assert(StartLineNumber <= EndLineNumber);
1212 auto SnippetRanges =
1213 std::make_unique<SmallVector<TextDiagnostic::StyleRange>[]>(
1214 EndLineNumber - StartLineNumber + 1);
1215
1216 if (!PP || !ShowColors)
1217 return SnippetRanges;
1218
1219 // Might cause emission of another diagnostic.
1221 return SnippetRanges;
1222
1223 auto Buff = llvm::MemoryBuffer::getMemBuffer(FileData);
1224 Lexer L{FID, *Buff, SM, LangOpts};
1225 L.SetKeepWhitespaceMode(true);
1226
1227 const char *FirstLineStart =
1228 FileData.data() +
1229 SM.getDecomposedLoc(SM.translateLineCol(FID, StartLineNumber, 1)).second;
1230 if (const char *CheckPoint = PP->getCheckPoint(FID, FirstLineStart)) {
1231 assert(CheckPoint >= Buff->getBufferStart() &&
1232 CheckPoint <= Buff->getBufferEnd());
1233 assert(CheckPoint <= FirstLineStart);
1234 size_t Offset = CheckPoint - Buff->getBufferStart();
1235 L.seek(Offset, /*IsAtStartOfLine=*/false);
1236 }
1237
1238 // Classify the given token and append it to the given vector.
1239 auto appendStyle =
1240 [PP, &LangOpts](SmallVector<TextDiagnostic::StyleRange> &Vec,
1241 const Token &T, unsigned Start, unsigned Length) -> void {
1242 if (T.is(tok::raw_identifier)) {
1243 StringRef RawIdent = T.getRawIdentifier();
1244 // Special case true/false/nullptr/... literals, since they will otherwise
1245 // be treated as keywords.
1246 // FIXME: It would be good to have a programmatic way of getting this
1247 // list.
1248 if (llvm::StringSwitch<bool>(RawIdent)
1249 .Case("true", true)
1250 .Case("false", true)
1251 .Case("nullptr", true)
1252 .Case("__func__", true)
1253 .Case("__objc_yes__", true)
1254 .Case("__objc_no__", true)
1255 .Case("__null", true)
1256 .Case("__FUNCDNAME__", true)
1257 .Case("__FUNCSIG__", true)
1258 .Case("__FUNCTION__", true)
1259 .Case("__FUNCSIG__", true)
1260 .Default(false)) {
1261 Vec.emplace_back(Start, Start + Length, LiteralColor);
1262 } else {
1263 const IdentifierInfo *II = PP->getIdentifierInfo(RawIdent);
1264 assert(II);
1265 if (II->isKeyword(LangOpts))
1266 Vec.emplace_back(Start, Start + Length, KeywordColor);
1267 }
1268 } else if (tok::isLiteral(T.getKind())) {
1269 Vec.emplace_back(Start, Start + Length, LiteralColor);
1270 } else {
1271 assert(T.is(tok::comment));
1272 Vec.emplace_back(Start, Start + Length, CommentColor);
1273 }
1274 };
1275
1276 bool Stop = false;
1277 while (!Stop) {
1278 Token T;
1279 Stop = L.LexFromRawLexer(T);
1280 if (T.is(tok::unknown))
1281 continue;
1282
1283 // We are only interested in identifiers, literals and comments.
1284 if (!T.is(tok::raw_identifier) && !T.is(tok::comment) &&
1285 !tok::isLiteral(T.getKind()))
1286 continue;
1287
1288 bool Invalid = false;
1289 unsigned TokenEndLine = SM.getSpellingLineNumber(T.getEndLoc(), &Invalid);
1290 if (Invalid || TokenEndLine < StartLineNumber)
1291 continue;
1292
1293 assert(TokenEndLine >= StartLineNumber);
1294
1295 unsigned TokenStartLine =
1296 SM.getSpellingLineNumber(T.getLocation(), &Invalid);
1297 if (Invalid)
1298 continue;
1299 // If this happens, we're done.
1300 if (TokenStartLine > EndLineNumber)
1301 break;
1302
1303 Bytes StartCol = SM.getSpellingColumnNumber(T.getLocation(), &Invalid) - 1;
1304 if (Invalid)
1305 continue;
1306
1307 // Simple tokens.
1308 if (TokenStartLine == TokenEndLine) {
1310 SnippetRanges[TokenStartLine - StartLineNumber];
1311 appendStyle(LineRanges, T, StartCol.V, T.getLength());
1312 continue;
1313 }
1314 assert((TokenEndLine - TokenStartLine) >= 1);
1315
1316 // For tokens that span multiple lines (think multiline comments), we
1317 // divide them into multiple StyleRanges.
1318 Bytes EndCol = SM.getSpellingColumnNumber(T.getEndLoc(), &Invalid) - 1;
1319 if (Invalid)
1320 continue;
1321
1322 std::string Spelling = Lexer::getSpelling(T, SM, LangOpts);
1323
1324 unsigned L = TokenStartLine;
1325 unsigned LineLength = 0;
1326 for (unsigned I = 0; I <= Spelling.size(); ++I) {
1327 // This line is done.
1328 if (I == Spelling.size() || isVerticalWhitespace(Spelling[I])) {
1329 if (L >= StartLineNumber) {
1331 SnippetRanges[L - StartLineNumber];
1332
1333 if (L == TokenStartLine) // First line
1334 appendStyle(LineRanges, T, StartCol.V, LineLength);
1335 else if (L == TokenEndLine) // Last line
1336 appendStyle(LineRanges, T, 0, EndCol.V);
1337 else
1338 appendStyle(LineRanges, T, 0, LineLength);
1339 }
1340
1341 ++L;
1342 if (L > EndLineNumber)
1343 break;
1344 LineLength = 0;
1345 continue;
1346 }
1347 ++LineLength;
1348 }
1349 }
1350
1351 return SnippetRanges;
1352}
1353
1354/// Emit a code snippet and caret line.
1355///
1356/// This routine emits a single line's code snippet and caret line..
1357///
1358/// \param Loc The location for the caret.
1359/// \param Ranges The underlined ranges for this code snippet.
1360/// \param Hints The FixIt hints active for this diagnostic.
1361void TextDiagnostic::emitSnippetAndCaret(
1364 assert(Loc.isValid() && "must have a valid source location here");
1365 assert(Loc.isFileID() && "must have a file location here");
1366
1367 // If caret diagnostics are enabled and we have location, we want to
1368 // emit the caret. However, we only do this if the location moved
1369 // from the last diagnostic, if the last diagnostic was a note that
1370 // was part of a different warning or error diagnostic, or if the
1371 // diagnostic has ranges. We don't want to emit the same caret
1372 // multiple times if one loc has multiple diagnostics.
1373 if (!DiagOpts.ShowCarets)
1374 return;
1375 if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
1377 return;
1378
1379 FileID FID = Loc.getFileID();
1380 const SourceManager &SM = Loc.getManager();
1381
1382 // Get information about the buffer it points into.
1383 bool Invalid = false;
1384 StringRef BufData = Loc.getBufferData(&Invalid);
1385 if (Invalid)
1386 return;
1387 const char *BufStart = BufData.data();
1388 const char *BufEnd = BufStart + BufData.size();
1389
1390 unsigned CaretLineNo = Loc.getLineNumber();
1391 Bytes CaretByte = Loc.getColumnNumber();
1392
1393 // Arbitrarily stop showing snippets when the line is too long.
1394 static const size_t MaxLineLengthToPrint = 4096;
1395 if (CaretByte > MaxLineLengthToPrint)
1396 return;
1397
1398 // Find the set of lines to include.
1399 const unsigned MaxLines = DiagOpts.SnippetLineLimit;
1400 std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
1401 unsigned DisplayLineNo = Loc.getPresumedLoc().getLine();
1402 for (const auto &I : Ranges) {
1403 if (auto OptionalRange = findLinesForRange(I, FID, SM))
1404 Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
1405
1406 DisplayLineNo =
1407 std::min(DisplayLineNo, SM.getPresumedLineNumber(I.getBegin()));
1408 }
1409
1410 // Our line numbers look like:
1411 // " [number] | "
1412 // Where [number] is MaxLineNoDisplayWidth columns
1413 // and the full thing is therefore MaxLineNoDisplayWidth + 4 columns.
1414 unsigned MaxLineNoDisplayWidth =
1415 DiagOpts.ShowLineNumbers
1416 ? std::max(4u, getNumDisplayWidth(DisplayLineNo + MaxLines))
1417 : 0;
1418 auto indentForLineNumbers = [&] {
1419 if (MaxLineNoDisplayWidth > 0)
1420 OS.indent(MaxLineNoDisplayWidth + 2) << "| ";
1421 };
1422
1423 Columns MessageLength = DiagOpts.MessageLength;
1424 // If we don't have enough columns available, just abort now.
1425 if (MessageLength != 0 && MessageLength <= Columns(MaxLineNoDisplayWidth + 4))
1426 return;
1427
1428 // Prepare source highlighting information for the lines we're about to
1429 // emit, starting from the first line.
1430 std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles =
1431 highlightLines(BufData, Lines.first, Lines.second, PP, LangOpts,
1432 DiagOpts.ShowColors, FID, SM);
1433
1434 SmallVector<LineRange> LineRanges =
1435 prepareAndFilterRanges(Ranges, SM, Lines, FID, LangOpts);
1436
1437 for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1;
1438 ++LineNo, ++DisplayLineNo) {
1439 // Rewind from the current position to the start of the line.
1440 const char *LineStart =
1441 BufStart +
1442 SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
1443 if (LineStart == BufEnd)
1444 break;
1445
1446 // Compute the line end.
1447 const char *LineEnd = LineStart;
1448 while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
1449 ++LineEnd;
1450
1451 // Arbitrarily stop showing snippets when the line is too long.
1452 // FIXME: Don't print any lines in this case.
1453 if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
1454 return;
1455
1456 // Copy the line of code into an std::string for ease of manipulation.
1457 std::string SourceLine(LineStart, LineEnd);
1458 // Remove trailing null bytes.
1459 while (!SourceLine.empty() && SourceLine.back() == '\0' &&
1460 (LineNo != CaretLineNo ||
1461 SourceLine.size() > static_cast<size_t>(CaretByte.V)))
1462 SourceLine.pop_back();
1463
1464 // Build the byte to column map.
1465 const SourceColumnMap SourceColMap(SourceLine, DiagOpts.TabStop);
1466
1467 std::string CaretLine;
1468 // Highlight all of the characters covered by Ranges with ~ characters.
1469 for (const auto &LR : LineRanges) {
1470 if (LR.LineNo == LineNo)
1471 highlightRange(LR, SourceColMap, CaretLine);
1472 }
1473
1474 // Next, insert the caret itself.
1475 if (CaretLineNo == LineNo) {
1476 Columns Col = SourceColMap.byteToContainingColumn(CaretByte.prev());
1477 CaretLine.resize(
1478 std::max(static_cast<size_t>(Col.V) + 1, CaretLine.size()), ' ');
1479 CaretLine[Col.V] = '^';
1480 }
1481
1482 std::string FixItInsertionLine =
1483 buildFixItInsertionLine(FID, LineNo, SourceColMap, Hints, SM, DiagOpts);
1484
1485 // If the source line is too long for our terminal, select only the
1486 // "interesting" source region within that line.
1487 if (MessageLength != 0) {
1488 Columns NonGutterColumns = MessageLength;
1489 if (MaxLineNoDisplayWidth != 0)
1490 NonGutterColumns -= Columns(MaxLineNoDisplayWidth + 4);
1491 selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
1492 NonGutterColumns, SourceColMap,
1493 SourceStyles[LineNo - Lines.first]);
1494 }
1495
1496 // If we are in -fdiagnostics-print-source-range-info mode, we are trying
1497 // to produce easily machine parsable output. Add a space before the
1498 // source line and the caret to make it trivial to tell the main diagnostic
1499 // line from what the user is intended to see.
1500 if (DiagOpts.ShowSourceRanges && !SourceLine.empty()) {
1501 SourceLine = ' ' + SourceLine;
1502 CaretLine = ' ' + CaretLine;
1503 }
1504
1505 // Emit what we have computed.
1506 emitSnippet(SourceLine, MaxLineNoDisplayWidth, LineNo, DisplayLineNo,
1507 SourceStyles[LineNo - Lines.first]);
1508
1509 if (!CaretLine.empty()) {
1510 indentForLineNumbers();
1511 if (DiagOpts.ShowColors)
1512 OS.changeColor(CaretColor, true);
1513 OS << CaretLine << '\n';
1514 if (DiagOpts.ShowColors)
1515 OS.resetColor();
1516 }
1517
1518 if (!FixItInsertionLine.empty()) {
1519 indentForLineNumbers();
1520 if (DiagOpts.ShowColors)
1521 // Print fixit line in color
1522 OS.changeColor(FixitColor, false);
1523 if (DiagOpts.ShowSourceRanges)
1524 OS << ' ';
1525 OS << FixItInsertionLine << '\n';
1526 if (DiagOpts.ShowColors)
1527 OS.resetColor();
1528 }
1529 }
1530
1531 // Print out any parseable fixit information requested by the options.
1532 emitParseableFixits(Hints, SM);
1533}
1534
1535void TextDiagnostic::emitSnippet(StringRef SourceLine,
1536 unsigned MaxLineNoDisplayWidth,
1537 unsigned LineNo, unsigned DisplayLineNo,
1538 ArrayRef<StyleRange> Styles) {
1539 // Emit line number.
1540 if (MaxLineNoDisplayWidth > 0) {
1541 unsigned LineNoDisplayWidth = getNumDisplayWidth(DisplayLineNo);
1542 OS.indent(MaxLineNoDisplayWidth - LineNoDisplayWidth + 1)
1543 << DisplayLineNo << " | ";
1544 }
1545
1546 // Print the source line one character at a time.
1547 bool PrintReversed = false;
1548 std::optional<llvm::raw_ostream::Colors> CurrentColor;
1549 size_t I = 0; // Bytes.
1550 while (I < SourceLine.size()) {
1551 auto [Str, WasPrintable] =
1552 printableTextForNextCharacter(SourceLine, &I, DiagOpts.TabStop);
1553
1554 // Toggle inverted colors on or off for this character.
1555 if (DiagOpts.ShowColors) {
1556 if (WasPrintable == PrintReversed) {
1557 PrintReversed = !PrintReversed;
1558 if (PrintReversed)
1559 OS.reverseColor();
1560 else {
1561 OS.resetColor();
1562 CurrentColor = std::nullopt;
1563 }
1564 }
1565
1566 // Apply syntax highlighting information.
1567 const auto *CharStyle = llvm::find_if(Styles, [I](const StyleRange &R) {
1568 return (R.Start < I && R.End >= I);
1569 });
1570
1571 if (CharStyle != Styles.end()) {
1572 if (!CurrentColor ||
1573 (CurrentColor && *CurrentColor != CharStyle->Color)) {
1574 OS.changeColor(CharStyle->Color);
1575 CurrentColor = CharStyle->Color;
1576 }
1577 } else if (CurrentColor) {
1578 OS.resetColor();
1579 CurrentColor = std::nullopt;
1580 }
1581 }
1582
1583 OS << Str;
1584 }
1585
1586 if (DiagOpts.ShowColors)
1587 OS.resetColor();
1588
1589 OS << '\n';
1590}
1591
1592void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
1593 const SourceManager &SM) {
1594 if (!DiagOpts.ShowParseableFixits)
1595 return;
1596
1597 // We follow FixItRewriter's example in not (yet) handling
1598 // fix-its in macros.
1599 for (const auto &H : Hints) {
1600 if (H.RemoveRange.isInvalid() || H.RemoveRange.getBegin().isMacroID() ||
1601 H.RemoveRange.getEnd().isMacroID())
1602 return;
1603 }
1604
1605 for (const auto &H : Hints) {
1606 SourceLocation BLoc = H.RemoveRange.getBegin();
1607 SourceLocation ELoc = H.RemoveRange.getEnd();
1608
1609 FileIDAndOffset BInfo = SM.getDecomposedLoc(BLoc);
1610 FileIDAndOffset EInfo = SM.getDecomposedLoc(ELoc);
1611
1612 // Adjust for token ranges.
1613 if (H.RemoveRange.isTokenRange())
1614 EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
1615
1616 // We specifically do not do word-wrapping or tab-expansion here,
1617 // because this is supposed to be easy to parse.
1618 PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
1619 if (PLoc.isInvalid())
1620 break;
1621
1622 OS << "fix-it:\"";
1623 OS.write_escaped(PLoc.getFilename());
1624 OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
1625 << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
1626 << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
1627 << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
1628 << "}:\"";
1629 OS.write_escaped(H.CodeToInsert);
1630 OS << "\"\n";
1631 }
1632}
#define V(N, I)
static StringRef bytes(const std::vector< T, Allocator > &v)
static size_t getNumDisplayWidth(size_t N)
Definition Disasm.cpp:133
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 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,...
__device__ __2f16 float c
Represents a character-granular source range.
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
SourceLocation getEnd() const
SourceLocation getBegin() 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:237
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:78
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:277
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:451
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:498
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:97
The JSON file list parser is used to communicate input to InstallAPI.
static const TerminalColor CommentColor
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:208
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
std::pair< FileID, unsigned > FileIDAndOffset
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
const FunctionProtoType * T
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.