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/raw_ostream.h"
26static const enum raw_ostream::Colors
noteColor = raw_ostream::CYAN;
37static const enum raw_ostream::Colors
errorColor = raw_ostream::RED;
38static const enum raw_ostream::Colors
fatalColor = raw_ostream::RED;
41 raw_ostream::SAVEDCOLOR;
47static constexpr raw_ostream::Colors
CommentColor = raw_ostream::YELLOW;
48static constexpr raw_ostream::Colors
LiteralColor = raw_ostream::GREEN;
49static constexpr raw_ostream::Colors
KeywordColor = raw_ostream::BLUE;
56 OS << Str.slice(0, Pos);
57 if (Pos == StringRef::npos)
60 Str = Str.substr(Pos + 1);
78 if (SourceLine[--i]==
'\t')
104static std::pair<SmallString<16>,
bool>
107 assert(I &&
"I must not be null");
108 assert(*I < SourceLine.size() &&
"must point to a valid index");
110 if (SourceLine[*I] ==
'\t') {
112 "Invalid -ftabstop value");
114 unsigned NumSpaces = TabStop - (Col % TabStop);
115 assert(0 < NumSpaces && NumSpaces <= TabStop
116 &&
"Invalid computation of space amt");
120 ExpandedTab.assign(NumSpaces,
' ');
121 return std::make_pair(ExpandedTab,
true);
124 const unsigned char *
Begin = SourceLine.bytes_begin() + *I;
127 if (*
Begin < 0x80 && llvm::sys::locale::isPrint(*
Begin)) {
131 unsigned CharSize = llvm::getNumBytesForUTF8(*
Begin);
132 const unsigned char *End =
Begin + CharSize;
135 if (End <= SourceLine.bytes_end() && llvm::isLegalUTF8Sequence(
Begin, End)) {
137 llvm::UTF32 *CPtr = &
C;
140 unsigned char const *OriginalBegin =
Begin;
141 llvm::ConversionResult Res = llvm::ConvertUTF8toUTF32(
142 &
Begin, End, &CPtr, CPtr + 1, llvm::strictConversion);
144 assert(Res == llvm::conversionOK);
145 assert(OriginalBegin <
Begin);
146 assert(
unsigned(
Begin - OriginalBegin) == CharSize);
148 (*I) += (
Begin - OriginalBegin);
151 if (llvm::sys::locale::isPrint(
C))
157 Str.insert(Str.begin() + 3, llvm::hexdigit(
C % 16));
160 while (Str.size() < 8)
161 Str.insert(Str.begin() + 3, llvm::hexdigit(0));
162 return std::make_pair(Str,
false);
167 unsigned char Byte = SourceLine[*I];
168 ExpandedByte[1] = llvm::hexdigit(Byte / 16);
169 ExpandedByte[2] = llvm::hexdigit(Byte % 16);
171 return std::make_pair(ExpandedByte,
false);
174static void expandTabs(std::string &SourceLine,
unsigned TabStop) {
175 size_t I = SourceLine.size();
178 if (SourceLine[I] !=
'\t')
181 auto [Str, Printable] =
183 SourceLine.replace(I, 1, Str.c_str());
226 assert(BytesOut.empty());
227 assert(ColumnsOut.empty());
229 if (SourceLine.empty()) {
230 BytesOut.resize(1u, 0);
231 ColumnsOut.resize(1u, 0);
235 ColumnsOut.resize(SourceLine.size() + 1, -1);
239 while (I < SourceLine.size()) {
240 ColumnsOut[I] = Columns;
241 BytesOut.resize(Columns + 1, -1);
243 auto [Str, Printable] =
245 Columns += llvm::sys::locale::columnWidth(Str);
248 ColumnsOut.back() = Columns;
249 BytesOut.resize(Columns + 1, -1);
254struct SourceColumnMap {
255 SourceColumnMap(StringRef SourceLine,
unsigned TabStop)
256 : m_SourceLine(SourceLine) {
260 assert(m_byteToColumn.size()==SourceLine.size()+1);
261 assert(0 < m_byteToColumn.size() && 0 < m_columnToByte.size());
262 assert(m_byteToColumn.size()
263 ==
static_cast<unsigned>(m_columnToByte.back()+1));
264 assert(
static_cast<unsigned>(m_byteToColumn.back()+1)
265 == m_columnToByte.size());
267 int columns()
const {
return m_byteToColumn.back(); }
268 int bytes()
const {
return m_columnToByte.back(); }
272 int byteToColumn(
int n)
const {
273 assert(0<=n && n<
static_cast<int>(m_byteToColumn.size()));
274 return m_byteToColumn[n];
278 int byteToContainingColumn(
int N)
const {
279 assert(0 <= N && N <
static_cast<int>(m_byteToColumn.size()));
280 while (m_byteToColumn[N] == -1)
282 return m_byteToColumn[N];
288 int columnToByte(
int n)
const {
289 assert(0<=n && n<
static_cast<int>(m_columnToByte.size()));
290 return m_columnToByte[n];
294 int startOfNextColumn(
int N)
const {
295 assert(0 <= N && N <
static_cast<int>(m_byteToColumn.size() - 1));
296 while (byteToColumn(++N) == -1) {}
301 int startOfPreviousColumn(
int N)
const {
302 assert(0 < N && N <
static_cast<int>(m_byteToColumn.size()));
303 while (byteToColumn(--N) == -1) {}
307 StringRef getSourceLine()
const {
312 const std::string m_SourceLine;
321 std::string &CaretLine,
322 std::string &FixItInsertionLine,
324 const SourceColumnMap &map) {
325 unsigned CaretColumns = CaretLine.size();
326 unsigned FixItColumns = llvm::sys::locale::columnWidth(FixItInsertionLine);
327 unsigned MaxColumns = std::max(
static_cast<unsigned>(map.columns()),
328 std::max(CaretColumns, FixItColumns));
330 if (MaxColumns <= Columns)
334 assert(llvm::none_of(CaretLine, [](
char c) {
return c <
' ' ||
'~' <
c; }));
338 unsigned CaretStart = 0, CaretEnd = CaretLine.size();
339 for (; CaretStart != CaretEnd; ++CaretStart)
343 for (; CaretEnd != CaretStart; --CaretEnd)
352 if (!FixItInsertionLine.empty()) {
353 unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
354 for (; FixItStart != FixItEnd; ++FixItStart)
358 for (; FixItEnd != FixItStart; --FixItEnd)
365 unsigned FixItStartCol = FixItStart;
367 = llvm::sys::locale::columnWidth(FixItInsertionLine.substr(0, FixItEnd));
369 CaretStart = std::min(FixItStartCol, CaretStart);
370 CaretEnd = std::max(FixItEndCol, CaretEnd);
376 while (
static_cast<int>(CaretEnd) < map.columns() &&
377 -1 == map.columnToByte(CaretEnd))
380 assert((
static_cast<int>(CaretStart) > map.columns() ||
381 -1!=map.columnToByte(CaretStart)) &&
382 "CaretStart must not point to a column in the middle of a source"
384 assert((
static_cast<int>(CaretEnd) > map.columns() ||
385 -1!=map.columnToByte(CaretEnd)) &&
386 "CaretEnd must not point to a column in the middle of a source line"
394 unsigned SourceStart = map.columnToByte(std::min<unsigned>(CaretStart,
396 unsigned SourceEnd = map.columnToByte(std::min<unsigned>(CaretEnd,
399 unsigned CaretColumnsOutsideSource = CaretEnd-CaretStart
400 - (map.byteToColumn(SourceEnd)-map.byteToColumn(SourceStart));
402 char const *front_ellipse =
" ...";
403 char const *front_space =
" ";
404 char const *back_ellipse =
"...";
405 unsigned ellipses_space = strlen(front_ellipse) + strlen(back_ellipse);
407 unsigned TargetColumns = Columns;
410 if (TargetColumns > ellipses_space+CaretColumnsOutsideSource)
411 TargetColumns -= ellipses_space+CaretColumnsOutsideSource;
413 while (SourceStart>0 || SourceEnd<SourceLine.size()) {
414 bool ExpandedRegion =
false;
417 unsigned NewStart = map.startOfPreviousColumn(SourceStart);
423 NewStart = map.startOfPreviousColumn(NewStart);
427 unsigned Prev = map.startOfPreviousColumn(NewStart);
433 assert(map.byteToColumn(NewStart) != -1);
434 unsigned NewColumns = map.byteToColumn(SourceEnd) -
435 map.byteToColumn(NewStart);
436 if (NewColumns <= TargetColumns) {
437 SourceStart = NewStart;
438 ExpandedRegion =
true;
442 if (SourceEnd<SourceLine.size()) {
443 unsigned NewEnd = map.startOfNextColumn(SourceEnd);
448 while (NewEnd < SourceLine.size() &&
isWhitespace(SourceLine[NewEnd]))
449 NewEnd = map.startOfNextColumn(NewEnd);
452 while (NewEnd < SourceLine.size() &&
isWhitespace(SourceLine[NewEnd]))
453 NewEnd = map.startOfNextColumn(NewEnd);
455 assert(map.byteToColumn(NewEnd) != -1);
456 unsigned NewColumns = map.byteToColumn(NewEnd) -
457 map.byteToColumn(SourceStart);
458 if (NewColumns <= TargetColumns) {
460 ExpandedRegion =
true;
468 CaretStart = map.byteToColumn(SourceStart);
469 CaretEnd = map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource;
473 assert(CaretStart!=(
unsigned)-1 && CaretEnd!=(
unsigned)-1 &&
474 SourceStart!=(
unsigned)-1 && SourceEnd!=(
unsigned)-1);
475 assert(SourceStart <= SourceEnd);
476 assert(CaretStart <= CaretEnd);
478 unsigned BackColumnsRemoved
479 = map.byteToColumn(SourceLine.size())-map.byteToColumn(SourceEnd);
480 unsigned FrontColumnsRemoved = CaretStart;
481 unsigned ColumnsKept = CaretEnd-CaretStart;
484 assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns);
488 if (BackColumnsRemoved > strlen(back_ellipse))
489 SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
492 if (FrontColumnsRemoved+ColumnsKept <= Columns)
496 if (FrontColumnsRemoved > strlen(front_ellipse)) {
497 SourceLine.replace(0, SourceStart, front_ellipse);
498 CaretLine.replace(0, CaretStart, front_space);
499 if (!FixItInsertionLine.empty())
500 FixItInsertionLine.replace(0, CaretStart, front_space);
524 case '\'':
return '\'';
525 case '`':
return '\'';
526 case '"':
return '"';
527 case '(':
return ')';
528 case '[':
return ']';
529 case '{':
return '}';
542 unsigned Length,
unsigned Column,
544 assert(Start < Str.size() &&
"Invalid start position!");
545 unsigned End = Start + 1;
548 if (End == Str.size())
564 PunctuationEndStack.push_back(EndPunct);
565 while (End < Length && !PunctuationEndStack.empty()) {
566 if (Str[End] == PunctuationEndStack.back())
567 PunctuationEndStack.pop_back();
569 PunctuationEndStack.push_back(SubEndPunct);
578 unsigned PunctWordLength = End - Start;
580 Column + PunctWordLength <= Columns ||
583 PunctWordLength < Columns/3)
607 unsigned Column,
bool Bold) {
608 const unsigned Length = std::min(Str.find(
'\n'), Str.size());
609 bool TextNormal =
true;
611 bool Wrapped =
false;
612 for (
unsigned WordStart = 0, WordEnd; WordStart < Length;
613 WordStart = WordEnd) {
616 if (WordStart == Length)
623 unsigned WordLength = WordEnd - WordStart;
624 if (
Column + WordLength < Columns) {
649 assert(TextNormal &&
"Text highlighted at end of diagnostic message.");
665 uint64_t StartOfLocationInfo = OS.tell();
678 Message, OS.tell() - StartOfLocationInfo,
690 llvm_unreachable(
"Invalid diagnostic type");
701 llvm_unreachable(
"Invalid diagnostic type");
717 unsigned CurrentColumn,
732 assert(
Normal &&
"Formatting should have returned to normal");
762 TmpFilename =
File->getName();
763 llvm::sys::fs::make_absolute(TmpFilename);
764 llvm::sys::path::native(TmpFilename);
765 llvm::sys::path::remove_dots(TmpFilename,
true);
766 Filename = StringRef(TmpFilename.data(), TmpFilename.size());
789 emitFilename(FE->getName(),
Loc.getManager());
795 unsigned LineNo = PLoc.
getLine();
820 if (
LangOpts.MSCompatibilityVersion &&
835 if (
LangOpts.MSCompatibilityVersion &&
842 if (
DiagOpts.ShowSourceRanges && !Ranges.empty()) {
843 FileID CaretFileID =
Loc.getExpansionLoc().getFileID();
844 bool PrintedRange =
false;
847 for (
const auto &R : Ranges) {
858 if (
SM.getFileID(B) != CaretFileID ||
SM.getFileID(
E) != CaretFileID)
863 unsigned TokSize = 0;
869 << BF.getLineNumber() <<
':' << BF.getColumnNumber() <<
'-'
883 OS <<
"In file included from ";
885 OS <<
':' << PLoc.
getLine() <<
":\n";
887 OS <<
"In included file:\n";
891 StringRef ModuleName) {
893 OS <<
"In module '" << ModuleName <<
"' imported from "
896 OS <<
"In module '" << ModuleName <<
"':\n";
901 StringRef ModuleName) {
903 OS <<
"While building module '" << ModuleName <<
"' imported from "
906 OS <<
"While building module '" << ModuleName <<
"':\n";
910static std::optional<std::pair<unsigned, unsigned>>
918 if (
SM.getFileID(
Begin) != FID ||
SM.getFileID(End) != FID)
921 return std::make_pair(
SM.getExpansionLineNumber(
Begin),
922 SM.getExpansionLineNumber(End));
927static std::pair<unsigned, unsigned>
928maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
931 unsigned Slack = MaxRange - (A.second - A.first + 1);
936 unsigned Min = std::min(A.first, B.first);
937 unsigned Max = std::max(A.second, B.second);
938 if (
Max -
Min + 1 <= MaxRange)
943 if ((B.first > A.first && B.first - A.first + 1 > MaxRange) ||
944 (B.second < A.second && A.second - B.second + 1 > MaxRange))
953 A.second = std::min(A.second + (Slack + 1) / 2,
Max);
954 Slack = MaxRange - (A.second - A.first + 1);
955 A.first = std::max(
Min + Slack, A.first) - Slack;
956 A.second = std::min(A.first + MaxRange - 1,
Max);
968 std::string &CaretLine) {
971 while (StartColNo < Map.getSourceLine().size() &&
972 (Map.getSourceLine()[StartColNo] ==
' ' ||
973 Map.getSourceLine()[StartColNo] ==
'\t'))
974 StartColNo = Map.startOfNextColumn(StartColNo);
978 std::min(
static_cast<size_t>(R.
EndCol), Map.getSourceLine().size());
979 while (EndColNo && (Map.getSourceLine()[EndColNo - 1] ==
' ' ||
980 Map.getSourceLine()[EndColNo - 1] ==
'\t'))
981 EndColNo = Map.startOfPreviousColumn(EndColNo);
986 if (StartColNo > EndColNo)
990 StartColNo = Map.byteToContainingColumn(StartColNo);
991 EndColNo = Map.byteToContainingColumn(EndColNo);
993 assert(StartColNo <= EndColNo &&
"Invalid range!");
994 if (CaretLine.size() < EndColNo)
995 CaretLine.resize(EndColNo,
' ');
996 std::fill(CaretLine.begin() + StartColNo, CaretLine.begin() + EndColNo,
'~');
1000 const SourceColumnMap &map,
1004 std::string FixItInsertionLine;
1005 if (Hints.empty() || !DiagOpts.ShowFixits)
1006 return FixItInsertionLine;
1007 unsigned PrevHintEndCol = 0;
1009 for (
const auto &H : Hints) {
1010 if (H.CodeToInsert.empty())
1016 SM.getDecomposedExpansionLoc(H.RemoveRange.getBegin());
1017 if (FID == HintLocInfo.first &&
1018 LineNo ==
SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
1019 StringRef(H.CodeToInsert).find_first_of(
"\n\r") == StringRef::npos) {
1025 unsigned HintByteOffset =
1026 SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
1029 assert(HintByteOffset <
static_cast<unsigned>(map.bytes()) + 1);
1030 unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
1039 if (HintCol < PrevHintEndCol)
1040 HintCol = PrevHintEndCol + 1;
1044 unsigned NewFixItLineSize = FixItInsertionLine.size() +
1045 (HintCol - PrevHintEndCol) +
1046 H.CodeToInsert.size();
1047 if (NewFixItLineSize > FixItInsertionLine.size())
1048 FixItInsertionLine.resize(NewFixItLineSize,
' ');
1050 std::copy(H.CodeToInsert.begin(), H.CodeToInsert.end(),
1051 FixItInsertionLine.end() - H.CodeToInsert.size());
1053 PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(H.CodeToInsert);
1057 expandTabs(FixItInsertionLine, DiagOpts.TabStop);
1059 return FixItInsertionLine;
1063 unsigned L = 1u, M = 10u;
1064 while (M <= N && ++L != std::numeric_limits<unsigned>::digits10 + 1)
1078 const std::pair<unsigned, unsigned> &Lines,
FileID FID,
1088 unsigned StartLineNo =
SM.getExpansionLineNumber(
Begin);
1089 if (StartLineNo > Lines.second ||
SM.getFileID(
Begin) != FID)
1092 unsigned EndLineNo =
SM.getExpansionLineNumber(End);
1093 if (EndLineNo < Lines.first ||
SM.getFileID(End) != FID)
1096 unsigned StartColumn =
SM.getExpansionColumnNumber(
Begin);
1097 unsigned EndColumn =
SM.getExpansionColumnNumber(End);
1098 assert(StartColumn &&
"StartColumn must be valid, 0 is invalid");
1099 assert(EndColumn &&
"EndColumn must be valid, 0 is invalid");
1100 if (R.isTokenRange())
1104 if (StartLineNo == EndLineNo) {
1105 LineRanges.push_back({StartLineNo, StartColumn - 1, EndColumn - 1});
1110 LineRanges.push_back({StartLineNo, StartColumn - 1, ~0u});
1113 for (
unsigned S = StartLineNo + 1; S != EndLineNo; ++S)
1114 LineRanges.push_back({S, 0, ~0u});
1117 LineRanges.push_back({EndLineNo, 0, EndColumn - 1});
1130static std::unique_ptr<llvm::SmallVector<TextDiagnostic::StyleRange>[]>
1135 assert(StartLineNumber <= EndLineNumber);
1136 auto SnippetRanges =
1137 std::make_unique<SmallVector<TextDiagnostic::StyleRange>[]>(
1138 EndLineNumber - StartLineNumber + 1);
1141 return SnippetRanges;
1145 return SnippetRanges;
1147 auto Buff = llvm::MemoryBuffer::getMemBuffer(FileData);
1148 Lexer L{FID, *Buff,
SM, LangOpts};
1149 L.SetKeepWhitespaceMode(
true);
1151 const char *FirstLineStart =
1153 SM.getDecomposedLoc(
SM.translateLineCol(FID, StartLineNumber, 1)).second;
1154 if (
const char *CheckPoint = PP->
getCheckPoint(FID, FirstLineStart)) {
1155 assert(CheckPoint >= Buff->getBufferStart() &&
1156 CheckPoint <= Buff->getBufferEnd());
1157 assert(CheckPoint <= FirstLineStart);
1158 size_t Offset = CheckPoint - Buff->getBufferStart();
1159 L.seek(Offset,
false);
1165 const Token &
T,
unsigned Start,
unsigned Length) ->
void {
1166 if (
T.is(tok::raw_identifier)) {
1167 StringRef RawIdent =
T.getRawIdentifier();
1172 if (llvm::StringSwitch<bool>(RawIdent)
1174 .Case(
"false",
true)
1175 .Case(
"nullptr",
true)
1176 .Case(
"__func__",
true)
1177 .Case(
"__objc_yes__",
true)
1178 .Case(
"__objc_no__",
true)
1179 .Case(
"__null",
true)
1180 .Case(
"__FUNCDNAME__",
true)
1181 .Case(
"__FUNCSIG__",
true)
1182 .Case(
"__FUNCTION__",
true)
1183 .Case(
"__FUNCSIG__",
true)
1195 assert(
T.is(tok::comment));
1203 Stop = L.LexFromRawLexer(
T);
1204 if (
T.is(tok::unknown))
1208 if (!
T.is(tok::raw_identifier) && !
T.is(tok::comment) &&
1213 unsigned TokenEndLine =
SM.getSpellingLineNumber(
T.getEndLoc(), &
Invalid);
1214 if (
Invalid || TokenEndLine < StartLineNumber)
1217 assert(TokenEndLine >= StartLineNumber);
1219 unsigned TokenStartLine =
1220 SM.getSpellingLineNumber(
T.getLocation(), &
Invalid);
1224 if (TokenStartLine > EndLineNumber)
1228 SM.getSpellingColumnNumber(
T.getLocation(), &
Invalid) - 1;
1233 if (TokenStartLine == TokenEndLine) {
1235 SnippetRanges[TokenStartLine - StartLineNumber];
1236 appendStyle(LineRanges,
T, StartCol,
T.getLength());
1239 assert((TokenEndLine - TokenStartLine) >= 1);
1243 unsigned EndCol =
SM.getSpellingColumnNumber(
T.getEndLoc(), &
Invalid) - 1;
1249 unsigned L = TokenStartLine;
1250 unsigned LineLength = 0;
1251 for (
unsigned I = 0; I <= Spelling.size(); ++I) {
1254 if (L >= StartLineNumber) {
1256 SnippetRanges[L - StartLineNumber];
1258 if (L == TokenStartLine)
1259 appendStyle(LineRanges,
T, StartCol, LineLength);
1260 else if (L == TokenEndLine)
1261 appendStyle(LineRanges,
T, 0, EndCol);
1263 appendStyle(LineRanges,
T, 0, LineLength);
1267 if (L > EndLineNumber)
1276 return SnippetRanges;
1286void TextDiagnostic::emitSnippetAndCaret(
1289 assert(
Loc.
isValid() &&
"must have a valid source location here");
1290 assert(
Loc.
isFileID() &&
"must have a file location here");
1300 if (
Loc ==
LastLoc && Ranges.empty() && Hints.empty() &&
1309 StringRef BufData =
Loc.getBufferData(&
Invalid);
1312 const char *BufStart = BufData.data();
1313 const char *BufEnd = BufStart + BufData.size();
1315 unsigned CaretLineNo =
Loc.getLineNumber();
1316 unsigned CaretColNo =
Loc.getColumnNumber();
1319 static const size_t MaxLineLengthToPrint = 4096;
1320 if (CaretColNo > MaxLineLengthToPrint)
1324 const unsigned MaxLines =
DiagOpts.SnippetLineLimit;
1325 std::pair<unsigned, unsigned> Lines = {CaretLineNo, CaretLineNo};
1326 unsigned DisplayLineNo =
Loc.getPresumedLoc().getLine();
1327 for (
const auto &I : Ranges) {
1332 std::min(DisplayLineNo,
SM.getPresumedLineNumber(I.getBegin()));
1339 unsigned MaxLineNoDisplayWidth =
1343 auto indentForLineNumbers = [&] {
1344 if (MaxLineNoDisplayWidth > 0)
1345 OS.indent(MaxLineNoDisplayWidth + 2) <<
"| ";
1350 std::unique_ptr<SmallVector<StyleRange>[]> SourceStyles =
1357 for (
unsigned LineNo = Lines.first; LineNo != Lines.second + 1;
1358 ++LineNo, ++DisplayLineNo) {
1360 const char *LineStart =
1362 SM.getDecomposedLoc(
SM.translateLineCol(FID, LineNo, 1)).second;
1363 if (LineStart == BufEnd)
1367 const char *LineEnd = LineStart;
1368 while (*LineEnd !=
'\n' && *LineEnd !=
'\r' && LineEnd != BufEnd)
1373 if (
size_t(LineEnd - LineStart) > MaxLineLengthToPrint)
1377 std::string SourceLine(LineStart, LineEnd);
1379 while (!SourceLine.empty() && SourceLine.back() ==
'\0' &&
1380 (LineNo != CaretLineNo || SourceLine.size() > CaretColNo))
1381 SourceLine.pop_back();
1384 const SourceColumnMap sourceColMap(SourceLine,
DiagOpts.TabStop);
1386 std::string CaretLine;
1388 for (
const auto &LR : LineRanges) {
1389 if (LR.LineNo == LineNo)
1394 if (CaretLineNo == LineNo) {
1395 size_t Col = sourceColMap.byteToContainingColumn(CaretColNo - 1);
1396 CaretLine.resize(std::max(Col + 1, CaretLine.size()),
' ');
1397 CaretLine[Col] =
'^';
1400 std::string FixItInsertionLine =
1405 unsigned Columns =
DiagOpts.MessageLength;
1408 Columns, sourceColMap);
1414 if (
DiagOpts.ShowSourceRanges && !SourceLine.empty()) {
1415 SourceLine =
' ' + SourceLine;
1416 CaretLine =
' ' + CaretLine;
1420 emitSnippet(SourceLine, MaxLineNoDisplayWidth, LineNo, DisplayLineNo,
1421 SourceStyles[LineNo - Lines.first]);
1423 if (!CaretLine.empty()) {
1424 indentForLineNumbers();
1427 OS << CaretLine <<
'\n';
1432 if (!FixItInsertionLine.empty()) {
1433 indentForLineNumbers();
1439 OS << FixItInsertionLine <<
'\n';
1446 emitParseableFixits(Hints,
SM);
1449void TextDiagnostic::emitSnippet(StringRef SourceLine,
1450 unsigned MaxLineNoDisplayWidth,
1451 unsigned LineNo,
unsigned DisplayLineNo,
1454 if (MaxLineNoDisplayWidth > 0) {
1456 OS.indent(MaxLineNoDisplayWidth - LineNoDisplayWidth + 1)
1457 << DisplayLineNo <<
" | ";
1461 bool PrintReversed =
false;
1462 std::optional<llvm::raw_ostream::Colors> CurrentColor;
1464 while (I < SourceLine.size()) {
1465 auto [Str, WasPrintable] =
1470 if (WasPrintable == PrintReversed) {
1471 PrintReversed = !PrintReversed;
1476 CurrentColor = std::nullopt;
1481 const auto *CharStyle = llvm::find_if(Styles, [I](
const StyleRange &R) {
1482 return (R.Start < I && R.End >= I);
1485 if (CharStyle != Styles.end()) {
1486 if (!CurrentColor ||
1487 (CurrentColor && *CurrentColor != CharStyle->Color)) {
1488 OS.changeColor(CharStyle->Color,
false);
1489 CurrentColor = CharStyle->Color;
1491 }
else if (CurrentColor) {
1493 CurrentColor = std::nullopt;
1513 for (
const auto &H : Hints) {
1514 if (H.RemoveRange.isInvalid() || H.RemoveRange.getBegin().isMacroID() ||
1515 H.RemoveRange.getEnd().isMacroID())
1519 for (
const auto &H : Hints) {
1527 if (H.RemoveRange.isTokenRange())
1538 OS <<
"\":{" <<
SM.getLineNumber(BInfo.first, BInfo.second)
1539 <<
':' <<
SM.getColumnNumber(BInfo.first, BInfo.second)
1540 <<
'-' <<
SM.getLineNumber(EInfo.first, EInfo.second)
1541 <<
':' <<
SM.getColumnNumber(EInfo.first, EInfo.second)
1543 OS.write_escaped(H.CodeToInsert);
static StringRef bytes(const std::vector< T, Allocator > &v)
static size_t getNumDisplayWidth(size_t N)
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 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 std::string buildFixItInsertionLine(FileID FID, unsigned LineNo, const SourceColumnMap &map, ArrayRef< FixItHint > Hints, const SourceManager &SM, const DiagnosticOptions &DiagOpts)
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.
DiagnosticOptions & DiagOpts
DiagnosticsEngine::Level LastLevel
The level of the last diagnostic emitted.
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
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.
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'.
std::pair< FileID, unsigned > FileIDAndOffset
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