Skip to content

Commit 0f86f35

Browse files
Merge pull request #9630 from adrian-prantl/cherry-pick-stable-20240723-lldb-Fix-a-positioning-bug-in-diagnostics-output-116711
[Cherry-pick into stable/20240723] [lldb] Fix a positioning bug in diagnostics output (llvm#116711)
2 parents a4e81b5 + a4b1912 commit 0f86f35

File tree

2 files changed

+59
-24
lines changed

2 files changed

+59
-24
lines changed

lldb/source/Utility/DiagnosticsRendering.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "lldb/Utility/DiagnosticsRendering.h"
10+
#include <cstdint>
1011

1112
using namespace lldb_private;
1213
using namespace lldb;
@@ -98,7 +99,7 @@ void RenderDiagnosticDetails(Stream &stream,
9899
}
99100

100101
// Sort the diagnostics.
101-
auto sort = [](auto &ds) {
102+
auto sort = [](std::vector<DiagnosticDetail> &ds) {
102103
std::stable_sort(ds.begin(), ds.end(), [](auto &d1, auto &d2) {
103104
auto l1 = d1.source_location.value_or(DiagnosticDetail::SourceLocation{});
104105
auto l2 = d2.source_location.value_or(DiagnosticDetail::SourceLocation{});
@@ -121,15 +122,27 @@ void RenderDiagnosticDetails(Stream &stream,
121122
continue;
122123

123124
stream << std::string(loc.column - x_pos, ' ') << cursor;
124-
++x_pos;
125+
x_pos = loc.column + 1;
125126
for (unsigned i = 0; i + 1 < loc.length; ++i) {
126127
stream << underline;
127-
++x_pos;
128+
x_pos += 1;
128129
}
129130
}
130131
}
131132
stream << '\n';
132133

134+
// Reverse the order within groups of diagnostics that are on the same column.
135+
auto group = [](std::vector<DiagnosticDetail> &details) {
136+
for (auto it = details.begin(), end = details.end(); it != end;) {
137+
auto eq_end = std::find_if(it, end, [&](const DiagnosticDetail &d) {
138+
return d.source_location->column != it->source_location->column;
139+
});
140+
std::reverse(it, eq_end);
141+
it = eq_end;
142+
}
143+
};
144+
group(remaining_details);
145+
133146
// Work through each detail in reverse order using the vector/stack.
134147
bool did_print = false;
135148
for (auto detail = remaining_details.rbegin();
@@ -142,14 +155,19 @@ void RenderDiagnosticDetails(Stream &stream,
142155
for (auto &remaining_detail :
143156
llvm::ArrayRef(remaining_details).drop_back(1)) {
144157
uint16_t column = remaining_detail.source_location->column;
145-
if (x_pos <= column)
158+
// Is this a note with the same column as another diagnostic?
159+
if (column == detail->source_location->column)
160+
continue;
161+
162+
if (column >= x_pos) {
146163
stream << std::string(column - x_pos, ' ') << vbar;
147-
x_pos = column + 1;
164+
x_pos = column + 1;
165+
}
148166
}
149167

150-
// Print the line connecting the ^ with the error message.
151168
uint16_t column = detail->source_location->column;
152-
if (x_pos <= column)
169+
// Print the line connecting the ^ with the error message.
170+
if (column >= x_pos)
153171
stream << std::string(column - x_pos, ' ') << joint << hbar << spacer;
154172

155173
// Print a colorized string based on the message's severity type.

lldb/unittests/Utility/DiagnosticsRenderingTest.cpp

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,22 @@ TEST_F(ErrorDisplayTest, RenderStatus) {
2929
{
3030
// Test that diagnostics on the same column can be handled and all
3131
// three errors are diagnosed.
32-
SourceLocation loc1 = {FileSpec{"a.c"}, 13, 11, 0, false, true};
33-
SourceLocation loc2 = {FileSpec{"a.c"}, 13, 13, 0, false, true};
32+
SourceLocation loc1 = {FileSpec{"a.c"}, 13, 5, 0, false, true};
33+
SourceLocation loc2 = {FileSpec{"a.c"}, 13, 7, 0, false, true};
34+
SourceLocation loc3 = {FileSpec{"a.c"}, 13, 9, 0, false, true};
3435
std::string result =
3536
Render({DiagnosticDetail{loc1, eSeverityError, "1", "1"},
36-
DiagnosticDetail{loc1, eSeverityError, "2", "2"},
37-
DiagnosticDetail{loc2, eSeverityError, "3", "3"}});
38-
ASSERT_TRUE(StringRef(result).contains("error: 1"));
39-
ASSERT_TRUE(StringRef(result).contains("error: 2"));
40-
ASSERT_TRUE(StringRef(result).contains("error: 3"));
37+
DiagnosticDetail{loc2, eSeverityError, "2a", "2a"},
38+
DiagnosticDetail{loc2, eSeverityInfo, "2b", "2b"},
39+
DiagnosticDetail{loc3, eSeverityError, "3", "3"}});
40+
llvm::SmallVector<StringRef> lines;
41+
StringRef(result).split(lines, '\n');
42+
// 1234567890123
43+
ASSERT_EQ(lines[0], " ^ ^ ^");
44+
ASSERT_EQ(lines[1], " | | error: 3");
45+
ASSERT_EQ(lines[2], " | error: 2a");
46+
ASSERT_EQ(lines[3], " | note: 2b");
47+
ASSERT_EQ(lines[4], " error: 1");
4148
}
4249
{
4350
// Test that diagnostics in reverse order are emitted correctly.
@@ -68,15 +75,25 @@ TEST_F(ErrorDisplayTest, RenderStatus) {
6875
std::string result =
6976
Render({DiagnosticDetail{loc1, eSeverityError, "X", "X"},
7077
DiagnosticDetail{loc2, eSeverityError, "Y", "Y"}});
71-
auto lines = StringRef(result).split('\n');
72-
auto line1 = lines.first;
73-
lines = lines.second.split('\n');
74-
auto line2 = lines.first;
75-
lines = lines.second.split('\n');
76-
auto line3 = lines.first;
77-
// 1234567
78-
ASSERT_EQ(line1, "^~~ ^~~");
79-
ASSERT_EQ(line2, "| error: Y");
80-
ASSERT_EQ(line3, "error: X");
78+
llvm::SmallVector<StringRef> lines;
79+
StringRef(result).split(lines, '\n');
80+
// 1234567
81+
ASSERT_EQ(lines[0], "^~~ ^~~");
82+
ASSERT_EQ(lines[1], "| error: Y");
83+
ASSERT_EQ(lines[2], "error: X");
84+
}
85+
{
86+
// Test diagnostics on the same line are emitted correctly.
87+
SourceLocation loc1 = {FileSpec{"a.c"}, 1, 2, 0, false, true};
88+
SourceLocation loc2 = {FileSpec{"a.c"}, 1, 6, 0, false, true};
89+
std::string result =
90+
Render({DiagnosticDetail{loc1, eSeverityError, "X", "X"},
91+
DiagnosticDetail{loc2, eSeverityError, "Y", "Y"}});
92+
llvm::SmallVector<StringRef> lines;
93+
StringRef(result).split(lines, '\n');
94+
// 1234567
95+
ASSERT_EQ(lines[0], " ^ ^");
96+
ASSERT_EQ(lines[1], " | error: Y");
97+
ASSERT_EQ(lines[2], " error: X");
8198
}
8299
}

0 commit comments

Comments
 (0)