This is an automated email from the ASF dual-hosted git repository.
paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 538f618b3d GROOVY-12161: pin catch-variable debug metadata for
try/catch without finally
538f618b3d is described below
commit 538f618b3d817f1bb0e1035646e94e64c4d81144
Author: Paul King <[email protected]>
AuthorDate: Thu Jul 16 16:14:21 2026 +1000
GROOVY-12161: pin catch-variable debug metadata for try/catch without
finally
Backfills the LocalVariableTable coverage relaxed in GROOVY-11362 when the
identity catch-all was omitted: assert the catch parameter stays named,
typed Exception (not Object), with a non-degenerate range — without
depending on brittle label numbers.
---
src/test/groovy/bugs/Groovy12161.groovy | 36 +++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/src/test/groovy/bugs/Groovy12161.groovy
b/src/test/groovy/bugs/Groovy12161.groovy
index f91120f578..15d6948888 100644
--- a/src/test/groovy/bugs/Groovy12161.groovy
+++ b/src/test/groovy/bugs/Groovy12161.groovy
@@ -248,6 +248,29 @@ final class Groovy12161 extends AbstractBytecodeTestCase {
''') == 'check call count: 1'
}
+ @Test
+ void testCatchVariableKeepsNamedTypedValidRangeWithoutFinally() {
+ // The plain try/catch path omits the identity catch-all, but the
user's catch
+ // parameter must remain a properly named, correctly typed local with
a non-degenerate
+ // LocalVariableTable range. GROOVY-11362 had to stop asserting this
once label numbers
+ // became unstable; pin it here without depending on brittle label
numbers.
+ compile method: 'm', '''
+ int m(int x) {
+ try {
+ return x
+ } catch (Exception e) {
+ return -1
+ }
+ }
+ '''
+
+ def locals = localVariables('m')
+ def e = locals.find { it.name == 'e' }
+ assert e != null: "catch variable 'e' missing from LocalVariableTable:
${locals*.name}"
+ assert e.desc == 'Ljava/lang/Exception;' // not Ljava/lang/Object;
+ assert e.start < e.end: "degenerate LVT range for 'e': [${e.start},
${e.end})"
+ }
+
//--------------------------------------------------------------------------
private List<TryCatchBlockNode> tryCatchBlocks(final String methodName) {
@@ -278,4 +301,17 @@ final class Groovy12161 extends AbstractBytecodeTestCase {
token.startsWith('FRAME') ? 'FRAME' : token
}
}
+
+ /** LocalVariableTable entries as name/desc plus instruction-index
start/end (valid iff start < end). */
+ private List<Map> localVariables(final String methodName) {
+ assert classBytes != null: 'compile(...) first'
+ def cn = new ClassNode()
+ new ClassReader(classBytes).accept(cn, 0) // keep debug attributes
(unlike tryCatchBlocks)
+ MethodNode mn = cn.methods.find { it.name == methodName }
+ assert mn != null: "method ${methodName} not found"
+ def insns = mn.instructions
+ (mn.localVariables ?: []).collect { lv ->
+ [name: lv.name, desc: lv.desc, start: insns.indexOf(lv.start),
end: insns.indexOf(lv.end)]
+ }
+ }
}