runtime(java): Optionally highlight the :: token for method references

This token will be highlighted, similar to the arrow of
lambda expressions, whenever "g:java_highlight_functions" is
defined.

Also:

- Improve the recognition of _switch-case_ labels
  (D-Cysteine).
- Remove insignificant empty statements in syntax test
  files.

closes: #15322

References:
https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.13
https://github.com/fleiner/vim/pull/1

Co-authored-by: D-Cysteine <54219287+D-Cysteine@users.noreply.github.com>
Signed-off-by: Aliaksei Budavei <0x000c70@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Aliaksei Budavei
2024-07-24 20:15:15 +02:00
committed by Christian Brabandt
parent df77c8ad39
commit e73e5b889b
41 changed files with 855 additions and 37 deletions

View File

@ -39,7 +39,7 @@ class FoldingTests {
break;
}
default: ;
};
}
}
{ Object bb = ((Object) new byte[]{}); }

View File

@ -136,7 +136,7 @@ class LambdaExpressionsTests // JDK 21+.
case String str_ -> str_;
}): { echo(str); break; }
case null: default: { echo("Other"); }
};
}
echo(switch (null) {
case String str when !"<empty>".equals(

View File

@ -136,7 +136,7 @@ class LambdaExpressions$Tests // JDK 21+.
case String str_ -> str_;
}): { echo(str); break; }
case null: default: { echo("Other"); }
};
}
echo(switch (null) {
case String str when !"<empty>".equals(

View File

@ -0,0 +1,186 @@
// VIM_TEST_SETUP let g:java_highlight_functions = 'style'
// VIM_TEST_SETUP let g:java_highlight_generics = 1
import java.lang.invoke.MethodHandle;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.IntSupplier;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
import java.util.function.UnaryOperator;
class MethodReferencesTests
{
static {
// Primary :: [TypeArguments] Identifier
try {
Runnable r1 = ((Runtime) null)::gc;
} catch (NullPointerException expected) {
}
Supplier<Integer> s1 = ((Number) 0)::hashCode;
Supplier<Integer> s2 = ((Comparable<?>) '\0')::hashCode;
Supplier<Integer> s3 = ((Comparable<?>) false)::hashCode;
Supplier<Integer> s4 = "::"::hashCode;
Supplier<Class<?>> s5 = int[].class::arrayType;
Supplier<Integer> s6 = new MethodReferencesTests() ::
hashCode;
Supplier<Integer> s7 = ((Number)
(new MethodReferencesTests().xy)[0])::intValue;
Supplier<int[]> s8 = new MethodReferencesTests().xy::
clone;
Consumer<Object> c1 = System.out :: println;
Supplier<byte[]> s9 = ((Supplier<String>) ()->"()").get()
::getBytes;
Supplier<String> sa = ((Supplier<String>)
((Supplier<String>) ((Supplier<String>)
((Supplier<String>) ((Supplier<String>)
() -> "() -> ()")
::toString)
::toString)
::get)
::toString)
::toString;
// ExpressionName :: [TypeArguments] Identifier
// ReferenceType :: [TypeArguments] Identifier
Function<String, IntSupplier> f1 = s ->
s :: length;
Function<int[][], Supplier<int[]>> f2 = ii ->
((int[]) (ii.length > 0 ? ii[0] : ii))
:: clone;
UnaryOperator<String> uo1 = String::valueOf;
ToIntFunction<String> tif1 = s -> s.transform(
String :: length);
// ClassType :: [TypeArguments] new
// ArrayType :: new
Function<Object, C2> f3 = C2::<Object>new;
Function<C2, C2.C21> f4 = pci -> pci.new
<String>C21(null); // Cf. "d".
Supplier<C1<?>> sb = C1::new;
Function<Byte, C1<?>> f5 = C1<Void> :: <Byte> new;
IntFunction<C1<?>[]> if1 = C1<?>[] :: new;
IntFunction<byte[]> if2 = byte[] :: new;
}
final int[] xy = { 0, 1 };
// super :: [TypeArguments] Identifier
// TypeName . super :: [TypeArguments] Identifier
<T> MethodReferencesTests()
{
Predicate<T> p1 = MethodReferencesTests.super::equals;
Predicate<T> p2 = MethodReferencesTests.this::equals;
}
interface I4<T> extends I3<T>
{
default Predicate<T> superEqualist()
{
return I3
.super::equals; /* "a" */
}
}
interface I3<T> extends I2<T>
{
default Predicate<T> superEqualist()
{
return I2.
super::equals; /* "b" */
}
}
interface I2<T> extends I1<T>
{
default Predicate<T> superEqualist()
{ /* Non-capturing gymnastics for super::equals. */
return Function.<Function<MethodHandle,
Predicate<T>>>
identity()
.apply(mh -> o -> MethodReferencesTests
.invokePredicate(mh, o))
.apply(EQUALS.bindTo(this));
}
}
interface I1<T>
{
default Predicate<T> equalist()
{ /* Non-capturing gymnastics for this::equals. */
return Function.<Function<I1<T>, Predicate<T>>>
identity()
.apply(that -> o -> Function
.<BiPredicate<I1<T>, T>>
identity()
.apply(I1<T>:: /* "c" */
equals)
.test(that, o))
.apply(I1.this);
}
}
static <T> boolean invokePredicate(MethodHandle mh, T o)
{
try {
return (boolean) mh.invokeExact(o);
} catch (Throwable th) {
throw new RuntimeException(th);
}
}
private static final MethodHandle EQUALS;
static {
try {
EQUALS = java.lang.invoke.MethodHandles.lookup()
.findSpecial(
I1.class,
"equals",
java.lang.invoke.MethodType.methodType(
boolean.class,
Object.class),
I2.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
static class C1<T>
{
C1() { }
<A> C1(A dummy) { }
}
static class C2
{
C2() { <String> this(""); }
<A> C2(A dummy)
{
C2.stringer().apply(((Function<C2, C2.C21>)
C2.C21::new) /* "d" */
.apply(C2.this));
}
class C21
{
C21() { <String> this(""); }
<B> C21(B dummy)
{
C2.stringer().apply(C2.this);
}
}
static <T extends Object> Function<T, String> stringer()
{
return T::toString; /* "e" */
}
}
}

View File

@ -0,0 +1,186 @@
// VIM_TEST_SETUP let g:java_highlight_functions = 'style'
// VIM_TEST_SETUP let g:java_highlight_signature = 1
// VIM_TEST_SETUP let g:java_highlight_generics = 1
import java.lang.invoke.MethodHandle;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.IntSupplier;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
import java.util.function.UnaryOperator;
class MethodReferences$Tests
{
static {
// Primary :: [TypeArguments] Identifier
try {
Runnable r1 = ((Runtime) null)::gc;
} catch (NullPointerException expected) {
}
Supplier<Integer> s1 = ((Number) 0)::hashCode;
Supplier<Integer> s2 = ((Comparable<?>) '\0')::hashCode;
Supplier<Integer> s3 = ((Comparable<?>) false)::hashCode;
Supplier<Integer> s4 = "::"::hashCode;
Supplier<Class<?>> s5 = int[].class::arrayType;
Supplier<Integer> s6 = new MethodReferences$Tests() ::
hashCode;
Supplier<Integer> s7 = ((Number)
(new MethodReferences$Tests().xy)[0])::intValue;
Supplier<int[]> s8 = new MethodReferences$Tests().xy::
clone;
Consumer<Object> c1 = System.out :: println;
Supplier<byte[]> s9 = ((Supplier<String>) ()->"()").get()
::getBytes;
Supplier<String> sa = ((Supplier<String>)
((Supplier<String>) ((Supplier<String>)
((Supplier<String>) ((Supplier<String>)
() -> "() -> ()")
::toString)
::toString)
::get)
::toString)
::toString;
// ExpressionName :: [TypeArguments] Identifier
// ReferenceType :: [TypeArguments] Identifier
Function<String, IntSupplier> f1 = s ->
s :: length;
Function<int[][], Supplier<int[]>> f2 = ii ->
((int[]) (ii.length > 0 ? ii[0] : ii))
:: clone;
UnaryOperator<String> uo1 = String::valueOf;
ToIntFunction<String> tif1 = s -> s.transform(
String :: length);
// ClassType :: [TypeArguments] new
// ArrayType :: new
Function<Object, C2> f3 = C2::<Object>new;
Function<C2, C2.C21> f4 = pci -> pci.new
<String>C21(null); // Cf. "d".
Supplier<C1<?>> sb = C1::new;
Function<Byte, C1<?>> f5 = C1<Void> :: <Byte> new;
IntFunction<C1<?>[]> if1 = C1<?>[] :: new;
IntFunction<byte[]> if2 = byte[] :: new;
}
final int[] xy = { 0, 1 };
// super :: [TypeArguments] Identifier
// TypeName . super :: [TypeArguments] Identifier
<T> MethodReferences$Tests()
{
Predicate<T> p1 = MethodReferences$Tests.super::equals;
Predicate<T> p2 = MethodReferences$Tests.this::equals;
}
interface I4<T> extends I3<T>
{
default Predicate<T> superEqualist()
{
return I3
.super::equals; /* "a" */
}
}
interface I3<T> extends I2<T>
{
default Predicate<T> superEqualist()
{
return I2.
super::equals; /* "b" */
}
}
interface I2<T> extends I1<T>
{
default Predicate<T> superEqualist()
{ /* Non-capturing gymnastics for super::equals. */
return Function.<Function<MethodHandle,
Predicate<T>>>
identity()
.apply(mh -> o -> MethodReferences$Tests
.invokePredicate(mh, o))
.apply(EQUALS.bindTo(this));
}
}
interface I1<T>
{
default Predicate<T> equalist()
{ /* Non-capturing gymnastics for this::equals. */
return Function.<Function<I1<T>, Predicate<T>>>
identity()
.apply(that -> o -> Function
.<BiPredicate<I1<T>, T>>
identity()
.apply(I1<T>:: /* "c" */
equals)
.test(that, o))
.apply(I1.this);
}
}
static <T> boolean invokePredicate(MethodHandle mh, T o)
{
try {
return (boolean) mh.invokeExact(o);
} catch (Throwable th) {
throw new RuntimeException(th);
}
}
private static final MethodHandle EQUALS;
static {
try {
EQUALS = java.lang.invoke.MethodHandles.lookup()
.findSpecial(
I1.class,
"equals",
java.lang.invoke.MethodType.methodType(
boolean.class,
Object.class),
I2.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
static class C1<T>
{
C1() { }
<A> C1(A dummy) { }
}
static class C2
{
C2() { <String> this(""); }
<A> C2(A dummy)
{
C2.stringer().apply(((Function<C2, C2.C21>)
C2.C21::new) /* "d" */
.apply(C2.this));
}
class C21
{
C21() { <String> this(""); }
<B> C21(B dummy)
{
C2.stringer().apply(C2.this);
}
}
static <T extends Object> Function<T, String> stringer()
{
return T::toString; /* "e" */
}
}
}

View File

@ -55,7 +55,7 @@ class SwitchTests // JDK 21+.
case null: { echo("null"); break; }
case Letters[] ll: { echo("SwitchTests$1Letters[]"); break; }
default: { echo("java.lang.Object"); break; }
};
}
echo(switch (o) {
case null -> "null";
@ -69,7 +69,7 @@ class SwitchTests // JDK 21+.
case 'a': { echo('a'); break; }
case 'b': { echo('b'); break; }
default: { echo('\u0000'); break; }
};
}
echo(switch (ch) {
case 'a' -> 'a';
@ -83,7 +83,7 @@ class SwitchTests // JDK 21+.
case ((byte) 0): { echo((byte) 0); break; }
case ((byte) 1): { echo((byte) 1); break; }
default: { echo((byte) -1); break; }
};
}
echo(switch (b) {
case ((byte) 0) -> (byte) 0;
@ -97,7 +97,7 @@ class SwitchTests // JDK 21+.
case ((short) 0): { echo((short) 0); break; }
case ((short) 1): { echo((short) 1); break; }
default: { echo((short) -1); break; }
};
}
echo(switch (sh) {
case ((short) 0) -> (short) 0;
@ -111,7 +111,7 @@ class SwitchTests // JDK 21+.
case 0b0__00___000: { echo(0); break; }
case 0x000___00__1: { echo(1); break; }
default: { echo(-1); break; }
};
}
echo(switch (i) {
case 0_0_0_0_0 -> 0;

View File

@ -39,7 +39,7 @@ class UnfoldingTests {
break;
}
default: ;
};
}
}
{ Object bb = ((Object) new byte[]{}); }