16#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/Support/ConvertUTF.h"
19#include "llvm/Support/ErrorHandling.h"
20#include "llvm/Support/Locale.h"
21#include "llvm/Support/Path.h"
22#include "llvm/Support/raw_ostream.h"
28static const enum raw_ostream::Colors
noteColor = raw_ostream::CYAN;
39static const enum raw_ostream::Colors
errorColor = raw_ostream::RED;
40static const enum raw_ostream::Colors
fatalColor = raw_ostream::RED;
43 raw_ostream::SAVEDCOLOR;
49static constexpr raw_ostream::Colors
CommentColor = raw_ostream::YELLOW;
50static constexpr raw_ostream::Colors
LiteralColor = raw_ostream::GREEN;
51static constexpr raw_ostream::Colors
KeywordColor = raw_ostream::BLUE;
58 OS << Str.slice(0, Pos);
59 if (Pos == StringRef::npos)
62 Str = Str.substr(Pos + 1);
80 if (SourceLine[--i]==
'\t')
106static std::pair<SmallString<16>,
bool>
109 assert(I &&
"I must not be null");
110 assert(*I < SourceLine.size() &&
"must point to a valid index");
112 if (SourceLine[*I] ==
'\t') {
114 "Invalid -ftabstop value");
116 unsigned NumSpaces = TabStop - (Col % TabStop);
117 assert(0 < NumSpaces && NumSpaces <= TabStop
118 &&
"Invalid computation of space amt");
122 ExpandedTab.assign(NumSpaces,
' ');
123 return std::make_pair(ExpandedTab,
true);
126 const unsigned char *
Begin = SourceLine.bytes_begin() + *I;
129 if (*
Begin < 0x80 && llvm::sys::locale::isPrint(*
Begin)) {
133 unsigned CharSize = llvm::getNumBytesForUTF8(*
Begin);
134 const unsigned char *End =
Begin + CharSize;
137 if (End <= SourceLine.bytes_end() && llvm::isLegalUTF8Sequence(
Begin, End)) {
139 llvm::UTF32 *CPtr = &
C;
142 unsigned char const *OriginalBegin =
Begin;
143 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
144 &
Begin, End, &CPtr, CPtr + 1, llvm::strictConversion);
146 assert(Res == llvm::conversionOK);
147 assert(OriginalBegin <
Begin);
148 assert(
unsigned(
Begin - OriginalBegin) == CharSize);
150 (*I) += (
Begin - OriginalBegin);
153 if (llvm::sys::locale::isPrint(
C))
159 Str.insert(Str.begin() + 3, llvm::hexdigit(
C % 16));
162 while (Str.size() < 8)
163 Str.insert(Str.begin() + 3, llvm::hexdigit(0));
164 return std::make_pair(Str,
false);
169 unsigned char Byte = SourceLine[*I];
170 ExpandedByte[1] = llvm::hexdigit(Byte / 16);
171 ExpandedByte[2] = llvm::hexdigit(Byte % 16);
173 return std::make_pair(ExpandedByte,
false);
176static void expandTabs(std::string &SourceLine,
unsigned TabStop) {
177 size_t I = SourceLine.size();
180 if (SourceLine[I] !=
'\t')
183 auto [Str, Printable] =
185 SourceLine.replace(I, 1, Str.c_str());
228 assert(BytesOut.empty());
229 assert(ColumnsOut.empty());
231 if (SourceLine.empty()) {
232 BytesOut.resize(1u, 0);
233 ColumnsOut.resize(1u, 0);
237 ColumnsOut.resize(SourceLine.size() + 1, -1);
241 while (I < SourceLine.size()) {
242 ColumnsOut[I] = Columns;
243 BytesOut.resize(Columns + 1, -1);
245 auto [Str, Printable] =
247 Columns += llvm::sys::locale::columnWidth(Str);
250 ColumnsOut.back() = Columns;
251 BytesOut.resize(Columns + 1, -1);
256struct SourceColumnMap {
257 SourceColumnMap(StringRef SourceLine,
unsigned TabStop)
258 : 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(); }
274 int byteToColumn(
int n)
const {
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];
290 int columnToByte(
int n)
const {
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));
298 while (byteToColumn(++N) == -1) {}
303 int startOfPreviousColumn(
int N)
const {
304 assert(0 < N && N <
static_cast<int>(m_byteToColumn.size()));
305 while (byteToColumn(--N) == -1) {}
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;
475 assert(CaretStart!=(
unsigned)-1 && CaretEnd!=(
unsigned)-1 &&
476 SourceStart!=(
unsigned)-1 && SourceEnd!=(
unsigned)-1);
477 assert(SourceStart <= SourceEnd);
478 assert(CaretStart <= CaretEnd);
480 unsigned BackColumnsRemoved
481 = map.byteToColumn(SourceLine.size())-map.byteToColumn(SourceEnd);
482 unsigned FrontColumnsRemoved = CaretStart;
483 unsigned ColumnsKept = CaretEnd-CaretStart;
486 assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns);
490 if (BackColumnsRemoved > strlen(back_ellipse))
491 SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
494 if (FrontColumnsRemoved+ColumnsKept <= Columns)
498 if (FrontColumnsRemoved > strlen(front_ellipse)) {
499 SourceLine.replace(0, SourceStart, front_ellipse);
500 CaretLine.replace(0, CaretStart, front_space);
501 if (!FixItInsertionLine.empty())
502 FixItInsertionLine.replace(0, CaretStart, front_space);
526 case '\'':
return '\'';
527 case '`':
return '\'';
528 case '"':
return '"';
529 case '(':
return ')';
530 case '[':
return ']';
531 case '{':
return '}';
544 unsigned Length,
unsigned Column,
546 assert(Start < Str.size() &&
"Invalid start position!");
547 unsigned End = Start + 1;
550 if (End == Str.size())
566 PunctuationEndStack.push_back(EndPunct);
567 while (End < Length && !PunctuationEndStack.empty()) {
568 if (Str[End] == PunctuationEndStack.back())
569 PunctuationEndStack.pop_back();
571 PunctuationEndStack.push_back(SubEndPunct);
580 unsigned PunctWordLength = End - Start;
582 Column + PunctWordLength <= Columns ||
585 PunctWordLength < Columns/3)
609 unsigned Column,
bool Bold) {
610 const unsigned Length = std::min(Str.find(
'\n'), Str.size());
611 bool TextNormal =
true;
613 bool Wrapped =
false;
614 for (
unsigned WordStart = 0, WordEnd; WordStart < Length;
615 WordStart = WordEnd) {
618 if (WordStart == Length)
625 unsigned WordLength = WordEnd - WordStart;
626 if (
Column + WordLength < Columns) {
651 assert(TextNormal &&
"Text highlighted at end of diagnostic message.");
667 uint64_t StartOfLocationInfo = OS.tell();
680 Message, OS.tell() - StartOfLocationInfo,
692 llvm_unreachable(
"Invalid diagnostic type");
703 llvm_unreachable(
"Invalid diagnostic type");
719 unsigned CurrentColumn,
734 assert(
Normal &&
"Formatting should have returned to normal");
764 TmpFilename =
File->getName();
765 llvm::sys::fs::make_absolute(TmpFilename);
766 llvm::sys::path::native(TmpFilename);
767 llvm::sys::path::remove_dots(TmpFilename,
true);
768 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
791 emitFilename(FE->getName(),
Loc.getManager());
797 unsigned LineNo = PLoc.
getLine();
822 if (
LangOpts.MSCompatibilityVersion &&
837 if (
LangOpts.MSCompatibilityVersion &&
844 if (
DiagOpts->ShowSourceRanges && !Ranges.empty()) {
845 FileID CaretFileID =
Loc.getExpansionLoc().getFileID();
846 bool PrintedRange =
false;
849 for (
const auto &R : Ranges) {
860 if (
SM.getFileID(B) != CaretFileID ||
SM.getFileID(
E) != CaretFileID)
865 unsigned TokSize = 0;
871 << BF.getLineNumber() <<
':' << BF.getColumnNumber() <<
'-'
885 OS <<
"In file included from ";
887 OS <<
':' << PLoc.
getLine() <<
":\n";
889 OS <<
"In included file:\n";
893 StringRef ModuleName) {
895 OS <<
"In module '" << ModuleName <<
"' imported from "
898 OS <<
"In module '" << ModuleName <<
"':\n";
903 StringRef ModuleName) {
905 OS <<
"While building module '" << ModuleName <<
"' imported from "
908 OS <<
"While building module '" << ModuleName <<
"':\n";
912static std::optional<std::pair<unsigned, unsigned>>
920 if (
SM.getFileID(
Begin) != FID ||
SM.getFileID(End) != FID)
923 return std::make_pair(
SM.getExpansionLineNumber(
Begin),
924 SM.getExpansionLineNumber(End));
929static std::pair<unsigned, unsigned>
930maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
933 unsigned Slack = MaxRange - (A.second - A.first + 1);
938 unsigned Min = std::min(A.first, B.first);
939 unsigned Max = std::max(A.second, B.second);
940 if (
Max -
Min + 1 <= MaxRange)
945 if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
946 (B.second < A.second && A.second - B.second + 1 > MaxRange))
955 A.second = std::min(A.second + (Slack + 1) / 2,
Max);
956 Slack = MaxRange - (A.second - A.first + 1);
957 A.first = std::max(
Min + Slack, A.first) - Slack;
958 A.second = std::min(A.first + MaxRange - 1,
Max);
970 std::string &CaretLine) {
973 while (StartColNo < Map.getSourceLine().size() &&
974 (Map.getSourceLine()[StartColNo] ==
' ' ||
975 Map.getSourceLine()[StartColNo] ==
'\t'))
976 StartColNo = Map.startOfNextColumn(StartColNo);
980 std::min(
static_cast<size_t>(R.
EndCol), Map.getSourceLine().size());
981 while (EndColNo && (Map.getSourceLine()[EndColNo - 1] ==
' ' ||
982 Map.getSourceLine()[EndColNo - 1] ==
'\t'))
983 EndColNo = Map.startOfPreviousColumn(EndColNo);
988 if (StartColNo > EndColNo)
992 StartColNo = Map.byteToContainingColumn(StartColNo);
993 EndColNo = Map.byteToContainingColumn(EndColNo);
995 assert(StartColNo <= EndColNo &&
"Invalid range!");
996 if (CaretLine.size() < EndColNo)
997 CaretLine.resize(EndColNo,
' ');
998 std::fill(CaretLine.begin() + StartColNo, CaretLine.begin() + EndColNo,
'~');
1003 const SourceColumnMap &map,
1007 std::string FixItInsertionLine;
1008 if (Hints.empty() || !DiagOpts->ShowFixits)
1009 return FixItInsertionLine;
1010 unsigned PrevHintEndCol = 0;
1012 for (
const auto &H : Hints) {
1013 if (H.CodeToInsert.empty())
1018 std::pair<FileID, unsigned> HintLocInfo =
1019 SM.getDecomposedExpansionLoc(H.RemoveRange.getBegin());
1020 if (FID == HintLocInfo.first &&
1021 LineNo ==
SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
1022 StringRef(H.CodeToInsert).find_first_of(
"\n\r") == StringRef::npos) {
1028 unsigned HintByteOffset =
1029 SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
1032 assert(HintByteOffset <
static_cast<unsigned>(map.bytes()) + 1);
1033 unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
1042 if (HintCol < PrevHintEndCol)
1043 HintCol = PrevHintEndCol + 1;
1047 unsigned NewFixItLineSize = FixItInsertionLine.size() +
1048 (HintCol - PrevHintEndCol) +
1049 H.CodeToInsert.size();
1050 if (NewFixItLineSize > FixItInsertionLine.size())
1051 FixItInsertionLine.resize(NewFixItLineSize,
' ');
1053 std::copy(H.CodeToInsert.begin(), H.CodeToInsert.end(),
1054 FixItInsertionLine.end() - H.CodeToInsert.size());
1056 PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(H.CodeToInsert);
1060 expandTabs(FixItInsertionLine, DiagOpts->TabStop);
1062 return FixItInsertionLine;
1066 unsigned L = 1u, M = 10u;
1067 while (M <= N && ++L != std::numeric_limits<unsigned>::digits10 + 1)
1081 const std::pair<unsigned, unsigned> &Lines,
FileID FID,
1091 unsigned StartLineNo =
SM.getExpansionLineNumber(
Begin);
1092 if (StartLineNo > Lines.second ||
SM.getFileID(
Begin) != FID)
1095 unsigned EndLineNo =
SM.getExpansionLineNumber(End);
1096 if (EndLineNo < Lines.first ||
SM.getFileID(End) != FID)
1099 unsigned StartColumn =
SM.getExpansionColumnNumber(
Begin);
1100 unsigned EndColumn =
SM.getExpansionColumnNumber(End);
1101 if (R.isTokenRange())
1105 if (StartLineNo == EndLineNo) {
1106 LineRanges.push_back({StartLineNo, StartColumn - 1, EndColumn - 1});
1111 LineRanges.push_back({StartLineNo, StartColumn - 1, ~0u});
1114 for (
unsigned S = StartLineNo + 1; S != EndLineNo; ++S)
1115 LineRanges.push_back({S, 0, ~0u});
1118 LineRanges.push_back({EndLineNo, 0, EndColumn - 1});
1131static std::unique_ptr<llvm::SmallVector<TextDiagnostic::StyleRange>[]>
1136 assert(StartLineNumber <= EndLineNumber);
1137 auto SnippetRanges =
1138 std::make_unique<SmallVector<TextDiagnostic::StyleRange>[]>(
1139 EndLineNumber - StartLineNumber + 1);
1142 return SnippetRanges;
1146 return SnippetRanges;
1148 auto Buff = llvm::MemoryBuffer::getMemBuffer(FileData);
1149 Lexer L{FID, *Buff,
SM, LangOpts};
1150 L.SetKeepWhitespaceMode(
true);
1152 const char *FirstLineStart =
1154 SM.getDecomposedLoc(
SM.translateLineCol(FID, StartLineNumber, 1)).second;
1155 if (
const char *CheckPoint = PP->
getCheckPoint(FID, FirstLineStart)) {
1156 assert(CheckPoint >= Buff->getBufferStart() &&
1157 CheckPoint <= Buff->getBufferEnd());
1158 assert(CheckPoint <= FirstLineStart);
1159 size_t Offset = CheckPoint - Buff->getBufferStart();
1160 L.seek(Offset,
false);
1166 const Token &
T,
unsigned Start,
unsigned Length) ->
void {
1167 if (
T.is(tok::raw_identifier)) {
1168 StringRef RawIdent =
T.getRawIdentifier();
1173 if (llvm::StringSwitch<bool>(RawIdent)
1175 .Case(
"false",
true)
1176 .Case(
"nullptr",
true)
1177 .Case(
"__func__",
true)
1178 .Case(
"__objc_yes__",
true)
1179 .Case(
"__objc_no__",
true)
1180 .Case(
"__null",
true)
1181 .Case(
"__FUNCDNAME__",
true)
1182 .Case(
"__FUNCSIG__",
true)
1183 .Case(
"__FUNCTION__",
true)
1184 .Case(
"__FUNCSIG__",
true)
1196 assert(
T.is(tok::comment));
1204 Stop = L.LexFromRawLexer(
T);
1205 if (
T.is(tok::unknown))
1209 if (!
T.is(tok::raw_identifier) && !
T.is(tok::comment) &&
1214 unsigned TokenEndLine =
SM.getSpellingLineNumber(
T.getEndLoc(), &
Invalid);
1215 if (
Invalid || TokenEndLine < StartLineNumber)
1218 assert(TokenEndLine >= StartLineNumber);
1220 unsigned TokenStartLine =
1221 SM.getSpellingLineNumber(
T.getLocation(), &
Invalid);
1225 if (TokenStartLine > EndLineNumber)
1229 SM.getSpellingColumnNumber(
T.getLocation(), &
Invalid) - 1;
1234 if (TokenStartLine == TokenEndLine) {
1236 SnippetRanges[TokenStartLine - StartLineNumber];
1237 appendStyle(LineRanges,
T, StartCol,
T.getLength());
1240 assert((TokenEndLine - TokenStartLine) >= 1);
1244 unsigned EndCol =
SM.getSpellingColumnNumber(
T.getEndLoc(), &
Invalid) - 1;
1250 unsigned L = TokenStartLine;
1251 unsigned LineLength = 0;
1252 for (
unsigned I = 0; I <= Spelling.size(); ++I) {
1256 SnippetRanges[L - StartLineNumber];
1258 if (L >= StartLineNumber) {
1259 if (L == TokenStartLine)
1260 appendStyle(LineRanges,
T, StartCol, LineLength);
1261 else if (L == TokenEndLine)
1262 appendStyle(LineRanges,
T, 0, EndCol);
1264 appendStyle(LineRanges,
T, 0, LineLength);
1268 if (L > EndLineNumber)
1277 return SnippetRanges;
1287void TextDiagnostic::emitSnippetAndCaret(
1290 assert(
Loc.
isValid() &&
"must have a valid source location here");
1291 assert(
Loc.
isFileID() &&
"must have a file location here");
1301 if (
Loc ==
LastLoc && Ranges.empty() && Hints.empty() &&
1310 StringRef BufData =
Loc.getBufferData(&
Invalid);
1313 const char *BufStart = BufData.data();
1314 const char *BufEnd = BufStart + BufData.size();
1316 unsigned CaretLineNo =
Loc.getLineNumber();
1317 unsigned CaretColNo =
Loc.getColumnNumber();
1320 static const size_t MaxLineLengthToPrint = 4096;
1321 if (CaretColNo > MaxLineLengthToPrint)
1325 const unsigned MaxLines =
DiagOpts->SnippetLineLimit;
1326 std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
1327 unsigned DisplayLineNo =
Loc.getPresumedLoc().getLine();
1328 for (
const auto &I : Ranges) {
1333 std::min(DisplayLineNo,
SM.getPresumedLineNumber(I.getBegin()));
1340 unsigned MaxLineNoDisplayWidth =
1344 auto indentForLineNumbers = [&] {
1345 if (MaxLineNoDisplayWidth > 0)
1346 OS.indent(MaxLineNoDisplayWidth + 2) <<
"| ";
1351 std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles =
1358 for (
unsigned LineNo = Lines.first; LineNo != Lines.second + 1;
1359 ++LineNo, ++DisplayLineNo) {
1361 const char *LineStart =
1363 SM.getDecomposedLoc(
SM.translateLineCol(FID, LineNo, 1)).second;
1364 if (LineStart == BufEnd)
1368 const char *LineEnd = LineStart;
1369 while (*LineEnd !=
'\n' && *LineEnd !=
'\r' && LineEnd != BufEnd)
1374 if (
size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
1378 std::string SourceLine(LineStart, LineEnd);
1380 while (!SourceLine.empty() && SourceLine.back() ==
'\0' &&
1381 (LineNo != CaretLineNo || SourceLine.size() > CaretColNo))
1382 SourceLine.pop_back();
1385 const SourceColumnMap sourceColMap(SourceLine,
DiagOpts->TabStop);
1387 std::string CaretLine;
1389 for (
const auto &LR : LineRanges) {
1390 if (LR.LineNo == LineNo)
1395 if (CaretLineNo == LineNo) {
1396 size_t Col = sourceColMap.byteToContainingColumn(CaretColNo - 1);
1397 CaretLine.resize(std::max(Col + 1, CaretLine.size()),
' ');
1398 CaretLine[Col] =
'^';
1402 FID, LineNo, sourceColMap, Hints,
SM,
DiagOpts.get());
1406 unsigned Columns =
DiagOpts->MessageLength;
1409 Columns, sourceColMap);
1415 if (
DiagOpts->ShowSourceRanges && !SourceLine.empty()) {
1416 SourceLine =
' ' + SourceLine;
1417 CaretLine =
' ' + CaretLine;
1421 emitSnippet(SourceLine, MaxLineNoDisplayWidth, LineNo, DisplayLineNo,
1422 SourceStyles[LineNo - Lines.first]);
1424 if (!CaretLine.empty()) {
1425 indentForLineNumbers();
1428 OS << CaretLine <<
'\n';
1433 if (!FixItInsertionLine.empty()) {
1434 indentForLineNumbers();
1440 OS << FixItInsertionLine <<
'\n';
1447 emitParseableFixits(Hints,
SM);
1450void TextDiagnostic::emitSnippet(StringRef SourceLine,
1451 unsigned MaxLineNoDisplayWidth,
1452 unsigned LineNo,
unsigned DisplayLineNo,
1455 if (MaxLineNoDisplayWidth > 0) {
1457 OS.indent(MaxLineNoDisplayWidth - LineNoDisplayWidth + 1)
1458 << DisplayLineNo <<
" | ";
1462 bool PrintReversed =
false;
1463 std::optional<llvm::raw_ostream::Colors> CurrentColor;
1465 while (I < SourceLine.size()) {
1466 auto [Str, WasPrintable] =
1471 if (WasPrintable == PrintReversed) {
1472 PrintReversed = !PrintReversed;
1477 CurrentColor = std::nullopt;
1482 const auto *CharStyle = llvm::find_if(Styles, [I](
const StyleRange &R) {
1483 return (R.Start < I && R.End >= I);
1486 if (CharStyle != Styles.end()) {
1487 if (!CurrentColor ||
1488 (CurrentColor && *CurrentColor != CharStyle->Color)) {
1489 OS.changeColor(CharStyle->Color,
false);
1490 CurrentColor = CharStyle->Color;
1492 }
else if (CurrentColor) {
1494 CurrentColor = std::nullopt;
1509 if (!
DiagOpts->ShowParseableFixits)
1514 for (
const auto &H : Hints) {
1515 if (H.RemoveRange.isInvalid() || H.RemoveRange.getBegin().isMacroID() ||
1516 H.RemoveRange.getEnd().isMacroID())
1520 for (
const auto &H : Hints) {
1524 std::pair<FileID, unsigned> BInfo =
SM.getDecomposedLoc(BLoc);
1525 std::pair<FileID, unsigned> EInfo =
SM.getDecomposedLoc(ELoc);
1528 if (H.RemoveRange.isTokenRange())
1539 OS <<
"\":{" <<
SM.getLineNumber(BInfo.first, BInfo.second)
1540 <<
':' <<
SM.getColumnNumber(BInfo.first, BInfo.second)
1541 <<
'-' <<
SM.getLineNumber(EInfo.first, EInfo.second)
1542 <<
':' <<
SM.getColumnNumber(EInfo.first, EInfo.second)
1544 OS.write_escaped(H.CodeToInsert);
static StringRef bytes(const std::vector< T, Allocator > &v)
Defines the clang::FileManager interface and associated types.
Defines the clang::Preprocessor interface.
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 constexpr raw_ostream::Colors CommentColor
static constexpr raw_ostream::Colors LiteralColor
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 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 enum raw_ostream::Colors remarkColor
static enum raw_ostream::Colors fatalColor
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 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 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 expandTabs(std::string &SourceLine, unsigned TabStop)
static void genColumnByteMapping(StringRef SourceLine, unsigned TabStop, SmallVectorImpl< int > &BytesOut, SmallVectorImpl< int > &ColumnsOut)
BytesOut: A mapping from columns to the byte of the source line that produced the character displayin...
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 unsigned getNumDisplayWidth(unsigned N)
static enum raw_ostream::Colors templateColor
static SmallVector< LineRange > prepareAndFilterRanges(const SmallVectorImpl< CharSourceRange > &Ranges, const SourceManager &SM, const std::pair< unsigned, unsigned > &Lines, FileID FID, const LangOptions &LangOpts)
Filter out invalid ranges, ranges that don't fit into the window of source lines we will print,...
__device__ __2f16 float c
Represents a character-granular source range.
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
SourceLocation getEnd() const
SourceLocation getBegin() const
Options for controlling the compiler diagnostics engine.
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.
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
unsigned getLineNumber(bool *Invalid=nullptr) 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...
bool isCompatibleWithMSVC(MSVCMajorVersion MajorVersion) const
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
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,...
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 ...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
const char * getCheckPoint(FileID FID, const char *Start) const
Returns a pointer into the given file's buffer that's guaranteed to be between tokens.
IdentifierInfo * getIdentifierInfo(StringRef Name) const
Return information about the specified preprocessor identifier token.
IdentifierTable & getIdentifierTable()
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
const char * getFilename() const
Return the presumed filename of this location.
unsigned getLine() const
Return the presumed line number of this location.
bool isInvalid() const
Return true if this object is invalid or uninitialized.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
This class handles loading and caching of source files into memory.
static void printDiagnosticMessage(raw_ostream &OS, bool IsSupplemental, StringRef Message, unsigned CurrentColumn, unsigned Columns, bool ShowColors)
Pretty-print a diagnostic message to a raw_ostream.
~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.
TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts, DiagnosticOptions *DiagOpts, const Preprocessor *PP=nullptr)
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.
bool isLiteral(TokenKind K)
Return true if this is a "literal" kind, like a numeric constant, string, etc.
The JSON file list parser is used to communicate input to InstallAPI.
static const TerminalColor CommentColor
LLVM_READONLY bool isVerticalWhitespace(unsigned char c)
Returns true if this character is vertical ASCII whitespace: '\n', '\r'.
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.
const FunctionProtoType * T