From 0a092ff8b7792089de958ff59bae424f75dd0281 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Sat, 17 Oct 2026 15:53:39 +0100 Subject: [PATCH 1/2] Fix last object parameter type boundary --- .../instrument/classmatch/MethodOutline.java | 3 ++ .../classmatch/MethodOutlineTest.java | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 class-match/src/test/java/datadog/instrument/classmatch/MethodOutlineTest.java diff --git a/class-match/src/main/java/datadog/instrument/classmatch/MethodOutline.java b/class-match/src/main/java/datadog/instrument/classmatch/MethodOutline.java index f00a10b..cebeeff 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/MethodOutline.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/MethodOutline.java @@ -73,6 +73,9 @@ TypeString parameterTypeString(int paramIndex) { return null; // don't create type-strings for primitive/array types } int end = boundaries[paramIndex] - 1; + if (paramIndex == boundaries.length - 1) { + end--; // move back past ')' to get the end of the last param type + } return new TypeString(descriptor, start, end, getHash(paramIndex, start, end)); } diff --git a/class-match/src/test/java/datadog/instrument/classmatch/MethodOutlineTest.java b/class-match/src/test/java/datadog/instrument/classmatch/MethodOutlineTest.java new file mode 100644 index 0000000..9e8718b --- /dev/null +++ b/class-match/src/test/java/datadog/instrument/classmatch/MethodOutlineTest.java @@ -0,0 +1,30 @@ +package datadog.instrument.classmatch; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class MethodOutlineTest { + @ParameterizedTest + @ValueSource(strings = {"(LA;)V", "(ILA;)V", "(LA;LA;)V"}) + void lastObjectParameterExcludesDescriptorDelimiters(String descriptor) { + MethodOutline method = new MethodOutline(0, "example", descriptor, new String[0]); + int index = method.parameterCount() - 1; + + TypeString type = method.parameterTypeString(index); + assertEquals("A", type.toString()); + assertEquals("A".hashCode(), type.hashCode()); + assertTrue(MethodMatcher.method().parameter(index, TypeMatcher.type("A")).test(method)); + } + + @ParameterizedTest + @ValueSource(strings = {"(LA;I)V", "(LA;LA;)V"}) + void earlierObjectParameterExcludesDescriptorDelimiters(String descriptor) { + MethodOutline method = new MethodOutline(0, "example", descriptor, new String[0]); + + assertEquals("A", method.parameterTypeString(0).toString()); + assertTrue(MethodMatcher.method().parameter(0, TypeMatcher.type("A")).test(method)); + } +} From 12e79b18638cd4e5bc37dd36d5ec3b46f990e12e Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Sat, 17 Oct 2026 15:53:51 +0100 Subject: [PATCH 2/2] Keep type prefix and suffix matches within descriptor windows --- .../instrument/classmatch/TypeString.java | 5 +-- .../instrument/classmatch/TypeStringTest.java | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 class-match/src/test/java/datadog/instrument/classmatch/TypeStringTest.java diff --git a/class-match/src/main/java/datadog/instrument/classmatch/TypeString.java b/class-match/src/main/java/datadog/instrument/classmatch/TypeString.java index 4353399..c0395a1 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/TypeString.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/TypeString.java @@ -96,7 +96,7 @@ public String toString() { static boolean startsWith(CharSequence cs, String prefix) { if (cs instanceof TypeString) { TypeString ts = (TypeString) cs; - return ts.descriptor.startsWith(prefix, ts.offset); + return prefix.length() <= ts.len && ts.descriptor.startsWith(prefix, ts.offset); } else { return cs.toString().startsWith(prefix); } @@ -106,7 +106,8 @@ static boolean startsWith(CharSequence cs, String prefix) { static boolean endsWith(CharSequence cs, String suffix) { if (cs instanceof TypeString) { TypeString ts = (TypeString) cs; - return ts.descriptor.startsWith(suffix, (ts.offset + ts.len) - suffix.length()); + return suffix.length() <= ts.len + && ts.descriptor.startsWith(suffix, (ts.offset + ts.len) - suffix.length()); } else { return cs.toString().endsWith(suffix); } diff --git a/class-match/src/test/java/datadog/instrument/classmatch/TypeStringTest.java b/class-match/src/test/java/datadog/instrument/classmatch/TypeStringTest.java new file mode 100644 index 0000000..bccfa1e --- /dev/null +++ b/class-match/src/test/java/datadog/instrument/classmatch/TypeStringTest.java @@ -0,0 +1,32 @@ +package datadog.instrument.classmatch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class TypeStringTest { + @ParameterizedTest + @MethodSource("typeStrings") + void prefixAndSuffixMatchingStayWithinTypeString(TypeString type) { + String name = type.toString(); + for (String candidate : new String[] {"", "A", "L", "LA", "A;", "A;I", "()LA", "Longer"}) { + assertEquals( + name.startsWith(candidate), + TypeMatcher.typeStartsWith(candidate).test(type), + "prefix: " + candidate); + assertEquals( + name.endsWith(candidate), + TypeMatcher.typeEndsWith(candidate).test(type), + "suffix: " + candidate); + } + } + + static Stream typeStrings() { + return Stream.of( + new FieldOutline(0, "example", "LA;").typeString(), + new MethodOutline(0, "example", "(LA;I)V", new String[0]).parameterTypeString(0), + new MethodOutline(0, "example", "()LA;", new String[0]).returnTypeString()); + } +}