0
# Language Framework
1
2
The Language Framework provides modular support for multiple programming languages within PMD. It enables language detection, version management, extension handling, and language-specific configuration through a registry-based architecture.
3
4
## Capabilities
5
6
### Language Interface
7
8
Core interface representing a programming language module with metadata, version support, and file extension handling.
9
10
```java { .api }
11
/**
12
* Core interface representing a programming language module.
13
* Provides metadata, version support, and file extension handling.
14
*/
15
public interface Language extends Comparable<Language> {
16
17
/**
18
* Get full language name (e.g., "Java", "JavaScript")
19
* @return Full descriptive name of the language
20
*/
21
String getName();
22
23
/**
24
* Get short/acronym name (e.g., "Java", "JS")
25
* @return Short name or acronym for the language
26
*/
27
String getShortName();
28
29
/**
30
* Get unique language ID (e.g., "java", "javascript")
31
* @return Unique identifier for the language (lowercase)
32
*/
33
String getId();
34
35
/**
36
* Get base language ID for dialect languages (experimental)
37
* @return Base language ID if this is a dialect, null otherwise
38
*/
39
@Nullable String getBaseLanguageId();
40
41
/**
42
* Check if this language is a dialect of another language (experimental)
43
* @param language Language to check against
44
* @return true if this language is a dialect of the given language
45
*/
46
boolean isDialectOf(Language language);
47
48
/**
49
* Get supported file extensions (without dots)
50
* @return List of file extensions this language handles
51
*/
52
List<String> getExtensions();
53
54
/**
55
* Check if language handles specific file extension
56
* @param extensionWithoutDot File extension without the dot prefix
57
* @return true if language supports the extension
58
*/
59
boolean hasExtension(String extensionWithoutDot);
60
61
/**
62
* Get all supported language versions
63
* @return List of all LanguageVersion instances for this language
64
*/
65
List<LanguageVersion> getVersions();
66
67
/**
68
* Get latest/newest language version
69
* @return Most recent LanguageVersion available
70
*/
71
LanguageVersion getLatestVersion();
72
73
/**
74
* Get all version names and aliases
75
* @return Set of all version identifiers and aliases
76
*/
77
Set<String> getVersionNamesAndAliases();
78
79
/**
80
* Check if specific version exists
81
* @param version Version string to check
82
* @return true if version is supported by this language
83
*/
84
boolean hasVersion(String version);
85
86
/**
87
* Get LanguageVersion by string identifier
88
* @param version Version identifier or alias
89
* @return LanguageVersion instance, or null if not found
90
*/
91
@Nullable LanguageVersion getVersion(String version);
92
93
/**
94
* Get default language version
95
* @return Default LanguageVersion for this language
96
*/
97
@NonNull LanguageVersion getDefaultVersion();
98
99
/**
100
* Create new property bundle for language-specific configuration
101
* @return LanguagePropertyBundle for this language
102
*/
103
LanguagePropertyBundle newPropertyBundle();
104
105
/**
106
* Get dependency language IDs
107
* @return Set of language IDs this language depends on
108
*/
109
Set<String> getDependencies();
110
}
111
```
112
113
**Usage Examples:**
114
115
```java
116
import net.sourceforge.pmd.lang.Language;
117
import net.sourceforge.pmd.lang.LanguageRegistry;
118
import net.sourceforge.pmd.lang.LanguageVersion;
119
120
// Getting language by ID
121
Language java = LanguageRegistry.PMD.getLanguageById("java");
122
if (java != null) {
123
System.out.printf("Language: %s (Short: %s)%n",
124
java.getName(), java.getShortName());
125
126
// Check file extension support
127
if (java.hasExtension("java")) {
128
System.out.println("Java language handles .java files");
129
}
130
131
// List all supported extensions
132
System.out.printf("Supported extensions: %s%n",
133
java.getExtensions());
134
135
// Work with versions
136
LanguageVersion defaultVersion = java.getDefaultVersion();
137
LanguageVersion latestVersion = java.getLatestVersion();
138
139
System.out.printf("Default version: %s%n", defaultVersion.getVersion());
140
System.out.printf("Latest version: %s%n", latestVersion.getVersion());
141
142
// Check specific version support
143
if (java.hasVersion("17")) {
144
LanguageVersion java17 = java.getVersion("17");
145
System.out.printf("Java 17: %s%n", java17.getName());
146
}
147
148
// List all versions
149
for (LanguageVersion version : java.getVersions()) {
150
System.out.printf(" Version: %s (%s)%n",
151
version.getVersion(), version.getName());
152
}
153
}
154
155
// Working with language properties
156
LanguagePropertyBundle javaProps = java.newPropertyBundle();
157
// Configure language-specific properties as needed
158
159
// Check dependencies
160
Set<String> dependencies = java.getDependencies();
161
if (!dependencies.isEmpty()) {
162
System.out.printf("Dependencies: %s%n", dependencies);
163
}
164
165
// Language comparison and sorting
166
List<Language> languages = new ArrayList<>(LanguageRegistry.PMD.getLanguages());
167
Collections.sort(languages); // Uses Comparable<Language> implementation
168
for (Language lang : languages) {
169
System.out.printf("Language: %s%n", lang.getName());
170
}
171
```
172
173
### Language Registry
174
175
Registry providing centralized access to supported languages with filtering, discovery, and dependency management capabilities.
176
177
```java { .api }
178
/**
179
* Registry of languages with convenient access methods and filtering capabilities.
180
* Implements Iterable<Language> for easy iteration over supported languages.
181
*/
182
public final class LanguageRegistry implements Iterable<Language> {
183
184
/**
185
* PMD-capable languages loaded from classpath
186
*/
187
public static final LanguageRegistry PMD;
188
189
/**
190
* CPD-capable languages loaded from classpath
191
*/
192
public static final LanguageRegistry CPD;
193
194
/**
195
* Create registry with specific set of languages
196
* @param languages Set of Language instances to include
197
*/
198
LanguageRegistry(Set<? extends Language> languages);
199
200
/**
201
* Create filtered registry based on predicate
202
* @param filterFun Predicate to filter languages
203
* @return New LanguageRegistry with filtered languages
204
*/
205
LanguageRegistry filter(Predicate<Language> filterFun);
206
207
/**
208
* Create registry containing single language
209
* @param l Language to include in registry
210
* @return LanguageRegistry containing only specified language
211
*/
212
static LanguageRegistry singleton(Language l);
213
214
/**
215
* Load languages from classpath using ClassLoader
216
* @param classLoader ClassLoader for discovering language implementations
217
* @return LanguageRegistry with discovered languages
218
*/
219
static @NonNull LanguageRegistry loadLanguages(ClassLoader classLoader);
220
221
/**
222
* Get registry containing language and its dependencies
223
* @param lang Language to include with dependencies
224
* @return LanguageRegistry with language and all its dependencies
225
*/
226
LanguageRegistry getDependenciesOf(Language lang);
227
228
/**
229
* Iterate over languages in registry
230
* @return Iterator for Language instances
231
*/
232
@NonNull Iterator<Language> iterator();
233
234
/**
235
* Get all languages in registry
236
* @return Set of all Language instances
237
*/
238
Set<Language> getLanguages();
239
240
/**
241
* Get language by unique ID
242
* @param langId Language identifier (e.g., "java", "javascript")
243
* @return Language instance, or null if not found
244
*/
245
@Nullable Language getLanguageById(@Nullable String langId);
246
247
/**
248
* Get language version by language ID and version string
249
* @param langId Language identifier
250
* @param version Version string or alias
251
* @return LanguageVersion instance, or null if not found
252
*/
253
@Nullable LanguageVersion getLanguageVersionById(@Nullable String langId, @Nullable String version);
254
255
/**
256
* Get language by full name
257
* @param languageName Full language name (e.g., "Java", "JavaScript")
258
* @return Language instance, or null if not found
259
*/
260
@Nullable Language getLanguageByFullName(String languageName);
261
262
/**
263
* Format languages as comma-separated list
264
* @param formatter Function to format each language
265
* @return Comma-separated string of formatted language names
266
*/
267
@NonNull String commaSeparatedList(Function<? super Language, String> formatter);
268
269
/**
270
* Get string representation of registry
271
* @return String describing registry contents
272
*/
273
String toString();
274
}
275
```
276
277
**Usage Examples:**
278
279
```java
280
import net.sourceforge.pmd.lang.*;
281
import java.util.Set;
282
import java.util.function.Predicate;
283
284
// Using predefined registries
285
LanguageRegistry pmdLanguages = LanguageRegistry.PMD;
286
LanguageRegistry cpdLanguages = LanguageRegistry.CPD;
287
288
System.out.printf("PMD supports %d languages%n", pmdLanguages.getLanguages().size());
289
System.out.printf("CPD supports %d languages%n", cpdLanguages.getLanguages().size());
290
291
// List all PMD languages
292
System.out.println("PMD Languages:");
293
for (Language lang : pmdLanguages) {
294
System.out.printf(" %s (%s) - Extensions: %s%n",
295
lang.getName(),
296
lang.getId(),
297
lang.getExtensions());
298
}
299
300
// Find specific languages
301
Language java = pmdLanguages.getLanguageById("java");
302
Language javascript = pmdLanguages.getLanguageByFullName("JavaScript");
303
304
if (java != null) {
305
System.out.printf("Found Java language: %s%n", java.getName());
306
}
307
308
// Get specific language version
309
LanguageVersion java11 = pmdLanguages.getLanguageVersionById("java", "11");
310
if (java11 != null) {
311
System.out.printf("Java 11: %s%n", java11.getName());
312
}
313
314
// Create filtered registry - only languages with specific extensions
315
LanguageRegistry jvmLanguages = pmdLanguages.filter(
316
lang -> lang.hasExtension("java") ||
317
lang.hasExtension("kt") ||
318
lang.hasExtension("scala")
319
);
320
321
// Create registry for single language
322
LanguageRegistry javaOnly = LanguageRegistry.singleton(java);
323
324
// Work with dependencies
325
LanguageRegistry javaWithDeps = pmdLanguages.getDependenciesOf(java);
326
System.out.printf("Java with dependencies: %d languages%n",
327
javaWithDeps.getLanguages().size());
328
329
// Custom filtering examples
330
LanguageRegistry scriptingLanguages = pmdLanguages.filter(
331
lang -> lang.getId().contains("script") ||
332
lang.getId().equals("python") ||
333
lang.getId().equals("ruby")
334
);
335
336
LanguageRegistry webLanguages = pmdLanguages.filter(
337
lang -> lang.hasExtension("js") ||
338
lang.hasExtension("ts") ||
339
lang.hasExtension("html") ||
340
lang.hasExtension("css")
341
);
342
343
// Format language list
344
String languageList = pmdLanguages.commaSeparatedList(Language::getName);
345
System.out.printf("Supported languages: %s%n", languageList);
346
347
String idList = pmdLanguages.commaSeparatedList(Language::getId);
348
System.out.printf("Language IDs: %s%n", idList);
349
350
// Load languages from custom ClassLoader
351
ClassLoader customLoader = Thread.currentThread().getContextClassLoader();
352
LanguageRegistry customLanguages = LanguageRegistry.loadLanguages(customLoader);
353
```
354
355
### Language Version Discovery
356
357
Automatic detection and management of language versions based on file characteristics and configuration.
358
359
```java { .api }
360
/**
361
* Discovers and manages language versions for files based on extensions and configuration.
362
*/
363
interface LanguageVersionDiscoverer {
364
365
/**
366
* Get default language version for specific language
367
* @param language Target language
368
* @return Default LanguageVersion for the language
369
*/
370
LanguageVersion getDefaultLanguageVersion(Language language);
371
372
/**
373
* Get language version for specific file
374
* @param fileName File name to analyze
375
* @return LanguageVersion based on file extension and configuration, or null
376
*/
377
@Nullable LanguageVersion getLanguageVersionOfFile(String fileName);
378
379
/**
380
* Set default version for specific language
381
* @param languageVersion Default version to use for language
382
*/
383
void setDefaultLanguageVersion(LanguageVersion languageVersion);
384
385
/**
386
* Set multiple default language versions
387
* @param languageVersions List of default versions for different languages
388
*/
389
void setDefaultLanguageVersions(List<LanguageVersion> languageVersions);
390
}
391
```
392
393
**Usage Examples:**
394
395
```java
396
import net.sourceforge.pmd.lang.*;
397
398
// Working with language version discovery
399
PMDConfiguration config = new PMDConfiguration();
400
LanguageVersionDiscoverer discoverer = config.getLanguageVersionDiscoverer();
401
402
// Set default versions for languages
403
Language java = LanguageRegistry.PMD.getLanguageById("java");
404
LanguageVersion java11 = java.getVersion("11");
405
discoverer.setDefaultLanguageVersion(java11);
406
407
// Set multiple defaults
408
List<LanguageVersion> defaults = Arrays.asList(
409
LanguageRegistry.PMD.getLanguageVersionById("java", "11"),
410
LanguageRegistry.PMD.getLanguageVersionById("javascript", "es6"),
411
LanguageRegistry.PMD.getLanguageVersionById("python", "3.9")
412
);
413
discoverer.setDefaultLanguageVersions(defaults);
414
415
// Discover language version for files
416
LanguageVersion detected = discoverer.getLanguageVersionOfFile("Example.java");
417
if (detected != null) {
418
System.out.printf("Detected %s for Java file%n", detected.getName());
419
}
420
421
// Check different file types
422
String[] testFiles = {
423
"script.js",
424
"component.ts",
425
"style.css",
426
"template.html",
427
"config.xml",
428
"data.json"
429
};
430
431
for (String fileName : testFiles) {
432
LanguageVersion version = discoverer.getLanguageVersionOfFile(fileName);
433
if (version != null) {
434
System.out.printf("%s -> %s (%s)%n",
435
fileName,
436
version.getLanguage().getName(),
437
version.getVersion());
438
} else {
439
System.out.printf("%s -> No language detected%n", fileName);
440
}
441
}
442
```
443
444
## Types
445
446
```java { .api }
447
/**
448
* Represents a specific version of a programming language
449
*/
450
interface LanguageVersion extends Comparable<LanguageVersion> {
451
452
/**
453
* Get the language this version belongs to
454
* @return Language instance
455
*/
456
Language getLanguage();
457
458
/**
459
* Get version string identifier
460
* @return Version string (e.g., "11", "ES6", "3.9")
461
*/
462
String getVersion();
463
464
/**
465
* Get full descriptive name
466
* @return Full name including language and version
467
*/
468
String getName();
469
470
/**
471
* Get short name
472
* @return Abbreviated name for the version
473
*/
474
String getShortName();
475
476
/**
477
* Get terse name (very short identifier)
478
* @return Minimal identifier for the version
479
*/
480
String getTerseName();
481
482
/**
483
* Compare versions for ordering
484
* @param other LanguageVersion to compare against
485
* @return Comparison result for ordering
486
*/
487
int compareTo(LanguageVersion other);
488
}
489
490
/**
491
* Property bundle for language-specific configuration
492
*/
493
interface LanguagePropertyBundle extends PropertySource {
494
495
/**
496
* Get the language this bundle configures
497
* @return Language instance
498
*/
499
Language getLanguage();
500
501
/**
502
* Create copy of bundle for different language
503
* @param language Target language for copy
504
* @return New LanguagePropertyBundle for specified language
505
*/
506
LanguagePropertyBundle copyForLanguage(Language language);
507
}
508
509
/**
510
* Language module providing parsing and analysis capabilities
511
*/
512
interface LanguageModule {
513
514
/**
515
* Get language metadata
516
* @return Language instance with metadata
517
*/
518
Language getLanguage();
519
520
/**
521
* Get parser for language
522
* @param languageVersion Specific version to parse
523
* @return Parser implementation for the language version
524
*/
525
Parser getParser(LanguageVersion languageVersion);
526
527
/**
528
* Get rule chain visitor for language
529
* @return RuleChainVisitor for processing rules
530
*/
531
RuleChainVisitor getRuleChainVisitor();
532
533
/**
534
* Get CPD visitor for copy-paste detection
535
* @param languageVersion Language version for CPD analysis
536
* @return CpdVisitor for tokenizing source code
537
*/
538
CpdVisitor getCpdVisitor(LanguageVersion languageVersion);
539
}
540
541
/**
542
* Service for managing language implementations
543
*/
544
interface LanguageService {
545
546
/**
547
* Get all available language modules
548
* @return Set of LanguageModule instances
549
*/
550
Set<LanguageModule> getLanguageModules();
551
552
/**
553
* Get language module by language ID
554
* @param languageId Language identifier
555
* @return LanguageModule instance, or null if not found
556
*/
557
@Nullable LanguageModule getLanguageModule(String languageId);
558
559
/**
560
* Register custom language module
561
* @param module LanguageModule to register
562
*/
563
void registerLanguageModule(LanguageModule module);
564
}
565
566
/**
567
* Exception thrown when language operations fail
568
*/
569
class LanguageException extends Exception {
570
String getLanguageId();
571
String getVersionId();
572
}
573
```