Skip to content

Commit 26ca686

Browse files
author
Jim Verheijde
committed
Bump PMD to 7.8.0
- Bump the pmd dependency from 6.0.0 to the latest version 7.8.0. - This is needed in particular for Java 21 support. - Changed the PmdProcessor to be compatible with the new PMD 7.8.0 version. - For PMD we now just use the PmdAnalysis class to perform the PMD checks based on our PMDConfiguration, giving back the Report. - Therefore, we don't need to do our own manual CollectorRenderer anymore, so that is now removed. - Note that the rulesets have changed to be category based in the test properties, this will also need to be updated in the properties of end users.
1 parent 17d84ff commit 26ca686

File tree

6 files changed

+85
-280
lines changed

6 files changed

+85
-280
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ dependencies {
8484
}
8585

8686
// PMD dependencies
87-
implementation('net.sourceforge.pmd:pmd-java:6.0.0') {
87+
implementation('net.sourceforge.pmd:pmd-java:7.8.0') {
8888
exclude group: 'jaxen'
8989
exclude group: 'xerces'
9090
exclude group: 'junit'

src/main/java/pl/touk/sputnik/processor/pmd/CollectorRenderer.java

Lines changed: 0 additions & 102 deletions
This file was deleted.
Lines changed: 81 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,41 @@
11
package pl.touk.sputnik.processor.pmd;
22

3-
import com.google.common.base.Joiner;
43
import lombok.extern.slf4j.Slf4j;
5-
import net.sourceforge.pmd.PMD;
64
import net.sourceforge.pmd.PMDConfiguration;
7-
import net.sourceforge.pmd.Rule;
8-
import net.sourceforge.pmd.RuleContext;
9-
import net.sourceforge.pmd.RuleSet;
10-
import net.sourceforge.pmd.RuleSetFactory;
11-
import net.sourceforge.pmd.RuleSets;
12-
import net.sourceforge.pmd.RulesetsFactoryUtils;
13-
import net.sourceforge.pmd.benchmark.Benchmark;
14-
import net.sourceforge.pmd.benchmark.Benchmarker;
15-
import net.sourceforge.pmd.lang.Language;
16-
import net.sourceforge.pmd.lang.LanguageVersion;
17-
import net.sourceforge.pmd.lang.LanguageVersionDiscoverer;
18-
import net.sourceforge.pmd.renderers.Renderer;
19-
import net.sourceforge.pmd.util.ResourceLoader;
20-
import net.sourceforge.pmd.util.datasource.DataSource;
5+
6+
import net.sourceforge.pmd.PmdAnalysis;
7+
import net.sourceforge.pmd.lang.document.FileId;
8+
import net.sourceforge.pmd.lang.rule.RulePriority;
9+
10+
import org.apache.commons.lang3.StringUtils;
2111
import org.jetbrains.annotations.NotNull;
2212
import org.jetbrains.annotations.Nullable;
13+
14+
import net.sourceforge.pmd.reporting.Report;
15+
import net.sourceforge.pmd.reporting.RuleViolation;
2316
import pl.touk.sputnik.configuration.Configuration;
2417
import pl.touk.sputnik.configuration.GeneralOption;
2518
import pl.touk.sputnik.review.Review;
2619
import pl.touk.sputnik.review.ReviewException;
2720
import pl.touk.sputnik.review.ReviewProcessor;
2821
import pl.touk.sputnik.review.ReviewResult;
22+
import pl.touk.sputnik.review.Severity;
23+
import pl.touk.sputnik.review.Violation;
2924
import pl.touk.sputnik.review.filter.PmdFilter;
3025
import pl.touk.sputnik.review.transformer.FileNameTransformer;
3126

32-
import java.io.IOException;
33-
import java.util.HashSet;
34-
import java.util.LinkedList;
27+
import java.nio.file.FileSystems;
28+
import java.nio.file.Path;
29+
import java.util.ArrayList;
30+
import java.util.Arrays;
3531
import java.util.List;
36-
import java.util.Set;
32+
import java.util.stream.Collectors;
3733

3834
@Slf4j
3935
public class PmdProcessor implements ReviewProcessor {
36+
private static final char LINE_SEPARATOR = '\n';
4037
private static final String SOURCE_NAME = "PMD";
41-
private static final char PMD_INPUT_PATH_SEPARATOR = ',';
42-
private Renderer renderer;
38+
private static final String PMD_INPUT_PATH_SEPARATOR = ",";
4339

4440
@NotNull
4541
private final Configuration config;
@@ -51,22 +47,41 @@ public PmdProcessor(Configuration configuration) {
5147
@Nullable
5248
@Override
5349
public ReviewResult process(@NotNull Review review) {
54-
List<String> filesToReview = review.getFiles(new PmdFilter(), new FileNameTransformer());
50+
List<Path> filesToReview = review.getFiles(new PmdFilter(), new FileNameTransformer()).stream()
51+
.map(file -> {
52+
Path path = FileSystems.getDefault().getPath(file);
53+
if (!path.toFile().exists()) {
54+
throw new ReviewException("File [" + file + "] does not exist");
55+
}
56+
return path;
57+
})
58+
.collect(Collectors.toList());
5559
if (filesToReview.isEmpty()) {
5660
return null;
5761
}
5862

5963
try {
6064
PMDConfiguration configuration = new PMDConfiguration();
61-
configuration.setReportFormat(CollectorRenderer.class.getCanonicalName());
6265
configuration.setRuleSets(getRulesets());
63-
configuration.setInputPaths(Joiner.on(PMD_INPUT_PATH_SEPARATOR).join(filesToReview));
64-
doPMD(configuration);
66+
configuration.setInputPathList(filesToReview);
67+
Report report = doPMD(configuration);
68+
return convertReportToReview(report);
6569
} catch (RuntimeException e) {
6670
log.error("PMD processing error. Something wrong with configuration or analyzed files are not in workspace.", e);
6771
throw new ReviewException("PMD processing error", e);
6872
}
69-
return renderer != null ? ((CollectorRenderer)renderer).getReviewResult() : null;
73+
}
74+
75+
@NotNull
76+
private ReviewResult convertReportToReview(Report report) {
77+
ReviewResult reviewResult = new ReviewResult();
78+
boolean showDetails = Boolean.parseBoolean(config.getProperty(GeneralOption.PMD_SHOW_VIOLATION_DETAILS));
79+
for (RuleViolation ruleViolation : report.getViolations()) {
80+
String violationDescription = showDetails ? renderViolationDetails(ruleViolation) :ruleViolation.getDescription();
81+
FileId myFileId = ruleViolation.getFileId();
82+
reviewResult.add(new Violation(myFileId.getOriginalPath(), ruleViolation.getBeginLine(), violationDescription, convert(ruleViolation.getRule().getPriority())));
83+
}
84+
return reviewResult;
7085
}
7186

7287
@NotNull
@@ -75,74 +90,57 @@ public String getName() {
7590
return SOURCE_NAME;
7691
}
7792

78-
@Nullable
79-
private String getRulesets() {
93+
private List<String> getRulesets() {
8094
String ruleSets = config.getProperty(GeneralOption.PMD_RULESETS);
8195
log.info("Using PMD rulesets {}", ruleSets);
82-
return ruleSets;
96+
if (ruleSets == null) {
97+
return new ArrayList<>();
98+
}
99+
return Arrays.asList(ruleSets.split(PMD_INPUT_PATH_SEPARATOR));
83100
}
84101

85102
/**
86-
* PMD has terrible design of process configuration. You must use report file with it. I paste this method here and
87-
* improve it.
103+
* Run PMD analysis
88104
*
89-
* @throws IllegalArgumentException
90-
* if the configuration is not correct
105+
* @return Report from PMD
106+
* @throws IllegalArgumentException if the configuration is not correct
91107
*/
92-
private void doPMD(@NotNull PMDConfiguration configuration) throws IllegalArgumentException {
93-
// Load the RuleSets
94-
RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.getRulesetFactory(configuration, new ResourceLoader());
95-
96-
RuleSets ruleSets = RulesetsFactoryUtils.getRuleSets(configuration.getRuleSets(), ruleSetFactory);
97-
// this is just double check - we don't get null here
98-
// instead IllegalArgumentException/RuntimeException is thrown if configuration is wrong
99-
if (ruleSets == null) {
100-
return;
108+
@NotNull
109+
private Report doPMD(@NotNull PMDConfiguration configuration) throws IllegalArgumentException {
110+
try (PmdAnalysis analysis = PmdAnalysis.create(configuration)) {
111+
return analysis.performAnalysisAndCollectReport();
101112
}
113+
}
102114

103-
Set<Language> languages = getApplicableLanguages(configuration, ruleSets);
104-
// this throws RuntimeException when modified file does not exist in workspace
105-
List<DataSource> files = PMD.getApplicableFiles(configuration, languages);
106-
107-
long reportStart = System.nanoTime();
108-
try {
109-
renderer = configuration.createRenderer();
110-
List<Renderer> renderers = new LinkedList<>();
111-
renderers.add(renderer);
112-
renderer.start();
113-
114-
Benchmarker.mark(Benchmark.Reporting, System.nanoTime() - reportStart, 0);
115-
116-
RuleContext ctx = new RuleContext();
117-
118-
PMD.processFiles(configuration, ruleSetFactory, files, ctx, renderers);
119-
120-
reportStart = System.nanoTime();
121-
renderer.end();
122-
} catch (IOException e) {
123-
log.error("PMD analysis error", e);
124-
} finally {
125-
Benchmarker.mark(Benchmark.Reporting, System.nanoTime() - reportStart, 0);
115+
@NotNull
116+
private static Severity convert(@NotNull RulePriority rulePriority) {
117+
switch (rulePriority) {
118+
case HIGH:
119+
return Severity.ERROR;
120+
case MEDIUM_HIGH:
121+
return Severity.WARNING;
122+
case MEDIUM:
123+
case MEDIUM_LOW:
124+
return Severity.INFO;
125+
case LOW:
126+
return Severity.IGNORE;
127+
default:
128+
throw new IllegalArgumentException("RulePriority " + rulePriority + " is not supported");
126129
}
127130
}
128131

129-
/**
130-
* Paste from PMD
131-
*/
132-
private static Set<Language> getApplicableLanguages(PMDConfiguration configuration, RuleSets ruleSets) {
133-
Set<Language> languages = new HashSet<>();
134-
LanguageVersionDiscoverer discoverer = configuration.getLanguageVersionDiscoverer();
135-
136-
for (Rule rule : ruleSets.getAllRules()) {
137-
Language language = rule.getLanguage();
138-
if (languages.contains(language))
139-
continue;
140-
LanguageVersion version = discoverer.getDefaultLanguageVersion(language);
141-
if (RuleSet.applies(rule, version)) {
142-
languages.add(language);
143-
log.debug("Using {} version: {}", language.getShortName(), version.getShortName());
144-
}
132+
private static String renderViolationDetails(RuleViolation ruleViolation) {
133+
StringBuilder fullDescription = new StringBuilder(ruleViolation.getDescription());
134+
135+
String reason = ruleViolation.getRule().getDescription();
136+
if (StringUtils.isNotEmpty(reason)) {
137+
fullDescription.append(LINE_SEPARATOR).append(reason);
138+
}
139+
String url = ruleViolation.getRule().getExternalInfoUrl();
140+
if (StringUtils.isNotEmpty(url)) {
141+
fullDescription.append(LINE_SEPARATOR).append(url);
145142
}
146-
return languages;
143+
144+
return fullDescription.toString();
147145
}
148146
}

0 commit comments

Comments
 (0)