Problem
Modifying the spacing around colons in Kotlin type references (e.g., val x : String, fun foo() : Int) is inconsistent and difficult for recipe authors.
Inconsistent Storage Locations
The space before the colon is stored in different places depending on context:
| Context |
Space stored in |
| Method return types |
TypeReferencePrefix.prefix marker on J.MethodDeclaration |
| Variable declarations |
JRightPadded.after of variables + TypeReferencePrefix.prefix marker |
| Function type parameters |
TypeReferencePrefix.prefix marker on the parameter |
| Type parameter bounds |
JContainer.before (marker prefix is EMPTY!) |
Awkward Recipe API
To modify spacing around colons, recipes must:
- Override
visitMarker() and check for TypeReferencePrefix
- Use
ListUtils.map to iterate through markers
- Know which location stores the space for each specific context
- Handle both the marker AND other LST element spaces depending on context
There's no dedicated visitor method like visitTypeReference() that would make this discoverable and consistent.
Example: Normalizing Spacing
To normalize val x : String to val x : String, a recipe needs:
@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations vd, ExecutionContext ctx) {
J.VariableDeclarations v = super.visitVariableDeclarations(vd, ctx);
// Modify the marker if present
Markers modifiedMarkers = v.getMarkers().withMarkers(
ListUtils.map(v.getMarkers().getMarkers(), marker -> {
if (marker instanceof TypeReferencePrefix) {
return ((TypeReferencePrefix) marker).withPrefix(Space.SINGLE_SPACE);
}
return marker;
})
);
v = v.withMarkers(modifiedMarkers);
// Also need to modify the space after the variable name
v = v.getPadding().withVariables(
ListUtils.map(v.getPadding().getVariables(), rpv ->
rpv.withAfter(Space.SINGLE_SPACE)));
// And the space after colon
if (v.getTypeExpression() != null) {
v = v.withTypeExpression(v.getTypeExpression().withPrefix(Space.SINGLE_SPACE));
}
return v;
}
This is significantly more complex than it should be.
Affected Contexts
The TypeReferencePrefix marker is used in:
- Function type parameters with names:
(name: Type)
- Method return types:
fun foo(): Type
- Variable declarations:
val x: Type
- Type parameters with bounds:
<T: Bound>
- Type constraints:
where T: Comparable<T>
Proposed Solution
Add a K.TypeReference LST element that would:
- Encapsulate the prefix space (before the colon)
- Contain the type tree (with space after colon in its prefix)
- Provide a dedicated
visitTypeReference() method
This would require changes to the parser, printer, visitor, and RPC serialization.
References
Problem
Modifying the spacing around colons in Kotlin type references (e.g.,
val x : String,fun foo() : Int) is inconsistent and difficult for recipe authors.Inconsistent Storage Locations
The space before the colon is stored in different places depending on context:
TypeReferencePrefix.prefixmarker onJ.MethodDeclarationJRightPadded.afterof variables +TypeReferencePrefix.prefixmarkerTypeReferencePrefix.prefixmarker on the parameterJContainer.before(marker prefix is EMPTY!)Awkward Recipe API
To modify spacing around colons, recipes must:
visitMarker()and check forTypeReferencePrefixListUtils.mapto iterate through markersThere's no dedicated visitor method like
visitTypeReference()that would make this discoverable and consistent.Example: Normalizing Spacing
To normalize
val x : Stringtoval x : String, a recipe needs:This is significantly more complex than it should be.
Affected Contexts
The
TypeReferencePrefixmarker is used in:(name: Type)fun foo(): Typeval x: Type<T: Bound>where T: Comparable<T>Proposed Solution
Add a
K.TypeReferenceLST element that would:visitTypeReference()methodThis would require changes to the parser, printer, visitor, and RPC serialization.
References
TypeReferencePrefixTest.java