forked from phoedos/pmd
Merge branch 'master' into pmd/7.0.x
This commit is contained in:
commit
8eb18114c9
@ -6538,6 +6538,25 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "JerritEic",
|
||||
"name": "JerritEic",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/60690273?v=4",
|
||||
"profile": "https://github.com/JerritEic",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "karel1980",
|
||||
"name": "Karel Vervaeke",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/153021?v=4",
|
||||
"profile": "https://github.com/karel1980",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
@ -9,26 +9,37 @@
|
||||
<div id="topbar-content-offset">
|
||||
{% include topnav.html %}
|
||||
<!-- Page Content -->
|
||||
<div class="container">
|
||||
<div class="col-lg-12"> </div>
|
||||
<!-- Content Row -->
|
||||
<div class="row">
|
||||
{% assign content_col_size = "col-md-12" %}
|
||||
{% unless page.hide_sidebar %}
|
||||
<!-- Sidebar Column -->
|
||||
<div class="col-md-3" id="tg-sb-sidebar">
|
||||
{% include sidebar.html %}
|
||||
</div>
|
||||
{% assign content_col_size = "col-md-9" %}
|
||||
{% endunless %}
|
||||
<div class="container-toc-wrapper">
|
||||
<div class="container">
|
||||
<div class="col-lg-12"> </div>
|
||||
<!-- Content Row -->
|
||||
<div class="row">
|
||||
{% assign content_col_size = "col-md-12" %}
|
||||
{% unless page.hide_sidebar %}
|
||||
<!-- Sidebar Column -->
|
||||
<div class="col-md-3" id="tg-sb-sidebar">
|
||||
{% include sidebar.html %}
|
||||
</div>
|
||||
{% assign content_col_size = "col-md-9" %}
|
||||
{% endunless %}
|
||||
|
||||
<!-- Content Column -->
|
||||
<div class="{{content_col_size}}" id="tg-sb-content">
|
||||
{{content}}
|
||||
<!-- Content Column -->
|
||||
<div class="{{content_col_size}}" id="tg-sb-content">
|
||||
{{content}}
|
||||
</div>
|
||||
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
<!-- /.container -->
|
||||
</div>
|
||||
<!-- /.container -->
|
||||
|
||||
{% unless page.toc == false %}
|
||||
<!-- Sticky TOC column -->
|
||||
<div class="toc-col">
|
||||
{% include toc.html %}
|
||||
</div>
|
||||
{% endunless %}
|
||||
<!-- /.toc-container-wrapper -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -12,9 +12,7 @@ layout: default
|
||||
<div class="summary">{{page.summary}}</div>
|
||||
{% endif %}
|
||||
|
||||
{% unless page.toc == false %}
|
||||
{% include toc.html %}
|
||||
{% endunless %}
|
||||
<div id="inline-toc"><!-- empty, move TOC here when screen size too small --></div>
|
||||
|
||||
|
||||
{% if site.github_editme_path %}
|
||||
|
@ -1,6 +1,70 @@
|
||||
body {
|
||||
font-size:15px;
|
||||
}
|
||||
@media (max-width: 1349px) {
|
||||
/* Small screen, inline TOC*/
|
||||
.container-toc-wrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.toc-col {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#toc{
|
||||
margin-top: 15px;
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1350px) {
|
||||
/* Medium screens, keep sticky TOC but remove justify-content*/
|
||||
div#toc{
|
||||
margin-top: 60px;
|
||||
margin-left: -15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
.container {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.container-toc-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1600px) {
|
||||
/* Sticky TOC functionality */
|
||||
div#toc{
|
||||
margin-top: 60px;
|
||||
margin-left: -15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
.container {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.container-toc-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.bs-callout {
|
||||
padding: 20px;
|
||||
|
@ -1,13 +1,23 @@
|
||||
|
||||
// Detect small devices and move the TOC in line
|
||||
function moveToc(){
|
||||
if(window.innerWidth < 1350){
|
||||
$( "#toc" ).detach().appendTo("#inline-toc").removeClass("position-fixed");
|
||||
} else {
|
||||
$( "#toc" ).detach().appendTo(".toc-col").addClass("position-fixed");
|
||||
}
|
||||
}
|
||||
|
||||
$( document ).ready(function() {
|
||||
|
||||
$('#mysidebar').height($(".nav").height());
|
||||
|
||||
// this script says, if the height of the viewport is greater than 800px, then insert position-fixed class,
|
||||
// this script says, if the height of the viewport is greater than 600px, then insert position-fixed class,
|
||||
// which makes the nav bar float in a fixed position as your scroll. If you have a lot of nav items,
|
||||
// this height may not work for you.
|
||||
var h = $(window).height();
|
||||
//console.log (h);
|
||||
if (h > 800) {
|
||||
if (h > 600) {
|
||||
$( "#mysidebar" ).attr("class", "nav position-fixed");
|
||||
}
|
||||
|
||||
@ -20,6 +30,8 @@ $( document ).ready(function() {
|
||||
* AnchorJS
|
||||
*/
|
||||
anchors.add('h2,h3,h4,h5');
|
||||
// Check if TOC needs to be moved on page load
|
||||
moveToc();
|
||||
|
||||
// This highlights the active parent class in the navgoco sidebar. This is critical so that the parent expands
|
||||
// when you're viewing a page.
|
||||
@ -71,3 +83,6 @@ $( document ).ready(function() {
|
||||
event.preventDefault();
|
||||
});
|
||||
});
|
||||
|
||||
// Check if TOC needs to be moved on window resizing
|
||||
$(window).resize(function () {moveToc();});
|
File diff suppressed because it is too large
Load Diff
@ -122,6 +122,14 @@ The examples below won't repeat this taskdef element, as this is always required
|
||||
</td>
|
||||
<td>No</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>threads</td>
|
||||
<td>
|
||||
Sets the number of threads used by PMD. Set threads to <code>0</code> to disable multi-threading processing.
|
||||
Default: 1
|
||||
</td>
|
||||
<td>No</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
@ -23,8 +23,14 @@ This is a {{ site.pmd.release_type }} release.
|
||||
|
||||
* core
|
||||
* [#3427](https://github.com/pmd/pmd/issues/3427): \[core] Stop printing CLI usage text when exiting due to invalid parameters
|
||||
* [#3768](https://github.com/pmd/pmd/issues/3768): \[core] SARIF formatter reports multiple locations when it should report multiple results
|
||||
* doc
|
||||
* [#2502](https://github.com/pmd/pmd/issues/2502): \[doc] Add floating table-of-contents (toc) on the right
|
||||
* [#3807](https://github.com/pmd/pmd/pull/3807): \[doc] Document Ant Task parameter `threads`
|
||||
* java
|
||||
* [#3698](https://github.com/pmd/pmd/issues/3697): \[java] Parsing error with try-with-resources and qualified resource
|
||||
* java-bestpractices
|
||||
* [#3605](https://github.com/pmd/pmd/issues/3605): \[java] SwitchStmtsShouldHaveDefault triggered when default case is present
|
||||
* java-codestyle
|
||||
* [#278](https://github.com/pmd/pmd/issues/278): \[java] ConfusingTernary should treat `!= null` as positive condition
|
||||
* java-performance
|
||||
@ -74,6 +80,7 @@ will change drastically in PMD 7.
|
||||
### External Contributions
|
||||
|
||||
* [#3767](https://github.com/pmd/pmd/pull/3767): \[core] Update GUI.java - [Vyom Yadav](https://github.com/Vyom-Yadav)
|
||||
* [#3804](https://github.com/pmd/pmd/pull/3804): \[doc] Add floating table of contents (issue #2502) - [JerritEic](https://github.com/JerritEic)
|
||||
|
||||
{% endtocmaker %}
|
||||
|
||||
|
@ -30,7 +30,7 @@ public class PMDTask extends Task {
|
||||
private String rulesetFiles;
|
||||
private boolean noRuleSetCompatibility;
|
||||
private String encoding;
|
||||
private int threads;
|
||||
private int threads = 1; // same default as in PMDParameters (CLI)
|
||||
private int minimumPriority;
|
||||
private int maxRuleViolations = 0;
|
||||
private String failuresPropertyName;
|
||||
|
@ -64,7 +64,7 @@ public class PMDParameters {
|
||||
|
||||
@Parameter(names = { "--threads", "-threads", "-t" }, description = "Sets the number of threads used by PMD.",
|
||||
validateWith = PositiveInteger.class)
|
||||
private int threads = 1;
|
||||
private int threads = 1; // see also default in PMDTask (Ant)
|
||||
|
||||
@Parameter(names = { "--benchmark", "-benchmark", "-b" },
|
||||
description = "Benchmark mode - output a benchmark report upon completion; default to System.err.")
|
||||
|
@ -4,38 +4,36 @@
|
||||
|
||||
package net.sourceforge.pmd.renderers.internal.sarif;
|
||||
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ArtifactLocation;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.AssociatedRule;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Component;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Exception;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Invocation;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Location;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Message;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.MultiformatMessage;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.PhysicalLocation;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.PropertyBag;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Region;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ReportingDescriptor;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Result;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Run;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Tool;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ToolConfigurationNotification;
|
||||
import static net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ToolExecutionNotification;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.PMDVersion;
|
||||
import net.sourceforge.pmd.Report;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ArtifactLocation;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.AssociatedRule;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Component;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Exception;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Invocation;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Location;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Message;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.MultiformatMessage;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.PhysicalLocation;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.PropertyBag;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Region;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ReportingDescriptor;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Result;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Run;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.Tool;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ToolConfigurationNotification;
|
||||
import net.sourceforge.pmd.renderers.internal.sarif.SarifLog.ToolExecutionNotification;
|
||||
|
||||
public class SarifLogBuilder {
|
||||
private final Map<ReportingDescriptor, List<Location>> locationsByRule = new HashMap<>();
|
||||
private final List<ReportingDescriptor> rules = new ArrayList<>();
|
||||
private final List<Result> results = new ArrayList<>();
|
||||
private final List<ToolConfigurationNotification> toolConfigurationNotifications = new ArrayList<>();
|
||||
private final List<ToolExecutionNotification> toolExecutionNotifications = new ArrayList<>();
|
||||
|
||||
@ -45,11 +43,15 @@ public class SarifLogBuilder {
|
||||
|
||||
public SarifLogBuilder add(RuleViolation violation) {
|
||||
final ReportingDescriptor ruleDescriptor = getReportingDescriptor(violation);
|
||||
final Location location = getRuleViolationLocation(violation);
|
||||
int ruleIndex = rules.indexOf(ruleDescriptor);
|
||||
if (ruleIndex == -1) {
|
||||
rules.add(ruleDescriptor);
|
||||
ruleIndex = rules.size() - 1;
|
||||
}
|
||||
|
||||
final List<Location> ruleLocation = locationsByRule.containsKey(ruleDescriptor) ? locationsByRule.get(ruleDescriptor) : new ArrayList<>();
|
||||
ruleLocation.add(location);
|
||||
locationsByRule.put(ruleDescriptor, ruleLocation);
|
||||
final Location location = getRuleViolationLocation(violation);
|
||||
final Result result = resultFrom(ruleDescriptor, ruleIndex, location);
|
||||
results.add(result);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -105,15 +107,6 @@ public class SarifLogBuilder {
|
||||
}
|
||||
|
||||
public SarifLog build() {
|
||||
final List<ReportingDescriptor> rules = new ArrayList<>(locationsByRule.keySet());
|
||||
|
||||
final List<Result> results = new ArrayList<>();
|
||||
for (int i = 0, size = rules.size(); i < size; i++) {
|
||||
ReportingDescriptor rule = rules.get(i);
|
||||
List<Location> locations = locationsByRule.get(rule);
|
||||
results.add(resultFrom(rule, i, locations));
|
||||
}
|
||||
|
||||
final Component driver = getDriverComponent().toBuilder().rules(rules).build();
|
||||
final Tool tool = Tool.builder().driver(driver).build();
|
||||
final Invocation invocation = Invocation.builder()
|
||||
@ -136,7 +129,7 @@ public class SarifLogBuilder {
|
||||
return toolExecutionNotifications.isEmpty() && toolConfigurationNotifications.isEmpty();
|
||||
}
|
||||
|
||||
private Result resultFrom(ReportingDescriptor rule, Integer ruleIndex, List<Location> locations) {
|
||||
private Result resultFrom(ReportingDescriptor rule, Integer ruleIndex, Location location) {
|
||||
final Result result = Result.builder()
|
||||
.ruleId(rule.getId())
|
||||
.ruleIndex(ruleIndex)
|
||||
@ -147,7 +140,7 @@ public class SarifLogBuilder {
|
||||
.build();
|
||||
|
||||
result.setMessage(message);
|
||||
result.setLocations(locations);
|
||||
result.setLocations(Collections.singletonList(location));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import net.sourceforge.pmd.Report;
|
||||
import net.sourceforge.pmd.Report.ConfigurationError;
|
||||
import net.sourceforge.pmd.Report.ProcessingError;
|
||||
import net.sourceforge.pmd.ReportTest;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RulePriority;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.RuleWithProperties;
|
||||
@ -68,31 +69,49 @@ public abstract class AbstractRendererTest {
|
||||
}
|
||||
|
||||
protected Consumer<FileAnalysisListener> reportOneViolation() {
|
||||
return it -> it.onRuleViolation(newRuleViolation(1));
|
||||
return it -> it.onRuleViolation(newRuleViolation(1, 1, 1, 1, createFooRule()));
|
||||
}
|
||||
|
||||
private Consumer<FileAnalysisListener> reportTwoViolations() {
|
||||
return it -> {
|
||||
RuleViolation informationalRuleViolation = newRuleViolation(1);
|
||||
informationalRuleViolation.getRule().setPriority(RulePriority.LOW);
|
||||
RuleViolation informationalRuleViolation = newRuleViolation(1, 1, 1, 1, createFooRule());
|
||||
it.onRuleViolation(informationalRuleViolation);
|
||||
RuleViolation severeRuleViolation = newRuleViolation(2);
|
||||
severeRuleViolation.getRule().setPriority(RulePriority.HIGH);
|
||||
RuleViolation severeRuleViolation = newRuleViolation(1, 1, 1, 2, createBooRule());
|
||||
it.onRuleViolation(severeRuleViolation);
|
||||
};
|
||||
}
|
||||
|
||||
protected RuleViolation newRuleViolation(int endColumn) {
|
||||
return newRuleViolation(endColumn, "Foo");
|
||||
protected DummyNode createNode(int beginLine, int beginColumn, int endLine, int endColumn) {
|
||||
DummyNode node = new DummyRoot().withFileName(getSourceCodeFilename());
|
||||
node.setCoords(beginLine, beginColumn, endLine, endColumn);
|
||||
return node;
|
||||
}
|
||||
|
||||
protected RuleViolation newRuleViolation(int endColumn, String ruleName) {
|
||||
DummyNode node = createNode(endColumn);
|
||||
FooRule rule = new FooRule();
|
||||
rule.setName(ruleName);
|
||||
protected RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLine, int endColumn, Rule rule) {
|
||||
DummyNode node = createNode(beginLine, beginColumn, endLine, endColumn);
|
||||
return new ParametricRuleViolation<Node>(rule, node, "blah");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new rule instance with name "Boo" and priority {@link RulePriority#HIGH}.
|
||||
*/
|
||||
protected Rule createBooRule() {
|
||||
Rule booRule = new FooRule();
|
||||
booRule.setName("Boo");
|
||||
booRule.setPriority(RulePriority.HIGH);
|
||||
return booRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new rule instance with name "Foo" and priority {@link RulePriority#LOW}.
|
||||
*/
|
||||
protected Rule createFooRule() {
|
||||
Rule fooRule = new FooRule();
|
||||
fooRule.setName("Foo");
|
||||
fooRule.setPriority(RulePriority.LOW);
|
||||
return fooRule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a resource file relative to this class's location.
|
||||
*/
|
||||
@ -104,19 +123,14 @@ public abstract class AbstractRendererTest {
|
||||
}
|
||||
}
|
||||
|
||||
protected DummyNode createNode(int endColumn) {
|
||||
DummyNode node = new DummyRoot().withFileName(getSourceCodeFilename());
|
||||
node.setCoords(1, 1, 1, endColumn);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRuleWithProperties() throws Exception {
|
||||
DummyNode node = createNode(1);
|
||||
DummyNode node = createNode(1, 1, 1, 1);
|
||||
RuleWithProperties theRule = new RuleWithProperties();
|
||||
theRule.setProperty(RuleWithProperties.STRING_PROPERTY_DESCRIPTOR,
|
||||
"the string value\nsecond line with \"quotes\"");
|
||||
String rendered = ReportTest.render(getRenderer(), it -> it.onRuleViolation(new ParametricRuleViolation<Node>(theRule, node, "blah")));
|
||||
String rendered = ReportTest.render(getRenderer(),
|
||||
it -> it.onRuleViolation(new ParametricRuleViolation<Node>(theRule, node, "blah")));
|
||||
assertEquals(filter(getExpectedWithProperties()), filter(rendered));
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ public class CSVRendererTest extends AbstractRendererTest {
|
||||
public String getExpectedMultiple() {
|
||||
return getHeader()
|
||||
+ "\"1\",\"\",\"" + getSourceCodeFilename() + "\",\"5\",\"1\",\"blah\",\"RuleSet\",\"Foo\"" + PMD.EOL
|
||||
+ "\"2\",\"\",\"" + getSourceCodeFilename() + "\",\"1\",\"1\",\"blah\",\"RuleSet\",\"Foo\"" + PMD.EOL;
|
||||
+ "\"2\",\"\",\"" + getSourceCodeFilename() + "\",\"1\",\"1\",\"blah\",\"RuleSet\",\"Boo\"" + PMD.EOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -46,8 +46,4 @@ public class CSVRendererTest extends AbstractRendererTest {
|
||||
private String getHeader() {
|
||||
return "\"Problem\",\"Package\",\"File\",\"Priority\",\"Line\",\"Description\",\"Rule set\",\"Rule\"" + PMD.EOL;
|
||||
}
|
||||
|
||||
public static junit.framework.Test suite() {
|
||||
return new junit.framework.JUnit4TestAdapter(CSVRendererTest.class);
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,6 @@ import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.ReportTest;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
import net.sourceforge.pmd.lang.rule.XPathRule;
|
||||
import net.sourceforge.pmd.lang.rule.xpath.XPathVersion;
|
||||
|
||||
@ -72,8 +69,8 @@ public class CodeClimateRendererTest extends AbstractRendererTest {
|
||||
+ "violationSuppressRegex | | Suppress violations with messages matching a regular expression\\n"
|
||||
+ "violationSuppressXPath | | Suppress violations on nodes which match a given relative XPath expression.\\n"
|
||||
+ "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"" + getSourceCodeFilename() + "\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}"
|
||||
+ "\u0000" + PMD.EOL + "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\","
|
||||
+ "\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: High\\n\\n"
|
||||
+ "\u0000" + PMD.EOL + "{\"type\":\"issue\",\"check_name\":\"Boo\",\"description\":\"blah\","
|
||||
+ "\"content\":{\"body\":\"## Boo\\n\\nSince: PMD null\\n\\nPriority: High\\n\\n"
|
||||
+ "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n"
|
||||
+ "[Remediation Points](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#remediation-points): 50000\\n\\n"
|
||||
+ "desc\\n\\n"
|
||||
@ -87,14 +84,13 @@ public class CodeClimateRendererTest extends AbstractRendererTest {
|
||||
|
||||
@Test
|
||||
public void testXPathRule() throws Exception {
|
||||
DummyNode node = createNode(1);
|
||||
XPathRule theRule = new XPathRule(XPathVersion.XPATH_3_1, "//dummyNode");
|
||||
|
||||
// Setup as FooRule
|
||||
theRule.setDescription("desc");
|
||||
theRule.setName("Foo");
|
||||
|
||||
String rendered = ReportTest.render(getRenderer(), it -> it.onRuleViolation(new ParametricRuleViolation<Node>(theRule, node, "blah")));
|
||||
String rendered = ReportTest.render(getRenderer(), it -> it.onRuleViolation(newRuleViolation(1, 1, 1, 2, theRule)));
|
||||
|
||||
// Output should be the exact same as for non xpath rules
|
||||
assertEquals(filter(getExpected()), filter(rendered));
|
||||
|
@ -10,6 +10,7 @@ import java.io.IOException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.FooRule;
|
||||
import net.sourceforge.pmd.Report.ConfigurationError;
|
||||
import net.sourceforge.pmd.Report.ProcessingError;
|
||||
import net.sourceforge.pmd.Report.SuppressedViolation;
|
||||
@ -79,7 +80,7 @@ public class JsonRendererTest extends AbstractRendererTest {
|
||||
@Test
|
||||
public void suppressedViolations() throws IOException {
|
||||
SuppressedViolation suppressed = new SuppressedViolation(
|
||||
newRuleViolation(1),
|
||||
newRuleViolation(1, 1, 1, 1, new FooRule()),
|
||||
ViolationSuppressor.NOPMD_COMMENT_SUPPRESSOR,
|
||||
"test"
|
||||
);
|
||||
|
@ -42,7 +42,7 @@ public class PapariTextRendererTest extends AbstractRendererTest {
|
||||
public String getExpectedMultiple() {
|
||||
return "* file: " + getSourceCodeFilename() + PMD.EOL + " src: " + getSourceCodeFilename() + ":1:1" + PMD.EOL + " rule: Foo" + PMD.EOL
|
||||
+ " msg: blah" + PMD.EOL + " code: public class Foo {}" + PMD.EOL + PMD.EOL + " src: "
|
||||
+ getSourceCodeFilename() + ":1:1" + PMD.EOL + " rule: Foo" + PMD.EOL + " msg: blah" + PMD.EOL
|
||||
+ getSourceCodeFilename() + ":1:1" + PMD.EOL + " rule: Boo" + PMD.EOL + " msg: blah" + PMD.EOL
|
||||
+ " code: public class Foo {}" + PMD.EOL + PMD.EOL + PMD.EOL + PMD.EOL + "Summary:" + PMD.EOL
|
||||
+ PMD.EOL + "* warnings: 2" + PMD.EOL;
|
||||
}
|
||||
@ -67,8 +67,4 @@ public class PapariTextRendererTest extends AbstractRendererTest {
|
||||
+ " err: a configuration error" + PMD.EOL + PMD.EOL
|
||||
+ "* errors: 1" + PMD.EOL + "* warnings: 0" + PMD.EOL;
|
||||
}
|
||||
|
||||
public static junit.framework.Test suite() {
|
||||
return new junit.framework.JUnit4TestAdapter(PapariTextRendererTest.class);
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,12 @@ import org.junit.runners.Suite.SuiteClasses;
|
||||
EmacsRendererTest.class,
|
||||
HTMLRendererTest.class,
|
||||
IDEAJRendererTest.class,
|
||||
JsonRendererTest.class,
|
||||
PapariTextRendererTest.class,
|
||||
SarifRendererTest.class,
|
||||
SummaryHTMLRendererTest.class,
|
||||
TextPadRendererTest.class,
|
||||
TextRendererTest.class,
|
||||
VBHTMLRendererTest.class,
|
||||
XMLRendererTest.class,
|
||||
XSLTRendererTest.class,
|
||||
|
@ -4,17 +4,17 @@
|
||||
|
||||
package net.sourceforge.pmd.renderers;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.Report;
|
||||
import net.sourceforge.pmd.ReportTest;
|
||||
import net.sourceforge.pmd.RulePriority;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.reporting.FileAnalysisListener;
|
||||
|
||||
public class SarifRendererTest extends AbstractRendererTest {
|
||||
@ -65,32 +65,34 @@ public class SarifRendererTest extends AbstractRendererTest {
|
||||
|
||||
@Override
|
||||
public String filter(String expected) {
|
||||
return expected.replaceAll("\r\n", "\n"); // make the test run on Windows, too
|
||||
return expected.replaceAll("\r\n", "\n") // make the test run on Windows, too
|
||||
.replaceAll("\"version\": \".+\",", "\"version\": \"unknown\",");
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Multiple occurrences of the same rule should be reported as individual results.
|
||||
*
|
||||
* @see <a href="https://github.com/pmd/pmd/issues/3768"> [core] SARIF formatter reports multiple locations
|
||||
* when it should report multiple results #3768</a>
|
||||
*/
|
||||
@Test
|
||||
public void testRendererMultiple() throws Exception {
|
||||
// Exercise
|
||||
String actual = ReportTest.render(getRenderer(), reportTwoViolations());
|
||||
public void testRendererMultipleLocations() throws Exception {
|
||||
String actual = ReportTest.render(getRenderer(), reportThreeViolationsTwoRules());
|
||||
|
||||
// Verify that both rules are and rule ids are linked in the results
|
||||
// Initially was comparing whole files but order of rules rendered can't be guaranteed when the report is being rendered
|
||||
// Refer to pmd-core/src/test/resources/net/sourceforge/pmd/renderers/sarif/expected-multiple.sarif.json to see an example data structure
|
||||
assertThat(filter(actual), containsString("\"ruleId\": \"Foo\""));
|
||||
assertThat(filter(actual), containsString("\"ruleId\": \"Boo\""));
|
||||
assertThat(filter(actual), containsString("\"id\": \"Foo\""));
|
||||
assertThat(filter(actual), containsString("\"id\": \"Boo\""));
|
||||
JSONObject json = new JSONObject(actual);
|
||||
JSONArray results = json.getJSONArray("runs").getJSONObject(0).getJSONArray("results");
|
||||
assertEquals(3, results.length());
|
||||
assertEquals(filter(readFile("expected-multiple-locations.sarif.json")), filter(actual));
|
||||
}
|
||||
|
||||
private Consumer<FileAnalysisListener> reportTwoViolations() {
|
||||
private Consumer<FileAnalysisListener> reportThreeViolationsTwoRules() {
|
||||
Rule fooRule = createFooRule();
|
||||
Rule booRule = createBooRule();
|
||||
|
||||
return reportBuilder -> {
|
||||
RuleViolation informationalRuleViolation = newRuleViolation(1, "Foo");
|
||||
informationalRuleViolation.getRule().setPriority(RulePriority.LOW);
|
||||
reportBuilder.onRuleViolation(informationalRuleViolation);
|
||||
RuleViolation severeRuleViolation = newRuleViolation(2, "Boo");
|
||||
severeRuleViolation.getRule().setPriority(RulePriority.HIGH);
|
||||
reportBuilder.onRuleViolation(severeRuleViolation);
|
||||
reportBuilder.onRuleViolation(newRuleViolation(1, 1, 1, 10, fooRule));
|
||||
reportBuilder.onRuleViolation(newRuleViolation(5, 1, 5, 11, fooRule));
|
||||
reportBuilder.onRuleViolation(newRuleViolation(2, 2, 3, 1, booRule));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,8 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest {
|
||||
return "<html><head><title>PMD</title></head><body>" + PMD.EOL + "<center><h2>Summary</h2></center>" + PMD.EOL
|
||||
+ "<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\">" + PMD.EOL
|
||||
+ "<tr><th>Rule name</th><th>Number of violations</th></tr>" + PMD.EOL
|
||||
+ "<tr><td>Foo</td><td align=center>2</td></tr>" + PMD.EOL + "</table>" + PMD.EOL
|
||||
+ "<tr><td>Boo</td><td align=center>1</td></tr>" + PMD.EOL
|
||||
+ "<tr><td>Foo</td><td align=center>1</td></tr>" + PMD.EOL + "</table>" + PMD.EOL
|
||||
+ "<center><h2>Detail</h2></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>"
|
||||
+ PMD.EOL
|
||||
+ "<center><h3>PMD report</h3></center><center><h3>Problems found</h3></center><table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>"
|
||||
|
@ -25,10 +25,6 @@ public class TextPadRendererTest extends AbstractRendererTest {
|
||||
|
||||
@Override
|
||||
public String getExpectedMultiple() {
|
||||
return getSourceCodeFilename() + "(1, Foo): blah" + PMD.EOL + getSourceCodeFilename() + "(1, Foo): blah" + PMD.EOL;
|
||||
}
|
||||
|
||||
public static junit.framework.Test suite() {
|
||||
return new junit.framework.JUnit4TestAdapter(TextPadRendererTest.class);
|
||||
return getSourceCodeFilename() + "(1, Foo): blah" + PMD.EOL + getSourceCodeFilename() + "(1, Boo): blah" + PMD.EOL;
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public class TextRendererTest extends AbstractRendererTest {
|
||||
@Override
|
||||
public String getExpectedMultiple() {
|
||||
return getSourceCodeFilename() + ":1:\tFoo:\tblah" + PMD.EOL
|
||||
+ getSourceCodeFilename() + ":1:\tFoo:\tblah" + PMD.EOL;
|
||||
+ getSourceCodeFilename() + ":1:\tBoo:\tblah" + PMD.EOL;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,8 +93,4 @@ public class VBHTMLRendererTest extends AbstractRendererTest {
|
||||
+ "--></style><body><center><br><table border=\"0\" width=\"80%\"><tr id=TableHeader><td colspan=\"2\"><font class=title> Configuration problems found</font></td></tr><tr id=RowColor2><td><font class=body>"
|
||||
+ error.rule().getName() + "</font></td><td><font class=body>" + error.issue() + "</font></td></tr></table></center></body></html>" + PMD.EOL;
|
||||
}
|
||||
|
||||
public static junit.framework.Test suite() {
|
||||
return new junit.framework.JUnit4TestAdapter(VBHTMLRendererTest.class);
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ public class XMLRendererTest extends AbstractRendererTest {
|
||||
return getHeader() + "<file name=\"" + getSourceCodeFilename() + "\">" + PMD.EOL
|
||||
+ "<violation beginline=\"1\" endline=\"1\" begincolumn=\"1\" endcolumn=\"1\" rule=\"Foo\" ruleset=\"RuleSet\" priority=\"5\">"
|
||||
+ PMD.EOL + "blah" + PMD.EOL + "</violation>" + PMD.EOL
|
||||
+ "<violation beginline=\"1\" endline=\"1\" begincolumn=\"1\" endcolumn=\"2\" rule=\"Foo\" ruleset=\"RuleSet\" priority=\"1\">"
|
||||
+ "<violation beginline=\"1\" endline=\"1\" begincolumn=\"1\" endcolumn=\"2\" rule=\"Boo\" ruleset=\"RuleSet\" priority=\"1\">"
|
||||
+ PMD.EOL + "blah" + PMD.EOL + "</violation>" + PMD.EOL + "</file>" + PMD.EOL + "</pmd>" + PMD.EOL;
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
@ -25,6 +24,7 @@ import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.Report.ConfigurationError;
|
||||
import net.sourceforge.pmd.Report.ProcessingError;
|
||||
import net.sourceforge.pmd.ReportTest;
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.lang.ast.DummyNode;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
@ -34,7 +34,7 @@ public class YAHTMLRendererTest extends AbstractRendererTest {
|
||||
|
||||
private File outputDir;
|
||||
|
||||
@Rule
|
||||
@org.junit.Rule
|
||||
public TemporaryFolder folder = new TemporaryFolder();
|
||||
|
||||
@Before
|
||||
@ -42,8 +42,8 @@ public class YAHTMLRendererTest extends AbstractRendererTest {
|
||||
outputDir = folder.newFolder("pmdtest");
|
||||
}
|
||||
|
||||
private RuleViolation newRuleViolation(int endColumn, final String packageNameArg, final String classNameArg) {
|
||||
DummyNode node = createNode(endColumn);
|
||||
private RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLine, int endColumn, final String packageNameArg, final String classNameArg) {
|
||||
DummyNode node = createNode(beginLine, beginColumn, endLine, endColumn);
|
||||
return new ParametricRuleViolation<Node>(new FooRule(), node, "blah") {
|
||||
{
|
||||
packageName = packageNameArg;
|
||||
@ -53,17 +53,17 @@ public class YAHTMLRendererTest extends AbstractRendererTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RuleViolation newRuleViolation(int endColumn) {
|
||||
return newRuleViolation(endColumn, "net.sf.pmd.test", "YAHTMLSampleClass");
|
||||
protected RuleViolation newRuleViolation(int beginLine, int beginColumn, int endLine, int endColumn, Rule rule) {
|
||||
return newRuleViolation(beginLine, beginColumn, endLine, endColumn, "net.sf.pmd.test", "YAHTMLSampleClass");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReportMultipleViolations() throws Exception {
|
||||
|
||||
String actual = ReportTest.render(getRenderer(), it -> {
|
||||
it.onRuleViolation(newRuleViolation(1, "net.sf.pmd.test", "YAHTMLSampleClass1"));
|
||||
it.onRuleViolation(newRuleViolation(2, "net.sf.pmd.test", "YAHTMLSampleClass1"));
|
||||
it.onRuleViolation(newRuleViolation(1, "net.sf.pmd.other", "YAHTMLSampleClass2"));
|
||||
it.onRuleViolation(newRuleViolation(1, 1, 1, 1, "net.sf.pmd.test", "YAHTMLSampleClass1"));
|
||||
it.onRuleViolation(newRuleViolation(1, 1, 1, 2, "net.sf.pmd.test", "YAHTMLSampleClass1"));
|
||||
it.onRuleViolation(newRuleViolation(1, 1, 1, 1, "net.sf.pmd.other", "YAHTMLSampleClass2"));
|
||||
});
|
||||
assertEquals(filter(getExpected()), filter(actual));
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
"endline": 1,
|
||||
"endcolumn": 2,
|
||||
"description": "blah",
|
||||
"rule": "Foo",
|
||||
"rule": "Boo",
|
||||
"ruleset": "RuleSet",
|
||||
"priority": 1
|
||||
}
|
||||
|
@ -0,0 +1,130 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
|
||||
"version": "2.1.0",
|
||||
"runs": [
|
||||
{
|
||||
"tool": {
|
||||
"driver": {
|
||||
"name": "PMD",
|
||||
"version": "unknown",
|
||||
"informationUri": "https://pmd.github.io/pmd/",
|
||||
"rules": [
|
||||
{
|
||||
"id": "Foo",
|
||||
"shortDescription": {
|
||||
"text": "blah"
|
||||
},
|
||||
"fullDescription": {
|
||||
"text": "desc"
|
||||
},
|
||||
"help": {
|
||||
"text": "desc"
|
||||
},
|
||||
"properties": {
|
||||
"ruleset": "RuleSet",
|
||||
"priority": 5,
|
||||
"tags": [
|
||||
"RuleSet"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Boo",
|
||||
"shortDescription": {
|
||||
"text": "blah"
|
||||
},
|
||||
"fullDescription": {
|
||||
"text": "desc"
|
||||
},
|
||||
"help": {
|
||||
"text": "desc"
|
||||
},
|
||||
"properties": {
|
||||
"ruleset": "RuleSet",
|
||||
"priority": 1,
|
||||
"tags": [
|
||||
"RuleSet"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "Foo",
|
||||
"ruleIndex": 0,
|
||||
"message": {
|
||||
"text": "blah"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "notAvailable.ext"
|
||||
},
|
||||
"region": {
|
||||
"startLine": 1,
|
||||
"startColumn": 1,
|
||||
"endLine": 1,
|
||||
"endColumn": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ruleId": "Boo",
|
||||
"ruleIndex": 1,
|
||||
"message": {
|
||||
"text": "blah"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "notAvailable.ext"
|
||||
},
|
||||
"region": {
|
||||
"startLine": 2,
|
||||
"startColumn": 2,
|
||||
"endLine": 3,
|
||||
"endColumn": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ruleId": "Foo",
|
||||
"ruleIndex": 0,
|
||||
"message": {
|
||||
"text": "blah"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "notAvailable.ext"
|
||||
},
|
||||
"region": {
|
||||
"startLine": 5,
|
||||
"startColumn": 1,
|
||||
"endLine": 5,
|
||||
"endColumn": 11
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"invocations": [
|
||||
{
|
||||
"executionSuccessful": true,
|
||||
"toolConfigurationNotifications": [],
|
||||
"toolExecutionNotifications": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -9,25 +9,6 @@
|
||||
"version": "unknown",
|
||||
"informationUri": "https://pmd.github.io/pmd/",
|
||||
"rules": [
|
||||
{
|
||||
"id": "Boo",
|
||||
"shortDescription": {
|
||||
"text": "blah"
|
||||
},
|
||||
"fullDescription": {
|
||||
"text": "desc"
|
||||
},
|
||||
"help": {
|
||||
"text": "desc"
|
||||
},
|
||||
"properties": {
|
||||
"ruleset": "RuleSet",
|
||||
"priority": 1,
|
||||
"tags": [
|
||||
"RuleSet"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Foo",
|
||||
"shortDescription": {
|
||||
@ -46,36 +27,33 @@
|
||||
"RuleSet"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Boo",
|
||||
"shortDescription": {
|
||||
"text": "blah"
|
||||
},
|
||||
"fullDescription": {
|
||||
"text": "desc"
|
||||
},
|
||||
"help": {
|
||||
"text": "desc"
|
||||
},
|
||||
"properties": {
|
||||
"ruleset": "RuleSet",
|
||||
"priority": 1,
|
||||
"tags": [
|
||||
"RuleSet"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"results": [
|
||||
{
|
||||
"ruleId": "Boo",
|
||||
"ruleIndex": 0,
|
||||
"message": {
|
||||
"text": "blah"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "notAvailable.ext"
|
||||
},
|
||||
"region": {
|
||||
"startLine": 1,
|
||||
"startColumn": 1,
|
||||
"endLine": 1,
|
||||
"endColumn": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ruleId": "Foo",
|
||||
"ruleIndex": 1,
|
||||
"ruleIndex": 0,
|
||||
"message": {
|
||||
"text": "blah"
|
||||
},
|
||||
@ -94,6 +72,28 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ruleId": "Boo",
|
||||
"ruleIndex": 1,
|
||||
"message": {
|
||||
"text": "blah"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"physicalLocation": {
|
||||
"artifactLocation": {
|
||||
"uri": "notAvailable.ext"
|
||||
},
|
||||
"region": {
|
||||
"startLine": 1,
|
||||
"startColumn": 1,
|
||||
"endLine": 1,
|
||||
"endColumn": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"invocations": [
|
||||
|
@ -107,4 +107,14 @@ public interface ASTSwitchLike extends JavaNode, Iterable<ASTSwitchBranch> {
|
||||
default Iterator<ASTSwitchBranch> iterator() {
|
||||
return children(ASTSwitchBranch.class).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this a switch which uses fallthrough branches
|
||||
* (old school {@code case label: break;}) and not arrow branches.
|
||||
* If the switch has no branches, returns false.
|
||||
*/
|
||||
default boolean isFallthroughSwitch() {
|
||||
return getBranches().filterIs(ASTSwitchFallthroughBranch.class).nonEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,4 +19,5 @@ public final class ASTSwitchStatement extends AbstractStatement implements ASTSw
|
||||
protected <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,5 +17,52 @@ public class ASTSwitchStatementTest extends BaseParserTest {
|
||||
.get(0);
|
||||
Assert.assertFalse(switchStatement.isExhaustiveEnumSwitch()); // this should not throw a NPE...
|
||||
Assert.assertTrue(switchStatement.hasDefaultCase());
|
||||
Assert.assertTrue(switchStatement.isFallthroughSwitch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultCaseWithArrowBlock() {
|
||||
ASTSwitchStatement switchStatement = getNodes(ASTSwitchStatement.class,
|
||||
"class Foo { void bar(int x) {"
|
||||
+ "switch (x) { default -> { } } } }")
|
||||
.get(0);
|
||||
Assert.assertFalse(switchStatement.isExhaustiveEnumSwitch());
|
||||
Assert.assertTrue(switchStatement.iterator().hasNext());
|
||||
Assert.assertTrue(switchStatement.hasDefaultCase());
|
||||
Assert.assertFalse(switchStatement.isFallthroughSwitch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptySwitch() {
|
||||
ASTSwitchStatement switchStatement = getNodes(ASTSwitchStatement.class,
|
||||
"class Foo { void bar(int x) {"
|
||||
+ "switch (x) { } } }")
|
||||
.get(0);
|
||||
Assert.assertFalse(switchStatement.isExhaustiveEnumSwitch());
|
||||
Assert.assertFalse(switchStatement.iterator().hasNext());
|
||||
Assert.assertFalse(switchStatement.hasDefaultCase());
|
||||
Assert.assertFalse(switchStatement.isFallthroughSwitch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultCaseWithArrowExprs() {
|
||||
ASTSwitchStatement switchStatement =
|
||||
getNodes(ASTSwitchStatement.class,
|
||||
"import net.sourceforge.pmd.lang.java.rule.bestpractices.switchstmtsshouldhavedefault.SimpleEnum;\n"
|
||||
+ "\n"
|
||||
+ " public class Foo {\n"
|
||||
+ " void bar(SimpleEnum x) {\n"
|
||||
+ " switch (x) {\n"
|
||||
+ " case FOO -> System.out.println(\"it is on\");\n"
|
||||
+ " case BAR -> System.out.println(\"it is off\");\n"
|
||||
+ " default -> System.out.println(\"it is neither on nor off - should not happen? maybe null?\");\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ " }")
|
||||
.get(0);
|
||||
Assert.assertFalse(switchStatement.isExhaustiveEnumSwitch());
|
||||
Assert.assertTrue(switchStatement.iterator().hasNext());
|
||||
Assert.assertFalse(switchStatement.isFallthroughSwitch());
|
||||
Assert.assertTrue(switchStatement.hasDefaultCase());
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user