27 #define COLOUR_PATH eColourBlue
28 #define COLOUR_UNDERLINE eColourMagenta
29 #define COLOUR_SEGMENT eColourGreen
30 #define COLOUR_NOTE_STAR eColourYellow
31 #define COLOUR_MESSAGE eColourRed
52 static void print_report_header(
rich_t *rich,
const char *message)
73 size_t first_line = SIZE_MAX;
75 for (
size_t i = 0; i < len; i++)
91 .last_line = first_line,
98 static void print_scan_header(
rich_t *rich,
size_t largest,
size_t line,
const scan_t *scan)
113 io_printf(config.
io,
" %s => %s\n", padding, coloured);
119 io_printf(config.
io,
" %s => %s [%s:%zu]\n", padding, lang, name, display_line);
123 static void print_file_header(
rich_t *rich,
const node_t *node)
140 io_printf(config.
io,
" %s => %s [%s:%zu]\n", padding, lang, name, line);
144 print_scan_header(rich, width, 0, scan);
158 for (
size_t i = 0; i < width; i++)
162 char c = view.text[i];
167 size_t underline_width = width;
173 const char *lines = (underline_width > 1) ?
str_repeat(
"~", underline_width - 1, arena) :
"";
179 static void print_file_segment(
rich_t *rich,
const node_t *node,
const char *message)
209 char *underline = fmt_underline(file, node, rich->
max_columns, rich->
arena);
212 const char *pretext = !isspace(source.text[0]) ?
" " :
"";
215 io_printf(config.
io,
" %s |%s%.*s\n", line, pretext, (
int)source.
length, source.text);
216 io_printf(config.
io,
" %s |%s%s %s.\n", padding, pretext, coloured_underline, first);
224 for (
size_t i = 1; i < len; i++)
229 io_printf(config.
io,
" %s |%s%s %s %s.\n", padding, pretext, extra, coloured, it);
233 static void print_segment_message(
rich_t *rich,
const char *message)
243 for (
size_t i = 0; i < len; i++)
251 static void print_file_segments(
rich_t *rich,
const typevec_t *segments)
257 for (
size_t i = 0; i < len; i++)
264 print_file_segment(rich, &segment->
node, segment->
message);
269 print_segment_message(rich, segment->
message);
274 static bool nodes_overlap(
const node_t *lhs,
const node_t *rhs)
309 for (
size_t i = 0; i < count; i++)
342 if (!nodes_overlap(&segment->
node, &other->
node))
346 .used_primary =
false,
354 .used_primary =
false,
357 if (segment->
message == primary)
364 else if (other->
message == primary)
387 for (
size_t i = 0; i < len; i++)
398 join_result_t join = join_node_messages(rich, segment, other, primary);
427 typevec_t *primary = collect_segments(rich, all, scan);
431 .message =
event->message,
442 static size_t longest_segment_line(
const typevec_t *segments)
449 for (
size_t i = 0; i < len; i++)
464 static void print_extra_files(
rich_t *rich)
469 if (event->segments == NULL)
475 for (
size_t i = 0; i < len; i++)
495 typevec_t *all = collect_segments(rich, event->segments, scan);
496 typevec_t *merged = merge_segments(rich, all, NULL);
498 size_t largest_line = longest_segment_line(merged);
499 where_t where = get_first_line(merged);
501 print_scan_header(rich, largest_line, where.
first_line, scan);
502 print_file_segments(rich, merged);
506 static void print_rich_notes(
rich_t *rich)
511 if (event->notes == NULL)
518 for (
size_t i = 0; i < len; i++)
520 const char *note =
vector_get(event->notes, i);
552 print_report_header(&ctx, event->
message);
558 print_file_header(&ctx, &event->
node);
559 print_file_segments(&ctx, primary);
561 print_extra_files(&ctx);
563 print_rich_notes(&ctx);
565 if (config.
cache == NULL)
STA_DECL char * colour_format(format_context_t context, colour_t idx, const char *fmt,...)
CT_NODISCARD CT_PUREFN CT_SCAN_API const char * scan_path(const scan_t *scan)
get the path of a scanner
CT_NODISCARD CT_PUREFN CT_SCAN_API const char * scan_language(const scan_t *scan)
get the source language of a scanner
CT_NODISCARD CT_PUREFN CT_SCAN_API bool scan_is_builtin(const scan_t *scan)
check if a scanner is the builtin scanner
#define STA_DECL
sal2 annotation on function implementations to copy annotations from the declaration
CT_NODISCARD CT_PUREFN CT_BASE_API size_t ctu_strlen(const char *str)
get the length of a string not including the null terminator equivalent to strlen but with safety che...
STA_RET_STRING CT_FORMAT_API char * colour_text(format_context_t context, colour_t idx, const char *text)
add colour to a string
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
CT_NODISCARD CT_STD_API set_t * set_new(size_t size, hash_info_t info, arena_t *arena)
create a new set
CT_STD_API const void * set_add(set_t *set, const void *key)
add a key to a set
CT_NODISCARD CT_PUREFN CT_STD_API set_iter_t set_iter(set_t *set)
acquire a set iterator for a set
CT_NODISCARD CT_STD_API const void * set_next(set_iter_t *iter)
get the next item from a set iterator
CT_NODISCARD CT_PUREFN CT_STD_API bool set_has_next(set_iter_t *iter)
check if a set iterator has more items
CT_IO_API size_t io_printf(io_t *io, STA_FORMAT_STRING const char *fmt,...)
printf to an io object
CT_NODISCARD CT_PUREFN CT_SCAN_API const scan_t * node_get_scan(const node_t *node)
get the associated source file of a node
CT_NODISCARD CT_PUREFN CT_SCAN_API where_t node_get_location(const node_t *node)
get the location of a node inside its source file
#define CT_UNUSED(x)
mark a variable as unused
severity_t
the default severity of a diagnostic
#define CTASSERT(expr)
assert a condition, prints the condition as a message
CT_NODISCARD CT_STD_API char * str_repeat(const char *str, size_t times, arena_t *arena)
repeat a string
CT_NODISCARD CT_STD_API vector_t * str_split(const char *str, const char *sep, arena_t *arena)
split a string into a vector by a separator
CT_NODISCARD STA_FORMAT_STRING const char * fmt
CT_STD_API const hash_info_t kTypeInfoPtr
type information for a generic pointer this operates on the pointer itself and not the data it points...
CT_STD_API void * typevec_push(typevec_t *vec, const void *src)
push a value onto the vector
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_data(const typevec_t *vec)
get a pointer to the underlying data
CT_NODISCARD CT_STD_API typevec_t * typevec_new(size_t width, size_t len, arena_t *arena)
create a new typed vector on the heap
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_offset(const typevec_t *vec, size_t index)
get a pointer to the value at the given index
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
STA_DECL char * str_format(arena_t *arena, const char *fmt,...)
const char * id
the id of the diagnostic should be in the format [A-Z]{2,3}[0-9]{4} e.g. CLI0001 this is not enforced...
an event handle TODO: make this and segment_t opaque
node_t node
the primary node that this event is attached to
const diagnostic_t * diagnostic
the related diagnostic
STA_FIELD_STRING char * message
the primary message
typevec_t * segments
extra segments that this event is attached to
the configuration for a file
bool override_fatal
if true all warnings are treated as fatal
size_t max_columns
the maximum number of columns to print set to 0 to use default
bool zeroth_line
the zeroth line of a file is the first line
a formatting context when using colours
a position in a source file
a segment inside an event
node_t node
the related node
STA_FIELD_STRING char * message
the message associated with this segment
const colour_pallete_t * colours
cache_map_t * cache
a shared cache between all reports, set to NULL to disable caching
size_t length
the number of characters in the text
a non-owning view of text
size_t length
the number of characters in the text
A vector with a fixed type size.
a generic vector of pointers
a location inside a scanner locations are inclusive and 0-based
ctu_column_t first_column
the first column of the location
ctu_column_t last_column
the last column of the location
ctu_line_t last_line
the last line of the location
ctu_line_t first_line
the first line of the location
STA_DECL void text_report_rich(text_config_t config, const event_t *event)