Merge remote-tracking branch 'upstream/master' into pmd6-extract-test-schema-module

This commit is contained in:
Clément Fournier committed 2022-07-10 13:57:29 +02:00
commit 0c1bad6972
8 files changed
+310 -34

No files matched your search

+9
View File
@@ -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,
+1
View File
@@ -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>
+8
View File
@@ -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
]
@@ -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>
@@ -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>
@@ -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>