diff options
Diffstat (limited to 'contrib/coccinelle')
-rw-r--r-- | contrib/coccinelle/README | 40 | ||||
-rw-r--r-- | contrib/coccinelle/config_fn_ctx.pending.cocci | 144 | ||||
-rw-r--r-- | contrib/coccinelle/git_config_number.cocci | 27 | ||||
-rw-r--r-- | contrib/coccinelle/tests/unused.c | 82 | ||||
-rw-r--r-- | contrib/coccinelle/tests/unused.res | 45 | ||||
-rw-r--r-- | contrib/coccinelle/the_repository.cocci | 123 | ||||
-rw-r--r-- | contrib/coccinelle/the_repository.pending.cocci | 128 | ||||
-rw-r--r-- | contrib/coccinelle/unused.cocci | 43 |
8 files changed, 330 insertions, 302 deletions
diff --git a/contrib/coccinelle/README b/contrib/coccinelle/README index d1daa1f626..055ad0e06a 100644 --- a/contrib/coccinelle/README +++ b/contrib/coccinelle/README @@ -1,7 +1,9 @@ -This directory provides examples of Coccinelle (http://coccinelle.lip6.fr/) -semantic patches that might be useful to developers. += coccinelle -There are two types of semantic patches: +This directory provides Coccinelle (http://coccinelle.lip6.fr/) semantic patches +that might be useful to developers. + +== 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 @@ -42,7 +44,7 @@ There are two types of semantic patches: This allows to expose plans of pending large scale refactorings without impacting the bad pattern checks. -Git-specific tips & things to know about how we run "spatch": +== Git-specific tips & things to know about how we run "spatch": * The "make coccicheck" will piggy-back on "COMPUTE_HEADER_DEPENDENCIES". If you've built a given object file @@ -90,3 +92,33 @@ Git-specific tips & things to know about how we run "spatch": The absolute times will differ for you, but the relative speedup from caching should be on that order. + +== Authoring and reviewing coccinelle changes + +* When a .cocci is made, both the Git changes and .cocci file should be + reviewed. When reviewing such a change, do your best to understand the .cocci + changes (e.g. by asking the author to explain the change) and be explicit + about your understanding of the changes. This helps us decide whether input + from coccinelle experts is needed or not. If you aren't sure of the cocci + changes, indicate what changes you actively endorse and leave an Acked-by + (instead of Reviewed-by). + +* Authors should consider that reviewers may not be coccinelle experts, thus the + the .cocci changes may not be self-evident. A plain text description of the + changes is strongly encouraged, especially when using more esoteric features + of the language. + +* .cocci rules should target only the problem it is trying to solve; "collateral + damage" is not allowed. Reviewers should look out and flag overly-broad rules. + +* Consider the cost-benefit ratio of .cocci changes. In particular, consider the + effect on the runtime of "make coccicheck", and how often your .cocci check + will catch something valuable. As a rule of thumb, rules that can bail early + if a file doesn't have a particular token will have a small impact on runtime, + and vice-versa. + +* .cocci files used for refactoring should be temporarily kept in-tree to aid + the refactoring of out-of-tree code (e.g. in-flight topics). Periodically + evaluate the cost-benefit ratio to determine when the file should be removed. + For example, consider how many out-of-tree users are left and how much this + slows down "make coccicheck". diff --git a/contrib/coccinelle/config_fn_ctx.pending.cocci b/contrib/coccinelle/config_fn_ctx.pending.cocci new file mode 100644 index 0000000000..6d3d1000a9 --- /dev/null +++ b/contrib/coccinelle/config_fn_ctx.pending.cocci @@ -0,0 +1,144 @@ +@ get_fn @ +identifier fn, R; +@@ +( +( +git_config_from_file +| +git_config_from_file_with_options +| +git_config_from_mem +| +git_config_from_blob_oid +| +read_early_config +| +read_very_early_config +| +config_with_options +| +git_config +| +git_protected_config +| +config_from_gitmodules +) + (fn, ...) +| +repo_config(R, fn, ...) +) + +@ extends get_fn @ +identifier C1, C2, D; +@@ +int fn(const char *C1, const char *C2, ++ const struct config_context *ctx, + void *D); + +@ extends get_fn @ +@@ +int fn(const char *, const char *, ++ const struct config_context *, + void *); + +@ extends get_fn @ +// Don't change fns that look like callback fns but aren't +identifier fn2 != tar_filter_config && != git_diff_heuristic_config && + != git_default_submodule_config && != git_color_config && + != bundle_list_update && != parse_object_filter_config; +identifier C1, C2, D1, D2, S; +attribute name UNUSED; +@@ +int fn(const char *C1, const char *C2, ++ const struct config_context *ctx, + void *D1) { +<+... +( +fn2(C1, C2 ++ , ctx +, D2); +| +if(fn2(C1, C2 ++ , ctx +, D2) < 0) { ... } +| +return fn2(C1, C2 ++ , ctx +, D2); +| +S = fn2(C1, C2 ++ , ctx +, D2); +) +...+> + } + +@ extends get_fn@ +identifier C1, C2, D; +attribute name UNUSED; +@@ +int fn(const char *C1, const char *C2, ++ const struct config_context *ctx UNUSED, + void *D) {...} + + +// The previous rules don't catch all callbacks, especially if they're defined +// in a separate file from the git_config() call. Fix these manually. +@@ +identifier C1, C2, D; +attribute name UNUSED; +@@ +int +( +git_ident_config +| +urlmatch_collect_fn +| +write_one_config +| +forbid_remote_url +| +credential_config_callback +) + (const char *C1, const char *C2, ++ const struct config_context *ctx UNUSED, + void *D) {...} + +@@ +identifier C1, C2, D, D2, S, fn2; +@@ +int +( +http_options +| +git_status_config +| +git_commit_config +| +git_default_core_config +| +grep_config +) + (const char *C1, const char *C2, ++ const struct config_context *ctx, + void *D) { +<+... +( +fn2(C1, C2 ++ , ctx +, D2); +| +if(fn2(C1, C2 ++ , ctx +, D2) < 0) { ... } +| +return fn2(C1, C2 ++ , ctx +, D2); +| +S = fn2(C1, C2 ++ , ctx +, D2); +) +...+> + } diff --git a/contrib/coccinelle/git_config_number.cocci b/contrib/coccinelle/git_config_number.cocci new file mode 100644 index 0000000000..7b57dceefe --- /dev/null +++ b/contrib/coccinelle/git_config_number.cocci @@ -0,0 +1,27 @@ +@@ +identifier C1, C2, C3; +@@ +( +( +git_config_int +| +git_config_int64 +| +git_config_ulong +| +git_config_ssize_t +) + (C1, C2 ++ , ctx->kvi + ) +| +( +git_configset_get_value +| +git_config_bool_or_int +) + (C1, C2 ++ , ctx->kvi + , C3 + ) +) diff --git a/contrib/coccinelle/tests/unused.c b/contrib/coccinelle/tests/unused.c deleted file mode 100644 index 8294d734ba..0000000000 --- a/contrib/coccinelle/tests/unused.c +++ /dev/null @@ -1,82 +0,0 @@ -void test_strbuf(void) -{ - struct strbuf sb1 = STRBUF_INIT; - struct strbuf sb2 = STRBUF_INIT; - struct strbuf sb3 = STRBUF_INIT; - struct strbuf sb4 = STRBUF_INIT; - struct strbuf sb5; - struct strbuf sb6 = { 0 }; - struct strbuf sb7 = STRBUF_INIT; - struct strbuf sb8 = STRBUF_INIT; - struct strbuf *sp1; - struct strbuf *sp2; - struct strbuf *sp3; - struct strbuf *sp4 = xmalloc(sizeof(struct strbuf)); - struct strbuf *sp5 = xmalloc(sizeof(struct strbuf)); - struct strbuf *sp6 = xmalloc(sizeof(struct strbuf)); - struct strbuf *sp7; - - strbuf_init(&sb5, 0); - strbuf_init(sp1, 0); - strbuf_init(sp2, 0); - strbuf_init(sp3, 0); - strbuf_init(sp4, 0); - strbuf_init(sp5, 0); - strbuf_init(sp6, 0); - strbuf_init(sp7, 0); - sp7 = xmalloc(sizeof(struct strbuf)); - - use_before(&sb3); - use_as_str("%s", sb7.buf); - use_as_str("%s", sp1->buf); - use_as_str("%s", sp6->buf); - pass_pp(&sp3); - - strbuf_release(&sb1); - strbuf_reset(&sb2); - strbuf_release(&sb3); - strbuf_release(&sb4); - strbuf_release(&sb5); - strbuf_release(&sb6); - strbuf_release(&sb7); - strbuf_release(sp1); - strbuf_release(sp2); - strbuf_release(sp3); - strbuf_release(sp4); - strbuf_release(sp5); - strbuf_release(sp6); - strbuf_release(sp7); - - use_after(&sb4); - - if (when_strict()) - return; - strbuf_release(&sb8); -} - -void test_other(void) -{ - struct string_list l = STRING_LIST_INIT_DUP; - struct strbuf sb = STRBUF_INIT; - - string_list_clear(&l, 0); - string_list_clear(&sb, 0); -} - -void test_worktrees(void) -{ - struct worktree **w1 = get_worktrees(); - struct worktree **w2 = get_worktrees(); - struct worktree **w3; - struct worktree **w4; - - w3 = get_worktrees(); - w4 = get_worktrees(); - - use_it(w4); - - free_worktrees(w1); - free_worktrees(w2); - free_worktrees(w3); - free_worktrees(w4); -} diff --git a/contrib/coccinelle/tests/unused.res b/contrib/coccinelle/tests/unused.res deleted file mode 100644 index 6d3e745683..0000000000 --- a/contrib/coccinelle/tests/unused.res +++ /dev/null @@ -1,45 +0,0 @@ -void test_strbuf(void) -{ - struct strbuf sb3 = STRBUF_INIT; - struct strbuf sb4 = STRBUF_INIT; - struct strbuf sb7 = STRBUF_INIT; - struct strbuf *sp1; - struct strbuf *sp3; - struct strbuf *sp6 = xmalloc(sizeof(struct strbuf)); - strbuf_init(sp1, 0); - strbuf_init(sp3, 0); - strbuf_init(sp6, 0); - - use_before(&sb3); - use_as_str("%s", sb7.buf); - use_as_str("%s", sp1->buf); - use_as_str("%s", sp6->buf); - pass_pp(&sp3); - - strbuf_release(&sb3); - strbuf_release(&sb4); - strbuf_release(&sb7); - strbuf_release(sp1); - strbuf_release(sp3); - strbuf_release(sp6); - - use_after(&sb4); - - if (when_strict()) - return; -} - -void test_other(void) -{ -} - -void test_worktrees(void) -{ - struct worktree **w4; - - w4 = get_worktrees(); - - use_it(w4); - - free_worktrees(w4); -} diff --git a/contrib/coccinelle/the_repository.cocci b/contrib/coccinelle/the_repository.cocci new file mode 100644 index 0000000000..765ad68967 --- /dev/null +++ b/contrib/coccinelle/the_repository.cocci @@ -0,0 +1,123 @@ +// Fully migrated "the_repository" additions +@@ +@@ +( +// cache.h +- get_oid ++ repo_get_oid +| +- get_oid_commit ++ repo_get_oid_commit +| +- get_oid_committish ++ repo_get_oid_committish +| +- get_oid_tree ++ repo_get_oid_tree +| +- get_oid_treeish ++ repo_get_oid_treeish +| +- get_oid_blob ++ repo_get_oid_blob +| +- get_oid_mb ++ repo_get_oid_mb +| +- find_unique_abbrev ++ repo_find_unique_abbrev +| +- find_unique_abbrev_r ++ repo_find_unique_abbrev_r +| +- for_each_abbrev ++ repo_for_each_abbrev +| +- interpret_branch_name ++ repo_interpret_branch_name +| +- peel_to_type ++ repo_peel_to_type +// commit-reach.h +| +- get_merge_bases ++ repo_get_merge_bases +| +- get_merge_bases_many ++ repo_get_merge_bases_many +| +- get_merge_bases_many_dirty ++ repo_get_merge_bases_many_dirty +| +- in_merge_bases ++ repo_in_merge_bases +| +- in_merge_bases_many ++ repo_in_merge_bases_many +// commit.h +| +- parse_commit_internal ++ repo_parse_commit_internal +| +- parse_commit ++ repo_parse_commit +| +- get_commit_buffer ++ repo_get_commit_buffer +| +- unuse_commit_buffer ++ repo_unuse_commit_buffer +| +- logmsg_reencode ++ repo_logmsg_reencode +| +- get_commit_tree ++ repo_get_commit_tree +// diff.h +| +- diff_setup ++ repo_diff_setup +// object-store.h +| +- read_object_file ++ repo_read_object_file +| +- has_object_file ++ repo_has_object_file +| +- has_object_file_with_flags ++ repo_has_object_file_with_flags +// pretty.h +| +- format_commit_message ++ repo_format_commit_message +// packfile.h +| +- approximate_object_count ++ repo_approximate_object_count +// promisor-remote.h +| +- promisor_remote_reinit ++ repo_promisor_remote_reinit +| +- promisor_remote_find ++ repo_promisor_remote_find +| +- has_promisor_remote ++ repo_has_promisor_remote +// refs.h +| +- dwim_ref ++ repo_dwim_ref +// rerere.h +| +- rerere ++ repo_rerere +// revision.h +| +- init_revisions ++ repo_init_revisions +) + ( ++ the_repository, + ...) diff --git a/contrib/coccinelle/the_repository.pending.cocci b/contrib/coccinelle/the_repository.pending.cocci deleted file mode 100644 index 747d382ff5..0000000000 --- a/contrib/coccinelle/the_repository.pending.cocci +++ /dev/null @@ -1,128 +0,0 @@ -// 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_object_file( -+ repo_has_object_file(the_repository, - E) - -@@ -expression E; -@@ -- 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/unused.cocci b/contrib/coccinelle/unused.cocci deleted file mode 100644 index d84046f82e..0000000000 --- a/contrib/coccinelle/unused.cocci +++ /dev/null @@ -1,43 +0,0 @@ -// This rule finds sequences of "unused" declerations and uses of a -// variable, where "unused" is defined to include only calling the -// equivalent of alloc, init & free functions on the variable. -@@ -type T; -identifier I; -// STRBUF_INIT, but also e.g. STRING_LIST_INIT_DUP (so no anchoring) -constant INIT_MACRO =~ "_INIT"; -identifier MALLOC1 =~ "^x?[mc]alloc$"; -identifier INIT_ASSIGN1 =~ "^get_worktrees$"; -identifier INIT_CALL1 =~ "^[a-z_]*_init$"; -identifier REL1 =~ "^[a-z_]*_(release|reset|clear|free)$"; -identifier REL2 =~ "^(release|clear|free)_[a-z_]*$"; -@@ - -( -- T I; -| -- T I = { 0 }; -| -- T I = INIT_MACRO; -| -- T I = MALLOC1(...); -| -- T I = INIT_ASSIGN1(...); -) - -<... when != \( I \| &I \) -( -- \( INIT_CALL1 \)( \( I \| &I \), ...); -| -- I = \( INIT_ASSIGN1 \)(...); -| -- I = MALLOC1(...); -) -...> - -( -- \( REL1 \| REL2 \)( \( I \| &I \), ...); -| -- \( REL1 \| REL2 \)( \( &I \| I \) ); -) - ... when != \( I \| &I \) |