PMD Core - The foundational library module providing essential infrastructure for PMD static code analysis including AST handling, rule execution, configuration management, and reporting mechanisms.
—
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.
Core interface representing a programming language module with metadata, version support, and file extension handling.
/**
* Core interface representing a programming language module.
* Provides metadata, version support, and file extension handling.
*/
public interface Language extends Comparable<Language> {
/**
* Get full language name (e.g., "Java", "JavaScript")
* @return Full descriptive name of the language
*/
String getName();
/**
* Get short/acronym name (e.g., "Java", "JS")
* @return Short name or acronym for the language
*/
String getShortName();
/**
* Get unique language ID (e.g., "java", "javascript")
* @return Unique identifier for the language (lowercase)
*/
String getId();
/**
* Get base language ID for dialect languages (experimental)
* @return Base language ID if this is a dialect, null otherwise
*/
@Nullable String getBaseLanguageId();
/**
* Check if this language is a dialect of another language (experimental)
* @param language Language to check against
* @return true if this language is a dialect of the given language
*/
boolean isDialectOf(Language language);
/**
* Get supported file extensions (without dots)
* @return List of file extensions this language handles
*/
List<String> getExtensions();
/**
* Check if language handles specific file extension
* @param extensionWithoutDot File extension without the dot prefix
* @return true if language supports the extension
*/
boolean hasExtension(String extensionWithoutDot);
/**
* Get all supported language versions
* @return List of all LanguageVersion instances for this language
*/
List<LanguageVersion> getVersions();
/**
* Get latest/newest language version
* @return Most recent LanguageVersion available
*/
LanguageVersion getLatestVersion();
/**
* Get all version names and aliases
* @return Set of all version identifiers and aliases
*/
Set<String> getVersionNamesAndAliases();
/**
* Check if specific version exists
* @param version Version string to check
* @return true if version is supported by this language
*/
boolean hasVersion(String version);
/**
* Get LanguageVersion by string identifier
* @param version Version identifier or alias
* @return LanguageVersion instance, or null if not found
*/
@Nullable LanguageVersion getVersion(String version);
/**
* Get default language version
* @return Default LanguageVersion for this language
*/
@NonNull LanguageVersion getDefaultVersion();
/**
* Create new property bundle for language-specific configuration
* @return LanguagePropertyBundle for this language
*/
LanguagePropertyBundle newPropertyBundle();
/**
* Get dependency language IDs
* @return Set of language IDs this language depends on
*/
Set<String> getDependencies();
}Usage Examples:
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersion;
// Getting language by ID
Language java = LanguageRegistry.PMD.getLanguageById("java");
if (java != null) {
System.out.printf("Language: %s (Short: %s)%n",
java.getName(), java.getShortName());
// Check file extension support
if (java.hasExtension("java")) {
System.out.println("Java language handles .java files");
}
// List all supported extensions
System.out.printf("Supported extensions: %s%n",
java.getExtensions());
// Work with versions
LanguageVersion defaultVersion = java.getDefaultVersion();
LanguageVersion latestVersion = java.getLatestVersion();
System.out.printf("Default version: %s%n", defaultVersion.getVersion());
System.out.printf("Latest version: %s%n", latestVersion.getVersion());
// Check specific version support
if (java.hasVersion("17")) {
LanguageVersion java17 = java.getVersion("17");
System.out.printf("Java 17: %s%n", java17.getName());
}
// List all versions
for (LanguageVersion version : java.getVersions()) {
System.out.printf(" Version: %s (%s)%n",
version.getVersion(), version.getName());
}
}
// Working with language properties
LanguagePropertyBundle javaProps = java.newPropertyBundle();
// Configure language-specific properties as needed
// Check dependencies
Set<String> dependencies = java.getDependencies();
if (!dependencies.isEmpty()) {
System.out.printf("Dependencies: %s%n", dependencies);
}
// Language comparison and sorting
List<Language> languages = new ArrayList<>(LanguageRegistry.PMD.getLanguages());
Collections.sort(languages); // Uses Comparable<Language> implementation
for (Language lang : languages) {
System.out.printf("Language: %s%n", lang.getName());
}Registry providing centralized access to supported languages with filtering, discovery, and dependency management capabilities.
/**
* Registry of languages with convenient access methods and filtering capabilities.
* Implements Iterable<Language> for easy iteration over supported languages.
*/
public final class LanguageRegistry implements Iterable<Language> {
/**
* PMD-capable languages loaded from classpath
*/
public static final LanguageRegistry PMD;
/**
* CPD-capable languages loaded from classpath
*/
public static final LanguageRegistry CPD;
/**
* Create registry with specific set of languages
* @param languages Set of Language instances to include
*/
LanguageRegistry(Set<? extends Language> languages);
/**
* Create filtered registry based on predicate
* @param filterFun Predicate to filter languages
* @return New LanguageRegistry with filtered languages
*/
LanguageRegistry filter(Predicate<Language> filterFun);
/**
* Create registry containing single language
* @param l Language to include in registry
* @return LanguageRegistry containing only specified language
*/
static LanguageRegistry singleton(Language l);
/**
* Load languages from classpath using ClassLoader
* @param classLoader ClassLoader for discovering language implementations
* @return LanguageRegistry with discovered languages
*/
static @NonNull LanguageRegistry loadLanguages(ClassLoader classLoader);
/**
* Get registry containing language and its dependencies
* @param lang Language to include with dependencies
* @return LanguageRegistry with language and all its dependencies
*/
LanguageRegistry getDependenciesOf(Language lang);
/**
* Iterate over languages in registry
* @return Iterator for Language instances
*/
@NonNull Iterator<Language> iterator();
/**
* Get all languages in registry
* @return Set of all Language instances
*/
Set<Language> getLanguages();
/**
* Get language by unique ID
* @param langId Language identifier (e.g., "java", "javascript")
* @return Language instance, or null if not found
*/
@Nullable Language getLanguageById(@Nullable String langId);
/**
* Get language version by language ID and version string
* @param langId Language identifier
* @param version Version string or alias
* @return LanguageVersion instance, or null if not found
*/
@Nullable LanguageVersion getLanguageVersionById(@Nullable String langId, @Nullable String version);
/**
* Get language by full name
* @param languageName Full language name (e.g., "Java", "JavaScript")
* @return Language instance, or null if not found
*/
@Nullable Language getLanguageByFullName(String languageName);
/**
* Format languages as comma-separated list
* @param formatter Function to format each language
* @return Comma-separated string of formatted language names
*/
@NonNull String commaSeparatedList(Function<? super Language, String> formatter);
/**
* Get string representation of registry
* @return String describing registry contents
*/
String toString();
}Usage Examples:
import net.sourceforge.pmd.lang.*;
import java.util.Set;
import java.util.function.Predicate;
// Using predefined registries
LanguageRegistry pmdLanguages = LanguageRegistry.PMD;
LanguageRegistry cpdLanguages = LanguageRegistry.CPD;
System.out.printf("PMD supports %d languages%n", pmdLanguages.getLanguages().size());
System.out.printf("CPD supports %d languages%n", cpdLanguages.getLanguages().size());
// List all PMD languages
System.out.println("PMD Languages:");
for (Language lang : pmdLanguages) {
System.out.printf(" %s (%s) - Extensions: %s%n",
lang.getName(),
lang.getId(),
lang.getExtensions());
}
// Find specific languages
Language java = pmdLanguages.getLanguageById("java");
Language javascript = pmdLanguages.getLanguageByFullName("JavaScript");
if (java != null) {
System.out.printf("Found Java language: %s%n", java.getName());
}
// Get specific language version
LanguageVersion java11 = pmdLanguages.getLanguageVersionById("java", "11");
if (java11 != null) {
System.out.printf("Java 11: %s%n", java11.getName());
}
// Create filtered registry - only languages with specific extensions
LanguageRegistry jvmLanguages = pmdLanguages.filter(
lang -> lang.hasExtension("java") ||
lang.hasExtension("kt") ||
lang.hasExtension("scala")
);
// Create registry for single language
LanguageRegistry javaOnly = LanguageRegistry.singleton(java);
// Work with dependencies
LanguageRegistry javaWithDeps = pmdLanguages.getDependenciesOf(java);
System.out.printf("Java with dependencies: %d languages%n",
javaWithDeps.getLanguages().size());
// Custom filtering examples
LanguageRegistry scriptingLanguages = pmdLanguages.filter(
lang -> lang.getId().contains("script") ||
lang.getId().equals("python") ||
lang.getId().equals("ruby")
);
LanguageRegistry webLanguages = pmdLanguages.filter(
lang -> lang.hasExtension("js") ||
lang.hasExtension("ts") ||
lang.hasExtension("html") ||
lang.hasExtension("css")
);
// Format language list
String languageList = pmdLanguages.commaSeparatedList(Language::getName);
System.out.printf("Supported languages: %s%n", languageList);
String idList = pmdLanguages.commaSeparatedList(Language::getId);
System.out.printf("Language IDs: %s%n", idList);
// Load languages from custom ClassLoader
ClassLoader customLoader = Thread.currentThread().getContextClassLoader();
LanguageRegistry customLanguages = LanguageRegistry.loadLanguages(customLoader);Automatic detection and management of language versions based on file characteristics and configuration.
/**
* Discovers and manages language versions for files based on extensions and configuration.
*/
interface LanguageVersionDiscoverer {
/**
* Get default language version for specific language
* @param language Target language
* @return Default LanguageVersion for the language
*/
LanguageVersion getDefaultLanguageVersion(Language language);
/**
* Get language version for specific file
* @param fileName File name to analyze
* @return LanguageVersion based on file extension and configuration, or null
*/
@Nullable LanguageVersion getLanguageVersionOfFile(String fileName);
/**
* Set default version for specific language
* @param languageVersion Default version to use for language
*/
void setDefaultLanguageVersion(LanguageVersion languageVersion);
/**
* Set multiple default language versions
* @param languageVersions List of default versions for different languages
*/
void setDefaultLanguageVersions(List<LanguageVersion> languageVersions);
}Usage Examples:
import net.sourceforge.pmd.lang.*;
// Working with language version discovery
PMDConfiguration config = new PMDConfiguration();
LanguageVersionDiscoverer discoverer = config.getLanguageVersionDiscoverer();
// Set default versions for languages
Language java = LanguageRegistry.PMD.getLanguageById("java");
LanguageVersion java11 = java.getVersion("11");
discoverer.setDefaultLanguageVersion(java11);
// Set multiple defaults
List<LanguageVersion> defaults = Arrays.asList(
LanguageRegistry.PMD.getLanguageVersionById("java", "11"),
LanguageRegistry.PMD.getLanguageVersionById("javascript", "es6"),
LanguageRegistry.PMD.getLanguageVersionById("python", "3.9")
);
discoverer.setDefaultLanguageVersions(defaults);
// Discover language version for files
LanguageVersion detected = discoverer.getLanguageVersionOfFile("Example.java");
if (detected != null) {
System.out.printf("Detected %s for Java file%n", detected.getName());
}
// Check different file types
String[] testFiles = {
"script.js",
"component.ts",
"style.css",
"template.html",
"config.xml",
"data.json"
};
for (String fileName : testFiles) {
LanguageVersion version = discoverer.getLanguageVersionOfFile(fileName);
if (version != null) {
System.out.printf("%s -> %s (%s)%n",
fileName,
version.getLanguage().getName(),
version.getVersion());
} else {
System.out.printf("%s -> No language detected%n", fileName);
}
}/**
* Represents a specific version of a programming language
*/
interface LanguageVersion extends Comparable<LanguageVersion> {
/**
* Get the language this version belongs to
* @return Language instance
*/
Language getLanguage();
/**
* Get version string identifier
* @return Version string (e.g., "11", "ES6", "3.9")
*/
String getVersion();
/**
* Get full descriptive name
* @return Full name including language and version
*/
String getName();
/**
* Get short name
* @return Abbreviated name for the version
*/
String getShortName();
/**
* Get terse name (very short identifier)
* @return Minimal identifier for the version
*/
String getTerseName();
/**
* Compare versions for ordering
* @param other LanguageVersion to compare against
* @return Comparison result for ordering
*/
int compareTo(LanguageVersion other);
}
/**
* Property bundle for language-specific configuration
*/
interface LanguagePropertyBundle extends PropertySource {
/**
* Get the language this bundle configures
* @return Language instance
*/
Language getLanguage();
/**
* Create copy of bundle for different language
* @param language Target language for copy
* @return New LanguagePropertyBundle for specified language
*/
LanguagePropertyBundle copyForLanguage(Language language);
}
/**
* Language module providing parsing and analysis capabilities
*/
interface LanguageModule {
/**
* Get language metadata
* @return Language instance with metadata
*/
Language getLanguage();
/**
* Get parser for language
* @param languageVersion Specific version to parse
* @return Parser implementation for the language version
*/
Parser getParser(LanguageVersion languageVersion);
/**
* Get rule chain visitor for language
* @return RuleChainVisitor for processing rules
*/
RuleChainVisitor getRuleChainVisitor();
/**
* Get CPD visitor for copy-paste detection
* @param languageVersion Language version for CPD analysis
* @return CpdVisitor for tokenizing source code
*/
CpdVisitor getCpdVisitor(LanguageVersion languageVersion);
}
/**
* Service for managing language implementations
*/
interface LanguageService {
/**
* Get all available language modules
* @return Set of LanguageModule instances
*/
Set<LanguageModule> getLanguageModules();
/**
* Get language module by language ID
* @param languageId Language identifier
* @return LanguageModule instance, or null if not found
*/
@Nullable LanguageModule getLanguageModule(String languageId);
/**
* Register custom language module
* @param module LanguageModule to register
*/
void registerLanguageModule(LanguageModule module);
}
/**
* Exception thrown when language operations fail
*/
class LanguageException extends Exception {
String getLanguageId();
String getVersionId();
}Install with Tessl CLI
npx tessl i tessl/maven-net-sourceforge-pmd--pmd-core