0
# Language Support
1
2
PMD Java provides comprehensive language processing capabilities as the core Java language module within the PMD framework. It supports Java versions from 1.3 through Java 24 (including preview features), with sophisticated parsing, lexical analysis, copy-paste detection, and Javadoc processing.
3
4
## Capabilities
5
6
### Language Module
7
8
The `JavaLanguageModule` serves as the main entry point and integration layer with the PMD framework.
9
10
```java { .api }
11
/**
12
* Java language module for the PMD framework
13
*/
14
public class JavaLanguageModule extends LanguageModuleBase
15
implements PmdCapableLanguage, CpdCapableLanguage {
16
17
/**
18
* Returns the singleton instance of the Java language module
19
*/
20
public static JavaLanguageModule getInstance();
21
22
/**
23
* Returns the Language instance for Java
24
*/
25
@Override
26
public Language getLanguage();
27
28
/**
29
* Creates a new property bundle for configuring Java analysis
30
*/
31
@Override
32
public LanguagePropertyBundle newPropertyBundle();
33
34
/**
35
* Creates a language processor for parsing and rule execution
36
*/
37
@Override
38
public LanguageProcessor createProcessor(LanguagePropertyBundle bundle);
39
40
/**
41
* Creates a CPD lexer for copy-paste detection
42
*/
43
@Override
44
public CpdLexer createCpdLexer(LanguagePropertyBundle bundle);
45
46
/**
47
* Returns the default file extensions for Java files
48
*/
49
@Override
50
public List<String> getExtensions();
51
}
52
```
53
54
### Language Properties
55
56
```java { .api }
57
/**
58
* Configuration properties for Java language processing
59
*/
60
public interface LanguagePropertyBundle {
61
/**
62
* Gets the language version to use for parsing
63
*/
64
LanguageVersion getLanguageVersion();
65
66
/**
67
* Sets the language version
68
*/
69
void setLanguageVersion(LanguageVersion version);
70
71
/**
72
* Gets a property value by descriptor
73
*/
74
<T> T getProperty(PropertyDescriptor<T> descriptor);
75
76
/**
77
* Sets a property value
78
*/
79
<T> void setProperty(PropertyDescriptor<T> descriptor, T value);
80
81
/**
82
* Returns true if the property is defined
83
*/
84
boolean isPropertyDefined(PropertyDescriptor<?> descriptor);
85
}
86
```
87
88
### Java Language Versions
89
90
```java { .api }
91
/**
92
* Supported Java language versions
93
*/
94
public class JavaLanguageModule extends LanguageModuleBase {
95
96
// Static version constants for all supported Java versions
97
public static final LanguageVersion JAVA_1_3;
98
public static final LanguageVersion JAVA_1_4;
99
public static final LanguageVersion JAVA_1_5; // Java 5 (generics, annotations)
100
public static final LanguageVersion JAVA_1_6; // Java 6
101
public static final LanguageVersion JAVA_1_7; // Java 7 (diamond operator, multi-catch)
102
public static final LanguageVersion JAVA_1_8; // Java 8 (lambdas, streams, default methods)
103
public static final LanguageVersion JAVA_9; // Java 9 (modules, private interface methods)
104
public static final LanguageVersion JAVA_10; // Java 10 (var keyword)
105
public static final LanguageVersion JAVA_11; // Java 11 (LTS)
106
public static final LanguageVersion JAVA_12; // Java 12 (switch expressions preview)
107
public static final LanguageVersion JAVA_13; // Java 13 (text blocks preview)
108
public static final LanguageVersion JAVA_14; // Java 14 (records preview, pattern matching)
109
public static final LanguageVersion JAVA_15; // Java 15 (text blocks, sealed classes preview)
110
public static final LanguageVersion JAVA_16; // Java 16 (records, pattern matching)
111
public static final LanguageVersion JAVA_17; // Java 17 (LTS, sealed classes)
112
public static final LanguageVersion JAVA_18; // Java 18 (UTF-8 by default)
113
public static final LanguageVersion JAVA_19; // Java 19 (virtual threads preview)
114
public static final LanguageVersion JAVA_20; // Java 20 (scoped values preview)
115
public static final LanguageVersion JAVA_21; // Java 21 (LTS, virtual threads, pattern matching)
116
public static final LanguageVersion JAVA_22; // Java 22 (unnamed patterns, string templates preview)
117
public static final LanguageVersion JAVA_23; // Java 23 (primitive types in patterns preview)
118
public static final LanguageVersion JAVA_24; // Java 24 (latest supported)
119
120
/**
121
* Returns the default Java version (latest stable LTS)
122
*/
123
@Override
124
public LanguageVersion getDefaultVersion();
125
126
/**
127
* Returns all supported language versions
128
*/
129
@Override
130
public List<LanguageVersion> getVersions();
131
}
132
```
133
134
## Parser and Lexer Creation
135
136
### Language Processor
137
138
```java { .api }
139
/**
140
* Main language processor for Java source code analysis
141
*/
142
public class JavaLanguageProcessor implements LanguageProcessor {
143
144
/**
145
* Processes a source file through the complete analysis pipeline
146
*/
147
@Override
148
public void processSource(TextFile sourceFile, RuleSet ruleSet, RuleContext ruleContext);
149
150
/**
151
* Creates analysis services (symbol resolution, type system, etc.)
152
*/
153
@Override
154
public AnalysisServices services();
155
156
/**
157
* Returns the language version being used
158
*/
159
public LanguageVersion getLanguageVersion();
160
}
161
162
/**
163
* Services provided during language processing
164
*/
165
public interface AnalysisServices {
166
/**
167
* Gets the symbol resolver for cross-reference analysis
168
*/
169
SymbolResolver getSymbolResolver();
170
171
/**
172
* Gets the type resolver for type analysis
173
*/
174
TypeResolver getTypeResolver();
175
176
/**
177
* Gets the complete semantic model
178
*/
179
SemanticModel getSemanticModel();
180
181
/**
182
* Gets the parser for creating ASTs
183
*/
184
Parser getParser();
185
}
186
```
187
188
### Parser Interface
189
190
```java { .api }
191
/**
192
* Java parser for creating Abstract Syntax Trees
193
*/
194
public interface Parser {
195
/**
196
* Parses source text into an AST
197
*/
198
ASTCompilationUnit parse(String sourceText, TextFile textFile);
199
200
/**
201
* Parses source text with custom parsing options
202
*/
203
ASTCompilationUnit parse(String sourceText, TextFile textFile, ParserOptions options);
204
205
/**
206
* Returns the language version used by this parser
207
*/
208
LanguageVersion getLanguageVersion();
209
}
210
211
/**
212
* Options for configuring parsing behavior
213
*/
214
public interface ParserOptions {
215
/**
216
* Whether to skip parsing errors and continue
217
*/
218
boolean isRecoverFromErrors();
219
220
/**
221
* Whether to suppress parser warnings
222
*/
223
boolean isSuppressWarnings();
224
225
/**
226
* Whether to parse Javadoc comments
227
*/
228
boolean isParseJavadoc();
229
230
/**
231
* Whether to keep tokens for exact source reconstruction
232
*/
233
boolean isKeepTokens();
234
}
235
```
236
237
### Lexer Support
238
239
```java { .api }
240
/**
241
* Lexical analyzer for Java source code
242
*/
243
public interface JavaLexer {
244
/**
245
* Tokenizes the input source
246
*/
247
List<JavaToken> tokenize(String source);
248
249
/**
250
* Returns the next token from the input
251
*/
252
JavaToken nextToken();
253
254
/**
255
* Returns true if there are more tokens
256
*/
257
boolean hasMoreTokens();
258
259
/**
260
* Gets the current position in the source
261
*/
262
Position getCurrentPosition();
263
}
264
265
/**
266
* Represents a Java language token
267
*/
268
public interface JavaToken {
269
/**
270
* Gets the token type (keyword, identifier, literal, etc.)
271
*/
272
TokenKind getKind();
273
274
/**
275
* Gets the token text
276
*/
277
String getText();
278
279
/**
280
* Gets the start position in source
281
*/
282
Position getBeginPosition();
283
284
/**
285
* Gets the end position in source
286
*/
287
Position getEndPosition();
288
289
/**
290
* Returns true if this is a keyword token
291
*/
292
boolean isKeyword();
293
294
/**
295
* Returns true if this is an identifier token
296
*/
297
boolean isIdentifier();
298
299
/**
300
* Returns true if this is a literal token
301
*/
302
boolean isLiteral();
303
}
304
```
305
306
## Copy-Paste Detection (CPD)
307
308
### CPD Lexer
309
310
```java { .api }
311
/**
312
* Specialized lexer for copy-paste detection analysis
313
*/
314
public class JavaCpdLexer implements CpdLexer {
315
316
/**
317
* Tokenizes source code for CPD analysis
318
*/
319
@Override
320
public void tokenize(SourceCode sourceCode, Tokens tokens);
321
322
/**
323
* Creates CPD lexer with default settings
324
*/
325
public JavaCpdLexer();
326
327
/**
328
* Creates CPD lexer with custom properties
329
*/
330
public JavaCpdLexer(LanguagePropertyBundle bundle);
331
}
332
333
/**
334
* Configuration properties for CPD analysis
335
*/
336
public class JavaCpdLexer implements CpdLexer {
337
338
// Property descriptors for CPD configuration
339
public static final PropertyDescriptor<Boolean> IGNORE_LITERALS;
340
public static final PropertyDescriptor<Boolean> IGNORE_IDENTIFIERS;
341
public static final PropertyDescriptor<Boolean> IGNORE_ANNOTATIONS;
342
public static final PropertyDescriptor<String> ANONYMIZE_LITERALS;
343
public static final PropertyDescriptor<String> ANONYMIZE_IDENTIFIERS;
344
}
345
```
346
347
### CPD Token Processing
348
349
```java { .api }
350
/**
351
* Represents a token in CPD analysis
352
*/
353
public interface CpdToken {
354
/**
355
* Gets the token text (possibly anonymized)
356
*/
357
String getText();
358
359
/**
360
* Gets the line number
361
*/
362
int getBeginLine();
363
364
/**
365
* Gets the column number
366
*/
367
int getBeginColumn();
368
369
/**
370
* Gets the end line number
371
*/
372
int getEndLine();
373
374
/**
375
* Gets the end column number
376
*/
377
int getEndColumn();
378
379
/**
380
* Returns true if this token should be ignored for CPD
381
*/
382
boolean isIgnored();
383
}
384
385
/**
386
* Collection of tokens for CPD analysis
387
*/
388
public interface Tokens extends Iterable<CpdToken> {
389
/**
390
* Adds a new token
391
*/
392
void add(String tokenText, int beginLine, int beginColumn, int endLine, int endColumn);
393
394
/**
395
* Gets the number of tokens
396
*/
397
int size();
398
399
/**
400
* Gets token at specific index
401
*/
402
CpdToken get(int index);
403
}
404
```
405
406
### CPD Suppression
407
408
```java { .api }
409
/**
410
* Support for suppressing CPD analysis in code regions
411
*/
412
public class JavaCpdLexer implements CpdLexer {
413
414
// Annotation-based suppression
415
public static final String CPD_START = "CPD-START";
416
public static final String CPD_END = "CPD-END";
417
418
/**
419
* Checks if CPD suppression is active at the current position
420
*/
421
protected boolean isCpdSuppressed(int line);
422
423
/**
424
* Processes suppression annotations in comments
425
*/
426
protected void processCpdSuppression(String commentText, int line);
427
}
428
```
429
430
**CPD Suppression Example:**
431
```java
432
public class MyClass {
433
434
// CPD-START
435
public void templateMethod1() {
436
// This code block will be ignored by CPD
437
setup();
438
process();
439
cleanup();
440
}
441
442
public void templateMethod2() {
443
// This similar code block will also be ignored
444
setup();
445
process();
446
cleanup();
447
}
448
// CPD-END
449
450
private void setup() { /* ... */ }
451
private void process() { /* ... */ }
452
private void cleanup() { /* ... */ }
453
}
454
```
455
456
## Javadoc Processing
457
458
### Javadoc Tags Support
459
460
```java { .api }
461
/**
462
* Standard Javadoc tags recognized by the parser
463
*/
464
public final class JavadocTag {
465
466
// Standard block tags
467
public static final JavadocTag AUTHOR = new JavadocTag("author");
468
public static final JavadocTag SINCE = new JavadocTag("since");
469
public static final JavadocTag VERSION = new JavadocTag("version");
470
public static final JavadocTag DEPRECATED = new JavadocTag("deprecated");
471
public static final JavadocTag PARAM = new JavadocTag("param");
472
public static final JavadocTag THROWS = new JavadocTag("throws");
473
public static final JavadocTag EXCEPTION = new JavadocTag("exception");
474
public static final JavadocTag RETURN = new JavadocTag("return");
475
public static final JavadocTag RETURNS = new JavadocTag("returns");
476
public static final JavadocTag SEE = new JavadocTag("see");
477
public static final JavadocTag LINK = new JavadocTag("link");
478
public static final JavadocTag LINKPLAIN = new JavadocTag("linkplain");
479
public static final JavadocTag VALUE = new JavadocTag("value");
480
public static final JavadocTag CODE = new JavadocTag("code");
481
public static final JavadocTag LITERAL = new JavadocTag("literal");
482
483
/**
484
* Creates or retrieves a tag instance for the given identifier
485
*/
486
public static JavadocTag tagFor(String tagId);
487
488
/**
489
* Returns all known tag identifiers
490
*/
491
public static Set<String> allTagIds();
492
493
/**
494
* Gets the tag identifier without @ prefix
495
*/
496
public String getTagId();
497
}
498
```
499
500
### Javadoc AST Nodes
501
502
```java { .api }
503
/**
504
* AST node representing a Javadoc comment
505
*/
506
public final class ASTJavadocComment extends AbstractJavaNode {
507
/**
508
* Gets the description text (before any tags)
509
*/
510
String getDescription();
511
512
/**
513
* Gets all Javadoc tags in this comment
514
*/
515
List<ASTJavadocTag> getTags();
516
517
/**
518
* Gets tags of a specific type
519
*/
520
List<ASTJavadocTag> getTags(JavadocTag tagType);
521
522
/**
523
* Gets the first tag of the specified type
524
*/
525
ASTJavadocTag getFirstTag(JavadocTag tagType);
526
527
/**
528
* Returns true if this Javadoc has the specified tag
529
*/
530
boolean hasTag(JavadocTag tagType);
531
}
532
533
/**
534
* AST node representing a Javadoc tag (@param, @return, etc.)
535
*/
536
public final class ASTJavadocTag extends AbstractJavaNode {
537
/**
538
* Gets the tag type
539
*/
540
JavadocTag getTag();
541
542
/**
543
* Gets the tag arguments (parameter name for @param, etc.)
544
*/
545
List<String> getArguments();
546
547
/**
548
* Gets the description text for this tag
549
*/
550
String getDescription();
551
552
/**
553
* Returns true if this tag has arguments
554
*/
555
boolean hasArguments();
556
}
557
```
558
559
## Multi-Version Support
560
561
### Version-Specific Features
562
563
```java { .api }
564
/**
565
* Version capability checking for language features
566
*/
567
public interface LanguageVersion {
568
/**
569
* Gets the version string (e.g., "1.8", "11", "17")
570
*/
571
String getVersion();
572
573
/**
574
* Gets the short name (e.g., "Java 8", "Java 17")
575
*/
576
String getShortName();
577
578
/**
579
* Gets the full name (e.g., "Java 1.8", "Java 17")
580
*/
581
String getName();
582
583
/**
584
* Compares version ordering
585
*/
586
int compareToVersion(String version);
587
588
/**
589
* Returns true if this version supports the specified feature
590
*/
591
boolean supportsFeature(JavaFeature feature);
592
}
593
594
/**
595
* Java language features by version
596
*/
597
public enum JavaFeature {
598
// Java 5 features
599
GENERICS(JavaLanguageModule.JAVA_1_5),
600
ANNOTATIONS(JavaLanguageModule.JAVA_1_5),
601
ENHANCED_FOR(JavaLanguageModule.JAVA_1_5),
602
VARARGS(JavaLanguageModule.JAVA_1_5),
603
AUTOBOXING(JavaLanguageModule.JAVA_1_5),
604
605
// Java 7 features
606
DIAMOND_OPERATOR(JavaLanguageModule.JAVA_1_7),
607
MULTI_CATCH(JavaLanguageModule.JAVA_1_7),
608
TRY_WITH_RESOURCES(JavaLanguageModule.JAVA_1_7),
609
610
// Java 8 features
611
LAMBDA_EXPRESSIONS(JavaLanguageModule.JAVA_1_8),
612
METHOD_REFERENCES(JavaLanguageModule.JAVA_1_8),
613
DEFAULT_METHODS(JavaLanguageModule.JAVA_1_8),
614
STREAMS(JavaLanguageModule.JAVA_1_8),
615
616
// Java 9 features
617
MODULES(JavaLanguageModule.JAVA_9),
618
PRIVATE_INTERFACE_METHODS(JavaLanguageModule.JAVA_9),
619
620
// Java 10 features
621
LOCAL_VARIABLE_TYPE_INFERENCE(JavaLanguageModule.JAVA_10), // var keyword
622
623
// Java 14 features
624
SWITCH_EXPRESSIONS(JavaLanguageModule.JAVA_14),
625
RECORDS_PREVIEW(JavaLanguageModule.JAVA_14),
626
PATTERN_MATCHING_INSTANCEOF_PREVIEW(JavaLanguageModule.JAVA_14),
627
628
// Java 15 features
629
TEXT_BLOCKS(JavaLanguageModule.JAVA_15),
630
SEALED_CLASSES_PREVIEW(JavaLanguageModule.JAVA_15),
631
632
// Java 16 features
633
RECORDS(JavaLanguageModule.JAVA_16),
634
PATTERN_MATCHING_INSTANCEOF(JavaLanguageModule.JAVA_16),
635
636
// Java 17 features (LTS)
637
SEALED_CLASSES(JavaLanguageModule.JAVA_17),
638
639
// Java 21 features (LTS)
640
PATTERN_MATCHING_SWITCH(JavaLanguageModule.JAVA_21),
641
RECORD_PATTERNS(JavaLanguageModule.JAVA_21),
642
VIRTUAL_THREADS(JavaLanguageModule.JAVA_21),
643
644
// Java 22+ preview features
645
STRING_TEMPLATES_PREVIEW(JavaLanguageModule.JAVA_22),
646
UNNAMED_PATTERNS_PREVIEW(JavaLanguageModule.JAVA_22);
647
648
private final LanguageVersion introducedIn;
649
650
JavaFeature(LanguageVersion version) {
651
this.introducedIn = version;
652
}
653
654
public LanguageVersion getIntroducedIn() {
655
return introducedIn;
656
}
657
}
658
```
659
660
### Version-Aware Parsing
661
662
```java { .api }
663
/**
664
* Parser factory that creates version-specific parsers
665
*/
666
public class JavaParserFactory {
667
668
/**
669
* Creates a parser for the specified Java version
670
*/
671
public static Parser createParser(LanguageVersion version);
672
673
/**
674
* Creates a parser with custom options
675
*/
676
public static Parser createParser(LanguageVersion version, ParserOptions options);
677
678
/**
679
* Returns the default parser for the latest Java version
680
*/
681
public static Parser createDefaultParser();
682
}
683
```
684
685
## Usage Examples
686
687
### Basic Language Module Setup
688
689
```java
690
// Get the Java language module instance
691
JavaLanguageModule javaModule = JavaLanguageModule.getInstance();
692
693
// Create property bundle for Java 17
694
LanguagePropertyBundle bundle = javaModule.newPropertyBundle();
695
bundle.setLanguageVersion(JavaLanguageModule.JAVA_17);
696
697
// Create language processor
698
LanguageProcessor processor = javaModule.createProcessor(bundle);
699
700
// Create CPD lexer
701
CpdLexer cpdLexer = javaModule.createCpdLexer(bundle);
702
```
703
704
### Version-Specific Feature Detection
705
706
```java
707
// Check if current version supports specific features
708
public class FeatureChecker {
709
710
public void checkFeatureSupport(LanguageVersion version) {
711
System.out.println("Checking features for " + version.getName());
712
713
// Check for modern features
714
if (version.supportsFeature(JavaFeature.LAMBDA_EXPRESSIONS)) {
715
System.out.println("✓ Lambda expressions supported");
716
}
717
718
if (version.supportsFeature(JavaFeature.RECORDS)) {
719
System.out.println("✓ Records supported");
720
}
721
722
if (version.supportsFeature(JavaFeature.SEALED_CLASSES)) {
723
System.out.println("✓ Sealed classes supported");
724
}
725
726
if (version.supportsFeature(JavaFeature.PATTERN_MATCHING_SWITCH)) {
727
System.out.println("✓ Pattern matching in switch supported");
728
}
729
730
// Check version comparisons
731
if (version.compareToVersion("17") >= 0) {
732
System.out.println("✓ LTS version 17+ features available");
733
}
734
}
735
}
736
```
737
738
### Custom Parser Configuration
739
740
```java
741
// Create parser with custom options
742
public class CustomParserExample {
743
744
public ASTCompilationUnit parseWithOptions(String sourceCode, String filename) {
745
// Create custom parser options
746
ParserOptions options = new ParserOptions() {
747
@Override
748
public boolean isRecoverFromErrors() {
749
return true; // Continue parsing despite errors
750
}
751
752
@Override
753
public boolean isSuppressWarnings() {
754
return false; // Show parser warnings
755
}
756
757
@Override
758
public boolean isParseJavadoc() {
759
return true; // Parse Javadoc comments
760
}
761
762
@Override
763
public boolean isKeepTokens() {
764
return true; // Keep tokens for exact reconstruction
765
}
766
};
767
768
// Create parser for Java 21
769
Parser parser = JavaParserFactory.createParser(
770
JavaLanguageModule.JAVA_21,
771
options
772
);
773
774
// Parse the source code
775
TextFile textFile = TextFile.forCharSeq(filename, sourceCode);
776
return parser.parse(sourceCode, textFile, options);
777
}
778
}
779
```
780
781
### CPD Configuration
782
783
```java
784
// Configure CPD lexer for copy-paste detection
785
public class CpdConfiguration {
786
787
public void configureCpdLexer() {
788
// Create property bundle for CPD
789
LanguagePropertyBundle bundle = JavaLanguageModule.getInstance().newPropertyBundle();
790
bundle.setLanguageVersion(JavaLanguageModule.JAVA_17);
791
792
// Configure CPD properties
793
bundle.setProperty(JavaCpdLexer.IGNORE_LITERALS, true);
794
bundle.setProperty(JavaCpdLexer.IGNORE_IDENTIFIERS, false);
795
bundle.setProperty(JavaCpdLexer.IGNORE_ANNOTATIONS, true);
796
bundle.setProperty(JavaCpdLexer.ANONYMIZE_LITERALS, "LITERAL");
797
bundle.setProperty(JavaCpdLexer.ANONYMIZE_IDENTIFIERS, "IDENTIFIER");
798
799
// Create CPD lexer with configuration
800
CpdLexer cpdLexer = JavaLanguageModule.getInstance().createCpdLexer(bundle);
801
802
// Use lexer for tokenization
803
SourceCode sourceCode = /* ... */;
804
Tokens tokens = new Tokens();
805
cpdLexer.tokenize(sourceCode, tokens);
806
807
System.out.println("Generated " + tokens.size() + " tokens for CPD analysis");
808
}
809
}
810
```
811
812
### Javadoc Processing
813
814
```java
815
// Process Javadoc comments in parsed AST
816
public class JavadocProcessor extends JavaVisitorBase<Void, Void> {
817
818
@Override
819
public Void visit(ASTMethodDeclaration node, Void data) {
820
// Get Javadoc comment if present
821
ASTJavadocComment javadoc = node.getJavadocComment();
822
823
if (javadoc != null) {
824
System.out.println("Method: " + node.getName());
825
System.out.println("Description: " + javadoc.getDescription());
826
827
// Process @param tags
828
for (ASTJavadocTag paramTag : javadoc.getTags(JavadocTag.PARAM)) {
829
List<String> args = paramTag.getArguments();
830
if (!args.isEmpty()) {
831
String paramName = args.get(0);
832
String description = paramTag.getDescription();
833
System.out.println(" @param " + paramName + ": " + description);
834
}
835
}
836
837
// Process @return tag
838
ASTJavadocTag returnTag = javadoc.getFirstTag(JavadocTag.RETURN);
839
if (returnTag != null) {
840
System.out.println(" @return: " + returnTag.getDescription());
841
}
842
843
// Check for @throws tags
844
for (ASTJavadocTag throwsTag : javadoc.getTags(JavadocTag.THROWS)) {
845
List<String> args = throwsTag.getArguments();
846
if (!args.isEmpty()) {
847
String exceptionType = args.get(0);
848
String description = throwsTag.getDescription();
849
System.out.println(" @throws " + exceptionType + ": " + description);
850
}
851
}
852
}
853
854
return super.visit(node, data);
855
}
856
857
@Override
858
public Void visit(ASTClassDeclaration node, Void data) {
859
ASTJavadocComment javadoc = node.getJavadocComment();
860
861
if (javadoc != null) {
862
// Check for deprecation
863
if (javadoc.hasTag(JavadocTag.DEPRECATED)) {
864
ASTJavadocTag deprecatedTag = javadoc.getFirstTag(JavadocTag.DEPRECATED);
865
System.out.println("Class " + node.getSimpleName() + " is deprecated: " +
866
deprecatedTag.getDescription());
867
}
868
869
// Check for @since tag
870
ASTJavadocTag sinceTag = javadoc.getFirstTag(JavadocTag.SINCE);
871
if (sinceTag != null) {
872
System.out.println("Available since: " + sinceTag.getDescription());
873
}
874
}
875
876
return super.visit(node, data);
877
}
878
}
879
```
880
881
### Integration with PMD Framework
882
883
```java
884
// Complete integration example
885
public class JavaAnalysisIntegration {
886
887
public void analyzeJavaFile(String filePath, String sourceCode) {
888
try {
889
// 1. Get Java language module
890
JavaLanguageModule javaModule = JavaLanguageModule.getInstance();
891
892
// 2. Configure for Java 17
893
LanguagePropertyBundle bundle = javaModule.newPropertyBundle();
894
bundle.setLanguageVersion(JavaLanguageModule.JAVA_17);
895
896
// 3. Create language processor
897
LanguageProcessor processor = javaModule.createProcessor(bundle);
898
899
// 4. Get analysis services
900
AnalysisServices services = processor.services();
901
Parser parser = services.getParser();
902
903
// 5. Parse source code
904
TextFile textFile = TextFile.forCharSeq(filePath, sourceCode);
905
ASTCompilationUnit ast = parser.parse(sourceCode, textFile);
906
907
// 6. Access semantic information
908
JSymbolTable symbolTable = ast.getSymbolTable();
909
TypeSystem typeSystem = ast.getTypeSystem();
910
911
// 7. Analyze the AST
912
MyAnalysisVisitor visitor = new MyAnalysisVisitor(symbolTable, typeSystem);
913
ast.acceptVisitor(visitor, null);
914
915
System.out.println("Analysis completed for: " + filePath);
916
917
} catch (Exception e) {
918
System.err.println("Analysis failed: " + e.getMessage());
919
}
920
}
921
922
private static class MyAnalysisVisitor extends JavaVisitorBase<Void, Void> {
923
private final JSymbolTable symbolTable;
924
private final TypeSystem typeSystem;
925
926
public MyAnalysisVisitor(JSymbolTable symbolTable, TypeSystem typeSystem) {
927
this.symbolTable = symbolTable;
928
this.typeSystem = typeSystem;
929
}
930
931
@Override
932
public Void visit(ASTMethodCall node, Void data) {
933
// Analyze method call with full semantic information
934
JMethodSymbol method = node.getMethodType();
935
JTypeMirror returnType = node.getTypeMirror();
936
937
System.out.println("Method call: " + node.getMethodName() +
938
" returns " + returnType);
939
940
return super.visit(node, data);
941
}
942
}
943
}
944
```