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