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

pmd / pmd / 196

16 Oct 2025 08:33AM UTC coverage: 78.642% (-0.02%) from 78.661%
196

push

github

web-flow
chore: fix dogfood issues from new rules (#6056)

18180 of 23973 branches covered (75.84%)

Branch coverage included in aggregate %.

2 of 27 new or added lines in 14 files covered. (7.41%)

2 existing lines in 1 file now uncovered.

39693 of 49617 relevant lines covered (80.0%)

0.81 hits per line

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

96.83
/pmd-core/src/main/java/net/sourceforge/pmd/renderers/internal/sarif/SarifLogBuilder.java
1
/*
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.renderers.internal.sarif;
6

7
import java.util.ArrayList;
8
import java.util.Arrays;
9
import java.util.Collections;
10
import java.util.HashSet;
11
import java.util.List;
12

13
import net.sourceforge.pmd.PMDVersion;
14
import net.sourceforge.pmd.lang.rule.RulePriority;
15
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ArtifactLocation;
16
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.AssociatedRule;
17
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Component;
18
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Exception;
19
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Invocation;
20
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Location;
21
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Message;
22
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.MultiformatMessage;
23
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.PhysicalLocation;
24
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.PropertyBag;
25
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Region;
26
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ReportingConfiguration;
27
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ReportingDescriptor;
28
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Result;
29
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Run;
30
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Tool;
31
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ToolConfigurationNotification;
32
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ToolExecutionNotification;
33
import net.sourceforge.pmd.reporting.Report;
34
import net.sourceforge.pmd.reporting.RuleViolation;
35
import net.sourceforge.pmd.util.AssertionUtil;
36

37
public class SarifLogBuilder {
1✔
38
    private final List<ReportingDescriptor> rules = new ArrayList<>();
1✔
39
    private final List<Result> results = new ArrayList<>();
1✔
40
    private final List<ToolConfigurationNotification> toolConfigurationNotifications = new ArrayList<>();
1✔
41
    private final List<ToolExecutionNotification> toolExecutionNotifications = new ArrayList<>();
1✔
42

43
    public static SarifLogBuilder sarifLogBuilder() {
44
        return new SarifLogBuilder();
1✔
45
    }
46

47
    public SarifLogBuilder add(RuleViolation violation) {
48
        final ReportingDescriptor ruleDescriptor = getReportingDescriptor(violation);
1✔
49
        int ruleIndex = rules.indexOf(ruleDescriptor);
1✔
50
        if (ruleIndex == -1) {
1✔
51
            rules.add(ruleDescriptor);
1✔
52
            ruleIndex = rules.size() - 1;
1✔
53
        }
54

55
        final Location location = getRuleViolationLocation(violation);
1✔
56
        final Result result = resultFrom(ruleDescriptor, ruleIndex, location, violation.getRule().getPriority());
1✔
57
        results.add(result);
1✔
58

59
        return this;
1✔
60
    }
61

62
    public SarifLogBuilder addRunTimeError(Report.ProcessingError error) {
63
        ArtifactLocation artifactLocation = ArtifactLocation.builder()
1✔
64
                .uri(error.getFileId().getUriString())
1✔
65
                .build();
1✔
66

67
        PhysicalLocation physicalLocation = PhysicalLocation.builder()
1✔
68
                .artifactLocation(artifactLocation)
1✔
69
                .build();
1✔
70

71
        Location location = Location
72
                .builder()
1✔
73
                .physicalLocation(physicalLocation)
1✔
74
                .build();
1✔
75

76
        Message message = Message.builder()
1✔
77
                .text(error.getMsg())
1✔
78
                .build();
1✔
79

80
        Exception exception = Exception.builder()
1✔
81
                .message(error.getDetail())
1✔
82
                .build();
1✔
83

84
        ToolExecutionNotification toolExecutionNotification = ToolExecutionNotification.builder()
1✔
85
                .locations(Collections.singletonList(location))
1✔
86
                .message(message)
1✔
87
                .exception(exception)
1✔
88
                .build();
1✔
89

90
        toolExecutionNotifications.add(toolExecutionNotification);
1✔
91

92
        return this;
1✔
93
    }
94

95
    public SarifLogBuilder addConfigurationError(Report.ConfigurationError error) {
96
        AssociatedRule associatedRule = AssociatedRule.builder()
1✔
97
                .id(error.rule().getName())
1✔
98
                .build();
1✔
99

100
        Message message = Message.builder().text(error.issue()).build();
1✔
101

102
        ToolConfigurationNotification toolConfigurationNotification = ToolConfigurationNotification.builder()
1✔
103
                .associatedRule(associatedRule)
1✔
104
                .message(message)
1✔
105
                .build();
1✔
106

107
        toolConfigurationNotifications.add(toolConfigurationNotification);
1✔
108

109
        return this;
1✔
110
    }
111

112
    public SarifLog build() {
113
        final Component driver = getDriverComponent().toBuilder().rules(rules).build();
1✔
114
        final Tool tool = Tool.builder().driver(driver).build();
1✔
115
        final Invocation invocation = Invocation.builder()
1✔
116
                .toolExecutionNotifications(toolExecutionNotifications)
1✔
117
                .toolConfigurationNotifications(toolConfigurationNotifications)
1✔
118
                .executionSuccessful(isExecutionSuccessful())
1✔
119
                .build();
1✔
120
        final Run run = Run.builder()
1✔
121
                .tool(tool)
1✔
122
                .results(results)
1✔
123
                .invocations(Collections.singletonList(invocation))
1✔
124
                .build();
1✔
125

126
        List<Run> runs = Collections.singletonList(run);
1✔
127

128
        return SarifLog.builder().runs(runs).build();
1✔
129
    }
130

131
    private boolean isExecutionSuccessful() {
132
        return toolExecutionNotifications.isEmpty() && toolConfigurationNotifications.isEmpty();
1✔
133
    }
134

135
    private Result resultFrom(ReportingDescriptor rule, Integer ruleIndex, Location location, RulePriority rulePriority) {
136
        final Result result = Result.builder()
1✔
137
                .ruleId(rule.getId())
1✔
138
                .ruleIndex(ruleIndex)
1✔
139
                .level(pmdPriorityToSarifSeverityLevel(rulePriority))
1✔
140
                .build();
1✔
141

142
        final Message message = Message.builder()
1✔
143
                .text(rule.getShortDescription().getText())
1✔
144
                .build();
1✔
145

146
        result.setMessage(message);
1✔
147
        result.setLocations(Collections.singletonList(location));
1✔
148

149
        return result;
1✔
150
    }
151

152
    private Location getRuleViolationLocation(RuleViolation rv) {
153
        ArtifactLocation artifactLocation = ArtifactLocation.builder()
1✔
154
                .uri(rv.getFileId().getUriString())
1✔
155
                .build();
1✔
156

157
        Region region = Region.builder()
1✔
158
            .startLine(rv.getBeginLine())
1✔
159
            .endLine(rv.getEndLine())
1✔
160
            .startColumn(rv.getBeginColumn())
1✔
161
            .endColumn(rv.getEndColumn())
1✔
162
            .build();
1✔
163

164
        PhysicalLocation physicalLocation = PhysicalLocation.builder()
1✔
165
                .artifactLocation(artifactLocation)
1✔
166
                .region(region)
1✔
167
                .build();
1✔
168

169
        return Location.builder()
1✔
170
            .physicalLocation(physicalLocation)
1✔
171
            .build();
1✔
172
    }
173

174
    private ReportingDescriptor getReportingDescriptor(RuleViolation rv) {
175
        return ReportingDescriptor.builder()
1✔
176
            .id(rv.getRule().getName())
1✔
177
            .shortDescription(new MultiformatMessage(rv.getDescription()))
1✔
178
            .fullDescription(new MultiformatMessage(rv.getRule().getDescription()))
1✔
179
            .helpUri(rv.getRule().getExternalInfoUrl())
1✔
180
            .help(new MultiformatMessage(rv.getRule().getDescription()))
1✔
181
            .properties(getRuleProperties(rv))
1✔
182
            .defaultConfiguration(getDefaultConfigForRuleViolation(rv))
1✔
183
            .build();
1✔
184
    }
185

186
    private ReportingConfiguration getDefaultConfigForRuleViolation(RuleViolation rv) {
187
        return ReportingConfiguration.builder()
1✔
188
                // get pmd level from rv and translate it to sarif level (for the config)
189
                .level(pmdPriorityToSarifSeverityLevel(rv.getRule().getPriority()))
1✔
190
                .build();
1✔
191
    }
192

193
    private PropertyBag getRuleProperties(RuleViolation rv) {
194
        return PropertyBag.builder()
1✔
195
                .ruleset(rv.getRule().getRuleSetName())
1✔
196
                .priority(rv.getRule().getPriority().getPriority())
1✔
197
                .tags(new HashSet<>(Arrays.asList(rv.getRule().getRuleSetName())))
1✔
198
                .build();
1✔
199
    }
200

201
    private Component getDriverComponent() {
202
        return Component.builder()
1✔
203
                .name("PMD")
1✔
204
                .version(PMDVersion.VERSION)
1✔
205
                .informationUri("https://docs.pmd-code.org/latest/")
1✔
206
                .build();
1✔
207
    }
208

209

210
    /**
211
     * Converts PMD's rule priority into the corresponding Sarif severity level.
212
     * @param rulePriority of a rule violation.
213
     * @return sarif's severity level.
214
     * @see net.sourceforge.pmd.lang.rule.RulePriority
215
     */
216
    private String pmdPriorityToSarifSeverityLevel(RulePriority rulePriority) {
217
        switch (rulePriority) {
1!
218
        case HIGH:
219
        case MEDIUM_HIGH:
220
            return "error";
1✔
221
        case MEDIUM:
222
            return "warning";
×
223
        case MEDIUM_LOW:
224
        case LOW:
225
            return "note";
1✔
226
        }
227
        // should not occur, above switch is exhaustive
NEW
228
        throw AssertionUtil.shouldNotReachHere("invalid rule priority " + rulePriority);
×
229
    }
230
}
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