@@ -124,16 +124,31 @@ namespace {
124
124
Out.resetColor ();
125
125
}
126
126
127
+ static void printStringAsSingleQuotedLine (StringRef str, raw_ostream &Out) {
128
+ Out << " '" ;
129
+ for (auto character : str) {
130
+ if (character == ' \n ' )
131
+ Out << " \\ n" ;
132
+ else
133
+ Out << character;
134
+ }
135
+ Out << " '" ;
136
+ }
137
+
127
138
// Describe a fix-it out-of-line.
128
139
static void describeFixIt (SourceManager &SM, DiagnosticInfo::FixIt fixIt,
129
140
raw_ostream &Out) {
130
141
if (fixIt.getRange ().getByteLength () == 0 ) {
131
- Out << " insert '" << fixIt.getText () << " '" ;
142
+ Out << " insert " ;
143
+ printStringAsSingleQuotedLine (fixIt.getText (), Out);
132
144
} else if (fixIt.getText ().empty ()) {
133
- Out << " remove '" << SM.extractText (fixIt.getRange ()) << " '" ;
145
+ Out << " remove " ;
146
+ printStringAsSingleQuotedLine (SM.extractText (fixIt.getRange ()), Out);
134
147
} else {
135
- Out << " replace '" << SM.extractText (fixIt.getRange ()) << " ' with '"
136
- << fixIt.getText () << " '" ;
148
+ Out << " replace " ;
149
+ printStringAsSingleQuotedLine (SM.extractText (fixIt.getRange ()), Out);
150
+ Out << " with " ;
151
+ printStringAsSingleQuotedLine (fixIt.getText (), Out);
137
152
}
138
153
}
139
154
@@ -280,6 +295,11 @@ namespace {
280
295
// line.
281
296
unsigned *byteToColumnMap = new unsigned [LineText.size () + 1 ];
282
297
unsigned extraColumns = 0 ;
298
+ // Track the location of the first character in the line that is not a
299
+ // whitespace character. This can be used to avoid underlining leading
300
+ // whitespace, which looks weird even though it is technically accurate.
301
+ unsigned firstNonWhitespaceColumn = 0 ;
302
+ bool seenNonWhitespaceCharacter = false ;
283
303
// We count one past the end of LineText here to handle trailing fix-it
284
304
// insertions.
285
305
for (unsigned i = 0 ; i < LineText.size () + 1 ; ++i) {
@@ -294,9 +314,17 @@ namespace {
294
314
}
295
315
}
296
316
}
297
- // Tabs are mapped to 2 spaces so they have a known column width.
298
- if (i < LineText.size () && LineText[i] == ' \t ' )
299
- extraColumns += 1 ;
317
+
318
+ if (i < LineText.size ()) {
319
+ // Tabs are mapped to 2 spaces so they have a known column width.
320
+ if (LineText[i] == ' \t ' )
321
+ extraColumns += 1 ;
322
+
323
+ if (!seenNonWhitespaceCharacter && !isspace (LineText[i])) {
324
+ firstNonWhitespaceColumn = i + extraColumns;
325
+ seenNonWhitespaceCharacter = true ;
326
+ }
327
+ }
300
328
301
329
byteToColumnMap[i] = i + extraColumns;
302
330
}
@@ -325,18 +353,28 @@ namespace {
325
353
if (isASCII) {
326
354
auto highlightLine = std::string (byteToColumnMap[LineText.size ()], ' ' );
327
355
for (auto highlight : Highlights) {
328
- for (unsigned i = highlight.StartByte ; i < highlight.EndByte ; ++i)
356
+ for (unsigned i =
357
+ std::max (highlight.StartByte , firstNonWhitespaceColumn);
358
+ i < highlight.EndByte ; ++i)
329
359
highlightLine[byteToColumnMap[i]] = ' ~' ;
330
360
}
331
361
332
362
for (auto fixIt : FixIts) {
333
363
// Mark deletions.
334
- for (unsigned i = fixIt.StartByte ; i < fixIt.EndByte ; ++i)
364
+ for (unsigned i = std::max (fixIt.StartByte , firstNonWhitespaceColumn);
365
+ i < fixIt.EndByte ; ++i)
335
366
highlightLine[byteToColumnMap[i]] = ' -' ;
336
-
337
- // Mark insertions.
338
- for (unsigned i = byteToColumnMap[fixIt.StartByte - 1 ] + 1 ;
339
- i < byteToColumnMap[fixIt.StartByte ]; ++i)
367
+ // Mark insertions. If the fix-it starts at the beginning of the line,
368
+ // highlight from column zero to the end column. Otherwise, find the
369
+ // column which immediately precedes the insertion. Then, highlight
370
+ // from the column after that to the end column. The end column in
371
+ // this case is obtained from the fix-it's starting byte, because
372
+ // insertions are printed before the deleted range.
373
+ unsigned startColumn = fixIt.StartByte == 0
374
+ ? 0
375
+ : byteToColumnMap[fixIt.StartByte - 1 ] + 1 ;
376
+ for (unsigned i = startColumn; i < byteToColumnMap[fixIt.StartByte ];
377
+ ++i)
340
378
highlightLine[i] = ' +' ;
341
379
}
342
380
@@ -640,7 +678,10 @@ static void annotateSnippetWithInfo(SourceManager &SM,
640
678
// Don't print inline fix-its for notes.
641
679
if (Info.Kind != DiagnosticKind::Note) {
642
680
for (auto fixIt : Info.FixIts ) {
643
- Snippet.addFixIt (fixIt.getRange (), fixIt.getText ());
681
+ // Don't print multi-line fix-its inline, only include them at the end of
682
+ // the message.
683
+ if (fixIt.getText ().find (" \n " ) == std::string::npos)
684
+ Snippet.addFixIt (fixIt.getRange (), fixIt.getText ());
644
685
}
645
686
}
646
687
// Add any explicitly grouped notes to the snippet.
0 commit comments