Skip to content

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

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

java
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

yaml
id: find-field-with-type
language: java
rule:
  kind: field_declaration
  has:
    field: type
    regex: ^String$

Example

java
@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

Made with ❤️ with Rust