Merge remote-tracking branch 'upstream/master' into pmd6-extract-test-schema-module
This commit is contained in:
8 files changed
+310
-34
No files matched your search
@@ -6749,6 +6749,15 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "341816041",
|
||||
"name": "茅延安",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/100549608?v=4",
|
||||
"profile": "https://github.com/341816041",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@@ -961,6 +961,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/magwas"><img src="https://avatars.githubusercontent.com/u/756838?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Árpád Magosányi</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Amagwas" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/clsaa"><img src="https://avatars.githubusercontent.com/u/32028545?v=4?s=100" width="100px;" alt=""/><br /><sub><b>任贵杰</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Aclsaa" title="Bug reports">🐛</a></td>
|
||||
<td align="center"><a href="https://github.com/341816041"><img src="https://avatars.githubusercontent.com/u/100549608?v=4?s=100" width="100px;" alt=""/><br /><sub><b>茅延安</b></sub></a><br /><a href="https://github.com/pmd/pmd/commits?author=341816041" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -25,6 +25,11 @@ Being based on a proper Antlr grammar, CPD can:
|
||||
* honor [comment-based suppressions](pmd_userdocs_cpd.html#suppression)
|
||||
|
||||
### Fixed Issues
|
||||
* java-bestpractices
|
||||
* [#3455](https://github.com/pmd/pmd/issues/3455): \[java] WhileLoopWithLiteralBoolean - false negative with complex expressions
|
||||
* java-design
|
||||
* [#3729](https://github.com/pmd/pmd/issues/3729): \[java] TooManyMethods ignores "real" methods which are named like getters or setters
|
||||
* [#3949](https://github.com/pmd/pmd/issues/3949): \[java] FinalFieldCouldBeStatic - false negative with unnecessary parenthesis
|
||||
* java-performance
|
||||
* [#3625](https://github.com/pmd/pmd/issues/3625): \[java] AddEmptyString - false negative with empty var
|
||||
|
||||
@@ -32,6 +37,9 @@ Being based on a proper Antlr grammar, CPD can:
|
||||
|
||||
### External Contributions
|
||||
* [#3984](https://github.com/pmd/pmd/pull/3984): \[java] Fix AddEmptyString false-negative issue - [@LiGaOg](https://github.com/LiGaOg)
|
||||
* [#3988](https://github.com/pmd/pmd/pull/3988): \[java] Modify WhileLoopWithLiteralBoolean to meet the missing case #3455 - [@VoidxHoshi](https://github.com/VoidxHoshi)
|
||||
* [#3992](https://github.com/pmd/pmd/pull/3992): \[java] FinalFieldCouldBeStatic - fix false negative with unnecessary parenthesis - [@dalizi007](https://github.com/dalizi007)
|
||||
* [#3994](https://github.com/pmd/pmd/pull/3994): \[java] TooManyMethods - improve getter/setter detection (#3729) - [@341816041](https://github.com/341816041)
|
||||
* [#4017](https://github.com/pmd/pmd/pull/4017): Add Gherkin support to CPD - [@ASBrouwers](https://github.com/ASBrouwers)
|
||||
|
||||
{% endtocmaker %}
|
||||
|
||||
@@ -2171,21 +2171,52 @@ a block `{}` is sufficient.
|
||||
<properties>
|
||||
<property name="xpath">
|
||||
<value>
|
||||
//DoStatement[Expression/PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral] |
|
||||
//WhileStatement[Expression/PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral[@True = false()]]
|
||||
<![CDATA[
|
||||
(: while loops with single boolean literal, maybe parenthesized :)
|
||||
//WhileStatement[Expression/(.|(PrimaryExpression/PrimaryPrefix/Expression))/PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral[@True = false()]]
|
||||
|
|
||||
(: do-while loops with single boolean literal, maybe parenthesized :)
|
||||
//DoStatement[Expression/(.|(PrimaryExpression/PrimaryPrefix/Expression))/PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral]
|
||||
|
|
||||
(: while loops with conditional or'ed boolean literals, maybe parenthesized :)
|
||||
//WhileStatement[Expression/(InclusiveOrExpression|ConditionalOrExpression|(PrimaryExpression/PrimaryPrefix/Expression/(InclusiveOrExpression|ConditionalOrExpression)))
|
||||
[count(PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral) = 2]
|
||||
(: at least one false literal :)
|
||||
[count(PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral[@True = false()]) >= 1]]
|
||||
|
|
||||
(: while loops with conditional and'ed boolean literals, maybe parenthesized :)
|
||||
//WhileStatement[Expression/(AndExpression|ConditionalAndExpression|(PrimaryExpression/PrimaryPrefix/Expression/(AndExpression|ConditionalAndExpression)))
|
||||
(: at least one false literal :)
|
||||
[count(PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral[@True = false()]) >= 1]]
|
||||
|
|
||||
(: do-while loops with conditional or'ed boolean literals, maybe parenthesized :)
|
||||
//DoStatement[Expression/(InclusiveOrExpression|ConditionalOrExpression|(PrimaryExpression/PrimaryPrefix/Expression/(InclusiveOrExpression|ConditionalOrExpression)))
|
||||
[count(PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral) = 2]]
|
||||
|
|
||||
(: do-while loops with conditional and'ed boolean literals, maybe parenthesized :)
|
||||
//DoStatement[Expression/(AndExpression|ConditionalAndExpression|(PrimaryExpression/PrimaryPrefix/Expression/(AndExpression|ConditionalAndExpression)))
|
||||
(: at least one false literal :)
|
||||
[count(PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral[@True = false()]) >= 1
|
||||
(: or two true literals (e.g. true & true) :)
|
||||
or count(PrimaryExpression/PrimaryPrefix/Literal/BooleanLiteral[@True = true()]) = 2]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
<property name="version" value="2.0" />
|
||||
</properties>
|
||||
<example>
|
||||
<![CDATA[
|
||||
public class Example {
|
||||
{
|
||||
while (true) { } // allowed
|
||||
while (false) { } // disallowed
|
||||
do { } while (true); // disallowed
|
||||
do { } while (false); // disallowed
|
||||
do { } while (false | false); // disallowed
|
||||
do { } while (false || false); // disallowed
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
|
||||
@@ -821,6 +821,18 @@ in each object at runtime.
|
||||
or
|
||||
(: another static field :)
|
||||
self::Name[@Image=//FieldDeclaration[@Static=true()]/VariableDeclarator/@Name]
|
||||
or
|
||||
(:unnecessary parenthesis :)
|
||||
self::Expression/PrimaryExpression/PrimaryPrefix/Literal
|
||||
or
|
||||
(:empty array allocation :)
|
||||
self::AllocationExpression[ArrayDimsAndInits/Expression/PrimaryExpression/PrimaryPrefix/*
|
||||
[
|
||||
self::Literal[@IntLiteral = true()][@Image="0"]
|
||||
or
|
||||
self::Expression/PrimaryExpression/PrimaryPrefix/Literal[@IntLiteral = true()][@Image="0"]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
/VariableDeclaratorId
|
||||
@@ -1678,36 +1690,14 @@ complexity and find a way to have more fine grained objects.
|
||||
<property name="version" value="2.0"/>
|
||||
<property name="xpath">
|
||||
<value>
|
||||
<!-- FIXME: Refine XPath to discard 'get' and 'set' methods with Block no more than 3 lines,
|
||||
something like this:
|
||||
not (
|
||||
(
|
||||
starts-with(@Name,'get')
|
||||
or
|
||||
starts-with(@Name,'set')
|
||||
or
|
||||
starts-with(@Name,'is')
|
||||
)
|
||||
and (
|
||||
(
|
||||
(../Block/attribute::endLine)
|
||||
-
|
||||
(../Block/attribute::beginLine)
|
||||
) <= 3
|
||||
)
|
||||
)
|
||||
This will avoid discarding 'real' methods...
|
||||
-->
|
||||
<![CDATA[
|
||||
//ClassOrInterfaceDeclaration/ClassOrInterfaceBody
|
||||
[
|
||||
count(./ClassOrInterfaceBodyDeclaration/MethodDeclaration[
|
||||
not (
|
||||
starts-with(@Name,'get')
|
||||
or
|
||||
starts-with(@Name,'set')
|
||||
or
|
||||
starts-with(@Name,'is')
|
||||
(starts-with(@Name,'get') or starts-with(@Name,'set') or starts-with(@Name,'is'))
|
||||
and
|
||||
count(Block/BlockStatement) <= 1
|
||||
)
|
||||
]) > $maxmethods
|
||||
]
|
||||
|
||||
+156
-7
@@ -6,13 +6,31 @@
|
||||
|
||||
<test-code>
|
||||
<description>do while true</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>3</expected-linenumbers>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>3,5</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
do {
|
||||
} while (true);
|
||||
do {
|
||||
} while ((true));
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>do while true | true</description>
|
||||
<expected-problems>4</expected-problems>
|
||||
<expected-linenumbers>3,4,5,6</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
do { } while (true | true);
|
||||
do { } while (true || true);
|
||||
do { } while ((true | true));
|
||||
do { } while ((true || true));
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
@@ -20,13 +38,48 @@ class Foo {
|
||||
|
||||
<test-code>
|
||||
<description>do while false</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>3</expected-linenumbers>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>3,5</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
do {
|
||||
} while (false);
|
||||
do {
|
||||
} while ((false));
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>do while false | false #3455</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>3,5</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
do {
|
||||
} while (false | false);
|
||||
do {
|
||||
} while ((false | false));
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>do while false || false #3455</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>3,6</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
do {
|
||||
} while (false || false);
|
||||
|
||||
do {
|
||||
} while ((false || false));
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
@@ -46,7 +99,7 @@ class Foo {
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>while true</description>
|
||||
<description>while true - allowed</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
@@ -60,13 +113,31 @@ class Foo {
|
||||
|
||||
<test-code>
|
||||
<description>while false</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>3</expected-linenumbers>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>3,5</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
while (false) {
|
||||
}
|
||||
while ((false)) {
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>while false | false</description>
|
||||
<expected-problems>4</expected-problems>
|
||||
<expected-linenumbers>3,4,5,6</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
while (false | false) { }
|
||||
while ((false | false)) { }
|
||||
while (false || false) { }
|
||||
while ((false || false)) { }
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
@@ -84,4 +155,82 @@ class Foo {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>conditional or with only one boolean literal</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
void bar(boolean arg) {
|
||||
while (false | arg) { }
|
||||
while (false || arg) { }
|
||||
do { } while (false || arg);
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>conditional and with only one boolean literal</description>
|
||||
<expected-problems>3</expected-problems>
|
||||
<expected-linenumbers>3,4,5</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
void bar(boolean arg) {
|
||||
while (false & arg) { }
|
||||
while (false && arg) { }
|
||||
do { } while (false && arg);
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>conditional-and boolean literal</description>
|
||||
<expected-problems>28</expected-problems>
|
||||
<expected-linenumbers>10,11,12,13,14,15,16,17,18,19,20,21,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
class Foo {
|
||||
{
|
||||
// these evaluate to true and are allowed
|
||||
while (true & true) { }
|
||||
while ((true & true)) { }
|
||||
while (true && true) { }
|
||||
while ((true && true)) { }
|
||||
|
||||
// these evaluate to false and should be flagged
|
||||
while (false & false) { } // line 10
|
||||
while ((false & false)) { }
|
||||
while (false && false) { }
|
||||
while ((false && false)) { }
|
||||
while (false & true) { }
|
||||
while ((false & true)) { }
|
||||
while (false && true) { }
|
||||
while ((false && true)) { }
|
||||
while (true & false) { }
|
||||
while ((true & false)) { }
|
||||
while (true && false) { }
|
||||
while ((true && false)) { }
|
||||
|
||||
// do-while loops should always be flagged
|
||||
do {} while (false & false);
|
||||
do {} while ((false & false));
|
||||
do {} while (false && false);
|
||||
do {} while ((false && false));
|
||||
do {} while (true & false);
|
||||
do {} while ((true & false));
|
||||
do {} while (true && false);
|
||||
do {} while ((true && false));
|
||||
do {} while (false & true);
|
||||
do {} while ((false & true));
|
||||
do {} while (false && true);
|
||||
do {} while ((false && true));
|
||||
do {} while (true & true);
|
||||
do {} while ((true & true));
|
||||
do {} while (true && true);
|
||||
do {} while ((true && true));
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
+39
@@ -189,6 +189,45 @@ public class Foo {
|
||||
//private static final int staticFinal = nonStatic; //noncompliant: Non-static field 'nonStatic' cannot be referenced from a static context
|
||||
private static int staticNonFinal = 1; //no violation cause non-final
|
||||
private final int nonStatic2 = staticNonFinal; //violation because it could be static
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#3949 - FinalFieldCouldBeStatic false negative with unnecessary parenthesis</description>
|
||||
<expected-problems>3</expected-problems>
|
||||
<expected-linenumbers>5,8,9</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Foo {
|
||||
public final int BAR = (42);
|
||||
|
||||
// these empty arrays could theoretically be shared and therefore be static
|
||||
private final Object[] argsObjs1 = new Object[0];
|
||||
private final Object[] argsObjs2 = new Object[(0)];
|
||||
|
||||
// not flagging anonymous class instantiation
|
||||
private final StringBuffer mFilter = new StringBuffer(new CharSequence() {
|
||||
@Override public char charAt(int index) { return 'A'; }
|
||||
@Override public int length() { return 1; }
|
||||
@Override public CharSequence subSequence(int start, int end) { return this; }
|
||||
@Override public String toString() { return "Foo"; }
|
||||
});
|
||||
|
||||
// not flagging any instantiation in order to avoid false positives
|
||||
// especially for lists one could still require a separate list for each instance...
|
||||
public final List<String> mList = new ArrayList<>();
|
||||
|
||||
// not flagging instantiation of boxed types - would be a different rule
|
||||
// this is to keep this rule simple
|
||||
public final Integer DefaultInit = new Integer(27);
|
||||
private final String mString = new String("Foo");
|
||||
|
||||
// not flagging array creation. Same reasoning as for lists:
|
||||
// one could still require a separate array for each instance...
|
||||
private final int[] p = new int[42];
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
+49
@@ -113,4 +113,53 @@ public class OuterClass {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<code-fragment id="code_22_real_methods"><![CDATA[
|
||||
public class Foo {
|
||||
public void setMethod1(){int a = 1;a++;}
|
||||
public void setMethod2(){int a = 1;a++;}
|
||||
public void setMethod3(){int a = 1;a++;}
|
||||
public void setMethod4(){int a = 1;a++;}
|
||||
public void setMethod5(){int a = 1;a++;}
|
||||
|
||||
public void getMethod6(){int a = 1;a++;}
|
||||
public void getMethod7(){int a = 1;a++;}
|
||||
public void getMethod8(){int a = 1;a++;}
|
||||
public void getMethod9(){int a = 1;a++;}
|
||||
public void getMethod10(){int a = 1;a++;}
|
||||
|
||||
public boolean isMethod11(){int a = 1;a++;}
|
||||
public boolean isMethod12(){int a = 1;a++;}
|
||||
public boolean isMethod13(){int a = 1;a++;}
|
||||
public boolean isMethod14(){int a = 1;a++;}
|
||||
public boolean isMethod15(){int a = 1;a++;}
|
||||
public boolean isMethod16(){int a = 1;a++;}
|
||||
|
||||
public void method17(){}
|
||||
public void method18(){}
|
||||
public void method19(){}
|
||||
public void method20(){}
|
||||
public void method21(){}
|
||||
public void method22(){}
|
||||
|
||||
private String field;
|
||||
public String getField() { return field; } // real getter
|
||||
public void setField(String field) { this.field = field; } // real setter
|
||||
}
|
||||
]]>
|
||||
</code-fragment>
|
||||
|
||||
<test-code>
|
||||
<description>#3729 TooManyMethods ignores "real" methods which are named like getters or setters - default</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>1</expected-linenumbers>
|
||||
<code-ref id="code_22_real_methods"/>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#3729 TooManyMethods ignores "real" methods which are named like getters or setters - max 22 methods</description>
|
||||
<rule-property name="maxmethods">22</rule-property>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code-ref id="code_22_real_methods"/>
|
||||
</test-code>
|
||||
</test-data>
|
||||
Reference in new issue
Block a user