CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-net-sourceforge-pmd--pmd-core

PMD Core - The foundational library module providing essential infrastructure for PMD static code analysis including AST handling, rule execution, configuration management, and reporting mechanisms.

Pending
Overview
Eval results
Files

rule-system.mddocs/

Rule System

The Rule System provides comprehensive infrastructure for defining, configuring, and executing static analysis rules. It includes rule interfaces, collection management, priority handling, loading mechanisms, and property-based configuration.

Capabilities

Rule Interface

Core interface for PMD rules with configuration, execution, and lifecycle management capabilities.

/**
 * Core interface for PMD rules with configuration and execution capabilities.
 * Extends PropertySource to support configurable properties.
 */
public interface Rule extends PropertySource {
    
    /**
     * Suppress violations by regex pattern property descriptor
     */
    PropertyDescriptor<Optional<Pattern>> VIOLATION_SUPPRESS_REGEX_DESCRIPTOR;
    
    /**
     * Suppress violations by XPath expression property descriptor
     */
    PropertyDescriptor<Optional<String>> VIOLATION_SUPPRESS_XPATH_DESCRIPTOR;
    
    /**
     * Get rule's target language
     * @return Language this rule analyzes
     */
    Language getLanguage();
    
    /**
     * Set rule's target language
     * @param language Language for this rule to analyze
     */
    void setLanguage(Language language);
    
    /**
     * Get minimum language version required by rule
     * @return Minimum LanguageVersion, or null if no minimum
     */
    LanguageVersion getMinimumLanguageVersion();
    
    /**
     * Set minimum language version required
     * @param version Minimum LanguageVersion required
     */
    void setMinimumLanguageVersion(LanguageVersion version);
    
    /**
     * Get maximum language version supported by rule
     * @return Maximum LanguageVersion, or null if no maximum
     */
    LanguageVersion getMaximumLanguageVersion();
    
    /**
     * Set maximum language version supported
     * @param version Maximum LanguageVersion supported
     */
    void setMaximumLanguageVersion(LanguageVersion version);
    
    /**
     * Check if rule is deprecated
     * @return true if rule is marked as deprecated
     */
    boolean isDeprecated();
    
    /**
     * Set deprecation status
     * @param deprecated true to mark rule as deprecated
     */
    void setDeprecated(boolean deprecated);
    
    /**
     * Get rule name (unique identifier within ruleset)
     * @return Name of the rule
     */
    String getName();
    
    /**
     * Set rule name
     * @param name Unique name for the rule
     */
    void setName(String name);
    
    /**
     * Get PMD version when rule was added
     * @return Version string when rule was introduced
     */
    String getSince();
    
    /**
     * Set PMD version when rule was added
     * @param since Version string when rule was introduced
     */
    void setSince(String since);
    
    /**
     * Get rule implementation class name
     * @return Fully qualified class name of rule implementation
     */
    String getRuleClass();
    
    /**
     * Set rule implementation class name
     * @param ruleClass Fully qualified class name
     */
    void setRuleClass(String ruleClass);
    
    /**
     * Get violation message template
     * @return Message template for violations (may contain {0} placeholders)
     */
    String getMessage();
    
    /**
     * Set violation message template
     * @param message Template for violation messages
     */
    void setMessage(String message);
    
    /**
     * Get rule description
     * @return Detailed description of what rule checks
     */
    String getDescription();
    
    /**
     * Set rule description
     * @param description Detailed description of rule purpose
     */
    void setDescription(String description);
    
    /**
     * Get external documentation URL
     * @return URL to external documentation, or null
     */
    String getExternalInfoUrl();
    
    /**
     * Set external documentation URL
     * @param externalInfoUrl URL to external documentation
     */
    void setExternalInfoUrl(String externalInfoUrl);
    
    /**
     * Get rule priority level
     * @return RulePriority indicating severity/importance
     */
    RulePriority getPriority();
    
    /**
     * Set rule priority level
     * @param priority RulePriority for violation severity
     */
    void setPriority(RulePriority priority);
    
    /**
     * Check if rule uses Data Flow Analysis (DFA)
     * @return true if rule requires DFA processing
     */
    boolean isDfa();
    
    /**
     * Enable/disable Data Flow Analysis
     * @param dfa true to enable DFA processing for this rule
     */
    void setDfa(boolean dfa);
    
    /**
     * Check if rule uses type resolution
     * @return true if rule requires type information
     */
    boolean isTypeResolution();
    
    /**
     * Enable/disable type resolution
     * @param typeResolution true to enable type resolution for this rule
     */
    void setTypeResolution(boolean typeResolution);
    
    /**
     * Check if rule processes multiple files
     * @return true if rule analyzes across multiple files
     */
    boolean usesMultifile();
    
    /**
     * Set multifile processing capability
     * @param multifile true if rule should process multiple files
     */
    void setMultifile(boolean multifile);
    
    /**
     * Create deep copy of rule with all properties
     * @return Independent copy of this rule
     */
    Rule deepCopy();
    
    /**
     * Apply rule to AST node within rule context
     * @param target AST node to analyze
     * @param ctx RuleContext for violation reporting
     */
    void apply(Node target, RuleContext ctx);
}

Usage Examples:

import net.sourceforge.pmd.lang.rule.*;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.properties.*;

// Example custom rule implementation
public class MyCustomRule extends AbstractRule {
    
    private static final PropertyDescriptor<Integer> THRESHOLD_DESCRIPTOR =
        PropertyFactory.intProperty("threshold")
            .desc("Maximum allowed complexity")
            .defaultValue(10)
            .build();
    
    public MyCustomRule() {
        definePropertyDescriptor(THRESHOLD_DESCRIPTOR);
        setName("MyCustomRule");
        setMessage("Complexity {0} exceeds threshold {1}");
        setDescription("Detects overly complex code structures");
        setPriority(RulePriority.MEDIUM);
        setLanguage(LanguageRegistry.getLanguage("java"));
    }
    
    @Override
    public void apply(Node target, RuleContext ctx) {
        int threshold = getProperty(THRESHOLD_DESCRIPTOR);
        
        int complexity = calculateComplexity(target);
        if (complexity > threshold) {
            ctx.addViolation(target, complexity, threshold);
        }
    }
    
    private int calculateComplexity(Node node) {
        // Custom complexity calculation logic
        return node.getNumChildren() + 1;
    }
}

// Configuring rule properties programmatically
Rule rule = new MyCustomRule();
rule.setProperty(MyCustomRule.THRESHOLD_DESCRIPTOR, 15);
rule.setPriority(RulePriority.HIGH);
rule.setMessage("Custom message: complexity {0} is too high");

// Creating rule copy with modifications
Rule ruleCopy = rule.deepCopy();
ruleCopy.setName("MyCustomRuleVariant");
ruleCopy.setPriority(RulePriority.LOW);

RuleSet Collection

Collection of rules with optional file filtering patterns and metadata management.

/**
 * Collection of rules with optional file filtering patterns.
 * Implements ChecksumAware for caching support.
 */
public class RuleSet implements ChecksumAware {
    
    /**
     * Copy constructor
     * @param rs RuleSet to copy
     */
    RuleSet(RuleSet rs);
    
    /**
     * Create ruleset containing single rule
     * @param rule Single rule for the ruleset
     * @return RuleSet containing only the specified rule
     */
    static RuleSet forSingleRule(Rule rule);
    
    /**
     * Create new ruleset builder for programmatic construction
     * @return RuleSetBuilder for fluent ruleset creation
     */
    static RuleSetBuilder create();
    
    /**
     * Get source filename where ruleset was defined
     * @return Filename of ruleset definition, or null if programmatic
     */
    String getFileName();
    
    /**
     * Get ruleset name
     * @return Name of the ruleset
     */
    String getName();
    
    /**
     * Get ruleset description
     * @return Description of ruleset purpose and contents
     */
    String getDescription();
    
    /**
     * Get all rules in set
     * @return Unmodifiable list of rules
     */
    List<Rule> getRules();
    
    /**
     * Get rule by name
     * @param ruleName Name of rule to find
     * @return Rule with matching name, or null if not found
     */
    Rule getRuleByName(String ruleName);
    
    /**
     * Check if ruleset applies to specific file
     * @param file FileId to check against include/exclude patterns
     * @return true if ruleset should be applied to file
     */
    boolean applies(FileId file);
    
    /**
     * Check if ruleset applies to language version
     * @param languageVersion LanguageVersion to check compatibility
     * @return true if ruleset contains rules for language version
     */
    boolean applies(LanguageVersion languageVersion);
    
    /**
     * Get checksum for caching and change detection
     * @return Checksum representing current ruleset state
     */
    long getChecksum();
    
    /**
     * Get number of rules in set
     * @return Count of rules
     */
    int size();
    
    /**
     * Iterate over rules in set
     * @return Iterator for rules
     */
    Iterator<Rule> iterator();
}

Usage Examples:

import net.sourceforge.pmd.lang.rule.*;
import java.util.Arrays;

// Creating ruleset from single rule
Rule customRule = new MyCustomRule();
RuleSet singleRuleSet = RuleSet.forSingleRule(customRule);

// Building ruleset programmatically
RuleSet programmaticRuleSet = RuleSet.create()
    .withName("Custom Analysis Rules")
    .withDescription("Rules for custom static analysis")
    .addRule(new MyCustomRule())
    .addRule(new AnotherCustomRule())
    .build();

// Working with loaded ruleset
RuleSetLoader loader = analysis.newRuleSetLoader();
RuleSet javaRules = loader.loadFromResource("rulesets/java/quickstart.xml");

System.out.printf("Loaded %d rules from %s%n", 
    javaRules.size(), 
    javaRules.getName());

// Check rule applicability
FileId javaFile = FileId.fromPathLikeString("src/main/java/Example.java");
if (javaRules.applies(javaFile)) {
    System.out.println("Ruleset applies to Java files");
}

// Find specific rule
Rule specificRule = javaRules.getRuleByName("UnusedPrivateField");
if (specificRule != null) {
    System.out.printf("Found rule: %s - %s%n", 
        specificRule.getName(), 
        specificRule.getDescription());
}

// Iterate through rules
for (Rule rule : javaRules) {
    System.out.printf("Rule: %s (Priority: %s)%n", 
        rule.getName(), 
        rule.getPriority().getName());
}

RuleSet Loading

Comprehensive ruleset loading from various sources including files, resources, URLs, and programmatic construction.

/**
 * Loads rulesets from various sources with filtering and configuration options.
 */
public final class RuleSetLoader {
    
    /**
     * Create RuleSetLoader from PMD configuration
     * @param configuration PMDConfiguration with loading settings
     * @return Configured RuleSetLoader instance
     */
    static RuleSetLoader fromPmdConfig(PMDConfiguration configuration);
    
    /**
     * Load ruleset from resource path, file, or URL
     * @param ruleSetReferenceId Resource path, file path, or URL to ruleset
     * @return Loaded RuleSet with all rules and configurations
     * @throws RuleSetLoadException if loading fails
     */
    RuleSet loadFromResource(String ruleSetReferenceId);
    
    /**
     * Load multiple rulesets from list of references
     * @param ruleSetReferenceIds List of resource paths, file paths, or URLs
     * @return List of loaded RuleSet instances
     * @throws RuleSetLoadException if any loading fails
     */
    List<RuleSet> loadFromResources(List<String> ruleSetReferenceIds);
    
    /**
     * Create new ruleset builder for programmatic construction
     * @return RuleSetBuilder for creating custom rulesets
     */
    RuleSetBuilder newRuleSetBuilder();
    
    /**
     * Enable compatibility mode for legacy rulesets
     * @param enable true to enable compatibility processing
     * @return Previous compatibility mode setting
     */
    boolean enableCompatibility(boolean enable);
    
    /**
     * Create filtered loader that only loads rules above priority threshold
     * @param minimumPriority Minimum RulePriority to include
     * @return New RuleSetLoader with priority filtering
     */
    RuleSetLoader filterAbovePriority(RulePriority minimumPriority);
    
    /**
     * Get exceptions that occurred during loading
     * @return List of RuleSetLoadException for failed loads
     */
    List<RuleSetLoadException> getLoadExceptions();
}

Usage Examples:

import net.sourceforge.pmd.lang.rule.*;
import java.util.Arrays;
import java.util.List;

// Create loader from configuration
PMDConfiguration config = new PMDConfiguration();
RuleSetLoader loader = RuleSetLoader.fromPmdConfig(config);

// Load single ruleset
try {
    RuleSet javaQuickstart = loader.loadFromResource("rulesets/java/quickstart.xml");
    System.out.printf("Loaded %d rules%n", javaQuickstart.size());
} catch (RuleSetLoadException e) {
    System.err.println("Failed to load ruleset: " + e.getMessage());
}

// Load multiple rulesets
List<String> rulesetPaths = Arrays.asList(
    "rulesets/java/quickstart.xml",
    "rulesets/java/design.xml",
    "rulesets/java/errorprone.xml",
    "custom-rules.xml",
    "https://example.com/remote-rules.xml"
);

try {
    List<RuleSet> ruleSets = loader.loadFromResources(rulesetPaths);
    int totalRules = ruleSets.stream().mapToInt(RuleSet::size).sum();
    System.out.printf("Loaded %d rulesets with %d total rules%n", 
        ruleSets.size(), totalRules);
} catch (RuleSetLoadException e) {
    System.err.println("Failed to load some rulesets: " + e.getMessage());
}

// Filter rules by priority
RuleSetLoader highPriorityLoader = loader.filterAbovePriority(RulePriority.MEDIUM);
RuleSet filteredRules = highPriorityLoader.loadFromResource("rulesets/java/quickstart.xml");

// Check for loading exceptions
List<RuleSetLoadException> exceptions = loader.getLoadExceptions();
if (!exceptions.isEmpty()) {
    System.err.println("Loading issues occurred:");
    for (RuleSetLoadException exception : exceptions) {
        System.err.printf("  %s: %s%n", exception.getLocation(), exception.getMessage());
    }
}

// Build custom ruleset
RuleSetBuilder builder = loader.newRuleSetBuilder();
RuleSet customRuleSet = builder
    .withName("Custom Project Rules")
    .withDescription("Rules specific to our project")
    .addRule(new MyCustomRule())
    .addRuleByReference("rulesets/java/design.xml/CyclomaticComplexity")
    .build();

Rule Priority System

Enumeration defining rule priority levels from HIGH to LOW with utility methods for comparison and conversion.

/**
 * Rule priority levels from HIGH (most important) to LOW (least important).
 * Used for filtering rules and determining violation severity.
 */
public enum RulePriority {
    
    /** Highest priority - critical issues */
    HIGH(1),
    
    /** Medium-high priority - important issues */
    MEDIUM_HIGH(2),
    
    /** Medium priority - standard issues */
    MEDIUM(3),
    
    /** Medium-low priority - minor issues */
    MEDIUM_LOW(4),
    
    /** Lowest priority - informational issues */
    LOW(5);
    
    /**
     * Get numeric priority value (lower numbers = higher priority)
     * @return Numeric priority (1-5)
     */
    int getPriority();
    
    /**
     * Get priority name as string
     * @return String representation of priority level
     */
    String getName();
    
    /**
     * Get RulePriority by numeric value
     * @param priority Numeric priority (1-5)
     * @return RulePriority corresponding to numeric value
     * @throws IllegalArgumentException if priority not in valid range
     */
    static RulePriority valueOf(int priority);
    
    /**
     * Get RulePriority by name (case-insensitive)
     * @param name Priority name (HIGH, MEDIUM, LOW, etc.)
     * @return RulePriority corresponding to name
     * @throws IllegalArgumentException if name not recognized
     */
    static RulePriority valueOfName(String name);
}

Usage Examples:

import net.sourceforge.pmd.lang.rule.RulePriority;

// Working with rule priorities
RulePriority high = RulePriority.HIGH;
System.out.printf("Priority %s has numeric value %d%n", 
    high.getName(), high.getPriority());

// Creating priorities from values
RulePriority medium = RulePriority.valueOf(3);
RulePriority low = RulePriority.valueOfName("LOW");

// Comparing priorities
if (RulePriority.HIGH.getPriority() < RulePriority.LOW.getPriority()) {
    System.out.println("HIGH priority has lower numeric value than LOW");
}

// Using priorities in rule configuration
Rule rule = new MyCustomRule();
rule.setPriority(RulePriority.MEDIUM_HIGH);

// Filtering by priority in configuration
PMDConfiguration config = new PMDConfiguration();
config.setMinimumPriority(RulePriority.MEDIUM);  // Only MEDIUM+ priority rules

// Priority-based rule filtering
RuleSetLoader loader = RuleSetLoader.fromPmdConfig(config);
RuleSetLoader highPriorityLoader = loader.filterAbovePriority(RulePriority.MEDIUM_HIGH);

// Setting priorities programmatically for different environments
if (isProductionBuild()) {
    config.setMinimumPriority(RulePriority.HIGH);
} else if (isDevelopmentBuild()) {
    config.setMinimumPriority(RulePriority.LOW);
} else {
    config.setMinimumPriority(RulePriority.MEDIUM);
}

Types

/**
 * Builder for constructing RuleSet instances programmatically
 */
interface RuleSetBuilder {
    RuleSetBuilder withName(String name);
    RuleSetBuilder withDescription(String description);
    RuleSetBuilder addRule(Rule rule);
    RuleSetBuilder addRuleByReference(String ruleReference);
    RuleSetBuilder filterRules(Predicate<Rule> filter);
    RuleSet build();
}

/**
 * Context for rule execution providing violation reporting capabilities
 */
interface RuleContext {
    void addViolation(Node node);
    void addViolation(Node node, Object... args);
    void addViolationWithMessage(Node node, String message);
    LanguageVersion getLanguageVersion();
    String getFilename();
    TextDocument getTextDocument();
    boolean isIgnored(Rule rule);
}

/**
 * Exception thrown when ruleset loading fails
 */
class RuleSetLoadException extends Exception {
    String getLocation();
    String getCause();
    List<String> getErrors();
}

/**
 * Interface for objects that can compute checksums for caching
 */
interface ChecksumAware {
    long getChecksum();
}

/**
 * File identifier for tracking files across analysis
 */
interface FileId {
    String getAbsolutePath();
    String getDisplayName();
    URI getUri();
    static FileId fromPathLikeString(String pathLike);
    static FileId fromPath(Path path);
}

/**
 * Language version representing specific version of programming language
 */
interface LanguageVersion extends Comparable<LanguageVersion> {
    Language getLanguage();
    String getVersion();
    String getName();
    String getShortName();
    String getTerseName();
}

/**
 * Abstract base class for rule implementations
 */
abstract class AbstractRule implements Rule {
    protected void definePropertyDescriptor(PropertyDescriptor<?> propertyDescriptor);
    protected void addRuleChainVisit(String astNodeName);
    protected void addRuleChainVisit(Class<? extends Node> nodeType);
}

Install with Tessl CLI

npx tessl i tessl/maven-net-sourceforge-pmd--pmd-core

docs

ast-processing.md

copy-paste-detection.md

core-analysis.md

index.md

language-framework.md

properties-system.md

rendering-system.md

reporting-system.md

rule-system.md

utilities.md

tile.json