/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd; import java.util.HashMap; import java.util.List; import java.util.Map; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.rule.RuleChainVisitor; /** * The RuleChain is a means by which Rules can participate in a uniform * visitation of the AST, and not need perform their own independent visitation. * The RuleChain exists as a means to improve the speed of PMD when there are * many Rules. */ public class RuleChain { // Mapping from Language to RuleChainVisitor private final Map<Language, RuleChainVisitor> languageToRuleChainVisitor = new HashMap<>(); /** * Add all Rules from the given RuleSet which want to participate in the * RuleChain. * * @param ruleSet * The RuleSet to add Rules from. */ public void add(RuleSet ruleSet) { for (Rule r : ruleSet.getRules()) { add(ruleSet, r); } } /** * Add the given Rule if it wants to participate in the RuleChain. * * @param ruleSet * The RuleSet to which the rule belongs. * @param rule * The Rule to add. */ private void add(RuleSet ruleSet, Rule rule) { RuleChainVisitor visitor = getRuleChainVisitor(rule.getLanguage()); if (visitor != null) { visitor.add(ruleSet, rule); } } /** * Apply the RuleChain to the given Nodes using the given RuleContext, for * those rules using the given Language. * * @param nodes * The Nodes. * @param ctx * The RuleContext. * @param language * The Language. */ public void apply(List<Node> nodes, RuleContext ctx, Language language) { RuleChainVisitor visitor = getRuleChainVisitor(language); if (visitor != null) { visitor.visitAll(nodes, ctx); } } // Get the RuleChainVisitor for the appropriate Language. private RuleChainVisitor getRuleChainVisitor(Language language) { RuleChainVisitor visitor = languageToRuleChainVisitor.get(language); if (visitor == null) { if (language.getRuleChainVisitorClass() != null) { try { visitor = (RuleChainVisitor) language.getRuleChainVisitorClass().newInstance(); } catch (InstantiationException e) { throw new IllegalStateException( "Failure to created RuleChainVisitor: " + language.getRuleChainVisitorClass(), e); } catch (IllegalAccessException e) { throw new IllegalStateException( "Failure to created RuleChainVisitor: " + language.getRuleChainVisitorClass(), e); } languageToRuleChainVisitor.put(language, visitor); } else { throw new IllegalArgumentException("Language does not have a RuleChainVisitor: " + language); } } return visitor; } }