@@ -945,87 +945,43 @@ maybeAddRange(std::pair<unsigned, unsigned> A, std::pair<unsigned, unsigned> B,
945
945
return A;
946
946
}
947
947
948
- // / Highlight a SourceRange (with ~'s) for any characters on LineNo.
949
- static void highlightRange (const CharSourceRange &R,
950
- unsigned LineNo, FileID FID,
951
- const SourceColumnMap &map,
952
- std::string &CaretLine,
953
- const SourceManager &SM,
954
- const LangOptions &LangOpts) {
955
- if (!R.isValid ()) return ;
956
-
957
- SourceLocation Begin = R.getBegin ();
958
- SourceLocation End = R.getEnd ();
959
-
960
- unsigned StartLineNo = SM.getExpansionLineNumber (Begin);
961
- if (StartLineNo > LineNo || SM.getFileID (Begin) != FID)
962
- return ; // No intersection.
963
-
964
- unsigned EndLineNo = SM.getExpansionLineNumber (End);
965
- if (EndLineNo < LineNo || SM.getFileID (End) != FID)
966
- return ; // No intersection.
967
-
968
- // Compute the column number of the start.
969
- unsigned StartColNo = 0 ;
970
- if (StartLineNo == LineNo) {
971
- StartColNo = SM.getExpansionColumnNumber (Begin);
972
- if (StartColNo) --StartColNo; // Zero base the col #.
973
- }
974
-
975
- // Compute the column number of the end.
976
- unsigned EndColNo = map.getSourceLine ().size ();
977
- if (EndLineNo == LineNo) {
978
- EndColNo = SM.getExpansionColumnNumber (End);
979
- if (EndColNo) {
980
- --EndColNo; // Zero base the col #.
981
-
982
- // Add in the length of the token, so that we cover multi-char tokens if
983
- // this is a token range.
984
- if (R.isTokenRange ())
985
- EndColNo += Lexer::MeasureTokenLength (End, SM, LangOpts);
986
- } else {
987
- EndColNo = CaretLine.size ();
988
- }
989
- }
990
-
991
- assert (StartColNo <= EndColNo && " Invalid range!" );
992
-
993
- // Check that a token range does not highlight only whitespace.
994
- if (R.isTokenRange ()) {
995
- // Pick the first non-whitespace column.
996
- while (StartColNo < map.getSourceLine ().size () &&
997
- (map.getSourceLine ()[StartColNo] == ' ' ||
998
- map.getSourceLine ()[StartColNo] == ' \t ' ))
999
- StartColNo = map.startOfNextColumn (StartColNo);
1000
-
1001
- // Pick the last non-whitespace column.
1002
- if (EndColNo > map.getSourceLine ().size ())
1003
- EndColNo = map.getSourceLine ().size ();
1004
- while (EndColNo &&
1005
- (map.getSourceLine ()[EndColNo-1 ] == ' ' ||
1006
- map.getSourceLine ()[EndColNo-1 ] == ' \t ' ))
1007
- EndColNo = map.startOfPreviousColumn (EndColNo);
1008
-
1009
- // If the start/end passed each other, then we are trying to highlight a
1010
- // range that just exists in whitespace. That most likely means we have
1011
- // a multi-line highlighting range that covers a blank line.
1012
- if (StartColNo > EndColNo) {
1013
- assert (StartLineNo != EndLineNo && " trying to highlight whitespace" );
1014
- StartColNo = EndColNo;
1015
- }
1016
- }
948
+ struct LineRange {
949
+ unsigned LineNo;
950
+ unsigned StartCol;
951
+ unsigned EndCol;
952
+ };
1017
953
1018
- assert (StartColNo <= map.getSourceLine ().size () && " Invalid range!" );
1019
- assert (EndColNo <= map.getSourceLine ().size () && " Invalid range!" );
954
+ // / Highlight \p R (with ~'s) on the current source line.
955
+ static void highlightRange (const LineRange &R, const SourceColumnMap &Map,
956
+ std::string &CaretLine) {
957
+ // Pick the first non-whitespace column.
958
+ unsigned StartColNo = R.StartCol ;
959
+ while (StartColNo < Map.getSourceLine ().size () &&
960
+ (Map.getSourceLine ()[StartColNo] == ' ' ||
961
+ Map.getSourceLine ()[StartColNo] == ' \t ' ))
962
+ StartColNo = Map.startOfNextColumn (StartColNo);
963
+
964
+ // Pick the last non-whitespace column.
965
+ unsigned EndColNo =
966
+ std::min (static_cast <size_t >(R.EndCol ), Map.getSourceLine ().size ());
967
+ while (EndColNo && (Map.getSourceLine ()[EndColNo - 1 ] == ' ' ||
968
+ Map.getSourceLine ()[EndColNo - 1 ] == ' \t ' ))
969
+ EndColNo = Map.startOfPreviousColumn (EndColNo);
970
+
971
+ // If the start/end passed each other, then we are trying to highlight a
972
+ // range that just exists in whitespace. That most likely means we have
973
+ // a multi-line highlighting range that covers a blank line.
974
+ if (StartColNo > EndColNo)
975
+ return ;
1020
976
1021
977
// Fill the range with ~'s.
1022
- StartColNo = map .byteToContainingColumn (StartColNo);
1023
- EndColNo = map .byteToContainingColumn (EndColNo);
978
+ StartColNo = Map .byteToContainingColumn (StartColNo);
979
+ EndColNo = Map .byteToContainingColumn (EndColNo);
1024
980
1025
981
assert (StartColNo <= EndColNo && " Invalid range!" );
1026
982
if (CaretLine.size () < EndColNo)
1027
- CaretLine.resize (EndColNo,' ' );
1028
- std::fill (CaretLine.begin ()+ StartColNo,CaretLine.begin ()+ EndColNo,' ~' );
983
+ CaretLine.resize (EndColNo, ' ' );
984
+ std::fill (CaretLine.begin () + StartColNo, CaretLine.begin () + EndColNo, ' ~' );
1029
985
}
1030
986
1031
987
static std::string buildFixItInsertionLine (FileID FID,
@@ -1100,6 +1056,57 @@ static unsigned getNumDisplayWidth(unsigned N) {
1100
1056
return L;
1101
1057
}
1102
1058
1059
+ // / Filter out invalid ranges, ranges that don't fit into the window of
1060
+ // / source lines we will print, and ranges from other files.
1061
+ // /
1062
+ // / For the remaining ranges, convert them to simple LineRange structs,
1063
+ // / which only cover one line at a time.
1064
+ static SmallVector<LineRange>
1065
+ prepareAndFilterRanges (const SmallVectorImpl<CharSourceRange> &Ranges,
1066
+ const SourceManager &SM,
1067
+ const std::pair<unsigned , unsigned > &Lines, FileID FID,
1068
+ const LangOptions &LangOpts) {
1069
+ SmallVector<LineRange> LineRanges;
1070
+
1071
+ for (const CharSourceRange &R : Ranges) {
1072
+ if (R.isInvalid ())
1073
+ continue ;
1074
+ SourceLocation Begin = R.getBegin ();
1075
+ SourceLocation End = R.getEnd ();
1076
+
1077
+ unsigned StartLineNo = SM.getExpansionLineNumber (Begin);
1078
+ if (StartLineNo > Lines.second || SM.getFileID (Begin) != FID)
1079
+ continue ;
1080
+
1081
+ unsigned EndLineNo = SM.getExpansionLineNumber (End);
1082
+ if (EndLineNo < Lines.first || SM.getFileID (End) != FID)
1083
+ continue ;
1084
+
1085
+ unsigned StartColumn = SM.getExpansionColumnNumber (Begin);
1086
+ unsigned EndColumn = SM.getExpansionColumnNumber (End);
1087
+ if (R.isTokenRange ())
1088
+ EndColumn += Lexer::MeasureTokenLength (End, SM, LangOpts);
1089
+
1090
+ // Only a single line.
1091
+ if (StartLineNo == EndLineNo) {
1092
+ LineRanges.push_back ({StartLineNo, StartColumn - 1 , EndColumn - 1 });
1093
+ continue ;
1094
+ }
1095
+
1096
+ // Start line.
1097
+ LineRanges.push_back ({StartLineNo, StartColumn - 1 , ~0u });
1098
+
1099
+ // Middle lines.
1100
+ for (unsigned S = StartLineNo + 1 ; S != EndLineNo; ++S)
1101
+ LineRanges.push_back ({S, 0 , ~0u });
1102
+
1103
+ // End line.
1104
+ LineRanges.push_back ({EndLineNo, 0 , EndColumn - 1 });
1105
+ }
1106
+
1107
+ return LineRanges;
1108
+ }
1109
+
1103
1110
// / Emit a code snippet and caret line.
1104
1111
// /
1105
1112
// / This routine emits a single line's code snippet and caret line..
@@ -1166,6 +1173,9 @@ void TextDiagnostic::emitSnippetAndCaret(
1166
1173
OS.indent (MaxLineNoDisplayWidth + 2 ) << " | " ;
1167
1174
};
1168
1175
1176
+ SmallVector<LineRange> LineRanges =
1177
+ prepareAndFilterRanges (Ranges, SM, Lines, FID, LangOpts);
1178
+
1169
1179
for (unsigned LineNo = Lines.first ; LineNo != Lines.second + 1 ;
1170
1180
++LineNo, ++DisplayLineNo) {
1171
1181
// Rewind from the current position to the start of the line.
@@ -1197,8 +1207,10 @@ void TextDiagnostic::emitSnippetAndCaret(
1197
1207
1198
1208
std::string CaretLine;
1199
1209
// Highlight all of the characters covered by Ranges with ~ characters.
1200
- for (const auto &I : Ranges)
1201
- highlightRange (I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
1210
+ for (const auto &LR : LineRanges) {
1211
+ if (LR.LineNo == LineNo)
1212
+ highlightRange (LR, sourceColMap, CaretLine);
1213
+ }
1202
1214
1203
1215
// Next, insert the caret itself.
1204
1216
if (CaretLineNo == LineNo) {
0 commit comments