diff options
Diffstat (limited to 'contrib/coccinelle')
-rw-r--r-- | contrib/coccinelle/README | 41 | ||||
-rw-r--r-- | contrib/coccinelle/commit.cocci | 6 | ||||
-rw-r--r-- | contrib/coccinelle/object_id.cocci | 123 | ||||
-rw-r--r-- | contrib/coccinelle/preincr.cocci | 5 | ||||
-rw-r--r-- | contrib/coccinelle/strbuf.cocci | 30 | ||||
-rw-r--r-- | contrib/coccinelle/the_repository.pending.cocci | 144 |
6 files changed, 289 insertions, 60 deletions
diff --git a/contrib/coccinelle/README b/contrib/coccinelle/README index 9c2f8879c2..f0e80bd7f0 100644 --- a/contrib/coccinelle/README +++ b/contrib/coccinelle/README @@ -1,2 +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/commit.cocci b/contrib/coccinelle/commit.cocci index a7e9215ffc..c49aa558f0 100644 --- a/contrib/coccinelle/commit.cocci +++ b/contrib/coccinelle/commit.cocci @@ -12,13 +12,13 @@ expression c; // These excluded functions must access c->maybe_tree direcly. @@ -identifier f !~ "^(get_commit_tree|get_commit_tree_in_graph|load_tree_for_commit)$"; +identifier f !~ "^(get_commit_tree|get_commit_tree_in_graph_one|load_tree_for_commit)$"; expression c; @@ - f(...) {... + f(...) {<... - c->maybe_tree + get_commit_tree(c) - ...} + ...>} @@ expression c; diff --git a/contrib/coccinelle/object_id.cocci b/contrib/coccinelle/object_id.cocci index 09afdbf994..3e536a9834 100644 --- a/contrib/coccinelle/object_id.cocci +++ b/contrib/coccinelle/object_id.cocci @@ -1,110 +1,119 @@ @@ -expression E1; +struct object_id OID; @@ -- is_null_sha1(E1.hash) -+ is_null_oid(&E1) +- is_null_sha1(OID.hash) ++ is_null_oid(&OID) @@ -expression E1; +struct object_id *OIDPTR; @@ -- is_null_sha1(E1->hash) -+ is_null_oid(E1) +- is_null_sha1(OIDPTR->hash) ++ is_null_oid(OIDPTR) @@ -expression E1; +struct object_id OID; @@ -- sha1_to_hex(E1.hash) -+ oid_to_hex(&E1) +- sha1_to_hex(OID.hash) ++ oid_to_hex(&OID) @@ identifier f != oid_to_hex; -expression E1; +struct object_id *OIDPTR; @@ - f(...) {... -- sha1_to_hex(E1->hash) -+ oid_to_hex(E1) - ...} + f(...) {<... +- sha1_to_hex(OIDPTR->hash) ++ oid_to_hex(OIDPTR) + ...>} @@ -expression E1, E2; +expression E; +struct object_id OID; @@ -- sha1_to_hex_r(E1, E2.hash) -+ oid_to_hex_r(E1, &E2) +- sha1_to_hex_r(E, OID.hash) ++ oid_to_hex_r(E, &OID) @@ identifier f != oid_to_hex_r; -expression E1, E2; +expression E; +struct object_id *OIDPTR; @@ - f(...) {... -- sha1_to_hex_r(E1, E2->hash) -+ oid_to_hex_r(E1, E2) - ...} + f(...) {<... +- sha1_to_hex_r(E, OIDPTR->hash) ++ oid_to_hex_r(E, OIDPTR) + ...>} @@ -expression E1; +struct object_id OID; @@ -- hashclr(E1.hash) -+ oidclr(&E1) +- hashclr(OID.hash) ++ oidclr(&OID) @@ identifier f != oidclr; -expression E1; +struct object_id *OIDPTR; @@ - f(...) {... -- hashclr(E1->hash) -+ oidclr(E1) - ...} + f(...) {<... +- hashclr(OIDPTR->hash) ++ oidclr(OIDPTR) + ...>} @@ -expression E1, E2; +struct object_id OID1, OID2; @@ -- hashcmp(E1.hash, E2.hash) -+ oidcmp(&E1, &E2) +- hashcmp(OID1.hash, OID2.hash) ++ oidcmp(&OID1, &OID2) @@ identifier f != oidcmp; -expression E1, E2; +struct object_id *OIDPTR1, OIDPTR2; @@ - f(...) {... -- hashcmp(E1->hash, E2->hash) -+ oidcmp(E1, E2) - ...} + f(...) {<... +- hashcmp(OIDPTR1->hash, OIDPTR2->hash) ++ oidcmp(OIDPTR1, OIDPTR2) + ...>} @@ -expression E1, E2; +struct object_id *OIDPTR; +struct object_id OID; @@ -- hashcmp(E1->hash, E2.hash) -+ oidcmp(E1, &E2) +- hashcmp(OIDPTR->hash, OID.hash) ++ oidcmp(OIDPTR, &OID) @@ -expression E1, E2; +struct object_id *OIDPTR; +struct object_id OID; @@ -- hashcmp(E1.hash, E2->hash) -+ oidcmp(&E1, E2) +- hashcmp(OID.hash, OIDPTR->hash) ++ oidcmp(&OID, OIDPTR) @@ -expression E1, E2; +struct object_id *OIDPTR1; +struct object_id *OIDPTR2; @@ -- hashcpy(E1.hash, E2.hash) -+ oidcpy(&E1, &E2) +- oidcmp(OIDPTR1, OIDPTR2) == 0 ++ oideq(OIDPTR1, OIDPTR2) @@ -identifier f != oidcpy; +identifier f != hasheq; expression E1, E2; @@ - f(...) {... -- hashcpy(E1->hash, E2->hash) -+ oidcpy(E1, E2) - ...} + f(...) {<... +- hashcmp(E1, E2) == 0 ++ hasheq(E1, E2) + ...>} @@ -expression E1, E2; +struct object_id *OIDPTR1; +struct object_id *OIDPTR2; @@ -- hashcpy(E1->hash, E2.hash) -+ oidcpy(E1, &E2) +- oidcmp(OIDPTR1, OIDPTR2) != 0 ++ !oideq(OIDPTR1, OIDPTR2) @@ +identifier f != hasheq; expression E1, E2; @@ -- hashcpy(E1.hash, E2->hash) -+ oidcpy(&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/strbuf.cocci b/contrib/coccinelle/strbuf.cocci index e34eada1ad..d9ada69b43 100644 --- a/contrib/coccinelle/strbuf.cocci +++ b/contrib/coccinelle/strbuf.cocci @@ -13,6 +13,36 @@ constant 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"; @@ 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); |