Java
This page curates a list of example ast-grep rules to check and to rewrite Java code.
No Unused Vars in Java Has Fix
Description
Identifying unused variables is a common task in code refactoring. You should rely on a Java linter or IDE for this task rather than writing a custom rule in ast-grep, but for educational purposes, this rule demonstrates how to find unused variables in Java.
This approach makes some simplifying assumptions. We only consider local variable declarations and ignore the other many ways variables can be declared: Method Parameters, Fields, Class Variables, Constructor Parameters, Loop Variables, Exception Handler Parameters, Lambda Parameters, Annotation Parameters, Enum Constants, and Record Components. Now you may see why it is recommended to use a rule from an established linter or IDE rather than writing your own.
YAML
id: no-unused-vars
rule:
kind: local_variable_declaration
all:
- has:
has:
kind: identifier
pattern: $IDENT
- not:
precedes:
stopBy: end
has:
stopBy: end
any:
- { kind: identifier, pattern: $IDENT }
- { has: {kind: identifier, pattern: $IDENT, stopBy: end}}
fix: ''
First, we identify the local variable declaration and capture the pattern of the identifier inside of it. Then we use not
and precedes
to only match the local variable declaration if the identifier we captured does not appear later in the code.
It is important to note that we use all
here to force the ordering of the has
rule to be before the not
rule. This guarantees that the meta-variable $IDENT
is captured by looking inside of the local variable declaration.
Additionally, when looking ahead in the code, we can't just look for the identifier directly, but for any node that may contain the identifier.
Example
String unused = "unused";
String used = "used";
System.out.println(used);
Find Java field declarations of type String
Description
To extract all Java field names of type String
is not as straightforward as one might think. A simple pattern like String $F;
would only match fields declared without any modifiers or annotations. However, a pattern like $MOD String $F;
cannot be correctly parsed by tree-sitter.
Use playground pattern debugger to explore the AST
You can use the playground's pattern tab to visualize the AST of class A { $MOD String $F; }
.
field_declaration
$MOD
variable_declarator
identifier: String
ERROR
identifier: $F
Tree-sitter does not think $MOD
is a valid modifier, so it produces an ERROR
.
While the valid AST for code like private String field;
produces different AST structures:
field_declaration
modifiers
type_identifier
variable_declarator
identifier: field
A more robust approach is to use a structural rule that targets field_declaration
nodes and applies a has
constraint on the type
child node to match the type String
. This method effectively captures fields regardless of their modifiers or annotations.
YAML
id: find-field-with-type
language: java
rule:
kind: field_declaration
has:
field: type
regex: ^String$
Example
@Component
class ABC extends Object{
@Resource
private final String with_anno;
private final String with_multi_mod;
public String simple;
}
Contributed by
Inspired by the post discussion