blame: enable funcname blaming with userdiff driver

In blame.c::cmd_blame, we send the 'path' field of the 'sb' 'struct blame_scoreboard' as the 'path' argument to 'line-range.c::parse_range_arg', but 'sb.path' is not set yet; it's set to the local variable 'path' a few lines later at line 1137. This 'path' argument is only used in 'parse_range_arg' if we are blaming a funcname, i.e. `git blame -L :<funcname> <path>`, and in that case it is sent to 'parse_range_funcname', where it is used to determine if a userdiff driver should be used for said <path> to match the given funcname. Since 'path' is yet unset, the userdiff driver is never used, so we fall back to the default funcname regex, which is usually not appropriate for paths that are set to use a specific userdiff driver, and thus either we match some unrelated lines, or we die with fatal: -L parameter '<funcname>' starting at line 1: no match This has been the case ever since `git blame` learned to blame a funcname in 13b8f68c1f (log -L: :pattern:file syntax to find by funcname, 2013-03-28). Enable funcname blaming for paths using specific userdiff drivers by initializing 'sb.path' earlier in 'cmd_blame', when some of its other fields are initialized, so that it is set when passed to 'parse_range_arg'. Add a regression test in 'annotate-tests.sh', which is sourced in t8001-annotate.sh and t8002-blame.sh, leveraging an existing file used to test the userdiff patterns in t4018-diff-funcname. Also, use 'sb.path' instead of 'path' when constructing the error message at line 1114, for consistency. Signed-off-by: Philippe Blain <levraiphilippeblain@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Philippe Blain committed Nov 1, 2020 at 17:28 UTC 9466e3809d2b5f9605918c56d63f21b17e98e230
2 files changed +20 -2
builtin/blame.c
+2 -2
@@ -1083,6 +1083,7 @@ parse_done:
1083 sb.contents_from = contents_from;
1084 sb.reverse = reverse;
1085 sb.repo = the_repository;
1086 + sb.path = path;
1087 build_ignorelist(&sb, &ignore_revs_file_list, &ignore_rev_list);
1088 string_list_clear(&ignore_revs_file_list, 0);
1089 string_list_clear(&ignore_rev_list, 0);
@@ -1112,7 +1113,7 @@ parse_done:
1113 if ((!lno && (top || bottom)) || lno < bottom)
1114 die(Q_("file %s has only %lu line",
1115 "file %s has only %lu lines",
1115 - lno), path, lno);
1116 + lno), sb.path, lno);
1117 if (bottom < 1)
1118 bottom = 1;
1119 if (top < 1 || lno < top)
@@ -1137,7 +1138,6 @@ parse_done:
1138 string_list_clear(&range_list, 0);
1139
1140 sb.ent = NULL;
1140 - sb.path = path;
1141
1142 if (blame_move_score)
1143 sb.move_score = blame_move_score;
t/annotate-tests.sh
+18
@@ -479,6 +479,24 @@ test_expect_success 'blame -L ^:RE (absolute: end-of-file)' '
479 check_count -f hello.c -L$n -L^:ma.. F 4 G 1 H 1
480 '
481
482 +test_expect_success 'setup -L :funcname with userdiff driver' '
483 + echo "fortran-* diff=fortran" >.gitattributes &&
484 + fortran_file=fortran-external-function &&
485 + orig_file="$TEST_DIRECTORY/t4018/$fortran_file" &&
486 + cp $orig_file . &&
487 + git add $fortran_file &&
488 + GIT_AUTHOR_NAME="A" GIT_AUTHOR_EMAIL="A@test.git" \
489 + git commit -m "add fortran file" &&
490 + sed -e "s/ChangeMe/IWasChanged/" <"$orig_file" >$fortran_file &&
491 + git add $fortran_file &&
492 + GIT_AUTHOR_NAME="B" GIT_AUTHOR_EMAIL="B@test.git" \
493 + git commit -m "change fortran file"
494 +'
495 +
496 +test_expect_success 'blame -L :funcname with userdiff driver' '
497 + check_count -f fortran-external-function -L:RIGHT A 7 B 1
498 +'
499 +
500 test_expect_success 'setup incremental' '
501 (
502 GIT_AUTHOR_NAME=I &&