diff options
Diffstat (limited to 'contrib/coccinelle')
-rw-r--r-- | contrib/coccinelle/.gitignore | 1 | ||||
-rw-r--r-- | contrib/coccinelle/README | 43 | ||||
-rw-r--r-- | contrib/coccinelle/array.cocci | 98 | ||||
-rw-r--r-- | contrib/coccinelle/commit.cocci | 52 | ||||
-rw-r--r-- | contrib/coccinelle/flex_alloc.cocci | 13 | ||||
-rw-r--r-- | contrib/coccinelle/free.cocci | 18 | ||||
-rw-r--r-- | contrib/coccinelle/hashmap.cocci | 16 | ||||
-rw-r--r-- | contrib/coccinelle/object_id.cocci | 87 | ||||
-rw-r--r-- | contrib/coccinelle/preincr.cocci | 5 | ||||
-rw-r--r-- | contrib/coccinelle/qsort.cocci | 37 | ||||
-rw-r--r-- | contrib/coccinelle/strbuf.cocci | 62 | ||||
-rw-r--r-- | contrib/coccinelle/swap.cocci | 28 | ||||
-rw-r--r-- | contrib/coccinelle/the_repository.pending.cocci | 144 | ||||
-rw-r--r-- | contrib/coccinelle/xcalloc.cocci | 10 | ||||
-rw-r--r-- | contrib/coccinelle/xopen.cocci | 16 | ||||
-rw-r--r-- | contrib/coccinelle/xstrdup_or_null.cocci | 13 |
16 files changed, 643 insertions, 0 deletions
diff --git a/contrib/coccinelle/.gitignore b/contrib/coccinelle/.gitignore new file mode 100644 index 0000000000..d3f29646dc --- /dev/null +++ b/contrib/coccinelle/.gitignore @@ -0,0 +1 @@ +*.patch* diff --git a/contrib/coccinelle/README b/contrib/coccinelle/README new file mode 100644 index 0000000000..f0e80bd7f0 --- /dev/null +++ b/contrib/coccinelle/README @@ -0,0 +1,43 @@ +This directory provides examples of Coccinelle (http://coccinelle.lip6.fr/) +semantic patches that might be useful to developers. + +There are two types of semantic patches: + + * Using the semantic transformation to check for bad patterns in the code; + The target 'make coccicheck' is designed to check for these patterns and + it is expected that any resulting patch indicates a regression. + The patches resulting from 'make coccicheck' are small and infrequent, + so once they are found, they can be sent to the mailing list as per usual. + + Example for introducing new patterns: + 67947c34ae (convert "hashcmp() != 0" to "!hasheq()", 2018-08-28) + b84c783882 (fsck: s/++i > 1/i++/, 2018-10-24) + + Example of fixes using this approach: + 248f66ed8e (run-command: use strbuf_addstr() for adding a string to + a strbuf, 2018-03-25) + f919ffebed (Use MOVE_ARRAY, 2018-01-22) + + These types of semantic patches are usually part of testing, c.f. + 0860a7641b (travis-ci: fail if Coccinelle static analysis found something + to transform, 2018-07-23) + + * Using semantic transformations in large scale refactorings throughout + the code base. + + When applying the semantic patch into a real patch, sending it to the + mailing list in the usual way, such a patch would be expected to have a + lot of textual and semantic conflicts as such large scale refactorings + change function signatures that are used widely in the code base. + A textual conflict would arise if surrounding code near any call of such + function changes. A semantic conflict arises when other patch series in + flight introduce calls to such functions. + + So to aid these large scale refactorings, semantic patches can be used. + However we do not want to store them in the same place as the checks for + bad patterns, as then automated builds would fail. + That is why semantic patches 'contrib/coccinelle/*.pending.cocci' + are ignored for checks, and can be applied using 'make coccicheck-pending'. + + This allows to expose plans of pending large scale refactorings without + impacting the bad pattern checks. diff --git a/contrib/coccinelle/array.cocci b/contrib/coccinelle/array.cocci new file mode 100644 index 0000000000..9a4f00cb1b --- /dev/null +++ b/contrib/coccinelle/array.cocci @@ -0,0 +1,98 @@ +@@ +expression dst, src, n, E; +@@ + memcpy(dst, src, n * sizeof( +- E[...] ++ *(E) + )) + +@@ +type T; +T *ptr; +T[] arr; +expression E, n; +@@ +( + memcpy(ptr, E, +- n * sizeof(*(ptr)) ++ n * sizeof(T) + ) +| + memcpy(arr, E, +- n * sizeof(*(arr)) ++ n * sizeof(T) + ) +| + memcpy(E, ptr, +- n * sizeof(*(ptr)) ++ n * sizeof(T) + ) +| + memcpy(E, arr, +- n * sizeof(*(arr)) ++ n * sizeof(T) + ) +) + +@@ +type T; +T *dst_ptr; +T *src_ptr; +T[] dst_arr; +T[] src_arr; +expression n; +@@ +( +- memcpy(dst_ptr, src_ptr, (n) * sizeof(T)) ++ COPY_ARRAY(dst_ptr, src_ptr, n) +| +- memcpy(dst_ptr, src_arr, (n) * sizeof(T)) ++ COPY_ARRAY(dst_ptr, src_arr, n) +| +- memcpy(dst_arr, src_ptr, (n) * sizeof(T)) ++ COPY_ARRAY(dst_arr, src_ptr, n) +| +- memcpy(dst_arr, src_arr, (n) * sizeof(T)) ++ COPY_ARRAY(dst_arr, src_arr, n) +) + +@@ +type T; +T *dst; +T *src; +expression n; +@@ +( +- memmove(dst, src, (n) * sizeof(*dst)); ++ MOVE_ARRAY(dst, src, n); +| +- memmove(dst, src, (n) * sizeof(*src)); ++ MOVE_ARRAY(dst, src, n); +| +- memmove(dst, src, (n) * sizeof(T)); ++ MOVE_ARRAY(dst, src, n); +) + +@@ +type T; +T *ptr; +expression n; +@@ +- ptr = xmalloc((n) * sizeof(*ptr)); ++ ALLOC_ARRAY(ptr, n); + +@@ +type T; +T *ptr; +expression n; +@@ +- ptr = xmalloc((n) * sizeof(T)); ++ ALLOC_ARRAY(ptr, n); + +@@ +type T; +T *ptr; +expression n != 1; +@@ +- ptr = xcalloc(n, \( sizeof(*ptr) \| sizeof(T) \) ) ++ CALLOC_ARRAY(ptr, n) diff --git a/contrib/coccinelle/commit.cocci b/contrib/coccinelle/commit.cocci new file mode 100644 index 0000000000..af6dd4c20c --- /dev/null +++ b/contrib/coccinelle/commit.cocci @@ -0,0 +1,52 @@ +@@ +expression c; +@@ +- &c->maybe_tree->object.oid ++ get_commit_tree_oid(c) + +@@ +expression c; +@@ +- c->maybe_tree->object.oid.hash ++ get_commit_tree_oid(c)->hash + +@@ +identifier f !~ "^set_commit_tree$"; +expression c; +expression s; +@@ + f(...) {<... +- c->maybe_tree = s ++ set_commit_tree(c, s) + ...>} + +// These excluded functions must access c->maybe_tree directly. +// Note that if c->maybe_tree is written somewhere outside of these +// functions, then the recommended transformation will be bogus with +// repo_get_commit_tree() on the LHS. +@@ +identifier f !~ "^(repo_get_commit_tree|get_commit_tree_in_graph_one|load_tree_for_commit|set_commit_tree)$"; +expression c; +@@ + f(...) {<... +- c->maybe_tree ++ repo_get_commit_tree(specify_the_right_repo_here, c) + ...>} + +@@ +struct commit *c; +expression E; +@@ +( +- c->generation = E; ++ commit_graph_data_at(c)->generation = E; +| +- c->graph_pos = E; ++ commit_graph_data_at(c)->graph_pos = E; +| +- c->generation ++ commit_graph_generation(c) +| +- c->graph_pos ++ commit_graph_position(c) +) diff --git a/contrib/coccinelle/flex_alloc.cocci b/contrib/coccinelle/flex_alloc.cocci new file mode 100644 index 0000000000..e9f7f6d861 --- /dev/null +++ b/contrib/coccinelle/flex_alloc.cocci @@ -0,0 +1,13 @@ +@@ +expression str; +identifier x, flexname; +@@ +- FLEX_ALLOC_MEM(x, flexname, str, strlen(str)); ++ FLEX_ALLOC_STR(x, flexname, str); + +@@ +expression str; +identifier x, ptrname; +@@ +- FLEXPTR_ALLOC_MEM(x, ptrname, str, strlen(str)); ++ FLEXPTR_ALLOC_STR(x, ptrname, str); diff --git a/contrib/coccinelle/free.cocci b/contrib/coccinelle/free.cocci new file mode 100644 index 0000000000..4490069df9 --- /dev/null +++ b/contrib/coccinelle/free.cocci @@ -0,0 +1,18 @@ +@@ +expression E; +@@ +- if (E) + free(E); + +@@ +expression E; +@@ +- if (!E) + free(E); + +@@ +expression E; +@@ +- free(E); ++ FREE_AND_NULL(E); +- E = NULL; diff --git a/contrib/coccinelle/hashmap.cocci b/contrib/coccinelle/hashmap.cocci new file mode 100644 index 0000000000..d69e120ccf --- /dev/null +++ b/contrib/coccinelle/hashmap.cocci @@ -0,0 +1,16 @@ +@ hashmap_entry_init_usage @ +expression E; +struct hashmap_entry HME; +@@ +- HME.hash = E; ++ hashmap_entry_init(&HME, E); + +@@ +identifier f !~ "^hashmap_entry_init$"; +expression E; +struct hashmap_entry *HMEP; +@@ + f(...) {<... +- HMEP->hash = E; ++ hashmap_entry_init(HMEP, E); + ...>} diff --git a/contrib/coccinelle/object_id.cocci b/contrib/coccinelle/object_id.cocci new file mode 100644 index 0000000000..ddf4f22bd7 --- /dev/null +++ b/contrib/coccinelle/object_id.cocci @@ -0,0 +1,87 @@ +@@ +struct object_id OID; +@@ +- is_null_sha1(OID.hash) ++ is_null_oid(&OID) + +@@ +struct object_id *OIDPTR; +@@ +- is_null_sha1(OIDPTR->hash) ++ is_null_oid(OIDPTR) + +@@ +struct object_id OID; +@@ +- hashclr(OID.hash) ++ oidclr(&OID) + +@@ +identifier f != oidclr; +struct object_id *OIDPTR; +@@ + f(...) {<... +- hashclr(OIDPTR->hash) ++ oidclr(OIDPTR) + ...>} + +@@ +struct object_id OID1, OID2; +@@ +- hashcmp(OID1.hash, OID2.hash) ++ oidcmp(&OID1, &OID2) + +@@ +identifier f != oidcmp; +struct object_id *OIDPTR1, OIDPTR2; +@@ + f(...) {<... +- hashcmp(OIDPTR1->hash, OIDPTR2->hash) ++ oidcmp(OIDPTR1, OIDPTR2) + ...>} + +@@ +struct object_id *OIDPTR; +struct object_id OID; +@@ +- hashcmp(OIDPTR->hash, OID.hash) ++ oidcmp(OIDPTR, &OID) + +@@ +struct object_id *OIDPTR; +struct object_id OID; +@@ +- hashcmp(OID.hash, OIDPTR->hash) ++ oidcmp(&OID, OIDPTR) + +@@ +struct object_id *OIDPTR1; +struct object_id *OIDPTR2; +@@ +- oidcmp(OIDPTR1, OIDPTR2) == 0 ++ oideq(OIDPTR1, OIDPTR2) + +@@ +identifier f != hasheq; +expression E1, E2; +@@ + f(...) {<... +- hashcmp(E1, E2) == 0 ++ hasheq(E1, E2) + ...>} + +@@ +struct object_id *OIDPTR1; +struct object_id *OIDPTR2; +@@ +- oidcmp(OIDPTR1, OIDPTR2) != 0 ++ !oideq(OIDPTR1, OIDPTR2) + +@@ +identifier f != hasheq; +expression E1, E2; +@@ + f(...) {<... +- hashcmp(E1, E2) != 0 ++ !hasheq(E1, E2) + ...>} diff --git a/contrib/coccinelle/preincr.cocci b/contrib/coccinelle/preincr.cocci new file mode 100644 index 0000000000..7fe1e8d2d9 --- /dev/null +++ b/contrib/coccinelle/preincr.cocci @@ -0,0 +1,5 @@ +@ preincrement @ +identifier i; +@@ +- ++i > 1 ++ i++ diff --git a/contrib/coccinelle/qsort.cocci b/contrib/coccinelle/qsort.cocci new file mode 100644 index 0000000000..22b93a9966 --- /dev/null +++ b/contrib/coccinelle/qsort.cocci @@ -0,0 +1,37 @@ +@@ +expression base, nmemb, compar; +@@ +- qsort(base, nmemb, sizeof(*base), compar); ++ QSORT(base, nmemb, compar); + +@@ +expression base, nmemb, compar; +@@ +- qsort(base, nmemb, sizeof(base[0]), compar); ++ QSORT(base, nmemb, compar); + +@@ +type T; +T *base; +expression nmemb, compar; +@@ +- qsort(base, nmemb, sizeof(T), compar); ++ QSORT(base, nmemb, compar); + +@@ +expression base, nmemb, compar; +@@ +- if (nmemb) + QSORT(base, nmemb, compar); + +@@ +expression base, nmemb, compar; +@@ +- if (nmemb > 0) + QSORT(base, nmemb, compar); + +@@ +expression base, nmemb, compar; +@@ +- if (nmemb > 1) + QSORT(base, nmemb, compar); diff --git a/contrib/coccinelle/strbuf.cocci b/contrib/coccinelle/strbuf.cocci new file mode 100644 index 0000000000..d9ada69b43 --- /dev/null +++ b/contrib/coccinelle/strbuf.cocci @@ -0,0 +1,62 @@ +@ strbuf_addf_with_format_only @ +expression E; +constant fmt !~ "%"; +@@ +- strbuf_addf ++ strbuf_addstr + (E, +( + fmt +| + _(fmt) +) + ); + +@@ +expression E; +struct strbuf SB; +format F =~ "s"; +@@ +- strbuf_addf(E, "%@F@", SB.buf); ++ strbuf_addbuf(E, &SB); + +@@ +expression E; +struct strbuf *SBP; +format F =~ "s"; +@@ +- strbuf_addf(E, "%@F@", SBP->buf); ++ strbuf_addbuf(E, SBP); + +@@ +expression E; +struct strbuf SB; +@@ +- strbuf_addstr(E, SB.buf); ++ strbuf_addbuf(E, &SB); + +@@ +expression E; +struct strbuf *SBP; +@@ +- strbuf_addstr(E, SBP->buf); ++ strbuf_addbuf(E, SBP); + +@@ +expression E1, E2; +format F =~ "s"; +@@ +- strbuf_addf(E1, "%@F@", E2); ++ strbuf_addstr(E1, E2); + +@@ +expression E1, E2, E3; +@@ +- strbuf_addstr(E1, find_unique_abbrev(E2, E3)); ++ strbuf_add_unique_abbrev(E1, E2, E3); + +@@ +expression E1, E2; +@@ +- strbuf_addstr(E1, real_path(E2)); ++ strbuf_add_real_path(E1, E2); diff --git a/contrib/coccinelle/swap.cocci b/contrib/coccinelle/swap.cocci new file mode 100644 index 0000000000..a0934d1fda --- /dev/null +++ b/contrib/coccinelle/swap.cocci @@ -0,0 +1,28 @@ +@ swap_with_declaration @ +type T; +identifier tmp; +T a, b; +@@ +- T tmp = a; ++ T tmp; ++ tmp = a; + a = b; + b = tmp; + +@ swap @ +type T; +T tmp, a, b; +@@ +- tmp = a; +- a = b; +- b = tmp; ++ SWAP(a, b); + +@ extends swap @ +identifier unused; +@@ + { + ... +- T unused; + ... when != unused + } diff --git a/contrib/coccinelle/the_repository.pending.cocci b/contrib/coccinelle/the_repository.pending.cocci new file mode 100644 index 0000000000..2ee702ecf7 --- /dev/null +++ b/contrib/coccinelle/the_repository.pending.cocci @@ -0,0 +1,144 @@ +// This file is used for the ongoing refactoring of +// bringing the index or repository struct in all of +// our code base. + +@@ +expression E; +expression F; +expression G; +@@ +- read_object_file( ++ repo_read_object_file(the_repository, + E, F, G) + +@@ +expression E; +@@ +- has_sha1_file( ++ repo_has_sha1_file(the_repository, + E) + +@@ +expression E; +expression F; +@@ +- has_sha1_file_with_flags( ++ repo_has_sha1_file_with_flags(the_repository, + E) + +@@ +expression E; +@@ +- has_object_file( ++ repo_has_object_file(the_repository, + E) + +@@ +expression E; +expression F; +@@ +- has_object_file_with_flags( ++ repo_has_object_file_with_flags(the_repository, + E) + +@@ +expression E; +expression F; +expression G; +@@ +- parse_commit_internal( ++ repo_parse_commit_internal(the_repository, + E, F, G) + +@@ +expression E; +expression F; +@@ +- parse_commit_gently( ++ repo_parse_commit_gently(the_repository, + E, F) + +@@ +expression E; +@@ +- parse_commit( ++ repo_parse_commit(the_repository, + E) + +@@ +expression E; +expression F; +@@ +- get_merge_bases( ++ repo_get_merge_bases(the_repository, + E, F); + +@@ +expression E; +expression F; +expression G; +@@ +- get_merge_bases_many( ++ repo_get_merge_bases_many(the_repository, + E, F, G); + +@@ +expression E; +expression F; +expression G; +@@ +- get_merge_bases_many_dirty( ++ repo_get_merge_bases_many_dirty(the_repository, + E, F, G); + +@@ +expression E; +expression F; +@@ +- in_merge_bases( ++ repo_in_merge_bases(the_repository, + E, F); + +@@ +expression E; +expression F; +expression G; +@@ +- in_merge_bases_many( ++ repo_in_merge_bases_many(the_repository, + E, F, G); + +@@ +expression E; +expression F; +@@ +- get_commit_buffer( ++ repo_get_commit_buffer(the_repository, + E, F); + +@@ +expression E; +expression F; +@@ +- unuse_commit_buffer( ++ repo_unuse_commit_buffer(the_repository, + E, F); + +@@ +expression E; +expression F; +expression G; +@@ +- logmsg_reencode( ++ repo_logmsg_reencode(the_repository, + E, F, G); + +@@ +expression E; +expression F; +expression G; +expression H; +@@ +- format_commit_message( ++ repo_format_commit_message(the_repository, + E, F, G, H); diff --git a/contrib/coccinelle/xcalloc.cocci b/contrib/coccinelle/xcalloc.cocci new file mode 100644 index 0000000000..c291011607 --- /dev/null +++ b/contrib/coccinelle/xcalloc.cocci @@ -0,0 +1,10 @@ +@@ +type T; +T *ptr; +expression n; +@@ + xcalloc( ++ n, + \( sizeof(T) \| sizeof(*ptr) \) +- , n + ) diff --git a/contrib/coccinelle/xopen.cocci b/contrib/coccinelle/xopen.cocci new file mode 100644 index 0000000000..814d7b8a1a --- /dev/null +++ b/contrib/coccinelle/xopen.cocci @@ -0,0 +1,16 @@ +@@ +identifier fd; +identifier die_fn =~ "^(die|die_errno)$"; +@@ +( + fd = +- open ++ xopen + (...); +| + int fd = +- open ++ xopen + (...); +) +- if ( \( fd < 0 \| fd == -1 \) ) { die_fn(...); } diff --git a/contrib/coccinelle/xstrdup_or_null.cocci b/contrib/coccinelle/xstrdup_or_null.cocci new file mode 100644 index 0000000000..8e05d1ca4b --- /dev/null +++ b/contrib/coccinelle/xstrdup_or_null.cocci @@ -0,0 +1,13 @@ +@@ +expression E; +expression V; +@@ +- if (E) +- V = xstrdup(E); ++ V = xstrdup_or_null(E); + +@@ +expression E; +@@ +- xstrdup(absolute_path(E)) ++ absolute_pathdup(E) |