Merge branch '7.0.x' into pr/3120

Refs #312O
This commit is contained in:
Clément Fournier committed 2021-02-19 22:11:06 +01:00
commit ad683b8c46
90 files changed
+1764 -2012

No files matched your search

+21 -21
View File
@@ -9,24 +9,24 @@
<!-- bestpractices.xml -->
<!-- <rule ref="category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod"/> -->
<rule ref="category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod"/>
<rule ref="category/java/bestpractices.xml/AccessorClassGeneration"/>
<rule ref="category/java/bestpractices.xml/AccessorMethodGeneration"/>
<!-- <rule ref="category/java/bestpractices.xml/ArrayIsStoredDirectly"/> -->
<rule ref="category/java/bestpractices.xml/AvoidMessageDigestField"/>
<rule ref="category/java/bestpractices.xml/AvoidPrintStackTrace"/>
<!-- <rule ref="category/java/bestpractices.xml/AvoidReassigningCatchVariables"/> -->
<!-- <rule ref="category/java/bestpractices.xml/AvoidReassigningLoopVariables"/> -->
<!-- <rule ref="category/java/bestpractices.xml/AvoidReassigningParameters"/> -->
<rule ref="category/java/bestpractices.xml/AvoidReassigningCatchVariables"/>
<rule ref="category/java/bestpractices.xml/AvoidReassigningLoopVariables"/>
<rule ref="category/java/bestpractices.xml/AvoidReassigningParameters"/>
<rule ref="category/java/bestpractices.xml/AvoidStringBufferField"/>
<!-- <rule ref="category/java/bestpractices.xml/AvoidUsingHardCodedIP"/> -->
<!-- <rule ref="category/java/bestpractices.xml/CheckResultSet"/> -->
<rule ref="category/java/bestpractices.xml/AvoidUsingHardCodedIP"/>
<rule ref="category/java/bestpractices.xml/CheckResultSet"/>
<rule ref="category/java/bestpractices.xml/ConstantsInInterface"/>
<rule ref="category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt"/>
<rule ref="category/java/bestpractices.xml/DoubleBraceInitialization"/>
<!-- <rule ref="category/java/bestpractices.xml/ForLoopCanBeForeach"/> -->
<rule ref="category/java/bestpractices.xml/ForLoopVariableCount"/>
<!-- <rule ref="category/java/bestpractices.xml/GuardLogStatement"/> -->
<rule ref="category/java/bestpractices.xml/GuardLogStatement"/>
<!-- <rule ref="category/java/bestpractices.xml/JUnit4SuitesShouldUseSuiteAnnotation"/> -->
<!-- <rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseAfterAnnotation"/> -->
<!-- <rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseBeforeAnnotation"/> -->
@@ -47,13 +47,13 @@
<!-- <rule ref="category/java/bestpractices.xml/ReplaceHashtableWithMap"/> -->
<!-- <rule ref="category/java/bestpractices.xml/ReplaceVectorWithList"/> -->
<rule ref="category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault"/>
<!-- <rule ref="category/java/bestpractices.xml/SystemPrintln"/> -->
<rule ref="category/java/bestpractices.xml/SystemPrintln"/>
<rule ref="category/java/bestpractices.xml/UnusedAssignment"/>
<!-- <rule ref="category/java/bestpractices.xml/UnusedFormalParameter"/> -->
<rule ref="category/java/bestpractices.xml/UnusedFormalParameter"/>
<!-- <rule ref="category/java/bestpractices.xml/UnusedImports"/> -->
<!-- <rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/> -->
<!-- <rule ref="category/java/bestpractices.xml/UnusedPrivateField"/> -->
<!-- <rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/> -->
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/>
<rule ref="category/java/bestpractices.xml/UseAssertEqualsInsteadOfAssertTrue"/>
<rule ref="category/java/bestpractices.xml/UseAssertNullInsteadOfAssertTrue"/>
<rule ref="category/java/bestpractices.xml/UseAssertSameInsteadOfAssertTrue"/>
@@ -61,7 +61,7 @@
<rule ref="category/java/bestpractices.xml/UseCollectionIsEmpty"/>
<!-- <rule ref="category/java/bestpractices.xml/UseTryWithResources"/> -->
<!-- <rule ref="category/java/bestpractices.xml/UseVarargs"/> -->
<!-- <rule ref="category/java/bestpractices.xml/WhileLoopWithLiteralBoolean"/> -->
<rule ref="category/java/bestpractices.xml/WhileLoopWithLiteralBoolean"/>
<!-- codestyle.xml -->
@@ -86,15 +86,15 @@
<rule ref="category/java/codestyle.xml/ForLoopShouldBeWhileLoop"/>
<rule ref="category/java/codestyle.xml/FormalParameterNamingConventions"/>
<rule ref="category/java/codestyle.xml/GenericsNaming"/>
<!-- <rule ref="category/java/codestyle.xml/IdenticalCatchBranches"/> -->
<rule ref="category/java/codestyle.xml/IdenticalCatchBranches"/>
<!-- <rule ref="category/java/codestyle.xml/LinguisticNaming"/> -->
<rule ref="category/java/codestyle.xml/LocalHomeNamingConvention"/>
<rule ref="category/java/codestyle.xml/LocalInterfaceSessionNamingConvention"/>
<!-- <rule ref="category/java/codestyle.xml/LocalVariableCouldBeFinal"/> -->
<rule ref="category/java/codestyle.xml/LocalVariableCouldBeFinal"/>
<rule ref="category/java/codestyle.xml/LocalVariableNamingConventions"/>
<rule ref="category/java/codestyle.xml/LongVariable"/>
<rule ref="category/java/codestyle.xml/MDBAndSessionBeanNamingConvention"/>
<!-- <rule ref="category/java/codestyle.xml/MethodArgumentCouldBeFinal"/> -->
<rule ref="category/java/codestyle.xml/MethodArgumentCouldBeFinal"/>
<rule ref="category/java/codestyle.xml/MethodNamingConventions"/>
<rule ref="category/java/codestyle.xml/NoPackage"/>
<!-- <rule ref="category/java/codestyle.xml/OnlyOneReturn"/> -->
@@ -110,7 +110,7 @@
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryCast"/> -->
<rule ref="category/java/codestyle.xml/UnnecessaryConstructor"/>
<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/>
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/> -->
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/>
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryModifier"/> -->
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryReturn"/> -->
<!-- <rule ref="category/java/codestyle.xml/UseDiamondOperator"/> -->
@@ -153,7 +153,7 @@
<!-- <rule ref="category/java/design.xml/SimplifiedTernary"/> -->
<!-- <rule ref="category/java/design.xml/SimplifyBooleanAssertion"/> -->
<rule ref="category/java/design.xml/SimplifyBooleanExpressions"/>
<!-- <rule ref="category/java/design.xml/SimplifyBooleanReturns"/> -->
<rule ref="category/java/design.xml/SimplifyBooleanReturns"/>
<!-- <rule ref="category/java/design.xml/SimplifyConditional"/> -->
<!-- <rule ref="category/java/design.xml/SingularField"/> -->
<!-- <rule ref="category/java/design.xml/SwitchDensity"/> -->
@@ -173,7 +173,7 @@
<!-- errorprone.xml -->
<!-- <rule ref="category/java/errorprone.xml/AssignmentInOperand"/> -->
<rule ref="category/java/errorprone.xml/AssignmentInOperand"/>
<!-- <rule ref="category/java/errorprone.xml/AssignmentToNonFinalStatic"/> -->
<rule ref="category/java/errorprone.xml/AvoidAssertAsIdentifier"/>
<!-- <rule ref="category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop"/> -->
@@ -295,10 +295,10 @@
<!-- <rule ref="category/java/performance.xml/BigIntegerInstantiation"/> -->
<!-- <rule ref="category/java/performance.xml/BooleanInstantiation"/> -->
<rule ref="category/java/performance.xml/ByteInstantiation"/>
<!-- <rule ref="category/java/performance.xml/ConsecutiveAppendsShouldReuse"/> -->
<rule ref="category/java/performance.xml/ConsecutiveAppendsShouldReuse"/>
<!-- <rule ref="category/java/performance.xml/ConsecutiveLiteralAppends"/> -->
<rule ref="category/java/performance.xml/InefficientEmptyStringCheck"/>
<!-- <rule ref="category/java/performance.xml/InefficientStringBuffering"/> -->
<rule ref="category/java/performance.xml/InefficientStringBuffering"/>
<!-- <rule ref="category/java/performance.xml/InsufficientStringBufferDeclaration"/> -->
<rule ref="category/java/performance.xml/IntegerInstantiation"/>
<rule ref="category/java/performance.xml/LongInstantiation"/>
+4
View File
@@ -122,18 +122,22 @@ The following previously deprecated rules have been finally removed:
* java-bestpractices
* [#342](https://github.com/pmd/pmd/issues/342): \[java] AccessorMethodGeneration: Name clash with another public field not properly handled
* [#755](https://github.com/pmd/pmd/issues/755): \[java] AccessorClassGeneration false positive for private constructors
* [#770](https://github.com/pmd/pmd/issues/770): \[java] UnusedPrivateMethod yields false positive for counter-variant arguments
* [#807](https://github.com/pmd/pmd/issues/807): \[java] AccessorMethodGeneration false positive with overloads
* [#1189](https://github.com/pmd/pmd/issues/1189): \[java] UnusedPrivateMethod false positive from inner class via external class
* [#1212](https://github.com/pmd/pmd/issues/1212): \[java] Don't raise JUnitTestContainsTooManyAsserts on JUnit 5's assertAll
* [#1422](https://github.com/pmd/pmd/issues/1422): \[java] JUnitTestsShouldIncludeAssert false positive with inherited @Rule field
* [#1565](https://github.com/pmd/pmd/issues/1565): \[java] JUnitAssertionsShouldIncludeMessage false positive with AssertJ
* [#1969](https://github.com/pmd/pmd/issues/1969): \[java] MissingOverride false-positive triggered by package-private method overwritten in another package by extending class
* [#1998](https://github.com/pmd/pmd/issues/1998): \[java] AccessorClassGeneration false-negative: subclass calls private constructor
* [#2130](https://github.com/pmd/pmd/issues/2130): \[java] UnusedLocalVariable: false-negative with array
* [#2147](https://github.com/pmd/pmd/issues/2147): \[java] JUnitTestsShouldIncludeAssert - false positives with lambdas and static methods
* [#2542](https://github.com/pmd/pmd/issues/2542): \[java] UseCollectionIsEmpty can not detect the case `foo.bar().size()`
* [#2796](https://github.com/pmd/pmd/issue/2796): \[java] UnusedAssignment false positive with call chains
* [#2797](https://github.com/pmd/pmd/issues/2797): \[java] MissingOverride long-standing issues
* [#2806](https://github.com/pmd/pmd/issues/2806): \[java] SwitchStmtsShouldHaveDefault false-positive with Java 14 switch non-fallthrough branches
* [#2883](https://github.com/pmd/pmd/issues/2883): \[java] JUnitAssertionsShouldIncludeMessage false positive with method call
* [#2890](https://github.com/pmd/pmd/issues/2890): \[java] UnusedPrivateMethod false positive with generics
* java-codestyle
* [#1673](https://github.com/pmd/pmd/issues/1673): \[java] UselessParentheses false positive with conditional operator
* [#1790](https://github.com/pmd/pmd/issues/1790): \[java] UnnecessaryFullyQualifiedName false positive with enum constant
@@ -454,7 +454,7 @@ public interface Node {
default @Nullable Node getNextSibling() {
Node parent = getParent();
int idx = getIndexInParent();
if (parent != null && idx < parent.getNumChildren()) {
if (parent != null && idx + 1 < parent.getNumChildren()) {
return parent.getChild(idx + 1);
}
return null;
@@ -129,7 +129,7 @@ import net.sourceforge.pmd.lang.ast.internal.StreamImpl;
*
* @since 7.0.0
*/
public interface NodeStream<T extends Node> extends Iterable<@NonNull T> {
public interface NodeStream<@NonNull T extends Node> extends Iterable<@NonNull T> {
/**
* Returns a node stream consisting of the results of replacing each
@@ -1086,7 +1086,7 @@ public interface NodeStream<T extends Node> extends Iterable<@NonNull T> {
*/
@SafeVarargs // this method is static because of the generic varargs
@SuppressWarnings("unchecked")
static <I, O> Function<@Nullable I, @Nullable O> asInstanceOf(Class<? extends O> c1, Class<? extends O>... rest) {
static <O> Function<@Nullable Object, @Nullable O> asInstanceOf(Class<? extends O> c1, Class<? extends O>... rest) {
if (rest.length == 0) {
return obj -> c1.isInstance(obj) ? (O) obj : null;
}
@@ -4,14 +4,18 @@
package net.sourceforge.pmd.properties;
import static java.util.Arrays.asList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.sourceforge.pmd.properties.PropertyBuilder.GenericCollectionPropertyBuilder;
import net.sourceforge.pmd.properties.PropertyBuilder.GenericPropertyBuilder;
import net.sourceforge.pmd.properties.PropertyBuilder.RegexPropertyBuilder;
import net.sourceforge.pmd.properties.constraints.NumericConstraints;
import net.sourceforge.pmd.properties.constraints.PropertyConstraint;
import net.sourceforge.pmd.util.CollectionUtil;
//@formatter:off
/**
@@ -320,4 +324,21 @@ public final class PropertyFactory {
}
/**
* Returns a builder for a property having as value a list of {@code <T>}. The
* format of the individual items is the same as for {@linkplain #enumProperty(String, Map)}.
*
* @param name Name of the property to build
* @param enumClass Class of the values
* @param labelMaker Function that associates enum constants to their label
* @param <T> Value type of the property
*
* @return A new builder
*/
public static <T extends Enum<T>> GenericCollectionPropertyBuilder<T, List<T>> enumListProperty(String name, Class<T> enumClass, Function<? super T, String> labelMaker) {
Map<String, T> enumMap = CollectionUtil.associateBy(asList(enumClass.getEnumConstants()), labelMaker);
return enumListProperty(name, enumMap);
}
}
@@ -4,13 +4,13 @@
package net.sourceforge.pmd.util;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyIterator;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -259,7 +259,7 @@ public final class CollectionUtil {
}
List<T> union = new ArrayList<>();
union.add(first);
union.addAll(Arrays.asList(rest));
union.addAll(asList(rest));
return Collections.unmodifiableList(union);
}
@@ -302,7 +302,7 @@ public final class CollectionUtil {
@SuppressWarnings("unchecked")
public static <V> Set<V> setUnion(Collection<? extends V> set, V first, V... newElements) {
if (set instanceof PSet) {
return ((PSet<V>) set).plus(first).plusAll(Arrays.asList(newElements));
return ((PSet<V>) set).plus(first).plusAll(asList(newElements));
}
Set<V> newSet = new LinkedHashSet<>(set.size() + 1 + newElements.length);
newSet.addAll(set);
@@ -414,7 +414,7 @@ public final class CollectionUtil {
if (from == null) {
return emptyList();
}
return map(Arrays.asList(from), f);
return map(asList(from), f);
}
/**
@@ -9,6 +9,7 @@ import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.root;
import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.tree;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.util.List;
@@ -113,6 +114,22 @@ public class AbstractNodeTest {
}
}
@Test
public void testPrevNextSiblings() {
DummyRoot root = tree(() -> root(node(), node()));
assertNull(root.getNextSibling());
assertNull(root.getPreviousSibling());
DummyNode c0 = root.getChild(0);
DummyNode c1 = root.getChild(1);
assertSame(c0, c1.getPreviousSibling());
assertSame(c1, c0.getNextSibling());
assertNull(c1.getNextSibling());
assertNull(c0.getPreviousSibling());
}
/**
* Explicitly tests the {@code remove} method, and implicitly the {@code removeChildAtIndex} method.
* This is a border case as the root node does not have any parent.
@@ -8,6 +8,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.rule.internal.JavaRuleUtil;
import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
import net.sourceforge.pmd.lang.java.types.JVariableSig;
@@ -95,7 +96,10 @@ public interface ASTAssignableExpr extends ASTPrimaryExpression {
/** The value of the variable is read. */
READ,
/** The value is written to, possibly being read before or after. */
/**
* The value is written to, possibly being read before or after.
* Also see {@link JavaRuleUtil#isVarAccessReadAndWrite(ASTNamedReferenceExpr)}.
*/
WRITE
}
}
@@ -21,7 +21,7 @@ import net.sourceforge.pmd.lang.ast.NodeStream;
*/
public final class ASTBreakStatement extends AbstractStatement {
private static final Function<JavaNode, ASTStatement> BREAK_TARGET_MAPPER =
private static final Function<Object, ASTStatement> BREAK_TARGET_MAPPER =
NodeStream.asInstanceOf(ASTLoopStatement.class, ASTSwitchStatement.class);
ASTBreakStatement(int id) {
@@ -22,7 +22,7 @@ import net.sourceforge.pmd.lang.ast.NodeStream;
*/
public final class ASTContinueStatement extends AbstractStatement {
private static final Function<JavaNode, ASTLoopStatement> CONTINUE_TARGET_MAPPER =
private static final Function<Object, ASTLoopStatement> CONTINUE_TARGET_MAPPER =
NodeStream.asInstanceOf(ASTLoopStatement.class);
ASTContinueStatement(int id) {
@@ -25,6 +25,7 @@ public final class ASTDoStatement extends AbstractStatement implements ASTLoopSt
* Returns the node that represents the guard of this loop.
* This may be any expression of type boolean.
*/
@Override
public ASTExpression getCondition() {
return (ASTExpression) getChild(1);
}
@@ -34,6 +35,7 @@ public final class ASTDoStatement extends AbstractStatement implements ASTLoopSt
* Returns the statement that will be run while the guard
* evaluates to true.
*/
@Override
public ASTStatement getBody() {
return (ASTStatement) getChild(0);
}
@@ -29,13 +29,7 @@ public final class ASTForStatement extends AbstractStatement implements ASTLoopS
}
/**
* Returns the node that represents the condition of this loop.
* This may be any expression of type boolean.
*
* <p>If there is no specified guard, then returns null.
*/
@Nullable
@Override
public ASTExpression getCondition() {
return getFirstChildOfType(ASTExpression.class);
}
@@ -58,9 +52,5 @@ public final class ASTForStatement extends AbstractStatement implements ASTLoopS
return update == null ? null : update.getExprList();
}
/** Returns the statement that represents the body of this loop. */
public ASTStatement getBody() {
return (ASTStatement) getChild(getNumChildren() - 1);
}
}
@@ -43,12 +43,5 @@ public final class ASTForeachStatement extends AbstractStatement implements Inte
return getFirstChildOfType(ASTExpression.class);
}
/**
* Returns the statement that represents the body of this
* loop.
*/
public ASTStatement getBody() {
return (ASTStatement) getChild(getNumChildren() - 1);
}
}
@@ -114,6 +114,19 @@ public abstract class ASTList<N extends JavaNode> extends AbstractJavaNode imple
return list == null ? 0 : list.size();
}
/**
* Returns the element if there is exactly one, otherwise returns null.
*
* @param list List node
* @param <N> Type of elements
*
* @return An element, or null.
*/
public static <N extends JavaNode> @Nullable N singleOrNull(@Nullable ASTList<N> list) {
return list == null || list.size() != 1 ? null : list.get(0);
}
/**
* Super type for *nonempty* lists that *only* have nodes of type {@code <T>}
* as a child.
@@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.java.ast;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* A loop statement.
*
@@ -19,4 +21,23 @@ package net.sourceforge.pmd.lang.java.ast;
*
*/
public interface ASTLoopStatement extends ASTStatement {
/** Returns the statement that represents the body of this loop. */
default ASTStatement getBody() {
return (ASTStatement) getLastChild();
}
/**
* Returns the node that represents the condition of this loop.
* This may be any expression of type boolean.
*
* <p>If there is no specified guard, then returns null (in particular,
* returns null if this is a foreach loop).
*/
default @Nullable ASTExpression getCondition() {
return null;
}
}
@@ -22,7 +22,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public final class ASTMethodCall extends AbstractInvocationExpr
implements ASTPrimaryExpression,
QualifiableExpression,
InvocationNode {
InvocationNode,
MethodUsage {
ASTMethodCall(int id) {
super(id);
@@ -50,7 +50,6 @@ public final class ASTMethodDeclaration extends AbstractMethodOrConstructorDecla
return visitor.visit(this, data);
}
/**
* Returns true if this method is overridden.
* TODO for now, this just checks for an @Override annotation,
@@ -22,7 +22,11 @@ import net.sourceforge.pmd.lang.java.types.TypeSystem;
*
* </pre>
*/
public final class ASTMethodReference extends AbstractJavaExpr implements ASTPrimaryExpression, QualifiableExpression, LeftRecursiveNode {
public final class ASTMethodReference extends AbstractJavaExpr
implements ASTPrimaryExpression,
QualifiableExpression,
LeftRecursiveNode,
MethodUsage {
private JMethodSig functionalMethod;
private JMethodSig compileTimeDecl;
@@ -90,6 +94,7 @@ public final class ASTMethodReference extends AbstractJavaExpr implements ASTPri
* Returns the method name, or an {@link JConstructorSymbol#CTOR_NAME}
* if this is a {@linkplain #isConstructorReference() constructor reference}.
*/
@Override
public @NonNull String getMethodName() {
return super.getImage();
}
@@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -11,6 +13,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.rule.xpath.DeprecatedAttribute;
@@ -50,6 +53,8 @@ public final class ASTVariableDeclaratorId extends AbstractTypedSymbolDeclarator
private VariableNameDeclaration nameDeclaration;
private List<ASTNamedReferenceExpr> usages = Collections.emptyList();
ASTVariableDeclaratorId(int id) {
super(id);
}
@@ -72,10 +77,33 @@ public final class ASTVariableDeclaratorId extends AbstractTypedSymbolDeclarator
nameDeclaration = decl;
}
/**
* @deprecated transitional, use {@link #getLocalUsages()}
*/
@Deprecated
public List<NameOccurrence> getUsages() {
return getScope().getDeclarations(VariableNameDeclaration.class).get(nameDeclaration);
}
/**
* Returns an unmodifiable list of the usages of this variable that
* are made in this file. Note that for a record component, this returns
* usages both for the formal parameter symbol and its field counterpart.
*
* <p>Note that a variable initializer is not part of the usages
* (though this should be evident from the return type).
*/
public List<ASTNamedReferenceExpr> getLocalUsages() {
return usages;
}
void addUsage(ASTNamedReferenceExpr usage) {
if (usages.isEmpty()) {
usages = new ArrayList<>(4); //make modifiable
}
usages.add(usage);
}
/**
* Returns the extra array dimensions associated with this variable.
* For example in the declaration {@code int a[]}, {@link #getTypeNode()}
@@ -94,13 +122,13 @@ public final class ASTVariableDeclaratorId extends AbstractTypedSymbolDeclarator
return getModifierOwnerParent().getModifiers();
}
@Override
public Visibility getVisibility() {
return isPatternBinding() ? Visibility.V_LOCAL
: getModifierOwnerParent().getVisibility();
}
private AccessNode getModifierOwnerParent() {
JavaNode parent = getParent();
if (parent instanceof ASTVariableDeclarator) {
@@ -24,19 +24,12 @@ public final class ASTWhileStatement extends AbstractStatement implements ASTLoo
* Returns the node that represents the guard of this loop.
* This may be any expression of type boolean.
*/
@Override
public ASTExpression getCondition() {
return (ASTExpression) getChild(0);
}
/**
* Returns the statement that will be run while the guard
* evaluates to true.
*/
public ASTStatement getBody() {
return (ASTStatement) getChild(1);
}
@Override
protected <P, R> R acceptVisitor(JavaVisitor<? super P, ? extends R> visitor, P data) {
@@ -161,4 +161,28 @@ public enum BinaryOp implements InternalInterfaces.OperatorLike {
return -1;
}
}
/**
* Complement, for boolean operators. Eg for {@code ==}, return {@code !=},
* for {@code <=}, returns {@code >}. Returns null if this is another kind
* of operator.
*/
public BinaryOp getComplement() {
switch (this) {
case CONDITIONAL_OR: return CONDITIONAL_AND;
case CONDITIONAL_AND: return CONDITIONAL_OR;
case OR: return AND;
case AND: return OR;
case EQ: return NE;
case NE: return EQ;
case LE: return GT;
case GE: return LT;
case GT: return LE;
case LT: return GE;
default: return null;
}
}
}
@@ -10,6 +10,7 @@ import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.ast.NodeStream;
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccTokenDocument;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
import net.sourceforge.pmd.lang.java.internal.JavaAstProcessor;
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
@@ -122,6 +123,20 @@ public final class InternalApiBridge {
AstDisambiguationPass.disambigWithCtx(nodes, ctx);
}
public static void usageResolution(JavaAstProcessor processor, ASTCompilationUnit root) {
root.descendants(ASTNamedReferenceExpr.class)
.crossFindBoundaries()
.forEach(node -> {
JVariableSymbol sym = node.getReferencedSym();
if (sym != null) {
ASTVariableDeclaratorId reffed = sym.tryGetNode();
if (reffed != null) { // declared in this file
reffed.addUsage(node);
}
}
});
}
public static @Nullable JTypeMirror getTypeMirrorInternal(TypeNode node) {
return ((AbstractJavaTypeNode) node).getTypeMirrorInternal();
}
@@ -4,10 +4,8 @@
package net.sourceforge.pmd.lang.java.ast;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
import net.sourceforge.pmd.lang.java.types.JMethodSig;
import net.sourceforge.pmd.lang.java.types.OverloadSelectionResult;
@@ -24,7 +22,7 @@ import net.sourceforge.pmd.lang.java.types.OverloadSelectionResult;
* of the {@linkplain #getMethodType() compile-time declaration}
* of this node.
*/
public interface InvocationNode extends TypeNode {
public interface InvocationNode extends TypeNode, MethodUsage {
/**
* Returns the node representing the list of arguments
@@ -57,12 +55,5 @@ public interface InvocationNode extends TypeNode {
*/
OverloadSelectionResult getOverloadSelectionInfo();
/**
* Returns the name of the called method. If this is a constructor
* call, returns {@link JConstructorSymbol#CTOR_NAME}.
*/
default @NonNull String getMethodName() {
return JConstructorSymbol.CTOR_NAME;
}
}
@@ -5,6 +5,7 @@
package net.sourceforge.pmd.lang.java.ast;
import net.sourceforge.pmd.lang.ast.AstVisitorBase;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
/**
* Base implementation of {@link JavaVisitor}. This adds delegation logic
@@ -185,11 +186,6 @@ public class JavaVisitorBase<P, R> extends AstVisitorBase<P, R> implements JavaV
return visitPrimaryExpr(node, data);
}
@Override
public R visit(ASTFieldAccess node, P data) {
return visitPrimaryExpr(node, data);
}
@Override
public R visit(ASTConstructorCall node, P data) {
return visitPrimaryExpr(node, data);
@@ -207,10 +203,18 @@ public class JavaVisitorBase<P, R> extends AstVisitorBase<P, R> implements JavaV
return visitPrimaryExpr(node, data);
}
public R visitNamedExpr(ASTNamedReferenceExpr node, P data) {
return visitPrimaryExpr(node, data);
}
@Override
public R visit(ASTVariableAccess node, P data) {
return visitPrimaryExpr(node, data);
return visitNamedExpr(node, data);
}
@Override
public R visit(ASTFieldAccess node, P data) {
return visitNamedExpr(node, data);
}
@@ -0,0 +1,27 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
/**
* A node that uses another method or constructor. Those are
* {@link InvocationNode#getMethodType() InvocationNode}s and
* {@link ASTMethodReference#getReferencedMethod() MethodReference}.
*
* TODO should these method be named the same, and added to this interface?
*/
public interface MethodUsage extends JavaNode {
/**
* Returns the name of the called method. If this is a constructor
* call, returns {@link JConstructorSymbol#CTOR_NAME}.
*/
default @NonNull String getMethodName() {
return JConstructorSymbol.CTOR_NAME;
}
}
@@ -145,6 +145,7 @@ public final class JavaAstProcessor {
bench("2. Symbol table resolution", () -> SymbolTableResolver.traverse(this, acu));
bench("3. AST disambiguation", () -> InternalApiBridge.disambigWithCtx(NodeStream.of(acu), ReferenceCtx.root(this, acu)));
bench("4. Comment assignment", () -> InternalApiBridge.assignComments(acu));
bench("5. Usage resolution", () -> InternalApiBridge.usageResolution(this, acu));
}
public TypeSystem getTypeSystem() {
@@ -5,45 +5,33 @@
package net.sourceforge.pmd.lang.java.rule.bestpractices;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.rule.RuleTargetSelector;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
public class AbstractClassWithoutAbstractMethodRule extends AbstractJavaRule {
public class AbstractClassWithoutAbstractMethodRule extends AbstractJavaRulechainRule {
@Override
protected @NonNull RuleTargetSelector buildTargetSelector() {
return RuleTargetSelector.forTypes(ASTClassOrInterfaceDeclaration.class);
public AbstractClassWithoutAbstractMethodRule() {
super(ASTClassOrInterfaceDeclaration.class);
}
@Override
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
if (!node.isAbstract() || doesExtend(node) || doesImplement(node)) {
if (node.isInterface() || !node.isAbstract() || doesExtend(node) || doesImplement(node)) {
return data;
}
int countOfAbstractMethods = 0;
for (ASTMethodDeclaration methodDecl : node.descendants(ASTMethodDeclaration.class)) {
if (methodDecl.isAbstract()) {
countOfAbstractMethods++;
}
}
if (countOfAbstractMethods == 0) {
if (node.getDeclarations(ASTMethodDeclaration.class).none(ASTMethodDeclaration::isAbstract)) {
addViolation(data, node);
}
return data;
}
private boolean doesExtend(ASTClassOrInterfaceDeclaration node) {
return node.getFirstChildOfType(ASTExtendsList.class) != null;
return node.getSuperClassTypeNode() != null;
}
private boolean doesImplement(ASTClassOrInterfaceDeclaration node) {
return node.getFirstChildOfType(ASTImplementsList.class) != null;
return !node.getSuperInterfaceTypeNodes().isEmpty();
}
}
@@ -4,48 +4,31 @@
package net.sourceforge.pmd.lang.java.rule.bestpractices;
import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
import net.sourceforge.pmd.lang.java.ast.ASTCatchClause;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.AccessType;
import net.sourceforge.pmd.lang.java.ast.ASTCatchParameter;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.lang.rule.RuleTargetSelector;
public class AvoidReassigningCatchVariablesRule extends AbstractJavaRule {
public AvoidReassigningCatchVariablesRule() {
addRuleChainVisit(ASTCatchClause.class);
@Override
protected @NonNull RuleTargetSelector buildTargetSelector() {
return RuleTargetSelector.forTypes(ASTCatchParameter.class);
}
@Override
public Object visit(ASTCatchClause catchStatement, Object data) {
ASTVariableDeclaratorId caughtExceptionId = catchStatement.getParameter().getVarId();
String caughtExceptionVar = caughtExceptionId.getName();
for (NameOccurrence usage : caughtExceptionId.getUsages()) {
JavaNode operation = getOperationOfUsage(usage);
if (isAssignment(operation)) {
String assignedVar = getAssignedVariableName(operation);
if (caughtExceptionVar.equals(assignedVar)) {
addViolation(data, operation, caughtExceptionVar);
}
public Object visit(ASTCatchParameter catchParam, Object data) {
ASTVariableDeclaratorId caughtExceptionId = catchParam.getVarId();
for (ASTNamedReferenceExpr usage : caughtExceptionId.getLocalUsages()) {
if (usage.getAccessType() == AccessType.WRITE) {
addViolation(data, usage, caughtExceptionId.getName());
}
}
return data;
}
private JavaNode getOperationOfUsage(NameOccurrence usage) {
return usage.getLocation()
.getFirstParentOfType(ASTPrimaryExpression.class)
.getParent();
}
private boolean isAssignment(JavaNode operation) {
return operation.hasDescendantOfType(ASTAssignmentOperator.class);
}
private String getAssignedVariableName(JavaNode operation) {
return operation.getFirstDescendantOfType(ASTName.class).getImage();
}
}
@@ -4,55 +4,43 @@
package net.sourceforge.pmd.lang.java.rule.bestpractices;
import java.util.List;
import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.AccessType;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
public class AvoidReassigningParametersRule extends AbstractJavaRule {
public class AvoidReassigningParametersRule extends AbstractJavaRulechainRule {
@Override
public Object visit(ASTMethodDeclarator node, Object data) {
Map<VariableNameDeclaration, List<NameOccurrence>> params = node.getScope()
.getDeclarations(VariableNameDeclaration.class);
this.lookForViolation(params, data);
return super.visit(node, data);
public AvoidReassigningParametersRule() {
super(ASTMethodDeclaration.class, ASTConstructorDeclaration.class);
}
private void lookForViolation(Map<VariableNameDeclaration, List<NameOccurrence>> params, Object data) {
for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry : params.entrySet()) {
VariableNameDeclaration decl = entry.getKey();
List<NameOccurrence> usages = entry.getValue();
@Override
public Object visit(ASTMethodDeclaration node, Object data) {
lookForViolations(node, data);
return data;
}
// Only look for formal parameters
if (!decl.getDeclaratorId().isFormalParameter()) {
continue;
}
for (NameOccurrence occ : usages) {
JavaNameOccurrence jocc = (JavaNameOccurrence) occ;
if ((jocc.isOnLeftHandSide() || jocc.isSelfAssignment())
&& jocc.getNameForWhichThisIsAQualifier() == null && !jocc.useThisOrSuper() && !decl.isVarargs()
&& (!decl.isArray()
|| jocc.getLocation().getParent().getParent().getNumChildren() == 1)) {
// not an array or no primary suffix to access the array
// values
addViolation(data, decl.getNode(), decl.getImage());
@Override
public Object visit(ASTConstructorDeclaration node, Object data) {
lookForViolations(node, data);
return data;
}
private void lookForViolations(ASTMethodOrConstructorDeclaration node, Object data) {
for (ASTFormalParameter formal : node.getFormalParameters()) {
ASTVariableDeclaratorId varId = formal.getVarId();
for (ASTNamedReferenceExpr usage : varId.getLocalUsages()) {
if (usage.getAccessType() == AccessType.WRITE) {
addViolation(data, usage, varId.getName());
}
}
}
}
@Override
public Object visit(ASTConstructorDeclaration node, Object data) {
Map<VariableNameDeclaration, List<NameOccurrence>> params = node.getScope()
.getDeclarations(VariableNameDeclaration.class);
this.lookForViolation(params, data);
return super.visit(node, data);
}
}
Loaded 30 of 90 files, more files were not shown because too many files have changed in this diff. Show more