91 {
92 if (diagnostics.empty()) {
93 return "";
94 }
95
96 std::string result;
97 int error_count = 0;
98 int warning_count = 0;
99
100 for (const auto& diag : diagnostics) {
102 error_count++;
103 } else {
104 warning_count++;
105 }
106
107 if (!result.empty()) {
108 result += "\n";
109 }
110 std::string severity_name = std::string(
enum_name(diag.severity));
111
112 const LineMapping* mapping = nullptr;
113 auto it = std::ranges::find_if(line_map, [&](const auto& m) {
114 return m.preprocessed_line == diag.range.start.line;
115 });
116 if (it != line_map.end()) {
117 mapping = &(*it);
118 }
119
120 Range range = diag.range;
121 std::string message = diag.message;
122
123 if (mapping != nullptr) {
124 range.start.line = mapping->original_line;
125 range.end.line = mapping->original_line;
126
127 if (!mapping->expansions.empty()) {
128 std::string expansion_trace;
129 std::vector<const MacroExpansion*> containing_expansions;
130
131 for (const auto& expansion : mapping->expansions) {
132 if (diag.range.start.column + 1 >=
133 expansion.preprocessed_start_column &&
134 diag.range.end.column <
135 expansion.preprocessed_end_column) {
136 containing_expansions.push_back(&expansion);
137 }
138 }
139
140 std::ranges::sort(containing_expansions,
141 [](const auto* a, const auto* b) {
142 return (a->preprocessed_end_column -
143 a->preprocessed_start_column) <
144 (b->preprocessed_end_column -
145 b->preprocessed_start_column);
146 });
147
148 for (const auto* expansion : containing_expansions) {
149 expansion_trace += std::format(
150 "\n note: in expansion of macro '{}' from {}:{}",
151 expansion->macro_name, mapping->original_line,
152 expansion->original_column);
153 }
154 message += expansion_trace;
155 }
156 }
157
158 result += std::format("{} - {}: {}", range.to_string(), severity_name,
159 message);
160 }
161
162 std::string summary;
163 if (error_count > 0 && warning_count > 0) {
164 summary = std::format("\nFound {} error(s) and {} warning(s).",
165 error_count, warning_count);
166 } else if (error_count > 0) {
167 summary = std::format("\nFound {} error(s).", error_count);
168 } else if (warning_count > 0) {
169 summary = std::format("\nFound {} warning(s).", warning_count);
170 }
171
172 result += summary;
173 return result;
174}
consteval std::string_view enum_name()