dte test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 50.0% high: ≥ 85.0%
Coverage Exec / Excl / Total
Lines: 96.8% 61 / 0 / 63
Functions: 100.0% 5 / 0 / 5
Branches: 80.8% 21 / 10 / 36

src/syntax/merge.c
Line Branch Exec Source
1 #include <errno.h>
2 #include <stdbool.h>
3 #include <string.h>
4 #include "merge.h"
5 #include "util/debug.h"
6 #include "util/hashmap.h"
7 #include "util/numtostr.h"
8 #include "util/string-view.h"
9 #include "util/xmalloc.h"
10 #include "util/xstring.h"
11
12 enum {
13 FIXBUF_SIZE = 512
14 };
15
16 4491 static const char *fix_name(char *buf, StringView prefix, const char *name)
17 {
18 4491 size_t plen = prefix.length;
19 4491 BUG_ON(plen >= FIXBUF_SIZE);
20 4491 size_t avail = FIXBUF_SIZE - plen;
21 4491 char *end = memccpy(xmempcpy(buf, prefix.data, plen), name, '\0', avail);
22
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 4491 times.
4491 FATAL_ERROR_ON(!end, ENOBUFS);
23 4491 return buf;
24 }
25
26 3731 static void fix_action(const Syntax *syn, Action *a, StringView prefix, char *buf)
27 {
28
2/2
✓ Branch 2 → 3 taken 2861 times.
✓ Branch 2 → 6 taken 870 times.
3731 if (a->destination) {
29 2861 const char *name = fix_name(buf, prefix, a->destination->name);
30 2861 a->destination = find_state(syn, name);
31 }
32 3731 }
33
34 1449 static void fix_conditions (
35 const Syntax *syn,
36 State *s,
37 const SyntaxMerge *m,
38 StringView prefix,
39 char *buf
40 ) {
41 1449 BUG_ON(!s); // Silence spurious `-Wnull-dereference` warning in GCC 9
42
2/2
✓ Branch 13 → 5 taken 2282 times.
✓ Branch 13 → 14 taken 1449 times.
3731 for (size_t i = 0, n = s->conds.count; i < n; i++) {
43 2282 Condition *c = s->conds.ptrs[i];
44 2282 fix_action(syn, &c->a, prefix, buf);
45
4/4
✓ Branch 6 → 7 taken 423 times.
✓ Branch 6 → 9 taken 1859 times.
✓ Branch 7 → 8 taken 332 times.
✓ Branch 7 → 9 taken 91 times.
2282 if (!c->a.destination && cond_type_has_destination(c->type)) {
46 332 c->a.destination = m->return_state;
47 }
48
1/4
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 12 taken 2282 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
2282 if (m->delim && c->type == COND_HEREDOCEND) {
49 c->u.heredocend = string_view(m->delim, m->delim_len);
50 }
51 }
52
53 1449 fix_action(syn, &s->default_action, prefix, buf);
54
2/2
✓ Branch 15 → 16 taken 447 times.
✓ Branch 15 → 17 taken 1002 times.
1449 if (!s->default_action.destination) {
55 447 s->default_action.destination = m->return_state;
56 }
57 1449 }
58
59 // Generate a prefix for merged state names, to avoid clashes
60 181 static StringView make_prefix_str(char *buf)
61 {
62 181 static unsigned int counter;
63 181 size_t n = 0;
64 181 buf[n++] = 'm';
65 181 n += buf_uint_to_str(counter++, buf + n);
66 181 buf[n++] = '-';
67 181 return string_view(buf, n);
68 }
69
70 // Merge a sub-syntax into another syntax, copying or updating
71 // pointers and strings as appropriate.
72 // NOTE: string_lists is owned by Syntax, so there's no need to
73 // copy it. Freeing Condition does not free any string lists.
74 181 State *merge_syntax(Syntax *syn, SyntaxMerge *merge, const StyleMap *styles)
75 {
76 181 const HashMap *subsyn_states = &merge->subsyn->states;
77 181 HashMap *states = &syn->states;
78 181 char prefix_buf[64];
79 181 StringView prefix = make_prefix_str(prefix_buf);
80 181 char buf[FIXBUF_SIZE];
81
82
2/2
✓ Branch 20 → 4 taken 1449 times.
✓ Branch 20 → 21 taken 181 times.
1630 for (HashMapIter it = hashmap_iter(subsyn_states); hashmap_next(&it); ) {
83 1449 State *s = xmemdup(it.entry->value, sizeof(State));
84 1449 s->name = xmemjoin(prefix.data, prefix.length, s->name, strlen(s->name) + 1);
85 1449 hashmap_insert(states, s->name, s);
86
87
2/2
✓ Branch 7 → 8 taken 1429 times.
✓ Branch 7 → 16 taken 20 times.
1449 if (s->conds.count > 0) {
88 // Deep copy conds PointerArray
89 1429 BUG_ON(s->conds.alloc < s->conds.count);
90 1429 void **ptrs = xmallocarray(s->conds.alloc, sizeof(*ptrs));
91
2/2
✓ Branch 14 → 12 taken 2282 times.
✓ Branch 14 → 15 taken 1429 times.
3711 for (size_t i = 0, n = s->conds.count; i < n; i++) {
92 2282 ptrs[i] = xmemdup(s->conds.ptrs[i], sizeof(Condition));
93 }
94 1429 s->conds.ptrs = ptrs;
95 } else {
96 20 BUG_ON(s->conds.alloc != 0);
97 }
98
99 // Mark unvisited, so that return-only states get visited
100 1449 s->visited = false;
101
102 // Don't complain about unvisited, copied states
103 1449 s->copied = true;
104 }
105
106 // Fix conditions and update styles for newly merged states
107
2/2
✓ Branch 31 → 22 taken 1449 times.
✓ Branch 31 → 32 taken 181 times.
1811 for (HashMapIter it = hashmap_iter(subsyn_states); hashmap_next(&it); ) {
108 1449 const State *subsyn_state = it.entry->value;
109 1449 BUG_ON(!subsyn_state);
110 1449 const char *new_name = fix_name(buf, prefix, subsyn_state->name);
111 1449 State *new_state = hashmap_xget(states, new_name);
112 1449 fix_conditions(syn, new_state, merge, prefix, buf);
113
1/2
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 30 taken 1449 times.
1449 if (merge->delim) {
114 update_state_styles(syn, new_state, styles);
115 }
116 }
117
118 181 const char *name = fix_name(buf, prefix, merge->subsyn->start_state->name);
119 181 State *start_state = hashmap_xget(states, name);
120 181 merge->subsyn->used = true;
121 181 return start_state;
122 }
123