Subject: [PATCH v5] userdiff: improve java hunk header regex

From: Tassilo Horn <[email-masked]>
Date: Wed, 11 Aug 2021 16:53:41 +0200

Currently, the git diff hunk headers show the wrong method signature if the
method has a qualified return type, an array return type, or a generic return
type because the regex doesn't allow dots (.), [], or < and > in the return
type.  Also, type parameter declarations couldn't be matched.

Add several t4018 tests asserting the right hunk headers for different cases:

  - enum constant change
  - change in generic method with bounded type parameters
  - change in generic method with wildcard
  - field change in a nested class

Signed-off-by: Tassilo Horn <[email-masked]>
---
 t/t4018/java-class-member-function          | 6 +++++-
 t/t4018/java-enum-constant                  | 6 ++++++
 t/t4018/java-method-return-generic-bounded  | 9 +++++++++
 t/t4018/java-method-return-generic-wildcard | 9 +++++++++
 t/t4018/java-nested-field                   | 6 ++++++
 userdiff.c                                  | 6 +++++-
 6 files changed, 40 insertions(+), 2 deletions(-)
 create mode 100644 t/t4018/java-enum-constant
 create mode 100644 t/t4018/java-method-return-generic-bounded
 create mode 100644 t/t4018/java-method-return-generic-wildcard
 create mode 100644 t/t4018/java-nested-field

diff --git a/t/t4018/java-class-member-function b/t/t4018/java-class-member-function
index 298bc7a71b..a8d7850412 100644
--- a/t/t4018/java-class-member-function
+++ b/t/t4018/java-class-member-function
@@ -3,6 +3,10 @@ public class Beer
 	int special;
 	public static void main(String RIGHT[])
 	{
-		System.out.print("ChangeMe");
+            someMethodCall();
+            someOtherMethod("17")
+                .doThat();
+            // Whatever
+            System.out.print("ChangeMe");
 	}
 }
diff --git a/t/t4018/java-enum-constant b/t/t4018/java-enum-constant
new file mode 100644
index 0000000000..a1931c8379
--- /dev/null
+++ b/t/t4018/java-enum-constant
@@ -0,0 +1,6 @@
+private enum RIGHT {
+    ONE,
+    TWO,
+    THREE,
+    ChangeMe
+}
diff --git a/t/t4018/java-method-return-generic-bounded b/t/t4018/java-method-return-generic-bounded
new file mode 100644
index 0000000000..66dd78c379
--- /dev/null
+++ b/t/t4018/java-method-return-generic-bounded
@@ -0,0 +1,9 @@
+class MyExample {
+    public <T extends Bar & Foo<T>, R> Map<T, R[]> foo(String[] RIGHT) {
+        someMethodCall();
+        someOtherMethod()
+            .doThat();
+        // Whatever...
+        return (List<T>) Arrays.asList("ChangeMe");
+    }
+}
diff --git a/t/t4018/java-method-return-generic-wildcard b/t/t4018/java-method-return-generic-wildcard
new file mode 100644
index 0000000000..96e9e5f2c1
--- /dev/null
+++ b/t/t4018/java-method-return-generic-wildcard
@@ -0,0 +1,9 @@
+class MyExample {
+    public List<? extends Comparable> foo(String[] RIGHT) {
+        someMethodCall();
+        someOtherMethod()
+            .doThat();
+        // Whatever...
+        return Arrays.asList("ChangeMe");
+    }
+}
diff --git a/t/t4018/java-nested-field b/t/t4018/java-nested-field
new file mode 100644
index 0000000000..d92d3ec688
--- /dev/null
+++ b/t/t4018/java-nested-field
@@ -0,0 +1,6 @@
+class MyExample {
+    private static class RIGHT {
+        // change an inner class field
+        String inner = "ChangeMe";
+    }
+}
diff --git a/userdiff.c b/userdiff.c
index 3c3bbe38b0..6644931ce1 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -142,7 +142,11 @@ PATTERNS("html",
 	 "[^<>= \t]+"),
 PATTERNS("java",
 	 "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
-	 "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$",
+         /* Class, enum, and interface declarations */
+         "^[ \t]*(([a-z]+[ \t]+)*(class|enum|interface)[ \t]+[A-Za-z][A-Za-z0-9_$]*[ \t]+.*)$\n"
+         /* Method definitions; note that constructor signatures are not */
+         /* matched because they are indistinguishable from method calls. */
+         "^[ \t]*(([A-Za-z_<>&][][?&<>.,A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$",
 	 /* -- */
 	 "[a-zA-Z_][a-zA-Z0-9_]*"
 	 "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
-- 
2.32.0