|
1 | 1 | # Java 17 sealed types (JEP 409): sealed interface with a permits clause and its |
2 | 2 | # permitted classes (final, non-sealed). |
3 | 3 | # |
4 | | -# Known gap: the indexer does not extract the `permits` clause itself |
5 | | -# (no handling of the tree-sitter `permits_clause` node in |
6 | | -# crates/code-graph/src/v2/langs/generic/java.rs). The Extends edges asserted |
7 | | -# below come from each permitted class's `implements Shape` clause, not from |
8 | | -# `permits`. A sealed type whose permitted subtypes carry no resolvable |
9 | | -# extends/implements clause would produce no permits-derived edges. |
| 4 | +# How `permits` is represented (#847): the clause is not extracted into |
| 5 | +# metadata and produces no semantic Extends edge — in valid Java every |
| 6 | +# permitted subtype carries its own extends/implements clause (JLS 8.1.1.2), |
| 7 | +# which is where the Extends edges asserted below come from. The permitted |
| 8 | +# type names in the clause (a `permits` field on class/interface_declaration |
| 9 | +# holding a `type_list`) are picked up by the bare `reference("type_identifier")` |
| 10 | +# rule and attributed to the sealed parent, so the parent->child relationship |
| 11 | +# stays reachable as a Calls edge even when the child file is missing or |
| 12 | +# malformed. The Quad/Square fixtures below pin that fallback. |
10 | 13 | name: "Java 17: sealed interfaces and permitted classes" |
11 | 14 | fixtures: |
12 | 15 | - path: com/example/shapes/Shape.java |
@@ -48,6 +51,27 @@ fixtures: |
48 | 51 | public double area() { return 0; } |
49 | 52 | } |
50 | 53 |
|
| 54 | + # Malformed pair: Square does not declare `implements Quad` (illegal Java, |
| 55 | + # but indexable), so the parent-side `permits` clause is the only place the |
| 56 | + # relationship is stated. |
| 57 | + - path: com/example/shapes/Quad.java |
| 58 | + content: | |
| 59 | + package com.example.shapes; |
| 60 | +
|
| 61 | + public sealed interface Quad permits Square { |
| 62 | + double perimeter(); |
| 63 | + } |
| 64 | +
|
| 65 | + - path: com/example/shapes/Square.java |
| 66 | + content: | |
| 67 | + package com.example.shapes; |
| 68 | +
|
| 69 | + public final class Square { |
| 70 | + private final double side; |
| 71 | + public Square(double side) { this.side = side; } |
| 72 | + public double perimeter() { return 4 * side; } |
| 73 | + } |
| 74 | +
|
51 | 75 | tests: |
52 | 76 | - name: "Sealed interface Shape is extracted as an Interface definition" |
53 | 77 | query: | |
@@ -86,3 +110,41 @@ tests: |
86 | 110 | - { row: { child: "com.example.shapes.Circle", parent: "com.example.shapes.Shape", kind: Extends } } |
87 | 111 | - { row: { child: "com.example.shapes.Rectangle", parent: "com.example.shapes.Shape", kind: Extends } } |
88 | 112 | - { row: { child: "com.example.shapes.Triangle", parent: "com.example.shapes.Shape", kind: Extends } } |
| 113 | + |
| 114 | + - name: "Permits-side references link the sealed parent to each permitted class" |
| 115 | + query: | |
| 116 | + MATCH (parent:Definition)-[e:DefinitionToDefinition]->(child:Definition) |
| 117 | + WHERE parent.fqn = 'com.example.shapes.Shape' |
| 118 | + AND e.edge_kind = 'Calls' |
| 119 | + AND child.fqn IN [ |
| 120 | + 'com.example.shapes.Circle', |
| 121 | + 'com.example.shapes.Rectangle', |
| 122 | + 'com.example.shapes.Triangle' |
| 123 | + ] |
| 124 | + RETURN child.fqn AS child |
| 125 | + assert: |
| 126 | + - { row_count: 3 } |
| 127 | + - { row: { child: "com.example.shapes.Circle" } } |
| 128 | + - { row: { child: "com.example.shapes.Rectangle" } } |
| 129 | + - { row: { child: "com.example.shapes.Triangle" } } |
| 130 | + |
| 131 | + - name: "Malformed child: no Extends edge exists between Square and Quad" |
| 132 | + query: | |
| 133 | + MATCH (child:Definition)-[e:DefinitionToDefinition]->(parent:Definition) |
| 134 | + WHERE child.fqn = 'com.example.shapes.Square' |
| 135 | + AND parent.fqn = 'com.example.shapes.Quad' |
| 136 | + AND e.edge_kind = 'Extends' |
| 137 | + RETURN child.fqn AS child |
| 138 | + assert: |
| 139 | + - { empty: true } |
| 140 | + |
| 141 | + - name: "Malformed child: the permits-side reference is the only remaining link" |
| 142 | + query: | |
| 143 | + MATCH (parent:Definition)-[e:DefinitionToDefinition]->(child:Definition) |
| 144 | + WHERE parent.fqn = 'com.example.shapes.Quad' |
| 145 | + AND child.fqn = 'com.example.shapes.Square' |
| 146 | + AND e.edge_kind = 'Calls' |
| 147 | + RETURN child.fqn AS child |
| 148 | + assert: |
| 149 | + - { row_count: 1 } |
| 150 | + - { row: { child: "com.example.shapes.Square" } } |
0 commit comments