• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / #3786

pending completion
#3786

push

github actions

web-flow
Merge pull request #4370 from Monits/rule-improvements

[java] Rule improvements

5 of 5 new or added lines in 2 files covered. (100.0%)

67060 of 127680 relevant lines covered (52.52%)

0.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/internal/RuleApplicator.java
1
/*
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.lang.rule.internal;
6

7
import java.util.Collection;
8
import java.util.Iterator;
9

10
import org.apache.commons.lang3.exception.ExceptionContext;
11
import org.slf4j.Logger;
12
import org.slf4j.LoggerFactory;
13

14
import net.sourceforge.pmd.Report.ProcessingError;
15
import net.sourceforge.pmd.Rule;
16
import net.sourceforge.pmd.RuleContext;
17
import net.sourceforge.pmd.RuleSet;
18
import net.sourceforge.pmd.benchmark.TimeTracker;
19
import net.sourceforge.pmd.benchmark.TimedOperation;
20
import net.sourceforge.pmd.benchmark.TimedOperationCategory;
21
import net.sourceforge.pmd.internal.SystemProps;
22
import net.sourceforge.pmd.lang.LanguageVersion;
23
import net.sourceforge.pmd.lang.ast.Node;
24
import net.sourceforge.pmd.lang.ast.RootNode;
25
import net.sourceforge.pmd.reporting.FileAnalysisListener;
26
import net.sourceforge.pmd.util.AssertionUtil;
27
import net.sourceforge.pmd.util.StringUtil;
28

29
/** Applies a set of rules to a set of ASTs. */
30
public class RuleApplicator {
31

32
    private static final Logger LOG = LoggerFactory.getLogger(RuleApplicator.class);
1✔
33
    // we reuse the type lattice from run to run, eventually it converges
34
    // towards the final topology (all node types have been encountered)
35
    // This has excellent performance! Indexing time is insignificant
36
    // compared to rule application for any non-trivial ruleset. Even
37
    // when you use a single rule, indexing time is insignificant compared
38
    // to eg type resolution.
39

40
    private final TreeIndex idx;
41
    private LanguageVersion currentLangVer;
42

43
    public RuleApplicator(TreeIndex index) {
1✔
44
        this.idx = index;
1✔
45
    }
1✔
46

47

48
    public void index(RootNode root) {
49
        idx.reset();
1✔
50
        indexTree(root, idx);
1✔
51
        currentLangVer = root.getLanguageVersion();
1✔
52
    }
1✔
53

54
    public void apply(Collection<? extends Rule> rules, FileAnalysisListener listener) {
55
        applyOnIndex(idx, rules, listener);
1✔
56
    }
1✔
57

58
    private void applyOnIndex(TreeIndex idx, Collection<? extends Rule> rules, FileAnalysisListener listener) {
59
        for (Rule rule : rules) {
1✔
60
            if (!RuleSet.applies(rule, currentLangVer)) {
1✔
61
                continue; // No point in even trying to apply the rule
×
62
            }
63
            
64
            RuleContext ctx = RuleContext.create(listener, rule);
1✔
65
            rule.start(ctx);
1✔
66
            try (TimedOperation rcto = TimeTracker.startOperation(TimedOperationCategory.RULE, rule.getName())) {
1✔
67

68
                int nodeCounter = 0;
1✔
69
                Iterator<? extends Node> targets = rule.getTargetSelector().getVisitedNodes(idx);
1✔
70
                while (targets.hasNext()) {
1✔
71
                    Node node = targets.next();
1✔
72

73
                    try {
74
                        nodeCounter++;
1✔
75
                        rule.apply(node, ctx);
1✔
76
                    } catch (RuntimeException e) {
1✔
77
                        reportOrRethrow(listener, rule, node, AssertionUtil.contexted(e), true);
1✔
78
                    } catch (StackOverflowError e) {
×
79
                        reportOrRethrow(listener, rule, node, AssertionUtil.contexted(e), SystemProps.isErrorRecoveryMode());
×
80
                    } catch (AssertionError e) {
1✔
81
                        reportOrRethrow(listener, rule, node, AssertionUtil.contexted(e), SystemProps.isErrorRecoveryMode());
1✔
82
                    }
1✔
83
                }
1✔
84
                
85
                rcto.close(nodeCounter);
1✔
86
            } finally {
87
                rule.end(ctx);
1✔
88
            }
89
        }
1✔
90
    }
1✔
91

92

93
    private <E extends Throwable> void reportOrRethrow(FileAnalysisListener listener, Rule rule, Node node, E e, boolean reportAndDontThrow) throws E {
94
        if (e instanceof ExceptionContext) {
1✔
95
            ((ExceptionContext) e).addContextValue("Rule applied on node", node);
1✔
96
        }
97

98
        if (reportAndDontThrow) {
1✔
99
            reportException(listener, rule, node, e);
1✔
100
        } else {
101
            throw e;
1✔
102
        }
103
    }
1✔
104

105

106
    private void reportException(FileAnalysisListener listener, Rule rule, Node node, Throwable e) {
107
        // The listener handles logging if needed,
108
        // it may also rethrow the error.
109
        listener.onError(new ProcessingError(e, node.getTextDocument().getDisplayName()));
1✔
110

111
        // fixme - maybe duplicated logging
112
        LOG.warn("Exception applying rule {} on file {}, continuing with next rule", rule.getName(), node.getTextDocument().getPathId(), e);
1✔
113
        String nodeToString = StringUtil.elide(node.toString(), 600, " ... (truncated)");
1✔
114
        LOG.warn("Exception occurred on node {}", nodeToString);
1✔
115
    }
1✔
116

117

118
    private void indexTree(Node top, TreeIndex idx) {
119
        idx.indexNode(top);
1✔
120
        for (Node child : top.children()) {
1✔
121
            indexTree(child, idx);
×
122
        }
×
123
    }
1✔
124

125
    public static RuleApplicator build(Iterable<? extends Rule> rules) {
126
        TargetSelectorInternal.ApplicatorBuilder builder = new TargetSelectorInternal.ApplicatorBuilder();
1✔
127
        for (Rule it : rules) {
1✔
128
            it.getTargetSelector().prepare(builder);
1✔
129
        }
1✔
130
        return builder.build();
1✔
131
    }
132

133
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc