Skip to content

Commit 889e6ad

Browse files
[lldb] Fix a crash when two diagnostics are on the same column or in … (#112451)
…reverse order The second inner loop (only) was missing the check for offset > column. Also this patch sorts the diagnostics before printing them.
1 parent 1de15c1 commit 889e6ad

File tree

2 files changed

+60
-9
lines changed

2 files changed

+60
-9
lines changed

lldb/source/Utility/DiagnosticsRendering.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,7 @@ void RenderDiagnosticDetails(Stream &stream,
7777
spacer = "";
7878
}
7979

80-
// Print a line with caret indicator(s) below the lldb prompt + command.
81-
const size_t padding = *offset_in_command;
82-
stream << std::string(padding, ' ');
83-
84-
size_t offset = 1;
80+
// Partition the diagnostics.
8581
std::vector<DiagnosticDetail> remaining_details, other_details,
8682
hidden_details;
8783
for (const DiagnosticDetail &detail : details) {
@@ -98,10 +94,31 @@ void RenderDiagnosticDetails(Stream &stream,
9894
continue;
9995
}
10096

101-
auto &loc = *detail.source_location;
10297
remaining_details.push_back(detail);
98+
}
99+
100+
// Sort the diagnostics.
101+
auto sort = [](auto &ds) {
102+
llvm::sort(ds.begin(), ds.end(), [](auto &d1, auto &d2) {
103+
auto l1 = d1.source_location.value_or(DiagnosticDetail::SourceLocation{});
104+
auto l2 = d2.source_location.value_or(DiagnosticDetail::SourceLocation{});
105+
return std::pair(l1.line, l2.column) < std::pair(l1.line, l2.column);
106+
});
107+
};
108+
sort(remaining_details);
109+
sort(other_details);
110+
sort(hidden_details);
111+
112+
// Print a line with caret indicator(s) below the lldb prompt + command.
113+
const size_t padding = *offset_in_command;
114+
stream << std::string(padding, ' ');
115+
size_t offset = 1;
116+
for (const DiagnosticDetail &detail : remaining_details) {
117+
auto &loc = *detail.source_location;
118+
103119
if (offset > loc.column)
104120
continue;
121+
105122
stream << std::string(loc.column - offset, ' ') << cursor;
106123
for (unsigned i = 0; i + 1 < loc.length; ++i)
107124
stream << underline;
@@ -121,7 +138,8 @@ void RenderDiagnosticDetails(Stream &stream,
121138
for (auto &remaining_detail :
122139
llvm::ArrayRef(remaining_details).drop_back(1)) {
123140
uint16_t column = remaining_detail.source_location->column;
124-
stream << std::string(column - offset, ' ') << vbar;
141+
if (offset <= column)
142+
stream << std::string(column - offset, ' ') << vbar;
125143
offset = column + 1;
126144
}
127145

lldb/unittests/Utility/DiagnosticsRenderingTest.cpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,45 @@ std::string Render(std::vector<DiagnosticDetail> details) {
1616
} // namespace
1717

1818
TEST_F(ErrorDisplayTest, RenderStatus) {
19-
DiagnosticDetail::SourceLocation inline_loc;
20-
inline_loc.in_user_input = true;
19+
using SourceLocation = DiagnosticDetail::SourceLocation;
2120
{
21+
SourceLocation inline_loc;
22+
inline_loc.in_user_input = true;
2223
std::string result =
2324
Render({DiagnosticDetail{inline_loc, eSeverityError, "foo", ""}});
2425
ASSERT_TRUE(StringRef(result).contains("error:"));
2526
ASSERT_TRUE(StringRef(result).contains("foo"));
2627
}
28+
29+
{
30+
// Test that diagnostics on the same column can be handled and all
31+
// 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};
34+
std::string result =
35+
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"));
41+
}
42+
{
43+
// Test that diagnostics in reverse order are emitted correctly.
44+
SourceLocation loc1 = {FileSpec{"a.c"}, 1, 20, 0, false, true};
45+
SourceLocation loc2 = {FileSpec{"a.c"}, 2, 10, 0, false, true};
46+
std::string result =
47+
Render({DiagnosticDetail{loc2, eSeverityError, "X", "X"},
48+
DiagnosticDetail{loc1, eSeverityError, "Y", "Y"}});
49+
ASSERT_LT(StringRef(result).find("Y"), StringRef(result).find("X"));
50+
}
51+
{
52+
// Test that diagnostics in reverse order are emitted correctly.
53+
SourceLocation loc1 = {FileSpec{"a.c"}, 2, 10, 0, false, true};
54+
SourceLocation loc2 = {FileSpec{"a.c"}, 1, 20, 0, false, true};
55+
std::string result =
56+
Render({DiagnosticDetail{loc2, eSeverityError, "X", "X"},
57+
DiagnosticDetail{loc1, eSeverityError, "Y", "Y"}});
58+
ASSERT_LT(StringRef(result).find("Y"), StringRef(result).find("X"));
59+
}
2760
}

0 commit comments

Comments
 (0)