Merge branch 'master' of https://github.com/pmd/pmd
This commit is contained in:
@ -103,11 +103,7 @@ precision in a floating point number. This may result in numeric calculations b
|
||||
|
||||
**This rule is defined by the following XPath expression:**
|
||||
```
|
||||
//NumberLiteral[
|
||||
@Image != @Number
|
||||
and translate(@Image, "e", "E") != @Number
|
||||
and concat(@Image, ".0") != @Number
|
||||
and @Image != substring-before(translate(@Number, ".", ""), "E")]
|
||||
//NumberLiteral[@NormalizedImage != @Number]
|
||||
```
|
||||
|
||||
**Example(s):**
|
||||
|
@ -20,6 +20,11 @@ This is a minor release.
|
||||
### New and noteworthy
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
* ecmascript
|
||||
* [#861](https://github.com/pmd/pmd/issues/861): \[ecmascript] InnaccurateNumericLiteral false positive with hex literals
|
||||
* java-codestyle
|
||||
* [#1158](https://github.com/pmd/pmd/issues/1158): \[java] Fix IdenticalCatchBranches false positive
|
||||
* xml
|
||||
* [#715](https://github.com/pmd/pmd/issues/715): \[xml] ProjectVersionAsDependencyVersion false positive
|
||||
|
||||
|
@ -75,8 +75,8 @@ check_lib_dir() {
|
||||
}
|
||||
|
||||
jre_specific_vm_options() {
|
||||
# java_ver is eg "18" for java 1.8, "90" for java 9.0
|
||||
java_ver=$(java -version 2>&1 | sed -n ';s/^.* version "\(.*\)\.\(.*\)\..*".*$/\1\2/p;')
|
||||
# java_ver is eg "18" for java 1.8, "90" for java 9.0, "100" for java 10.0.x
|
||||
java_ver=$(java -version 2>&1 | sed -n -e 's/-ea/.0.0/i' -e 's/^.* version "\(.*\)\.\(.*\)\..*".*$/\1\2/p')
|
||||
options=""
|
||||
|
||||
if [ "$java_ver" -ge 90 ] && [ "${APPNAME}" = "designer" ]
|
||||
|
@ -12,6 +12,9 @@ import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTryStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTType;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||
@ -31,7 +34,7 @@ public class IdenticalCatchBranchesRule extends AbstractJavaRule {
|
||||
}
|
||||
|
||||
|
||||
// groups catch statements by equivalence class, according to the string value of their tokens.
|
||||
/** groups catch statements by equivalence class, according to the equivalence {@link #areEquivalent(ASTCatchStatement, ASTCatchStatement)}. */
|
||||
private Set<List<ASTCatchStatement>> equivalenceClasses(List<ASTCatchStatement> catches) {
|
||||
Set<List<ASTCatchStatement>> result = new HashSet<>(catches.size());
|
||||
for (ASTCatchStatement stmt : catches) {
|
||||
@ -103,19 +106,15 @@ public class IdenticalCatchBranchesRule extends AbstractJavaRule {
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether two nodes has same subtree.
|
||||
* Note, it wouldn't be sensitive to changes in the exception variable name.
|
||||
* Checks whether two nodes define the same subtree,
|
||||
* up to the renaming of one local variable.
|
||||
*
|
||||
* @param node1
|
||||
* the first node to check
|
||||
* @param node2
|
||||
* the second node to check
|
||||
* @param exceptionName1
|
||||
* the first exception variable name
|
||||
* @param exceptionName2
|
||||
* the second exception variable name
|
||||
* @return <code>ture</code> if two nodes has same subtree, otherwise <code>false</code>
|
||||
* @param node1 the first node to check
|
||||
* @param node2 the second node to check
|
||||
* @param exceptionName1 the first exception variable name
|
||||
* @param exceptionName2 the second exception variable name
|
||||
*/
|
||||
private boolean hasSameSubTree(Node node1, Node node2, String exceptionName1, String exceptionName2) {
|
||||
if (node1 == null && node2 == null) {
|
||||
@ -131,18 +130,7 @@ public class IdenticalCatchBranchesRule extends AbstractJavaRule {
|
||||
|
||||
for (int num = 0; num < node1.jjtGetNumChildren(); num++) {
|
||||
|
||||
//type of nodes are different
|
||||
if (node1.jjtGetChild(num).getClass() != node2.jjtGetChild(num).getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String image1 = node1.jjtGetChild(num).getImage();
|
||||
String image2 = node2.jjtGetChild(num).getImage();
|
||||
|
||||
//image of nodes are different
|
||||
if (!Objects.equals(image1, image2)
|
||||
// wouldn't be sensitive to changes in the exception variable name
|
||||
&& !Objects.equals(image1, exceptionName1) && Objects.equals(image2, exceptionName2)) {
|
||||
if (!basicEquivalence(node1.jjtGetChild(num), node2.jjtGetChild(num), exceptionName1, exceptionName2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -154,4 +142,44 @@ public class IdenticalCatchBranchesRule extends AbstractJavaRule {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// no subtree comparison
|
||||
private boolean basicEquivalence(Node node1, Node node2, String varName1, String varName2) {
|
||||
// Nodes must have the same type
|
||||
if (node1.getClass() != node2.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String image1 = node1.getImage();
|
||||
String image2 = node2.getImage();
|
||||
|
||||
// image of nodes must be the same
|
||||
return Objects.equals(image1, image2)
|
||||
// or must be references to the variable we allow to interchange
|
||||
|| Objects.equals(image1, varName1) && Objects.equals(image2, varName2)
|
||||
// which means we must filter out method references.
|
||||
&& isNoMethodName(node1) && isNoMethodName(node2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private boolean isNoMethodName(Node name) {
|
||||
|
||||
if (name instanceof ASTName
|
||||
&& (name.jjtGetParent() instanceof ASTPrimaryPrefix || name.jjtGetParent() instanceof ASTPrimarySuffix)) {
|
||||
|
||||
Node prefixOrSuffix = name.jjtGetParent();
|
||||
|
||||
if (prefixOrSuffix.jjtGetParent().jjtGetNumChildren() > 1 + prefixOrSuffix.jjtGetChildIndex()) {
|
||||
// there's one next sibling
|
||||
|
||||
Node next = prefixOrSuffix.jjtGetParent().jjtGetChild(prefixOrSuffix.jjtGetChildIndex() + 1);
|
||||
if (next instanceof ASTPrimarySuffix) {
|
||||
return !((ASTPrimarySuffix) next).isArguments();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -71,5 +71,74 @@
|
||||
</code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1158 false positive 1</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code>
|
||||
<![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
try {
|
||||
// do something
|
||||
} catch (FieldNotFound e) {
|
||||
throw new IllegalStateException("field not found", e);
|
||||
} catch (FieldException | FieldConvertError e) {
|
||||
throw new IllegalArgumentException("field exception ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1158 false positive 2</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code>
|
||||
<![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
try {
|
||||
// do something
|
||||
} catch (Exception1 exception) {
|
||||
throw new Exception3("Error message 1", exception);
|
||||
} catch (Exception2 exception) {
|
||||
throw new Exception3("Error message 2", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>False positive with method name mistaken for exception parameter</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code>
|
||||
<![CDATA[
|
||||
class Foo {
|
||||
static {
|
||||
try {
|
||||
// do something
|
||||
} catch (Exception1 exception) {
|
||||
exception(exception);
|
||||
} catch (Exception2 exception2) {
|
||||
exception2(exception2);
|
||||
}
|
||||
}
|
||||
|
||||
private static void exception(Exception exception) {
|
||||
throw new Exception3("Error message 1", exception);
|
||||
}
|
||||
|
||||
|
||||
private static exception2(Exception exception) {
|
||||
throw new Exception3("Error message 2", exception);
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</code>
|
||||
</test-code>
|
||||
|
||||
|
||||
</test-data>
|
@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.ecmascript.ast;
|
||||
|
||||
import org.mozilla.javascript.ast.NumberLiteral;
|
||||
|
||||
// TODO The Rhino node does not tell us whether this was specified via decimal, octal or hexidecimal.
|
||||
public class ASTNumberLiteral extends AbstractEcmascriptNode<NumberLiteral> {
|
||||
public ASTNumberLiteral(NumberLiteral numberLiteral) {
|
||||
super(numberLiteral);
|
||||
@ -21,8 +20,20 @@ public class ASTNumberLiteral extends AbstractEcmascriptNode<NumberLiteral> {
|
||||
}
|
||||
|
||||
public String getNormalizedImage() {
|
||||
// TODO Implement
|
||||
return super.getImage();
|
||||
String image = getImage();
|
||||
image = normalizeHexIntegerLiteral(image);
|
||||
image = image.replace('e', 'E');
|
||||
if (image.indexOf('.') == -1 && image.indexOf('E') == -1) {
|
||||
image = image + ".0";
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private String normalizeHexIntegerLiteral(String image) {
|
||||
if (image.startsWith("0x") || image.startsWith("0X")) {
|
||||
return String.valueOf(Integer.parseInt(image.substring(2), 16));
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
public double getNumber() {
|
||||
|
@ -107,11 +107,7 @@ precision in a floating point number. This may result in numeric calculations b
|
||||
<property name="xpath">
|
||||
<value>
|
||||
<![CDATA[
|
||||
//NumberLiteral[
|
||||
@Image != @Number
|
||||
and translate(@Image, "e", "E") != @Number
|
||||
and concat(@Image, ".0") != @Number
|
||||
and @Image != substring-before(translate(@Number, ".", ""), "E")]
|
||||
//NumberLiteral[@NormalizedImage != @Number]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
|
@ -3,64 +3,66 @@
|
||||
xmlns="http://pmd.sourceforge.net/rule-tests"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
|
||||
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
Ok integer
|
||||
]]></description>
|
||||
<description>Ok integer</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
var x = 1;
|
||||
]]></code>
|
||||
<source-type>ecmascript 3</source-type>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
Bad integer
|
||||
]]></description>
|
||||
<description>Bad integer</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
var x = 999999999999999999999999;
|
||||
]]></code>
|
||||
<code>var x = 999999999999999999999999;</code>
|
||||
<source-type>ecmascript 3</source-type>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
Ok float
|
||||
]]></description>
|
||||
<description>Ok float</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
var x = 1.1234567890123;
|
||||
]]></code>
|
||||
<source-type>ecmascript 3</source-type>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
Bad float
|
||||
]]></description>
|
||||
<description>Bad float</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
var z = 1.12345678901234567;
|
||||
]]></code>
|
||||
<source-type>ecmascript 3</source-type>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
Ok float w/ exponent
|
||||
]]></description>
|
||||
<description>Ok float w/ exponent</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
var x = 1.12e-4;
|
||||
]]></code>
|
||||
<source-type>ecmascript 3</source-type>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
Bad float w/ exponent
|
||||
]]></description>
|
||||
<description>Bad float w/ exponent</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
var x = 1.12345678901234567e-4;
|
||||
]]></code>
|
||||
<source-type>ecmascript 3</source-type>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#861 [ecmascript] InnaccurateNumericLiteral false positive</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
var hex1 = 0x20;
|
||||
var hex2 = 0X20;
|
||||
]]></code>
|
||||
<source-type>ecmascript 3</source-type>
|
||||
</test-code>
|
||||
</test-data>
|
||||
|
@ -27,6 +27,15 @@
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
<configuration>
|
||||
<rulesets>
|
||||
<ruleset>/net/sourceforge/pmd/pmd-ui-dogfood-config.xml</ruleset>
|
||||
</rulesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
@ -115,6 +115,7 @@ public class EditPropertyDialogController implements Initializable {
|
||||
backingDescriptor.ifPresent(PropertyDescriptorSpec::unbind);
|
||||
backingDescriptor.setValue(null);
|
||||
backingDescriptorList.setValue(null);
|
||||
this.nameProperty().setValue(""); // necessary to get the validator to reevaluate each time
|
||||
}
|
||||
|
||||
|
||||
|
@ -47,11 +47,11 @@ public class NodeInfoPanelController implements Initializable {
|
||||
@FXML
|
||||
private TabPane nodeInfoTabPane;
|
||||
@FXML
|
||||
private Tab xpathAttributesTitledPane;
|
||||
private Tab xpathAttributesTab;
|
||||
@FXML
|
||||
private ListView<String> xpathAttributesListView;
|
||||
@FXML
|
||||
private Tab metricResultsTitledPane;
|
||||
private Tab metricResultsTab;
|
||||
@FXML
|
||||
private ListView<MetricResult> metricResultsListView;
|
||||
@FXML
|
||||
@ -118,9 +118,9 @@ public class NodeInfoPanelController implements Initializable {
|
||||
|
||||
|
||||
private void notifyMetricsAvailable(long numMetrics) {
|
||||
metricResultsTitledPane.setText("Metrics\t(" + (numMetrics == 0 ? "none" : numMetrics) + ")");
|
||||
metricResultsTab.setText("Metrics\t(" + (numMetrics == 0 ? "none" : numMetrics) + ")");
|
||||
metricsTitleLabel.setText("Metrics\t(" + (numMetrics == 0 ? "none" : numMetrics) + " available)");
|
||||
metricResultsTitledPane.setDisable(numMetrics == 0);
|
||||
metricResultsTab.setDisable(numMetrics == 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -73,7 +73,7 @@ public class XPathPanelController implements Initializable, SettingsOwner {
|
||||
private final ObservableXPathRuleBuilder ruleBuilder = new ObservableXPathRuleBuilder();
|
||||
|
||||
@FXML
|
||||
private PropertyTableView propertyView;
|
||||
private PropertyTableView propertyTableView;
|
||||
@FXML
|
||||
private CustomCodeArea xpathExpressionArea;
|
||||
@FXML
|
||||
@ -167,7 +167,7 @@ public class XPathPanelController implements Initializable, SettingsOwner {
|
||||
DesignerUtil.rewire(getRuleBuilder().xpathExpressionProperty(), xpathExpressionProperty());
|
||||
|
||||
DesignerUtil.rewire(getRuleBuilder().rulePropertiesProperty(),
|
||||
propertyView.rulePropertiesProperty(), propertyView::setRuleProperties);
|
||||
propertyTableView.rulePropertiesProperty(), propertyTableView::setRuleProperties);
|
||||
}
|
||||
|
||||
|
||||
|
@ -157,14 +157,13 @@ public final class DesignerUtil {
|
||||
*/
|
||||
public static <T> void rewire(Property<T> underlying, ObservableValue<? extends T> ui, Consumer<? super T> setter) {
|
||||
setter.accept(underlying.getValue());
|
||||
underlying.unbind();
|
||||
underlying.bind(ui); // Bindings are garbage collected after the popup dies
|
||||
rewire(underlying, ui);
|
||||
}
|
||||
|
||||
/** Like rewire, with no initialisation. */
|
||||
public static <T> void rewire(Property<T> underlying, ObservableValue<? extends T> source) {
|
||||
underlying.unbind();
|
||||
underlying.bind(source);
|
||||
underlying.bind(source); // Bindings are garbage collected after the popup dies
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,9 +6,11 @@ package net.sourceforge.pmd.util.fxdesigner.util.beans;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
@ -90,6 +92,9 @@ public class RestorePropertyVisitor extends BeanNodeVisitor<SettingsOwner> {
|
||||
|
||||
Iterator<SettingsOwner> existingItems = container.iterator();
|
||||
Class<?> itemType = null;
|
||||
// use a buffer to avoid concurrent modification
|
||||
List<SettingsOwner> itemsToAdd = new ArrayList<>();
|
||||
|
||||
for (SimpleBeanModelNode child : model.getChildrenNodes()) {
|
||||
SettingsOwner item;
|
||||
if (existingItems.hasNext()) {
|
||||
@ -108,9 +113,11 @@ public class RestorePropertyVisitor extends BeanNodeVisitor<SettingsOwner> {
|
||||
}
|
||||
|
||||
child.accept(this, item);
|
||||
container.add(item);
|
||||
itemsToAdd.add(item);
|
||||
}
|
||||
|
||||
container.addAll(itemsToAdd);
|
||||
|
||||
try {
|
||||
PropertyUtils.setProperty(target, model.getPropertyName(), container);
|
||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
|
@ -17,7 +17,7 @@
|
||||
<TabPane fx:id="nodeInfoTabPane" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="300.0" side="LEFT" stylesheets="@../css/designer.css" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER" xmlns="http://javafx.com/javafx/9" xmlns:fx="http://javafx.com/fxml/1" fx:controller="net.sourceforge.pmd.util.fxdesigner.NodeInfoPanelController">
|
||||
|
||||
<tabs>
|
||||
<Tab text="Attributes" fx:id="xpathAttributesTitledPane">
|
||||
<Tab text="Attributes">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<children>
|
||||
@ -41,7 +41,7 @@
|
||||
</AnchorPane>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="metricResultsTitledPane" text="Metrics">
|
||||
<Tab fx:id="metricResultsTab" text="Metrics">
|
||||
<content>
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<children>
|
||||
|
@ -25,7 +25,7 @@
|
||||
AnchorPane.topAnchor="0.0">
|
||||
<content>
|
||||
<AnchorPane>
|
||||
<PropertyTableView fx:id="propertyView"
|
||||
<PropertyTableView fx:id="propertyTableView"
|
||||
AnchorPane.bottomAnchor="0.0"
|
||||
AnchorPane.leftAnchor="0.0"
|
||||
AnchorPane.rightAnchor="0.0"
|
||||
|
6
pom.xml
6
pom.xml
@ -274,7 +274,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code
|
||||
|
||||
<argLine>-Xmx512m -Dfile.encoding=${project.build.sourceEncoding}</argLine>
|
||||
|
||||
<pmd.build-tools.version>1.1.0</pmd.build-tools.version>
|
||||
<pmd.build-tools.version>1.1.1-SNAPSHOT</pmd.build-tools.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@ -448,12 +448,12 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-core</artifactId>
|
||||
<version>6.1.0</version>
|
||||
<version>6.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-java</artifactId>
|
||||
<version>6.1.0</version>
|
||||
<version>6.4.0</version>
|
||||
</dependency>
|
||||
<!-- This contains the dogfood ruleset -->
|
||||
<dependency>
|
||||
|
Reference in New Issue
Block a user