1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| | // This rule finds sequences of "unused" declerations, init and
// release(). E.g.:
//
// struct strbuf buf = STRBUF_INIT;
// [.. no other use of "buf" in the function ..]
// strbuf_release(&buf)
//
// To do do this we find (continued below)...
@@
type T;
identifier I;
// STRBUF_INIT, but also e.g. STRING_LIST_INIT_DUP (so no anchoring)
constant INIT =~ "_INIT";
// I = get_worktrees() etc.
identifier INIT_ASSIGN1 =~ "^get_worktrees$";
// strbuf_init(&I, ...) etc.
identifier INIT_CALL1 =~ "^[a-z_]*_init$";
// stbuf_release(), string_list_clear() etc.
identifier REL1 =~ "^[a-z_]*_(release|clear|free)$";
// release_patch(), clear_pathspec() etc.
identifier REL2 =~ "^(release|clear|free)_[a-z_]*$";
@@
// .. A declaration like "struct strbuf buf;"...
(
- T I;
// ... or "struct STRBUF buf = STRBUF_INIT;" ...
|
- T I = INIT;
)
// ... Optionally followed by lines that make no use of "buf", "&buf"
// etc., but which ...
<... when != \( I \| &I \)
when strict
// .. (only) make use of "buf" or "&buf" to call something like
// "strbuf_init(&buf, ...)" ...
(
- \( INIT_CALL1 \)( \( I \| &I \), ...);
|
// .. or e.g. "worktrees = get_worktrees();", i.e. a known "assignment
// init" ...
- I = \( INIT_ASSIGN1 \)(...);
)
...>
// ... and then no mention of "buf" or "&buf" until we get to a
// strbuf_release(&buf) at the end ...
(
- \( REL1 \| REL2 \)( \( I \| &I \), ...);
|
- \( REL1 \| REL2 \)( \( &I \| I \) );
)
// ... and no use *after* either, e.g. we don't want to delete
// init/strbuf_release() patterns, where "&buf" could be used
// afterwards.
... when != \( I \| &I \)
when strict
// Note that we're intentionally loose in accepting e.g. a
// "strbuf_init(&buf)" followed by a "string_list_clear(&buf,
// 0)". It's assumed that the compiler will catch any such invalid
// code, i.e. that our constructors/destructors don't take a "void *".
//
// This rule also isn't capable of finding cases where &buf is used,
// but only to e.g. pass that variable to a static function which
// doesn't use it. The analysis is only function-local.
|