0
# AST Processing
1
2
The PMD Java module provides comprehensive Abstract Syntax Tree (AST) processing capabilities with 187+ node types covering all Java language constructs. This includes support for modern Java features like records, pattern matching, sealed classes, and preview features through Java 24.
3
4
## Capabilities
5
6
### Core AST Interface
7
8
The foundation of AST processing is the `JavaNode` interface, which all Java AST nodes implement.
9
10
```java { .api }
11
/**
12
* Root interface for all Nodes of the Java AST
13
*/
14
public interface JavaNode extends JjtreeNode<JavaNode> {
15
/**
16
* Returns the node representing the type declaration this node is found in
17
* @return The enclosing type declaration or null if not inside a type
18
*/
19
ASTTypeDeclaration getEnclosingType();
20
21
/**
22
* Returns the compilation unit this node belongs to
23
*/
24
@NonNull ASTCompilationUnit getRoot();
25
26
/**
27
* Returns the symbol table for the program point represented by this node
28
*/
29
@NonNull JSymbolTable getSymbolTable();
30
31
/**
32
* Returns the type system with which this node was created
33
*/
34
TypeSystem getTypeSystem();
35
}
36
```
37
38
### Abstract Base Node
39
40
All concrete AST nodes extend `AbstractJavaNode` which provides the base implementation.
41
42
```java { .api }
43
/**
44
* Base implementation for all Java AST nodes
45
*/
46
public abstract class AbstractJavaNode implements JavaNode {
47
/**
48
* Accept method for the visitor pattern
49
*/
50
protected abstract <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data);
51
}
52
```
53
54
### Compilation Unit
55
56
The root node of all Java ASTs representing a complete source file.
57
58
```java { .api }
59
/**
60
* The root node of all Java ASTs
61
*/
62
public final class ASTCompilationUnit extends AbstractJavaNode implements RootNode {
63
/**
64
* Returns the package declaration, if there is one
65
*/
66
@Nullable ASTPackageDeclaration getPackageDeclaration();
67
68
/**
69
* Returns the package name of this compilation unit
70
* @return Package name or empty string if no package declaration
71
*/
72
@NonNull String getPackageName();
73
74
/**
75
* Returns the top-level type declarations declared in this compilation unit
76
*/
77
NodeStream<ASTTypeDeclaration> getTypeDeclarations();
78
79
/**
80
* Returns the module declaration, if this is a modular compilation unit
81
*/
82
@Nullable ASTModuleDeclaration getModuleDeclaration();
83
84
/**
85
* Returns comments associated with this compilation unit
86
*/
87
List<JavaComment> getComments();
88
89
/**
90
* Checks if this is a simple compilation unit (Java 22+ preview feature)
91
*/
92
boolean isSimpleCompilationUnit();
93
}
94
```
95
96
## Type Declaration Nodes
97
98
### Class Declarations
99
100
```java { .api }
101
/**
102
* Represents a class declaration
103
*/
104
public final class ASTClassDeclaration extends AbstractTypeDeclaration
105
implements ASTAnyTypeDeclaration, ModifierOwner, Annotatable {
106
107
/**
108
* Returns the simple name of this class
109
*/
110
@NonNull String getSimpleName();
111
112
/**
113
* Returns the superclass type, or null if this extends Object implicitly
114
*/
115
@Nullable ASTClassType getSuperClassTypeNode();
116
117
/**
118
* Returns the implemented interfaces
119
*/
120
NodeStream<ASTClassType> getSuperInterfaceTypeNodes();
121
122
/**
123
* Returns the type parameters of this class
124
*/
125
@Nullable ASTTypeParameters getTypeParameters();
126
127
/**
128
* Returns the body of this class containing field and method declarations
129
*/
130
ASTClassBody getBody();
131
132
/**
133
* Returns the class symbol for symbol resolution
134
*/
135
JClassSymbol getSymbol();
136
137
/**
138
* Checks if this is a local class (defined within a method or initializer)
139
*/
140
boolean isLocal();
141
142
/**
143
* Checks if this is a nested class (not top-level)
144
*/
145
boolean isNested();
146
}
147
```
148
149
### Interface Declarations
150
151
```java { .api }
152
/**
153
* Represents an interface declaration
154
*/
155
public final class ASTInterfaceDeclaration extends AbstractTypeDeclaration
156
implements ASTAnyTypeDeclaration, ModifierOwner, Annotatable {
157
158
/**
159
* Returns the simple name of this interface
160
*/
161
@NonNull String getSimpleName();
162
163
/**
164
* Returns the extended interfaces
165
*/
166
NodeStream<ASTClassType> getSuperInterfaceTypeNodes();
167
168
/**
169
* Returns the type parameters of this interface
170
*/
171
@Nullable ASTTypeParameters getTypeParameters();
172
173
/**
174
* Returns the body of this interface
175
*/
176
ASTInterfaceBody getBody();
177
178
/**
179
* Returns the interface symbol
180
*/
181
JClassSymbol getSymbol();
182
}
183
```
184
185
### Record Declarations (Java 14+)
186
187
```java { .api }
188
/**
189
* Represents a record declaration (Java 14+)
190
*/
191
public final class ASTRecordDeclaration extends AbstractTypeDeclaration
192
implements ASTAnyTypeDeclaration, ModifierOwner, Annotatable {
193
194
/**
195
* Returns the simple name of this record
196
*/
197
@NonNull String getSimpleName();
198
199
/**
200
* Returns the record components (parameters)
201
*/
202
ASTRecordComponentList getComponentList();
203
204
/**
205
* Returns the implemented interfaces
206
*/
207
NodeStream<ASTClassType> getSuperInterfaceTypeNodes();
208
209
/**
210
* Returns the type parameters of this record
211
*/
212
@Nullable ASTTypeParameters getTypeParameters();
213
214
/**
215
* Returns the body of this record
216
*/
217
ASTRecordBody getBody();
218
219
/**
220
* Returns the record symbol
221
*/
222
JClassSymbol getSymbol();
223
}
224
```
225
226
### Enum Declarations
227
228
```java { .api }
229
/**
230
* Represents an enum declaration
231
*/
232
public final class ASTEnumDeclaration extends AbstractTypeDeclaration
233
implements ASTAnyTypeDeclaration, ModifierOwner, Annotatable {
234
235
/**
236
* Returns the simple name of this enum
237
*/
238
@NonNull String getSimpleName();
239
240
/**
241
* Returns the implemented interfaces
242
*/
243
NodeStream<ASTClassType> getSuperInterfaceTypeNodes();
244
245
/**
246
* Returns the type parameters (for generic enums - rare)
247
*/
248
@Nullable ASTTypeParameters getTypeParameters();
249
250
/**
251
* Returns the body of this enum
252
*/
253
ASTEnumBody getBody();
254
255
/**
256
* Returns the enum symbol
257
*/
258
JClassSymbol getSymbol();
259
}
260
```
261
262
## Expression Nodes
263
264
### Method Calls
265
266
```java { .api }
267
/**
268
* A method invocation expression (qualified and unqualified)
269
*/
270
public final class ASTMethodCall extends AbstractInvocationExpr
271
implements QualifiableExpression {
272
273
/**
274
* Returns the name of the invoked method
275
*/
276
@NonNull String getMethodName();
277
278
/**
279
* Returns the argument list of this method call
280
*/
281
@NonNull ASTArgumentList getArguments();
282
283
/**
284
* Returns explicit type arguments if present (e.g., obj.<String>method())
285
*/
286
@Nullable ASTTypeArguments getExplicitTypeArguments();
287
288
/**
289
* Returns the qualifier expression (left side of the dot)
290
*/
291
@Nullable ASTExpression getQualifier();
292
293
/**
294
* Returns the resolved method symbol
295
*/
296
JMethodSymbol getMethodType();
297
298
/**
299
* Returns the return type of this method call
300
*/
301
JTypeMirror getTypeMirror();
302
}
303
```
304
305
### Field Access
306
307
```java { .api }
308
/**
309
* A field access expression
310
*/
311
public final class ASTFieldAccess extends AbstractJavaExpr
312
implements QualifiableExpression, AssignmentTarget {
313
314
/**
315
* Returns the name of the accessed field
316
*/
317
@NonNull String getName();
318
319
/**
320
* Returns the qualifier expression (object whose field is accessed)
321
*/
322
@Nullable ASTExpression getQualifier();
323
324
/**
325
* Returns the resolved field symbol
326
*/
327
JFieldSymbol getReferencedSym();
328
329
/**
330
* Returns the type of this field access
331
*/
332
JTypeMirror getTypeMirror();
333
}
334
```
335
336
### Variable Access
337
338
```java { .api }
339
/**
340
* A variable access expression (local variables, parameters)
341
*/
342
public final class ASTVariableAccess extends AbstractJavaExpr
343
implements AssignmentTarget {
344
345
/**
346
* Returns the name of the accessed variable
347
*/
348
@NonNull String getName();
349
350
/**
351
* Returns the resolved variable symbol
352
*/
353
JVariableSymbol getReferencedSym();
354
355
/**
356
* Returns the type of this variable
357
*/
358
JTypeMirror getTypeMirror();
359
}
360
```
361
362
### Lambda Expressions (Java 8+)
363
364
```java { .api }
365
/**
366
* A lambda expression (Java 8+)
367
*/
368
public final class ASTLambdaExpression extends AbstractJavaExpr {
369
/**
370
* Returns the parameter list of this lambda
371
*/
372
ASTLambdaParameterList getParameters();
373
374
/**
375
* Returns the body of this lambda (expression or block)
376
*/
377
JavaNode getBody();
378
379
/**
380
* Checks if the body is a block statement
381
*/
382
boolean isBlockBody();
383
384
/**
385
* Checks if the body is an expression
386
*/
387
boolean isExpressionBody();
388
389
/**
390
* Returns the functional interface type this lambda implements
391
*/
392
JTypeMirror getTypeMirror();
393
}
394
```
395
396
### Literal Expressions
397
398
```java { .api }
399
/**
400
* Base class for all literal expressions
401
*/
402
public abstract class ASTLiteral extends AbstractJavaExpr {
403
/**
404
* Returns the constant value represented by this literal
405
*/
406
Object getConstValue();
407
408
/**
409
* Returns the type of this literal
410
*/
411
JTypeMirror getTypeMirror();
412
}
413
414
/**
415
* A string literal
416
*/
417
public final class ASTStringLiteral extends ASTLiteral {
418
/**
419
* Returns the string value (with escape sequences processed)
420
*/
421
String getConstValue();
422
423
/**
424
* Checks if this is a text block (Java 15+)
425
*/
426
boolean isTextBlock();
427
}
428
429
/**
430
* A numeric literal (integers, floats, etc.)
431
*/
432
public final class ASTNumericLiteral extends ASTLiteral {
433
/**
434
* Returns the numeric value as Number
435
*/
436
Number getConstValue();
437
438
/**
439
* Returns the base of this numeric literal (2, 8, 10, or 16)
440
*/
441
int getBase();
442
443
/**
444
* Checks if this literal has a suffix (L, F, D, etc.)
445
*/
446
boolean hasSuffix();
447
}
448
449
/**
450
* A boolean literal (true/false)
451
*/
452
public final class ASTBooleanLiteral extends ASTLiteral {
453
/**
454
* Returns the boolean value
455
*/
456
boolean isTrue();
457
}
458
```
459
460
## Statement Nodes
461
462
### Control Flow Statements
463
464
```java { .api }
465
/**
466
* An if statement
467
*/
468
public final class ASTIfStatement extends AbstractJavaStatement {
469
/**
470
* Returns the condition expression
471
*/
472
ASTExpression getCondition();
473
474
/**
475
* Returns the then-branch statement
476
*/
477
ASTStatement getThenBranch();
478
479
/**
480
* Returns the else-branch statement, if present
481
*/
482
@Nullable ASTStatement getElseBranch();
483
484
/**
485
* Checks if this if statement has an else clause
486
*/
487
boolean hasElse();
488
}
489
490
/**
491
* A for statement
492
*/
493
public final class ASTForStatement extends AbstractJavaStatement {
494
/**
495
* Returns the init clause (traditional for loop)
496
*/
497
@Nullable ASTForInit getInit();
498
499
/**
500
* Returns the condition expression
501
*/
502
@Nullable ASTExpression getCondition();
503
504
/**
505
* Returns the update clause
506
*/
507
@Nullable ASTForUpdate getUpdate();
508
509
/**
510
* Returns the loop body
511
*/
512
ASTStatement getBody();
513
}
514
515
/**
516
* An enhanced for statement (for-each, Java 5+)
517
*/
518
public final class ASTForeachStatement extends AbstractJavaStatement {
519
/**
520
* Returns the loop variable declaration
521
*/
522
ASTForeachVariable getVariable();
523
524
/**
525
* Returns the iterable expression
526
*/
527
ASTExpression getIterable();
528
529
/**
530
* Returns the loop body
531
*/
532
ASTStatement getBody();
533
}
534
```
535
536
### Switch Statements
537
538
```java { .api }
539
/**
540
* A switch statement with modern pattern matching support
541
*/
542
public final class ASTSwitchStatement extends AbstractJavaStatement {
543
/**
544
* Returns the switch expression (what we're switching on)
545
*/
546
ASTExpression getTestedExpression();
547
548
/**
549
* Returns all switch branches (cases and default)
550
*/
551
NodeStream<ASTSwitchBranch> getBranches();
552
553
/**
554
* Checks if this is a switch expression (returns a value)
555
*/
556
boolean isExpressionSwitch();
557
}
558
559
/**
560
* A switch branch (case or default)
561
*/
562
public abstract class ASTSwitchBranch extends AbstractJavaNode {
563
/**
564
* Returns the statements in this branch
565
*/
566
NodeStream<ASTStatement> getStatements();
567
568
/**
569
* Checks if this branch is a switch arrow branch (->)
570
*/
571
boolean isArrowBranch();
572
}
573
574
/**
575
* A switch labeled rule (case with arrow syntax)
576
*/
577
public final class ASTSwitchArrowBranch extends ASTSwitchBranch {
578
/**
579
* Returns the case labels for this branch
580
*/
581
NodeStream<ASTSwitchLabel> getLabels();
582
583
/**
584
* Returns the right-hand side (expression or statement)
585
*/
586
JavaNode getRightHandSide();
587
}
588
```
589
590
## Type System Nodes
591
592
### Type Nodes
593
594
```java { .api }
595
/**
596
* Base class for all type nodes in the AST
597
*/
598
public abstract class ASTType extends AbstractJavaNode implements Iterable<ASTType> {
599
/**
600
* Returns the type mirror this AST node represents
601
*/
602
JTypeMirror getTypeMirror();
603
}
604
605
/**
606
* A primitive type (int, boolean, etc.)
607
*/
608
public final class ASTPrimitiveType extends ASTType {
609
/**
610
* Returns the kind of primitive type
611
*/
612
JPrimitiveType.PrimitiveTypeKind getKind();
613
}
614
615
/**
616
* A class or interface type (possibly generic)
617
*/
618
public final class ASTClassType extends ASTType {
619
/**
620
* Returns the simple name of this type
621
*/
622
@NonNull String getSimpleName();
623
624
/**
625
* Returns the type arguments if this is a parameterized type
626
*/
627
@Nullable ASTTypeArguments getTypeArguments();
628
629
/**
630
* Returns the qualifier if this is a qualified type name
631
*/
632
@Nullable ASTClassType getQualifier();
633
634
/**
635
* Returns the resolved type symbol
636
*/
637
JClassSymbol getReferencedSym();
638
}
639
640
/**
641
* An array type
642
*/
643
public final class ASTArrayType extends ASTType {
644
/**
645
* Returns the element type of this array
646
*/
647
ASTType getElementType();
648
649
/**
650
* Returns the array dimensions
651
*/
652
ASTArrayDimensions getDimensions();
653
654
/**
655
* Returns the number of dimensions
656
*/
657
int getArrayDepth();
658
}
659
```
660
661
## Visitor Pattern
662
663
### Base Visitor
664
665
```java { .api }
666
/**
667
* Base visitor implementation for traversing Java ASTs
668
*/
669
public abstract class JavaVisitorBase<P, R> implements JavaVisitor<P, R> {
670
// Visit methods for all AST node types (187+ methods)
671
672
// Compilation unit and top-level declarations
673
public R visit(ASTCompilationUnit node, P data);
674
public R visit(ASTPackageDeclaration node, P data);
675
public R visit(ASTImportDeclaration node, P data);
676
677
// Type declarations
678
public R visit(ASTClassDeclaration node, P data);
679
public R visit(ASTInterfaceDeclaration node, P data);
680
public R visit(ASTEnumDeclaration node, P data);
681
public R visit(ASTRecordDeclaration node, P data);
682
public R visit(ASTAnnotationTypeDeclaration node, P data);
683
684
// Method and field declarations
685
public R visit(ASTMethodDeclaration node, P data);
686
public R visit(ASTConstructorDeclaration node, P data);
687
public R visit(ASTFieldDeclaration node, P data);
688
689
// Expressions (30+ visit methods)
690
public R visit(ASTMethodCall node, P data);
691
public R visit(ASTFieldAccess node, P data);
692
public R visit(ASTVariableAccess node, P data);
693
public R visit(ASTLambdaExpression node, P data);
694
public R visit(ASTMethodReference node, P data);
695
696
// Literals
697
public R visit(ASTStringLiteral node, P data);
698
public R visit(ASTNumericLiteral node, P data);
699
public R visit(ASTBooleanLiteral node, P data);
700
public R visit(ASTNullLiteral node, P data);
701
702
// Statements (25+ visit methods)
703
public R visit(ASTIfStatement node, P data);
704
public R visit(ASTForStatement node, P data);
705
public R visit(ASTForeachStatement node, P data);
706
public R visit(ASTWhileStatement node, P data);
707
public R visit(ASTSwitchStatement node, P data);
708
public R visit(ASTTryStatement node, P data);
709
710
// Type nodes
711
public R visit(ASTPrimitiveType node, P data);
712
public R visit(ASTClassType node, P data);
713
public R visit(ASTArrayType node, P data);
714
public R visit(ASTWildcardType node, P data);
715
716
// Pattern nodes (Java 14+)
717
public R visit(ASTTypePattern node, P data);
718
public R visit(ASTRecordPattern node, P data);
719
720
// Default delegation method
721
protected R visitJavaNode(JavaNode node, P data);
722
}
723
```
724
725
**Usage Examples:**
726
727
```java
728
// Example visitor to find all method calls
729
public class MethodCallVisitor extends JavaVisitorBase<Void, Void> {
730
private List<String> methodNames = new ArrayList<>();
731
732
@Override
733
public Void visit(ASTMethodCall node, Void data) {
734
methodNames.add(node.getMethodName());
735
return super.visit(node, data); // Continue traversing children
736
}
737
738
public List<String> getMethodNames() {
739
return methodNames;
740
}
741
}
742
743
// Example visitor to calculate complexity
744
public class ComplexityVisitor extends JavaVisitorBase<Void, Integer> {
745
@Override
746
public Integer visit(ASTIfStatement node, Void data) {
747
int complexity = 1; // Base complexity for if
748
if (node.hasElse()) {
749
complexity += 1; // Additional for else
750
}
751
return complexity + super.visit(node, data);
752
}
753
754
@Override
755
public Integer visit(ASTForStatement node, Void data) {
756
return 1 + super.visit(node, data); // Add 1 for loop
757
}
758
759
@Override
760
protected Integer visitJavaNode(JavaNode node, Void data) {
761
int total = 0;
762
for (JavaNode child : node.children()) {
763
Integer childComplexity = child.acceptVisitor(this, data);
764
if (childComplexity != null) {
765
total += childComplexity;
766
}
767
}
768
return total;
769
}
770
}
771
```
772
773
## Common Interfaces
774
775
### Modifier Support
776
777
```java { .api }
778
/**
779
* Interface for nodes that can have modifiers
780
*/
781
public interface ModifierOwner {
782
/**
783
* Returns the modifier list
784
*/
785
ASTModifierList getModifiers();
786
787
/**
788
* Returns the visibility of this declaration
789
*/
790
Visibility getVisibility();
791
792
/**
793
* Returns the effective visibility (considering enclosing scopes)
794
*/
795
Visibility getEffectiveVisibility();
796
797
/**
798
* Checks if this declaration has the specified modifiers
799
*/
800
boolean hasModifiers(JModifier... modifiers);
801
802
/**
803
* Checks if this declaration has explicit (written) modifiers
804
*/
805
boolean hasExplicitModifiers(JModifier... modifiers);
806
}
807
```
808
809
### Annotation Support
810
811
```java { .api }
812
/**
813
* Interface for nodes that can be annotated
814
*/
815
public interface Annotatable {
816
/**
817
* Returns all declared annotations on this element
818
*/
819
NodeStream<ASTAnnotation> getDeclaredAnnotations();
820
821
/**
822
* Checks if an annotation is present by binary name
823
*/
824
boolean isAnnotationPresent(String binaryName);
825
826
/**
827
* Checks if an annotation is present by class
828
*/
829
boolean isAnnotationPresent(Class<? extends java.lang.annotation.Annotation> clazz);
830
831
/**
832
* Returns a specific annotation by binary name
833
*/
834
@Nullable ASTAnnotation getAnnotation(String binaryName);
835
836
/**
837
* Returns a specific annotation by class
838
*/
839
@Nullable ASTAnnotation getAnnotation(Class<? extends java.lang.annotation.Annotation> clazz);
840
}
841
```