Merge branch '7.0.x' into pr/3120
Refs #312O
This commit is contained in:
commit
ad683b8c46
90 files changed
+1764
-2012
No files matched your search
+21
-21
@@ -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"/>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
+29
-1
@@ -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() {
|
||||
|
||||
+8
-20
@@ -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();
|
||||
}
|
||||
}
|
||||
+15
-32
@@ -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();
|
||||
}
|
||||
}
|
||||
+150
-220
File diff suppressed because it is too large.
Load diff
+27
-39
@@ -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
Reference in new issue
Block a user