clang 24.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 std::optional<CharSourceRange> FileRange =
925 getExpansionRangeInFile(R, CaretFileID, SM);
926 if (!FileRange)
927 continue;
928
929 SourceLocation B = FileRange->getBegin();
930 SourceLocation E = FileRange->getEnd();
931
932 // Add in the length of the token, so that we cover multi-char
933 // tokens.
934 unsigned TokSize = 0;
935 if (FileRange->isTokenRange())
936 TokSize = Lexer::MeasureTokenLength(E, SM, LangOpts);
937
938 FullSourceLoc BF(B, SM), EF(E, SM);
939 OS << '{'
940 << BF.getLineNumber() << ':' << BF.getColumnNumber() << '-'
941 << EF.getLineNumber() << ':' << (EF.getColumnNumber() + TokSize)
942 << '}';
943 PrintedRange = true;
944 }
945
946 if (PrintedRange)
947 OS << ':';
948 }
949 OS << ' ';
950}
951
953 if (DiagOpts.ShowLocation && PLoc.isValid()) {
954 OS << "In file included from ";
955 emitFilename(PLoc.getFilename(), Loc.getManager());
956 OS << ':' << PLoc.getLine() << ":\n";
957 } else
958 OS << "In included file:\n";
959}
960
962 StringRef ModuleName) {
963 if (DiagOpts.ShowLocation && PLoc.isValid())
964 OS << "In module '" << ModuleName << "' imported from "
965 << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
966 else
967 OS << "In module '" << ModuleName << "':\n";
968}
969
971 PresumedLoc PLoc,
972 StringRef ModuleName) {
973 if (DiagOpts.ShowLocation && PLoc.isValid())
974 OS << "While building module '" << ModuleName << "' imported from "
975 << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
976 else
977 OS << "While building module '" << ModuleName << "':\n";
978}
979
980/// Find the suitable set of lines to show to include a set of ranges.
981static std::optional<std::pair<unsigned, unsigned>>
983 const SourceManager &SM) {
984 if (!R.isValid())
985 return std::nullopt;
986
987 SourceLocation Begin = R.getBegin();
988 SourceLocation End = R.getEnd();
989 if (SM.getFileID(Begin) != FID || SM.getFileID(End) != FID)
990 return std::nullopt;
991
992 return std::make_pair(SM.getExpansionLineNumber(Begin),
993 SM.getExpansionLineNumber(End));
994}
995
996/// Add as much of range B into range A as possible without exceeding a maximum
997/// size of MaxRange. Ranges are inclusive.
998static std::pair<unsigned, unsigned>
999maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
1000 unsigned MaxRange) {
1001 // If A is already the maximum size, we're done.
1002 unsigned Slack = MaxRange - (A.second - A.first + 1);
1003 if (Slack == 0)
1004 return A;
1005
1006 // Easy case: merge succeeds within MaxRange.
1007 unsigned Min = std::min(A.first, B.first);
1008 unsigned Max = std::max(A.second, B.second);
1009 if (Max - Min + 1 <= MaxRange)
1010 return {Min, Max};
1011
1012 // If we can't reach B from A within MaxRange, there's nothing to do.
1013 // Don't add lines to the range that contain nothing interesting.
1014 if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
1015 (B.second < A.second && A.second - B.second + 1 > MaxRange))
1016 return A;
1017
1018 // Otherwise, expand A towards B to produce a range of size MaxRange. We
1019 // attempt to expand by the same amount in both directions if B strictly
1020 // contains A.
1021
1022 // Expand downwards by up to half the available amount, then upwards as
1023 // much as possible, then downwards as much as possible.
1024 A.second = std::min(A.second + (Slack + 1) / 2, Max);
1025 Slack = MaxRange - (A.second - A.first + 1);
1026 A.first = std::max(Min + Slack, A.first) - Slack;
1027 A.second = std::min(A.first + MaxRange - 1, Max);
1028 return A;
1029}
1030
1032 unsigned LineNo;
1034 Bytes EndByte;
1035};
1036
1037/// Highlight \p R (with ~'s) on the current source line.
1038static void highlightRange(const LineRange &R, const SourceColumnMap &Map,
1039 std::string &CaretLine) {
1040 // Pick the first non-whitespace column.
1041 Bytes StartByte = R.StartByte;
1042 while (StartByte < Map.bytes() && (Map.getSourceLine()[StartByte.V] == ' ' ||
1043 Map.getSourceLine()[StartByte.V] == '\t'))
1044 StartByte = Map.startOfNextColumn(StartByte);
1045
1046 // Pick the last non-whitespace column.
1047 Bytes EndByte = std::min(R.EndByte.V, Map.bytes().V);
1048 while (EndByte.V != 0 && (Map.getSourceLine()[EndByte.V - 1] == ' ' ||
1049 Map.getSourceLine()[EndByte.V - 1] == '\t'))
1050 EndByte = Map.startOfPreviousColumn(EndByte);
1051
1052 // If the start/end passed each other, then we are trying to highlight a
1053 // range that just exists in whitespace. That most likely means we have
1054 // a multi-line highlighting range that covers a blank line.
1055 if (StartByte > EndByte)
1056 return;
1057
1058 assert(StartByte <= EndByte && "Invalid range!");
1059 // Fill the range with ~'s.
1060 Columns StartCol = Map.byteToContainingColumn(StartByte);
1061 Columns EndCol = Map.byteToContainingColumn(EndByte);
1062
1063 if (CaretLine.size() < static_cast<size_t>(EndCol.V))
1064 CaretLine.resize(EndCol.V, ' ');
1065
1066 std::fill(CaretLine.begin() + StartCol.V, CaretLine.begin() + EndCol.V, '~');
1067}
1068
1069static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo,
1070 const SourceColumnMap &map,
1071 ArrayRef<FixItHint> Hints,
1072 const SourceManager &SM,
1073 const DiagnosticOptions &DiagOpts) {
1074 std::string FixItInsertionLine;
1075 if (Hints.empty() || !DiagOpts.ShowFixits)
1076 return FixItInsertionLine;
1077 Columns PrevHintEndCol = 0;
1078
1079 for (const auto &H : Hints) {
1080 if (H.CodeToInsert.empty())
1081 continue;
1082
1083 // We have an insertion hint. Determine whether the inserted
1084 // code contains no newlines and is on the same line as the caret.
1085 FileIDAndOffset HintLocInfo =
1086 SM.getDecomposedExpansionLoc(H.RemoveRange.getBegin());
1087 if (FID == HintLocInfo.first &&
1088 LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
1089 StringRef(H.CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
1090 // Insert the new code into the line just below the code
1091 // that the user wrote.
1092 // Note: When modifying this function, be very careful about what is a
1093 // "column" (printed width, platform-dependent) and what is a
1094 // "byte offset" (SourceManager "column").
1095 Bytes HintByteOffset =
1096 Bytes(SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second))
1097 .prev();
1098
1099 // The hint must start inside the source or right at the end
1100 assert(HintByteOffset < map.bytes().next());
1101 Columns HintCol = map.byteToContainingColumn(HintByteOffset);
1102
1103 // If we inserted a long previous hint, push this one forwards, and add
1104 // an extra space to show that this is not part of the previous
1105 // completion. This is sort of the best we can do when two hints appear
1106 // to overlap.
1107 //
1108 // Note that if this hint is located immediately after the previous
1109 // hint, no space will be added, since the location is more important.
1110 if (HintCol < PrevHintEndCol)
1111 HintCol = PrevHintEndCol + 1;
1112
1113 // This should NOT use HintByteOffset, because the source might have
1114 // Unicode characters in earlier columns.
1115 Columns NewFixItLineSize = Columns(FixItInsertionLine.size()) +
1116 (HintCol - PrevHintEndCol) +
1117 Columns(H.CodeToInsert.size());
1118 if (NewFixItLineSize > FixItInsertionLine.size())
1119 FixItInsertionLine.resize(NewFixItLineSize.V, ' ');
1120
1121 std::copy(H.CodeToInsert.begin(), H.CodeToInsert.end(),
1122 FixItInsertionLine.end() - H.CodeToInsert.size());
1123
1124 PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(H.CodeToInsert);
1125 }
1126 }
1127
1128 expandTabs(FixItInsertionLine, DiagOpts.TabStop);
1129
1130 return FixItInsertionLine;
1131}
1132
1133static unsigned getNumDisplayWidth(unsigned N) {
1134 unsigned L = 1u, M = 10u;
1135 while (M <= N && ++L != std::numeric_limits<unsigned>::digits10 + 1)
1136 M *= 10u;
1137
1138 return L;
1139}
1140
1141/// Filter out invalid ranges, ranges that don't fit into the window of
1142/// source lines we will print, and ranges from other files.
1143///
1144/// For the remaining ranges, convert them to simple LineRange structs,
1145/// which only cover one line at a time.
1148 const SourceManager &SM,
1149 const std::pair<unsigned, unsigned> &Lines, FileID FID,
1150 const LangOptions &LangOpts) {
1151 SmallVector<LineRange> LineRanges;
1152
1153 for (const CharSourceRange &R : Ranges) {
1154 if (R.isInvalid())
1155 continue;
1156 SourceLocation Begin = R.getBegin();
1157 SourceLocation End = R.getEnd();
1158
1159 unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
1160 if (StartLineNo > Lines.second || SM.getFileID(Begin) != FID)
1161 continue;
1162
1163 unsigned EndLineNo = SM.getExpansionLineNumber(End);
1164 if (EndLineNo < Lines.first || SM.getFileID(End) != FID)
1165 continue;
1166
1167 Bytes StartByte = SM.getExpansionColumnNumber(Begin);
1168 Bytes EndByte = SM.getExpansionColumnNumber(End);
1169 assert(StartByte.V != 0 && "StartByte must be valid, 0 is invalid");
1170 assert(EndByte.V != 0 && "EndByte must be valid, 0 is invalid");
1171 if (R.isTokenRange())
1172 EndByte += Bytes(Lexer::MeasureTokenLength(End, SM, LangOpts));
1173
1174 // Only a single line.
1175 if (StartLineNo == EndLineNo) {
1176 LineRanges.push_back({StartLineNo, StartByte.prev(), EndByte.prev()});
1177 continue;
1178 }
1179
1180 // Start line.
1181 LineRanges.push_back(
1182 {StartLineNo, StartByte.prev(), std::numeric_limits<int>::max()});
1183
1184 // Middle lines.
1185 for (unsigned S = StartLineNo + 1; S != EndLineNo; ++S)
1186 LineRanges.push_back({S, 0, std::numeric_limits<int>::max()});
1187
1188 // End line.
1189 LineRanges.push_back({EndLineNo, 0, EndByte.prev()});
1190 }
1191
1192 return LineRanges;
1193}
1194
1195/// Creates syntax highlighting information in form of StyleRanges.
1196///
1197/// The returned unique ptr has always exactly size
1198/// (\p EndLineNumber - \p StartLineNumber + 1). Each SmallVector in there
1199/// corresponds to syntax highlighting information in one line. In each line,
1200/// the StyleRanges are non-overlapping and sorted from start to end of the
1201/// line.
1202static std::unique_ptr<llvm::SmallVector<TextDiagnostic::StyleRange>[]>
1203highlightLines(StringRef FileData, unsigned StartLineNumber,
1204 unsigned EndLineNumber, const Preprocessor *PP,
1205 const LangOptions &LangOpts, bool ShowColors, FileID FID,
1206 const SourceManager &SM) {
1207 assert(StartLineNumber <= EndLineNumber);
1208 auto SnippetRanges =
1209 std::make_unique<SmallVector<TextDiagnostic::StyleRange>[]>(
1210 EndLineNumber - StartLineNumber + 1);
1211
1212 if (!PP || !ShowColors)
1213 return SnippetRanges;
1214
1215 // Might cause emission of another diagnostic.
1217 return SnippetRanges;
1218
1219 auto Buff = llvm::MemoryBuffer::getMemBuffer(FileData);
1220 Lexer L{FID, *Buff, SM, LangOpts};
1221 L.SetKeepWhitespaceMode(true);
1222
1223 const char *FirstLineStart =
1224 FileData.data() +
1225 SM.getDecomposedLoc(SM.translateLineCol(FID, StartLineNumber, 1)).second;
1226 if (const char *CheckPoint = PP->getCheckPoint(FID, FirstLineStart)) {
1227 assert(CheckPoint >= Buff->getBufferStart() &&
1228 CheckPoint <= Buff->getBufferEnd());
1229 assert(CheckPoint <= FirstLineStart);
1230 size_t Offset = CheckPoint - Buff->getBufferStart();
1231 L.seek(Offset, /*IsAtStartOfLine=*/false);
1232 }
1233
1234 // Classify the given token and append it to the given vector.
1235 auto appendStyle =
1236 [PP, &LangOpts](SmallVector<TextDiagnostic::StyleRange> &Vec,
1237 const Token &T, unsigned Start, unsigned Length) -> void {
1238 if (T.is(tok::raw_identifier)) {
1239 StringRef RawIdent = T.getRawIdentifier();
1240 // Special case true/false/nullptr/... literals, since they will otherwise
1241 // be treated as keywords.
1242 // FIXME: It would be good to have a programmatic way of getting this
1243 // list.
1244 if (llvm::StringSwitch<bool>(RawIdent)
1245 .Case("true", true)
1246 .Case("false", true)
1247 .Case("nullptr", true)
1248 .Case("__func__", true)
1249 .Case("__objc_yes__", true)
1250 .Case("__objc_no__", true)
1251 .Case("__null", true)
1252 .Case("__FUNCDNAME__", true)
1253 .Case("__FUNCSIG__", true)
1254 .Case("__FUNCTION__", true)
1255 .Case("__FUNCSIG__", true)
1256 .Default(false)) {
1257 Vec.emplace_back(Start, Start + Length, LiteralColor);
1258 } else {
1259 const IdentifierInfo *II = PP->getIdentifierInfo(RawIdent);
1260 assert(II);
1261 if (II->isKeyword(LangOpts))
1262 Vec.emplace_back(Start, Start + Length, KeywordColor);
1263 }
1264 } else if (tok::isLiteral(T.getKind())) {
1265 Vec.emplace_back(Start, Start + Length, LiteralColor);
1266 } else {
1267 assert(T.is(tok::comment));
1268 Vec.emplace_back(Start, Start + Length, CommentColor);
1269 }
1270 };
1271
1272 bool Stop = false;
1273 while (!Stop) {
1274 Token T;
1275 Stop = L.LexFromRawLexer(T);
1276 if (T.is(tok::unknown))
1277 continue;
1278
1279 // We are only interested in identifiers, literals and comments.
1280 if (!T.is(tok::raw_identifier) && !T.is(tok::comment) &&
1281 !tok::isLiteral(T.getKind()))
1282 continue;
1283
1284 bool Invalid = false;
1285 unsigned TokenEndLine = SM.getSpellingLineNumber(T.getEndLoc(), &Invalid);
1286 if (Invalid || TokenEndLine < StartLineNumber)
1287 continue;
1288
1289 assert(TokenEndLine >= StartLineNumber);
1290
1291 unsigned TokenStartLine =
1292 SM.getSpellingLineNumber(T.getLocation(), &Invalid);
1293 if (Invalid)
1294 continue;
1295 // If this happens, we're done.
1296 if (TokenStartLine > EndLineNumber)
1297 break;
1298
1299 Bytes StartCol = SM.getSpellingColumnNumber(T.getLocation(), &Invalid) - 1;
1300 if (Invalid)
1301 continue;
1302
1303 // Simple tokens.
1304 if (TokenStartLine == TokenEndLine) {
1306 SnippetRanges[TokenStartLine - StartLineNumber];
1307 appendStyle(LineRanges, T, StartCol.V, T.getLength());
1308 continue;
1309 }
1310 assert((TokenEndLine - TokenStartLine) >= 1);
1311
1312 // For tokens that span multiple lines (think multiline comments), we
1313 // divide them into multiple StyleRanges.
1314 Bytes EndCol = SM.getSpellingColumnNumber(T.getEndLoc(), &Invalid) - 1;
1315 if (Invalid)
1316 continue;
1317
1318 std::string Spelling = Lexer::getSpelling(T, SM, LangOpts);
1319
1320 unsigned L = TokenStartLine;
1321 unsigned LineLength = 0;
1322 for (unsigned I = 0; I <= Spelling.size(); ++I) {
1323 // This line is done.
1324 if (I == Spelling.size() || isVerticalWhitespace(Spelling[I])) {
1325 if (L >= StartLineNumber) {
1327 SnippetRanges[L - StartLineNumber];
1328
1329 if (L == TokenStartLine) // First line
1330 appendStyle(LineRanges, T, StartCol.V, LineLength);
1331 else if (L == TokenEndLine) // Last line
1332 appendStyle(LineRanges, T, 0, EndCol.V);
1333 else
1334 appendStyle(LineRanges, T, 0, LineLength);
1335 }
1336
1337 ++L;
1338 if (L > EndLineNumber)
1339 break;
1340 LineLength = 0;
1341 continue;
1342 }
1343 ++LineLength;
1344 }
1345 }
1346
1347 return SnippetRanges;
1348}
1349
1350/// Emit a code snippet and caret line.
1351///
1352/// This routine emits a single line's code snippet and caret line..
1353///
1354/// \param Loc The location for the caret.
1355/// \param Ranges The underlined ranges for this code snippet.
1356/// \param Hints The FixIt hints active for this diagnostic.
1357void TextDiagnostic::emitSnippetAndCaret(
1360 assert(Loc.isValid() && "must have a valid source location here");
1361 assert(Loc.isFileID() && "must have a file location here");
1362
1363 // If caret diagnostics are enabled and we have location, we want to
1364 // emit the caret. However, we only do this if the location moved
1365 // from the last diagnostic, if the last diagnostic was a note that
1366 // was part of a different warning or error diagnostic, or if the
1367 // diagnostic has ranges. We don't want to emit the same caret
1368 // multiple times if one loc has multiple diagnostics.
1369 if (!DiagOpts.ShowCarets)
1370 return;
1371 if (Loc == LastLoc && Ranges.empty() && Hints.empty() &&
1373 return;
1374
1375 FileID FID = Loc.getFileID();
1376 const SourceManager &SM = Loc.getManager();
1377
1378 // Get information about the buffer it points into.
1379 bool Invalid = false;
1380 StringRef BufData = Loc.getBufferData(&Invalid);
1381 if (Invalid)
1382 return;
1383 const char *BufStart = BufData.data();
1384 const char *BufEnd = BufStart + BufData.size();
1385
1386 unsigned CaretLineNo = Loc.getLineNumber();
1387 Bytes CaretByte = Loc.getColumnNumber();
1388
1389 // Arbitrarily stop showing snippets when the line is too long.
1390 static const size_t MaxLineLengthToPrint = 4096;
1391 if (CaretByte > MaxLineLengthToPrint)
1392 return;
1393
1394 // Find the set of lines to include.
1395 const unsigned MaxLines = DiagOpts.SnippetLineLimit;
1396 std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
1397 unsigned DisplayLineNo = Loc.getPresumedLoc().getLine();
1398 for (const auto &I : Ranges) {
1399 if (auto OptionalRange = findLinesForRange(I, FID, SM))
1400 Lines = maybeAddRange(Lines, *OptionalRange, MaxLines);
1401
1402 DisplayLineNo =
1403 std::min(DisplayLineNo, SM.getPresumedLineNumber(I.getBegin()));
1404 }
1405
1406 // Our line numbers look like:
1407 // " [number] | "
1408 // Where [number] is MaxLineNoDisplayWidth columns
1409 // and the full thing is therefore MaxLineNoDisplayWidth + 4 columns.
1410 unsigned MaxLineNoDisplayWidth =
1411 DiagOpts.ShowLineNumbers
1412 ? std::max(4u, getNumDisplayWidth(DisplayLineNo + MaxLines))
1413 : 0;
1414 auto indentForLineNumbers = [&] {
1415 if (MaxLineNoDisplayWidth > 0)
1416 OS.indent(MaxLineNoDisplayWidth + 2) << "| ";
1417 };
1418
1419 Columns MessageLength = DiagOpts.MessageLength;
1420 // If we don't have enough columns available, just abort now.
1421 if (MessageLength != 0 && MessageLength <= Columns(MaxLineNoDisplayWidth + 4))
1422 return;
1423
1424 // Prepare source highlighting information for the lines we're about to
1425 // emit, starting from the first line.
1426 std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles =
1427 highlightLines(BufData, Lines.first, Lines.second, PP, LangOpts,
1428 DiagOpts.showColors(OS.has_colors()), FID, SM);
1429
1430 SmallVector<LineRange> LineRanges =
1431 prepareAndFilterRanges(Ranges, SM, Lines, FID, LangOpts);
1432
1433 for (unsigned LineNo = Lines.first; LineNo != Lines.second + 1;
1434 ++LineNo, ++DisplayLineNo) {
1435 // Rewind from the current position to the start of the line.
1436 const char *LineStart =
1437 BufStart +
1438 SM.getDecomposedLoc(SM.translateLineCol(FID, LineNo, 1)).second;
1439 if (LineStart == BufEnd)
1440 break;
1441
1442 // Compute the line end.
1443 const char *LineEnd = LineStart;
1444 while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd != BufEnd)
1445 ++LineEnd;
1446
1447 // Arbitrarily stop showing snippets when the line is too long.
1448 // FIXME: Don't print any lines in this case.
1449 if (size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
1450 return;
1451
1452 // Copy the line of code into an std::string for ease of manipulation.
1453 std::string SourceLine(LineStart, LineEnd);
1454 // Remove trailing null bytes.
1455 while (!SourceLine.empty() && SourceLine.back() == '\0' &&
1456 (LineNo != CaretLineNo ||
1457 SourceLine.size() > static_cast<size_t>(CaretByte.V)))
1458 SourceLine.pop_back();
1459
1460 // Build the byte to column map.
1461 const SourceColumnMap SourceColMap(SourceLine, DiagOpts.TabStop);
1462
1463 std::string CaretLine;
1464 // Highlight all of the characters covered by Ranges with ~ characters.
1465 for (const auto &LR : LineRanges) {
1466 if (LR.LineNo == LineNo)
1467 highlightRange(LR, SourceColMap, CaretLine);
1468 }
1469
1470 // Next, insert the caret itself.
1471 if (CaretLineNo == LineNo) {
1472 Columns Col = SourceColMap.byteToContainingColumn(CaretByte.prev());
1473 CaretLine.resize(
1474 std::max(static_cast<size_t>(Col.V) + 1, CaretLine.size()), ' ');
1475 CaretLine[Col.V] = '^';
1476 }
1477
1478 std::string FixItInsertionLine =
1479 buildFixItInsertionLine(FID, LineNo, SourceColMap, Hints, SM, DiagOpts);
1480
1481 // If the source line is too long for our terminal, select only the
1482 // "interesting" source region within that line.
1483 if (MessageLength != 0) {
1484 Columns NonGutterColumns = MessageLength;
1485 if (MaxLineNoDisplayWidth != 0)
1486 NonGutterColumns -= Columns(MaxLineNoDisplayWidth + 4);
1487 selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
1488 NonGutterColumns, SourceColMap,
1489 SourceStyles[LineNo - Lines.first]);
1490 }
1491
1492 // If we are in -fdiagnostics-print-source-range-info mode, we are trying
1493 // to produce easily machine parsable output. Add a space before the
1494 // source line and the caret to make it trivial to tell the main diagnostic
1495 // line from what the user is intended to see.
1496 if (DiagOpts.ShowSourceRanges && !SourceLine.empty()) {
1497 SourceLine = ' ' + SourceLine;
1498 CaretLine = ' ' + CaretLine;
1499 }
1500
1501 // Emit what we have computed.
1502 emitSnippet(SourceLine, MaxLineNoDisplayWidth, LineNo, DisplayLineNo,
1503 SourceStyles[LineNo - Lines.first]);
1504
1505 if (!CaretLine.empty()) {
1506 indentForLineNumbers();
1507 if (DiagOpts.showColors(OS.has_colors()))
1508 OS.changeColor(CaretColor, true);
1509 OS << CaretLine << '\n';
1510 if (DiagOpts.showColors(OS.has_colors()))
1511 OS.resetColor();
1512 }
1513
1514 if (!FixItInsertionLine.empty()) {
1515 indentForLineNumbers();
1516 if (DiagOpts.showColors(OS.has_colors()))
1517 // Print fixit line in color
1518 OS.changeColor(FixitColor, false);
1519 if (DiagOpts.ShowSourceRanges)
1520 OS << ' ';
1521 OS << FixItInsertionLine << '\n';
1522 if (DiagOpts.showColors(OS.has_colors()))
1523 OS.resetColor();
1524 }
1525 }
1526
1527 // Print out any parseable fixit information requested by the options.
1528 emitParseableFixits(Hints, SM);
1529}
1530
1531void TextDiagnostic::emitSnippet(StringRef SourceLine,
1532 unsigned MaxLineNoDisplayWidth,
1533 unsigned LineNo, unsigned DisplayLineNo,
1534 ArrayRef<StyleRange> Styles) {
1535 // Emit line number.
1536 if (MaxLineNoDisplayWidth > 0) {
1537 unsigned LineNoDisplayWidth = getNumDisplayWidth(DisplayLineNo);
1538 OS.indent(MaxLineNoDisplayWidth - LineNoDisplayWidth + 1)
1539 << DisplayLineNo << " | ";
1540 }
1541
1542 // Print the source line one character at a time.
1543 bool PrintReversed = false;
1544 std::optional<llvm::raw_ostream::Colors> CurrentColor;
1545 size_t I = 0; // Bytes.
1546 while (I < SourceLine.size()) {
1547 auto [Str, WasPrintable] =
1548 printableTextForNextCharacter(SourceLine, &I, DiagOpts.TabStop);
1549
1550 // Toggle inverted colors on or off for this character.
1551 if (DiagOpts.showColors(OS.has_colors())) {
1552 if (WasPrintable == PrintReversed) {
1553 PrintReversed = !PrintReversed;
1554 if (PrintReversed)
1555 OS.reverseColor();
1556 else {
1557 OS.resetColor();
1558 CurrentColor = std::nullopt;
1559 }
1560 }
1561
1562 // Apply syntax highlighting information.
1563 const auto *CharStyle = llvm::find_if(Styles, [I](const StyleRange &R) {
1564 return (R.Start < I && R.End >= I);
1565 });
1566
1567 if (CharStyle != Styles.end()) {
1568 if (!CurrentColor ||
1569 (CurrentColor && *CurrentColor != CharStyle->Color)) {
1570 OS.changeColor(CharStyle->Color);
1571 CurrentColor = CharStyle->Color;
1572 }
1573 } else if (CurrentColor) {
1574 OS.resetColor();
1575 CurrentColor = std::nullopt;
1576 }
1577 }
1578
1579 OS << Str;
1580 }
1581
1582 if (DiagOpts.showColors(OS.has_colors()))
1583 OS.resetColor();
1584
1585 OS << '\n';
1586}
1587
1588void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
1589 const SourceManager &SM) {
1590 if (!DiagOpts.ShowParseableFixits)
1591 return;
1592
1593 // We follow FixItRewriter's example in not (yet) handling
1594 // fix-its in macros.
1595 for (const auto &H : Hints) {
1596 if (H.RemoveRange.isInvalid() || H.RemoveRange.getBegin().isMacroID() ||
1597 H.RemoveRange.getEnd().isMacroID())
1598 return;
1599 }
1600
1601 for (const auto &H : Hints) {
1602 SourceLocation BLoc = H.RemoveRange.getBegin();
1603 SourceLocation ELoc = H.RemoveRange.getEnd();
1604
1605 FileIDAndOffset BInfo = SM.getDecomposedLoc(BLoc);
1606 FileIDAndOffset EInfo = SM.getDecomposedLoc(ELoc);
1607
1608 // Adjust for token ranges.
1609 if (H.RemoveRange.isTokenRange())
1610 EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
1611
1612 // We specifically do not do word-wrapping or tab-expansion here,
1613 // because this is supposed to be easy to parse.
1614 PresumedLoc PLoc = SM.getPresumedLoc(BLoc);
1615 if (PLoc.isInvalid())
1616 break;
1617
1618 OS << "fix-it:\"";
1619 OS.write_escaped(PLoc.getFilename());
1620 OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second)
1621 << ':' << SM.getColumnNumber(BInfo.first, BInfo.second)
1622 << '-' << SM.getLineNumber(EInfo.first, EInfo.second)
1623 << ':' << SM.getColumnNumber(EInfo.first, EInfo.second)
1624 << "}:\"";
1625 OS.write_escaped(H.CodeToInsert);
1626 OS << "\"\n";
1627 }
1628}
#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)
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.
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
StringRef getCanonicalName(DirectoryEntryRef Dir)
Retrieve the canonical name for a given directory.
bool makeAbsolutePath(SmallVectorImpl< char > &Path, bool Canonicalize=false) const
Makes Path absolute taking into account FileSystemOptions and the working directory option,...
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true, bool IsText=true)
Get a FileEntryRef if it exists, without doing anything on error.
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:288
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:462
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:509
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.
FileIDAndOffset getDecomposedExpansionLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
FileIDAndOffset getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
unsigned getColumnNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Return the column # for the specified file position.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.
unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
unsigned getExpansionColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
SourceLocation translateLineCol(FileID FID, unsigned Line, unsigned Col) const
Get the source location in FID for the given line:col.
unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
FileManager & getFileManager() const
unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid=nullptr) const
Given a SourceLocation, return the spelling line number for the position indicated.
unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
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:109
Top level wrappers for InstallAPI frontend operations.
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.
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.
std::optional< CharSourceRange > getExpansionRangeInFile(CharSourceRange Range, FileID FID, const SourceManager &SM)
Maps both endpoints of Range to their macro expansion, so that the range can be shown to a user.