15#include "llvm/ADT/SmallString.h"
16#include "llvm/ADT/StringExtras.h"
17#include "llvm/Support/ConvertUTF.h"
18#include "llvm/Support/ErrorHandling.h"
19#include "llvm/Support/Locale.h"
20#include "llvm/Support/Path.h"
21#include "llvm/Support/raw_ostream.h"
39static const enum raw_ostream::Colors
errorColor = raw_ostream::RED;
40static const enum raw_ostream::Colors
fatalColor = raw_ostream::RED;
43 raw_ostream::SAVEDCOLOR;
50 OS << Str.slice(0, Pos);
51 if (Pos == StringRef::npos)
54 Str = Str.substr(Pos + 1);
72 if (SourceLine[--i]==
'\t')
98static std::pair<SmallString<16>,
bool>
101 assert(i &&
"i must not be null");
102 assert(*i<SourceLine.size() &&
"must point to a valid index");
104 if (SourceLine[*i]==
'\t') {
106 "Invalid -ftabstop value");
108 unsigned NumSpaces = TabStop - col%TabStop;
109 assert(0 < NumSpaces && NumSpaces <= TabStop
110 &&
"Invalid computation of space amt");
114 expandedTab.assign(NumSpaces,
' ');
115 return std::make_pair(expandedTab,
true);
118 unsigned char const *begin, *end;
119 begin =
reinterpret_cast<unsigned char const *
>(&*(SourceLine.begin() + *i));
120 end = begin + (SourceLine.size() - *i);
122 if (llvm::isLegalUTF8Sequence(begin, end)) {
124 llvm::UTF32 *cptr = &
c;
125 unsigned char const *original_begin = begin;
126 unsigned char const *cp_end =
127 begin + llvm::getNumBytesForUTF8(SourceLine[*i]);
129 llvm::ConversionResult res = llvm::ConvertUTF8toUTF32(
130 &begin, cp_end, &cptr, cptr + 1, llvm::strictConversion);
132 assert(llvm::conversionOK == res);
133 assert(0 < begin-original_begin
134 &&
"we must be further along in the string now");
135 *i += begin-original_begin;
137 if (!llvm::sys::locale::isPrint(
c)) {
141 expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(
c%16));
144 while (expandedCP.size() < 8)
145 expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(0));
146 return std::make_pair(expandedCP,
false);
156 unsigned char byte = SourceLine[*i];
157 expandedByte[1] = llvm::hexdigit(
byte / 16);
158 expandedByte[2] = llvm::hexdigit(
byte % 16);
160 return std::make_pair(expandedByte,
false);
163static void expandTabs(std::string &SourceLine,
unsigned TabStop) {
164 size_t i = SourceLine.size();
167 if (SourceLine[i]!=
'\t')
170 std::pair<SmallString<16>,
bool> res
172 SourceLine.replace(i, 1, res.first.c_str());
202 if (SourceLine.empty()) {
207 out.resize(SourceLine.size()+1, -1);
211 while (i<SourceLine.size()) {
213 std::pair<SmallString<16>,
bool> res
215 columns += llvm::sys::locale::columnWidth(res.first);
217 out.back() = columns;
236 if (SourceLine.empty()) {
243 while (i<SourceLine.size()) {
244 out.resize(columns+1, -1);
246 std::pair<SmallString<16>,
bool> res
248 columns += llvm::sys::locale::columnWidth(res.first);
250 out.resize(columns+1, -1);
255struct SourceColumnMap {
256 SourceColumnMap(StringRef SourceLine,
unsigned TabStop)
257 : m_SourceLine(SourceLine) {
262 assert(m_byteToColumn.size()==SourceLine.size()+1);
263 assert(0 < m_byteToColumn.size() && 0 < m_columnToByte.size());
264 assert(m_byteToColumn.size()
265 ==
static_cast<unsigned>(m_columnToByte.back()+1));
266 assert(
static_cast<unsigned>(m_byteToColumn.back()+1)
267 == m_columnToByte.size());
269 int columns()
const {
return m_byteToColumn.back(); }
270 int bytes()
const {
return m_columnToByte.back(); }
275 assert(0<=n && n<
static_cast<int>(m_byteToColumn.size()));
276 return m_byteToColumn[n];
280 int byteToContainingColumn(
int N)
const {
281 assert(0 <= N && N <
static_cast<int>(m_byteToColumn.size()));
282 while (m_byteToColumn[N] == -1)
284 return m_byteToColumn[N];
291 assert(0<=n && n<
static_cast<int>(m_columnToByte.size()));
292 return m_columnToByte[n];
296 int startOfNextColumn(
int N)
const {
297 assert(0 <= N && N <
static_cast<int>(m_byteToColumn.size() - 1));
303 int startOfPreviousColumn(
int N)
const {
304 assert(0 < N && N <
static_cast<int>(m_byteToColumn.size()));
309 StringRef getSourceLine()
const {
314 const std::string m_SourceLine;
323 std::string &CaretLine,
324 std::string &FixItInsertionLine,
326 const SourceColumnMap &map) {
327 unsigned CaretColumns = CaretLine.size();
328 unsigned FixItColumns = llvm::sys::locale::columnWidth(FixItInsertionLine);
329 unsigned MaxColumns = std::max(
static_cast<unsigned>(map.columns()),
330 std::max(CaretColumns, FixItColumns));
332 if (MaxColumns <= Columns)
336 assert(llvm::none_of(CaretLine, [](
char c) {
return c <
' ' ||
'~' <
c; }));
340 unsigned CaretStart = 0, CaretEnd = CaretLine.size();
341 for (; CaretStart != CaretEnd; ++CaretStart)
345 for (; CaretEnd != CaretStart; --CaretEnd)
354 if (!FixItInsertionLine.empty()) {
355 unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
356 for (; FixItStart != FixItEnd; ++FixItStart)
360 for (; FixItEnd != FixItStart; --FixItEnd)
367 unsigned FixItStartCol = FixItStart;
369 = llvm::sys::locale::columnWidth(FixItInsertionLine.substr(0, FixItEnd));
371 CaretStart = std::min(FixItStartCol, CaretStart);
372 CaretEnd = std::max(FixItEndCol, CaretEnd);
378 while (
static_cast<int>(CaretEnd) < map.columns() &&
379 -1 == map.columnToByte(CaretEnd))
382 assert((
static_cast<int>(CaretStart) > map.columns() ||
383 -1!=map.columnToByte(CaretStart)) &&
384 "CaretStart must not point to a column in the middle of a source"
386 assert((
static_cast<int>(CaretEnd) > map.columns() ||
387 -1!=map.columnToByte(CaretEnd)) &&
388 "CaretEnd must not point to a column in the middle of a source line"
396 unsigned SourceStart = map.columnToByte(std::min<unsigned>(CaretStart,
398 unsigned SourceEnd = map.columnToByte(std::min<unsigned>(CaretEnd,
401 unsigned CaretColumnsOutsideSource = CaretEnd-CaretStart
402 - (map.byteToColumn(SourceEnd)-map.byteToColumn(SourceStart));
404 char const *front_ellipse =
" ...";
405 char const *front_space =
" ";
406 char const *back_ellipse =
"...";
407 unsigned ellipses_space = strlen(front_ellipse) + strlen(back_ellipse);
409 unsigned TargetColumns = Columns;
412 if (TargetColumns > ellipses_space+CaretColumnsOutsideSource)
413 TargetColumns -= ellipses_space+CaretColumnsOutsideSource;
415 while (SourceStart>0 || SourceEnd<SourceLine.size()) {
416 bool ExpandedRegion =
false;
419 unsigned NewStart = map.startOfPreviousColumn(SourceStart);
425 NewStart = map.startOfPreviousColumn(NewStart);
429 unsigned Prev = map.startOfPreviousColumn(NewStart);
435 assert(map.byteToColumn(NewStart) != -1);
436 unsigned NewColumns = map.byteToColumn(SourceEnd) -
437 map.byteToColumn(NewStart);
438 if (NewColumns <= TargetColumns) {
439 SourceStart = NewStart;
440 ExpandedRegion =
true;
444 if (SourceEnd<SourceLine.size()) {
445 unsigned NewEnd = map.startOfNextColumn(SourceEnd);
450 while (NewEnd < SourceLine.size() &&
isWhitespace(SourceLine[NewEnd]))
451 NewEnd = map.startOfNextColumn(NewEnd);
454 while (NewEnd < SourceLine.size() &&
isWhitespace(SourceLine[NewEnd]))
455 NewEnd = map.startOfNextColumn(NewEnd);
457 assert(map.byteToColumn(NewEnd) != -1);
458 unsigned NewColumns = map.byteToColumn(NewEnd) -
459 map.byteToColumn(SourceStart);
460 if (NewColumns <= TargetColumns) {
462 ExpandedRegion =
true;
470 CaretStart = map.byteToColumn(SourceStart);
471 CaretEnd = map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource;
477 assert(CaretStart!=(
unsigned)-1 && CaretEnd!=(
unsigned)-1 &&
478 SourceStart!=(
unsigned)-1 && SourceEnd!=(
unsigned)-1);
479 assert(SourceStart <= SourceEnd);
480 assert(CaretStart <= CaretEnd);
482 unsigned BackColumnsRemoved
483 = map.byteToColumn(SourceLine.size())-map.byteToColumn(SourceEnd);
484 unsigned FrontColumnsRemoved = CaretStart;
485 unsigned ColumnsKept = CaretEnd-CaretStart;
488 assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns);
492 if (BackColumnsRemoved > strlen(back_ellipse))
493 SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
496 if (FrontColumnsRemoved+ColumnsKept <= Columns)
500 if (FrontColumnsRemoved > strlen(front_ellipse)) {
501 SourceLine.replace(0, SourceStart, front_ellipse);
502 CaretLine.replace(0, CaretStart, front_space);
503 if (!FixItInsertionLine.empty())
504 FixItInsertionLine.replace(0, CaretStart, front_space);
528 case '\'':
return '\'';
529 case '`':
return '\'';
530 case '"':
return '"';
531 case '(':
return ')';
532 case '[':
return ']';
533 case '{':
return '}';
546 unsigned Length,
unsigned Column,
548 assert(Start < Str.size() &&
"Invalid start position!");
549 unsigned End = Start + 1;
552 if (End == Str.size())
568 PunctuationEndStack.push_back(EndPunct);
569 while (End < Length && !PunctuationEndStack.empty()) {
570 if (Str[End] == PunctuationEndStack.back())
571 PunctuationEndStack.pop_back();
573 PunctuationEndStack.push_back(SubEndPunct);
582 unsigned PunctWordLength = End - Start;
584 Column + PunctWordLength <= Columns ||
587 PunctWordLength < Columns/3)
594 return findEndOfWord(Start + 1, Str, Length, Column + 1, Columns);
617 const unsigned Length = std::min(Str.find(
'\n'), Str.size());
618 bool TextNormal =
true;
622 IndentStr.assign(Indentation,
' ');
623 bool Wrapped =
false;
624 for (
unsigned WordStart = 0, WordEnd; WordStart < Length;
625 WordStart = WordEnd) {
628 if (WordStart == Length)
632 WordEnd =
findEndOfWord(WordStart, Str, Length, Column, Columns);
635 unsigned WordLength = WordEnd - WordStart;
636 if (Column + WordLength < Columns) {
644 Column += WordLength;
651 OS.write(&IndentStr[0], Indentation);
654 Column = Indentation + WordLength;
661 assert(TextNormal &&
"Text highlighted at end of diagnostic message.");
677 uint64_t StartOfLocationInfo = OS.tell();
690 Message, OS.tell() - StartOfLocationInfo,
702 llvm_unreachable(
"Invalid diagnostic type");
713 llvm_unreachable(
"Invalid diagnostic type");
729 unsigned CurrentColumn,
730 unsigned Columns,
bool ShowColors) {
732 if (ShowColors && !IsSupplemental) {
744 assert(
Normal &&
"Formatting should have returned to normal");
774 TmpFilename = (*File)->getName();
775 llvm::sys::fs::make_absolute(TmpFilename);
776 llvm::sys::path::native(TmpFilename);
777 llvm::sys::path::remove_dots(TmpFilename,
true);
778 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
802 emitFilename(FE->getName(), Loc.
getManager());
808 unsigned LineNo = PLoc.
getLine();
833 if (
LangOpts.MSCompatibilityVersion &&
848 if (
LangOpts.MSCompatibilityVersion &&
855 if (
DiagOpts->ShowSourceRanges && !Ranges.empty()) {
857 bool PrintedRange =
false;
863 if (!RI->isValid())
continue;
871 std::pair<FileID, unsigned> BInfo =
SM.getDecomposedLoc(B);
872 std::pair<FileID, unsigned> EInfo =
SM.getDecomposedLoc(E);
876 if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
881 unsigned TokSize = 0;
887 << BF.getLineNumber() <<
':' << BF.getColumnNumber() <<
'-'
901 OS <<
"In file included from " << PLoc.
getFilename() <<
':'
904 OS <<
"In included file:\n";
908 StringRef ModuleName) {
910 OS <<
"In module '" << ModuleName <<
"' imported from "
913 OS <<
"In module '" << ModuleName <<
"':\n";
918 StringRef ModuleName) {
920 OS <<
"While building module '" << ModuleName <<
"' imported from "
923 OS <<
"While building module '" << ModuleName <<
"':\n";
927static std::optional<std::pair<unsigned, unsigned>>
935 if (
SM.getFileID(
Begin) != FID ||
SM.getFileID(End) != FID)
938 return std::make_pair(
SM.getExpansionLineNumber(
Begin),
939 SM.getExpansionLineNumber(End));
944static std::pair<unsigned, unsigned>
945maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
948 unsigned Slack = MaxRange - (A.second - A.first + 1);
953 unsigned Min = std::min(A.first, B.first);
954 unsigned Max = std::max(A.second, B.second);
955 if (Max - Min + 1 <= MaxRange)
960 if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
961 (B.second < A.second && A.second - B.second + 1 > MaxRange))
970 A.second = std::min(A.second + (Slack + 1) / 2, Max);
971 Slack = MaxRange - (A.second - A.first + 1);
972 A.first = std::max(Min + Slack, A.first) - Slack;
973 A.second = std::min(A.first + MaxRange - 1, Max);
979 unsigned LineNo,
FileID FID,
980 const SourceColumnMap &map,
981 std::string &CaretLine,
989 unsigned StartLineNo =
SM.getExpansionLineNumber(
Begin);
990 if (StartLineNo > LineNo ||
SM.getFileID(
Begin) != FID)
993 unsigned EndLineNo =
SM.getExpansionLineNumber(End);
994 if (EndLineNo < LineNo ||
SM.getFileID(End) != FID)
998 unsigned StartColNo = 0;
999 if (StartLineNo == LineNo) {
1000 StartColNo =
SM.getExpansionColumnNumber(
Begin);
1001 if (StartColNo) --StartColNo;
1005 unsigned EndColNo = map.getSourceLine().size();
1006 if (EndLineNo == LineNo) {
1007 EndColNo =
SM.getExpansionColumnNumber(End);
1016 EndColNo = CaretLine.size();
1020 assert(StartColNo <= EndColNo &&
"Invalid range!");
1025 while (StartColNo < map.getSourceLine().size() &&
1026 (map.getSourceLine()[StartColNo] ==
' ' ||
1027 map.getSourceLine()[StartColNo] ==
'\t'))
1028 StartColNo = map.startOfNextColumn(StartColNo);
1031 if (EndColNo > map.getSourceLine().size())
1032 EndColNo = map.getSourceLine().size();
1034 (map.getSourceLine()[EndColNo-1] ==
' ' ||
1035 map.getSourceLine()[EndColNo-1] ==
'\t'))
1036 EndColNo = map.startOfPreviousColumn(EndColNo);
1041 if (StartColNo > EndColNo) {
1042 assert(StartLineNo != EndLineNo &&
"trying to highlight whitespace");
1043 StartColNo = EndColNo;
1047 assert(StartColNo <= map.getSourceLine().size() &&
"Invalid range!");
1048 assert(EndColNo <= map.getSourceLine().size() &&
"Invalid range!");
1051 StartColNo = map.byteToContainingColumn(StartColNo);
1052 EndColNo = map.byteToContainingColumn(EndColNo);
1054 assert(StartColNo <= EndColNo &&
"Invalid range!");
1055 if (CaretLine.size() < EndColNo)
1056 CaretLine.resize(EndColNo,
' ');
1057 std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,
'~');
1062 const SourceColumnMap &map,
1066 std::string FixItInsertionLine;
1067 if (Hints.empty() || !DiagOpts->ShowFixits)
1068 return FixItInsertionLine;
1069 unsigned PrevHintEndCol = 0;
1073 if (!I->CodeToInsert.empty()) {
1076 std::pair<FileID, unsigned> HintLocInfo
1077 =
SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
1078 if (FID == HintLocInfo.first &&
1079 LineNo ==
SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
1080 StringRef(I->CodeToInsert).find_first_of(
"\n\r") == StringRef::npos) {
1086 unsigned HintByteOffset
1087 =
SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
1090 assert(HintByteOffset <
static_cast<unsigned>(map.bytes())+1);
1091 unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
1100 if (HintCol < PrevHintEndCol)
1101 HintCol = PrevHintEndCol + 1;
1105 unsigned NewFixItLineSize = FixItInsertionLine.size() +
1106 (HintCol - PrevHintEndCol) + I->CodeToInsert.size();
1107 if (NewFixItLineSize > FixItInsertionLine.size())
1108 FixItInsertionLine.resize(NewFixItLineSize,
' ');
1110 std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
1111 FixItInsertionLine.end() - I->CodeToInsert.size());
1114 HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert);
1119 expandTabs(FixItInsertionLine, DiagOpts->TabStop);
1121 return FixItInsertionLine;
1131void TextDiagnostic::emitSnippetAndCaret(
1134 assert(Loc.
isValid() &&
"must have a valid source location here");
1135 assert(Loc.
isFileID() &&
"must have a file location here");
1145 if (Loc ==
LastLoc && Ranges.empty() && Hints.empty() &&
1151 FileID FID = LocInfo.first;
1164 static const size_t MaxLineLengthToPrint = 4096;
1165 if (CaretColNo > MaxLineLengthToPrint)
1169 const unsigned MaxLines =
DiagOpts->SnippetLineLimit;
1170 std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
1177 for (
unsigned LineNo = Lines.first; LineNo != Lines.second + 1; ++LineNo) {
1178 const char *BufStart = BufData.data();
1179 const char *BufEnd = BufStart + BufData.size();
1182 const char *LineStart =
1184 SM.getDecomposedLoc(
SM.translateLineCol(FID, LineNo, 1)).second;
1185 if (LineStart == BufEnd)
1189 const char *LineEnd = LineStart;
1190 while (*LineEnd !=
'\n' && *LineEnd !=
'\r' && LineEnd != BufEnd)
1195 if (
size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
1199 StringRef Line(LineStart, LineEnd - LineStart);
1200 while (!Line.empty() && Line.back() ==
'\0' &&
1201 (LineNo != CaretLineNo || Line.size() > CaretColNo))
1202 Line = Line.drop_back();
1205 std::string SourceLine(Line.begin(), Line.end());
1208 const SourceColumnMap sourceColMap(SourceLine,
DiagOpts->TabStop);
1212 std::string CaretLine(sourceColMap.columns(),
' ');
1221 if (CaretLineNo == LineNo) {
1222 CaretColNo = sourceColMap.byteToContainingColumn(CaretColNo - 1);
1223 if (CaretLine.size() < CaretColNo + 1)
1224 CaretLine.resize(CaretColNo + 1,
' ');
1225 CaretLine[CaretColNo] =
'^';
1229 FID, LineNo, sourceColMap, Hints,
SM,
DiagOpts.get());
1233 unsigned Columns =
DiagOpts->MessageLength;
1236 Columns, sourceColMap);
1243 SourceLine =
' ' + SourceLine;
1244 CaretLine =
' ' + CaretLine;
1248 while (!CaretLine.empty() && CaretLine[CaretLine.size() - 1] ==
' ')
1249 CaretLine.erase(CaretLine.end() - 1);
1252 emitSnippet(SourceLine);
1254 if (!CaretLine.empty()) {
1257 OS << CaretLine <<
'\n';
1262 if (!FixItInsertionLine.empty()) {
1268 OS << FixItInsertionLine <<
'\n';
1275 emitParseableFixits(Hints,
SM);
1278void TextDiagnostic::emitSnippet(StringRef line) {
1284 std::string to_print;
1285 bool print_reversed =
false;
1287 while (i<line.size()) {
1288 std::pair<SmallString<16>,
bool> res
1290 bool was_printable = res.second;
1292 if (
DiagOpts->ShowColors && was_printable == print_reversed) {
1301 print_reversed = !was_printable;
1302 to_print += res.first.str();
1305 if (print_reversed &&
DiagOpts->ShowColors)
1308 if (print_reversed &&
DiagOpts->ShowColors)
1316 if (!
DiagOpts->ShowParseableFixits)
1323 if (I->RemoveRange.isInvalid() ||
1324 I->RemoveRange.getBegin().isMacroID() ||
1325 I->RemoveRange.getEnd().isMacroID())
1334 std::pair<FileID, unsigned> BInfo =
SM.getDecomposedLoc(BLoc);
1335 std::pair<FileID, unsigned> EInfo =
SM.getDecomposedLoc(ELoc);
1338 if (I->RemoveRange.isTokenRange())
1349 OS <<
"\":{" <<
SM.getLineNumber(BInfo.first, BInfo.second)
1350 <<
':' <<
SM.getColumnNumber(BInfo.first, BInfo.second)
1351 <<
'-' <<
SM.getLineNumber(EInfo.first, EInfo.second)
1352 <<
':' <<
SM.getColumnNumber(EInfo.first, EInfo.second)
1354 OS.write_escaped(I->CodeToInsert);
static StringRef bytes(const std::vector< T, Allocator > &v)
Defines the clang::FileManager interface and associated types.
Defines the SourceManager interface.
static enum raw_ostream::Colors caretColor
static int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i)
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 std::pair< SmallString< 16 >, bool > printableTextForNextCharacter(StringRef SourceLine, size_t *i, unsigned TabStop)
returns a printable representation of first item from input range
static enum raw_ostream::Colors fixitColor
static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str, bool &Normal, bool Bold)
Add highlights to differences in template strings.
static enum raw_ostream::Colors savedColor
static enum raw_ostream::Colors errorColor
static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length)
Skip over whitespace in the string, starting at the given index.
static unsigned findEndOfWord(unsigned Start, StringRef Str, unsigned Length, unsigned Column, unsigned Columns)
Find the end of the word starting at the given offset within a string.
static enum raw_ostream::Colors remarkColor
static enum raw_ostream::Colors fatalColor
static bool printWordWrapped(raw_ostream &OS, StringRef Str, unsigned Columns, unsigned Column=0, bool Bold=false, unsigned Indentation=WordWrapIndentation)
Print the given string to a stream, word-wrapping it to some number of columns in the process.
static void highlightRange(const CharSourceRange &R, unsigned LineNo, FileID FID, const SourceColumnMap &map, std::string &CaretLine, const SourceManager &SM, const LangOptions &LangOpts)
Highlight a SourceRange (with ~'s) for any characters on LineNo.
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 void selectInterestingSourceRegion(std::string &SourceLine, std::string &CaretLine, std::string &FixItInsertionLine, unsigned Columns, const SourceColumnMap &map)
When the source code line we want to print is too long for the terminal, select the "interesting" reg...
static std::string buildFixItInsertionLine(FileID FID, unsigned LineNo, const SourceColumnMap &map, ArrayRef< FixItHint > Hints, const SourceManager &SM, const DiagnosticOptions *DiagOpts)
static enum raw_ostream::Colors warningColor
static char findMatchingPunctuation(char c)
If the given character is the start of some kind of balanced punctuation (e.g., quotes or parentheses...
static enum raw_ostream::Colors noteColor
static void byteToColumn(StringRef SourceLine, unsigned TabStop, SmallVectorImpl< int > &out)
This function takes a raw source line and produces a mapping from the bytes of the printable represen...
static void columnToByte(StringRef SourceLine, unsigned TabStop, SmallVectorImpl< int > &out)
This function takes a raw source line and produces a mapping from columns to the byte of the source l...
static void expandTabs(std::string &SourceLine, unsigned TabStop)
const unsigned WordWrapIndentation
Number of spaces to indent when word-wrapping.
static enum raw_ostream::Colors templateColor
__device__ __2f16 float c
Represents a character-granular source range.
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
SourceLocation getEnd() const
SourceLocation getBegin() const
Options for controlling the compiler diagnostics engine.
Class to encapsulate the logic for formatting a diagnostic message.
const LangOptions & LangOpts
SourceLocation LastLoc
The location of the previous diagnostic if known.
DiagnosticsEngine::Level LastLevel
The level of the last diagnostic emitted.
IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts
Level
The level of the diagnostic, after it has been through mapping.
Cached information about one file (either on disk or in the virtual file system).
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
A SourceLocation and its associated SourceManager.
unsigned getColumnNumber(bool *Invalid=nullptr) const
FullSourceLoc getExpansionLoc() const
unsigned getLineNumber(bool *Invalid=nullptr) const
StringRef getBufferData(bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
const FileEntry * getFileEntry() const
std::pair< FileID, unsigned > getDecomposedLoc() const
Decompose the specified location into a raw FileID + Offset pair.
const SourceManager & getManager() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const
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 ...
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
const char * getFilename() const
Return the presumed filename of this location.
unsigned getLine() const
Return the presumed line number of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
static void printDiagnosticMessage(raw_ostream &OS, bool IsSupplemental, StringRef Message, unsigned CurrentColumn, unsigned Columns, bool ShowColors)
Pretty-print a diagnostic message to a raw_ostream.
~TextDiagnostic() override
void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override
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
TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts, DiagnosticOptions *DiagOpts)
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
const char ToggleHighlight
Special character that the diagnostic printer will use to toggle the bold attribute.