[java] New rule ConfusingArgumentToVarargsMethod (#4971)

Merge pull request #4971 from oowekyala:new-rule-UnnecessaryVarargsArrayCreation
This commit is contained in:
Andreas Dangel committed 2024-04-25 11:40:35 +02:00
commit d0870f3aa3
33 files changed
+319 -129

No files matched your search

+3
View File
@@ -24,6 +24,9 @@ These improvements apply to all supported languages, irrespective of supported f
- The new Java rule {%rule java/bestpractices/UnnecessaryVarargsArrayCreation %} reports explicit array creation
when a varargs is expected. This is more heavy to read and could be simplified.
- The new Java rule {%rule java/errorprone/ConfusingArgumentToVarargsMethod %} reports some confusing situations
where a varargs method is called with an inexact argument type. These may end up in a mismatch between the expected
parameter type and the actual value.
- The new Java rule {% rule "java/codestyle/LambdaCanBeMethodReference" %} reports lambda expressions that can be replaced
with a method reference. Please read the documentation of the rule for more info. This rule is now part of the Quickstart
@@ -75,7 +75,7 @@ public class CognitiveComplexityRule extends AbstractApexRule {
String.valueOf(classLevelThreshold),
};
asCtx(data).addViolation(node, messageParams);
asCtx(data).addViolation(node, (Object[]) messageParams);
}
}
return data;
@@ -78,7 +78,7 @@ public class CyclomaticComplexityRule extends AbstractApexRule {
" total",
classWmc + " (highest " + classHighest + ")", };
asCtx(data).addViolation(node, messageParams);
asCtx(data).addViolation(node, (Object[]) messageParams);
}
}
return data;
@@ -76,7 +76,7 @@ public class AccessorMethodGenerationRule extends AbstractJavaRulechainRule {
JavaNode node = sym.tryGetNode();
assert node != null : "Node should be in the same compilation unit";
if (reportedNodes.add(node)) {
ruleContext.addViolation(node, new String[] {stripPackageName(refExpr.getEnclosingType().getSymbol())});
ruleContext.addViolation(node, stripPackageName(refExpr.getEnclosingType().getSymbol()));
}
}
}
@@ -24,7 +24,7 @@ public class MissingOverrideRule extends AbstractJavaRulechainRule {
@Override
public Object visit(ASTMethodDeclaration node, Object data) {
if (node.isOverridden() && !node.isAnnotationPresent(Override.class)) {
asCtx(data).addViolation(node, new Object[] { PrettyPrintingUtil.displaySignature(node) });
asCtx(data).addViolation(node, PrettyPrintingUtil.displaySignature(node));
}
return data;
}
@@ -11,10 +11,8 @@ import net.sourceforge.pmd.lang.java.ast.ASTArrayAllocation;
import net.sourceforge.pmd.lang.java.ast.InvocationNode;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
import net.sourceforge.pmd.lang.java.types.JArrayType;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
import net.sourceforge.pmd.lang.java.types.OverloadSelectionResult;
import net.sourceforge.pmd.lang.java.types.TypePrettyPrint;
public class UnnecessaryVarargsArrayCreationRule extends AbstractJavaRulechainRule {
@@ -26,6 +24,9 @@ public class UnnecessaryVarargsArrayCreationRule extends AbstractJavaRulechainRu
@Override
public Object visit(ASTArrayAllocation array, Object data) {
if (array.getArrayInitializer() == null) {
return null;
}
JavaNode parent = array.getParent();
if (parent instanceof ASTArgumentList && array.getIndexInParent() == parent.getNumChildren() - 1) {
@@ -39,19 +40,10 @@ public class UnnecessaryVarargsArrayCreationRule extends AbstractJavaRulechainRu
List<JTypeMirror> formals = info.getMethodType().getFormalParameters();
JTypeMirror lastFormal = formals.get(formals.size() - 1);
JTypeMirror expectedComponent = ((JArrayType) lastFormal).getComponentType();
if (array.getTypeMirror().isSubtypeOf(expectedComponent)
&& !array.getTypeMirror().equals(lastFormal)) {
// confusing
asCtx(data)
.addViolationWithMessage(
array,
"Unclear if a varargs or non-varargs call is intended. Cast to {0} or {0}[], or pass varargs parameters separately to clarify intent.",
TypePrettyPrint.prettyPrintWithSimpleNames(expectedComponent)
);
} else if (array.getArrayInitializer() != null) {
// just regular unnecessary
if (array.getTypeMirror().equals(lastFormal)) {
// If type not equal, then it would not actually be equivalent to remove the array creation.
// That case may be caught by ConfusingArgumentToVarargsMethod
asCtx(data).addViolation(array);
}
}
@@ -52,7 +52,7 @@ public class UnusedFormalParameterRule extends AbstractJavaRulechainRule {
for (ASTFormalParameter formal : node.getFormalParameters()) {
ASTVariableId varId = formal.getVarId();
if (JavaAstUtils.isNeverUsed(varId) && !JavaRuleUtil.isExplicitUnusedVarName(varId.getName())) {
asCtx(data).addViolation(varId, new Object[] { node instanceof ASTMethodDeclaration ? "method" : "constructor", varId.getName(), });
asCtx(data).addViolation(varId, node instanceof ASTMethodDeclaration ? "method" : "constructor", varId.getName());
}
}
}
@@ -60,11 +60,9 @@ abstract class AbstractNamingConventionRule<T extends JavaNode> extends Abstract
void checkMatches(T node, PropertyDescriptor<Pattern> regex, Object data) {
String name = nameExtractor(node);
if (!getProperty(regex).matcher(name).matches()) {
asCtx(data).addViolation(node, new Object[]{
kindDisplayName(node, regex),
name,
getProperty(regex).toString(),
});
asCtx(data).addViolation(node, kindDisplayName(node, regex),
name,
getProperty(regex).toString());
}
}
@@ -90,11 +90,9 @@ public class FieldNamingConventionsRule extends AbstractNamingConventionRule<AST
// This inlines checkMatches because there's no variable declarator id
if (!getProperty(enumConstantRegex).matcher(node.getImage()).matches()) {
asCtx(data).addViolation(node, new Object[]{
"enum constant",
node.getImage(),
getProperty(enumConstantRegex).toString(),
});
asCtx(data).addViolation(node, "enum constant",
node.getImage(),
getProperty(enumConstantRegex).toString());
}
return data;
@@ -91,7 +91,7 @@ public class IdenticalCatchBranchesRule extends AbstractJavaRulechainRule {
// By convention, lower catch blocks are collapsed into the highest one
// The first node of the equivalence class is thus the block that should be transformed
for (int i = 1; i < identicalStmts.size(); i++) {
asCtx(data).addViolation(identicalStmts.get(i), new String[]{identicalBranchName, });
asCtx(data).addViolation(identicalStmts.get(i), identicalBranchName);
}
}
}
@@ -116,7 +116,7 @@ public class LinguisticNamingRule extends AbstractJavaRulechainRule {
&& prefixes.contains(splitMethodName[0].toLowerCase(Locale.ROOT))) {
// "To" or any other configured prefix found
asCtx(data).addViolationWithMessage(node, "Linguistics Antipattern - The transform method ''{0}'' should not return void linguistically",
new Object[] { nameOfMethod });
nameOfMethod);
}
}
@@ -125,7 +125,7 @@ public class LinguisticNamingRule extends AbstractJavaRulechainRule {
if (node.isVoid() && containsCamelCaseWord(nameOfMethod, StringUtils.capitalize(infix))) {
// "To" or any other configured infix in the middle somewhere
asCtx(data).addViolationWithMessage(node, "Linguistics Antipattern - The transform method ''{0}'' should not return void linguistically",
new Object[] { nameOfMethod });
nameOfMethod);
// the first violation is sufficient - it is still the same method we are analyzing here
break;
}
@@ -135,14 +135,14 @@ public class LinguisticNamingRule extends AbstractJavaRulechainRule {
private void checkGetters(ASTMethodDeclaration node, Object data, String nameOfMethod) {
if (startsWithCamelCaseWord(nameOfMethod, "get") && node.isVoid()) {
asCtx(data).addViolationWithMessage(node, "Linguistics Antipattern - The getter ''{0}'' should not return void linguistically",
new Object[] { nameOfMethod });
nameOfMethod);
}
}
private void checkSetters(ASTMethodDeclaration node, Object data, String nameOfMethod) {
if (startsWithCamelCaseWord(nameOfMethod, "set") && !node.isVoid()) {
asCtx(data).addViolationWithMessage(node, "Linguistics Antipattern - The setter ''{0}'' should not return any type except void linguistically",
new Object[] { nameOfMethod });
nameOfMethod);
}
}
@@ -158,7 +158,7 @@ public class LinguisticNamingRule extends AbstractJavaRulechainRule {
for (String prefix : getProperty(BOOLEAN_METHOD_PREFIXES_PROPERTY)) {
if (startsWithCamelCaseWord(nameOfMethod, prefix) && !isBooleanType(t)) {
asCtx(data).addViolationWithMessage(node, "Linguistics Antipattern - The method ''{0}'' indicates linguistically it returns a boolean, but it returns ''{1}''",
new Object[] {nameOfMethod, PrettyPrintingUtil.prettyPrintType(t) });
nameOfMethod, PrettyPrintingUtil.prettyPrintType(t));
}
}
}
@@ -168,7 +168,7 @@ public class LinguisticNamingRule extends AbstractJavaRulechainRule {
for (String prefix : getProperty(BOOLEAN_FIELD_PREFIXES_PROPERTY)) {
if (startsWithCamelCaseWord(node.getName(), prefix) && !isBooleanType(typeNode)) {
asCtx(data).addViolationWithMessage(node, "Linguistics Antipattern - The field ''{0}'' indicates linguistically it is a boolean, but it is ''{1}''",
new Object[] { node.getName(), PrettyPrintingUtil.prettyPrintType(typeNode) });
node.getName(), PrettyPrintingUtil.prettyPrintType(typeNode));
}
}
}
@@ -177,7 +177,7 @@ public class LinguisticNamingRule extends AbstractJavaRulechainRule {
for (String prefix : getProperty(BOOLEAN_FIELD_PREFIXES_PROPERTY)) {
if (startsWithCamelCaseWord(node.getName(), prefix) && !isBooleanType(typeNode)) {
asCtx(data).addViolationWithMessage(node, "Linguistics Antipattern - The variable ''{0}'' indicates linguistically it is a boolean, but it is ''{1}''",
new Object[] { node.getName(), PrettyPrintingUtil.prettyPrintType(typeNode) });
node.getName(), PrettyPrintingUtil.prettyPrintType(typeNode));
}
}
}
@@ -88,7 +88,7 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRulechainRule
// we don't actually know where the method came from
String simpleName = formatMemberName(next, methodCall.getMethodType().getSymbol());
String unnecessary = produceQualifier(deepest, next, true);
asCtx(data).addViolation(next, new Object[] {unnecessary, simpleName, ""});
asCtx(data).addViolation(next, unnecessary, simpleName, "");
return null;
}
} else if (getProperty(REPORT_FIELDS) && opa instanceof ASTFieldAccess) {
@@ -98,7 +98,7 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRulechainRule
String simpleName = formatMemberName(next, fieldAccess.getReferencedSym());
String reasonToString = unnecessaryReasonWrapper(reasonForFieldInScope);
String unnecessary = produceQualifier(deepest, next, true);
asCtx(data).addViolation(next, new Object[] {unnecessary, simpleName, reasonToString});
asCtx(data).addViolation(next, unnecessary, simpleName, reasonToString);
return null;
}
}
@@ -108,7 +108,7 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRulechainRule
String simpleName = next.getSimpleName();
String reasonToString = unnecessaryReasonWrapper(bestReason);
String unnecessary = produceQualifier(deepest, next, false);
asCtx(data).addViolation(next, new Object[] {unnecessary, simpleName, reasonToString});
asCtx(data).addViolation(next, unnecessary, simpleName, reasonToString);
}
return null;
}
@@ -220,7 +220,7 @@ public class UnnecessaryImportRule extends AbstractJavaRule {
}
private void reportWithMessage(ASTImportDeclaration node, Object data, String message) {
asCtx(data).addViolationWithMessage(node, message, new String[] { PrettyPrintingUtil.prettyImport(node) });
asCtx(data).addViolationWithMessage(node, message, PrettyPrintingUtil.prettyImport(node));
}
@Override
@@ -54,12 +54,10 @@ public class UnnecessaryModifierRule extends AbstractJavaRulechainRule {
if (unnecessaryModifiers.isEmpty()) {
return;
}
asCtx(data).addViolation(node, new String[]{
formatUnnecessaryModifiers(unnecessaryModifiers),
PrettyPrintingUtil.getPrintableNodeKind(node),
PrettyPrintingUtil.getNodeName(node),
explanation.isEmpty() ? "" : ": " + explanation,
});
asCtx(data).addViolation(node, formatUnnecessaryModifiers(unnecessaryModifiers),
PrettyPrintingUtil.getPrintableNodeKind(node),
PrettyPrintingUtil.getNodeName(node),
explanation.isEmpty() ? "" : ": " + explanation);
}
@@ -85,7 +85,7 @@ public class UseDiamondOperatorRule extends AbstractJavaRulechainRule {
JavaNode reportNode = targs == null ? newTypeNode : targs;
String message = targs == null ? RAW_TYPE_MESSAGE : REPLACE_TYPE_ARGS_MESSAGE;
String replaceWith = produceSuggestedExprImage(ctorCall);
asCtx(data).addViolationWithMessage(reportNode, message, new String[] { replaceWith });
asCtx(data).addViolationWithMessage(reportNode, message, replaceWith);
}
return null;
}
@@ -56,10 +56,10 @@ public class CognitiveComplexityRule extends AbstractJavaRulechainRule {
int cognitive = MetricsUtil.computeMetric(COGNITIVE_COMPLEXITY, node);
final int reportLevel = getReportLevel();
if (cognitive >= reportLevel) {
asCtx(data).addViolation(node, new String[] { node instanceof ASTMethodDeclaration ? "method" : "constructor",
PrettyPrintingUtil.displaySignature(node),
String.valueOf(cognitive),
String.valueOf(reportLevel) });
asCtx(data).addViolation(node, node instanceof ASTMethodDeclaration ? "method" : "constructor",
PrettyPrintingUtil.displaySignature(node),
String.valueOf(cognitive),
String.valueOf(reportLevel));
}
return data;
@@ -89,7 +89,7 @@ public class CyclomaticComplexityRule extends AbstractJavaRulechainRule {
" total",
classWmc + " (highest " + classHighest + ")", };
asCtx(data).addViolation(node, messageParams);
asCtx(data).addViolation(node, (Object[]) messageParams);
}
}
return data;
@@ -120,11 +120,7 @@ public class CyclomaticComplexityRule extends AbstractJavaRulechainRule {
String kindname = node instanceof ASTConstructorDeclaration ? "constructor" : "method";
asCtx(data).addViolation(node, new String[] {kindname,
opname,
"",
"" + cyclo, });
asCtx(data).addViolation(node, kindname, opname, "", "" + cyclo);
}
}
}
@@ -53,9 +53,9 @@ public class DataClassRule extends AbstractJavaRulechainRule {
int noam = MetricsUtil.computeMetric(NUMBER_OF_ACCESSORS, node);
int wmc = MetricsUtil.computeMetric(WEIGHED_METHOD_COUNT, node);
asCtx(data).addViolation(node, new Object[] {node.getSimpleName(),
StringUtil.percentageString(woc, 3),
nopa, noam, wmc, });
asCtx(data).addViolation(node, node.getSimpleName(),
StringUtil.percentageString(woc, 3),
nopa, noam, wmc);
}
}
@@ -59,9 +59,9 @@ public class GodClassRule extends AbstractJavaRulechainRule {
if (wmc >= WMC_VERY_HIGH && atfd > FEW_ATFD_THRESHOLD && tcc < TCC_THRESHOLD) {
asCtx(data).addViolation(node, new Object[] {wmc,
StringUtil.percentageString(tcc, 3),
atfd, });
asCtx(data).addViolation(node, wmc,
StringUtil.percentageString(tcc, 3),
atfd);
}
return data;
}
@@ -132,11 +132,9 @@ public class LawOfDemeterRule extends AbstractJavaRule {
asCtx(data).addViolationWithMessage(
node,
FIELD_ACCESS_ON_FOREIGN_VALUE,
new Object[] {
node.getName(),
PrettyPrintingUtil.prettyPrint(node.getQualifier()),
foreignDegree(node.getQualifier()),
});
node.getName(),
PrettyPrintingUtil.prettyPrint(node.getQualifier()),
foreignDegree(node.getQualifier()));
}
return null;
}
@@ -147,11 +145,9 @@ public class LawOfDemeterRule extends AbstractJavaRule {
asCtx(data).addViolationWithMessage(
node,
METHOD_CALL_ON_FOREIGN_VALUE,
new Object[] {
node.getMethodName(),
PrettyPrintingUtil.prettyPrint(node.getQualifier()),
foreignDegree(node.getQualifier()),
});
node.getMethodName(),
PrettyPrintingUtil.prettyPrint(node.getQualifier()),
foreignDegree(node.getQualifier()));
}
return null;
}
@@ -86,11 +86,11 @@ public class LoosePackageCouplingRule extends AbstractJavaRule {
// On demand imports automatically fail because they include
// everything
if (node.isImportOnDemand()) {
asCtx(data).addViolation(node, new Object[] { node.getImportedName(), pkg });
asCtx(data).addViolation(node, node.getImportedName(), pkg);
break;
} else {
if (!isAllowedClass(node)) {
asCtx(data).addViolation(node, new Object[] { node.getImportedName(), pkg });
asCtx(data).addViolation(node, node.getImportedName(), pkg);
break;
}
}
@@ -51,10 +51,10 @@ public class NPathComplexityRule extends AbstractJavaRulechainRule {
BigInteger npath = MetricsUtil.computeMetric(JavaMetrics.NPATH, node);
if (npath.compareTo(BigInteger.valueOf(reportLevel)) >= 0) {
asCtx(data).addViolation(node, new String[] {node instanceof ASTMethodDeclaration ? "method" : "constructor",
PrettyPrintingUtil.displaySignature(node),
String.valueOf(npath),
String.valueOf(reportLevel)});
asCtx(data).addViolation(node, node instanceof ASTMethodDeclaration ? "method" : "constructor",
PrettyPrintingUtil.displaySignature(node),
String.valueOf(npath),
String.valueOf(reportLevel));
}
return data;
@@ -101,7 +101,7 @@ public final class NcssCountRule extends AbstractJavaRulechainRule {
node.getSimpleName(),
classSize + " (Highest = " + classHighest + ")", };
asCtx(data).addViolation(node, messageParams);
asCtx(data).addViolation(node, (Object[]) messageParams);
}
}
}
@@ -115,9 +115,8 @@ public final class NcssCountRule extends AbstractJavaRulechainRule {
if (JavaMetrics.NCSS.supports(node)) {
int methodSize = MetricsUtil.computeMetric(JavaMetrics.NCSS, node, ncssOptions);
if (methodSize >= level) {
asCtx(data).addViolation(node, new String[] {
node instanceof ASTMethodDeclaration ? "method" : "constructor",
PrettyPrintingUtil.displaySignature(node), "" + methodSize, });
asCtx(data).addViolation(node, node instanceof ASTMethodDeclaration ? "method" : "constructor",
PrettyPrintingUtil.displaySignature(node), "" + methodSize);
}
}
}
@@ -176,7 +176,7 @@ public class CloseResourceRule extends AbstractJavaRule {
if (isWrappingResourceSpecifiedInTry(resVar)) {
reportedVarNames.add(resVar.getName());
asCtx(data).addViolationWithMessage(resVar, WRAPPING_TRY_WITH_RES_VAR_MESSAGE,
new Object[] { resVar.getName() });
resVar.getName());
} else if (shouldVarOfTypeBeClosedInMethod(resVar, resVarType, methodOrConstructor)) {
reportedVarNames.add(resVar.getName());
addCloseResourceViolation(resVar, runtimeType, data);
@@ -185,7 +185,7 @@ public class CloseResourceRule extends AbstractJavaRule {
if (reassigningStatement != null) {
reportedVarNames.add(resVar.getName());
asCtx(data).addViolationWithMessage(reassigningStatement, REASSIGN_BEFORE_CLOSED_MESSAGE,
new Object[] { resVar.getName() });
resVar.getName());
}
}
}
@@ -696,7 +696,7 @@ public class CloseResourceRule extends AbstractJavaRule {
ASTVariableAccess closedVar = (ASTVariableAccess) node.getQualifier();
if (isNotInFinallyBlock(closedVar) && !reportedVarNames.contains(closedVar.getName())) {
asCtx(data).addViolationWithMessage(closedVar, CLOSE_IN_FINALLY_BLOCK_MESSAGE,
new Object[] { closedVar.getName() });
closedVar.getName());
}
}
@@ -0,0 +1,62 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.errorprone;
import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
import net.sourceforge.pmd.lang.java.ast.ASTArrayAllocation;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.InvocationNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
import net.sourceforge.pmd.lang.java.types.JArrayType;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
import net.sourceforge.pmd.lang.java.types.OverloadSelectionResult;
import net.sourceforge.pmd.lang.java.types.TypePrettyPrint;
public class ConfusingArgumentToVarargsMethodRule extends AbstractJavaRulechainRule {
public ConfusingArgumentToVarargsMethodRule() {
super(ASTArgumentList.class);
}
@Override
public Object visit(ASTArgumentList argList, Object data) {
if (argList.isEmpty()) {
return null;
}
// node is the last param in an arguments list
InvocationNode call = (InvocationNode) argList.getParent();
OverloadSelectionResult info = call.getOverloadSelectionInfo();
if (info.isFailed()
|| info.isVarargsCall()
|| !info.getMethodType().isVarargs()) {
return null;
}
List<JTypeMirror> formals = info.getMethodType().getFormalParameters();
JTypeMirror lastFormal = formals.get(formals.size() - 1);
JTypeMirror expectedComponent = ((JArrayType) lastFormal).getComponentType();
// since we know this is not a varargs call the last arg has an array type
ASTExpression varargsArg = argList.getLastChild();
assert varargsArg != null;
if (varargsArg.getTypeMirror().isSubtypeOf(expectedComponent)
&& !varargsArg.getTypeMirror().equals(lastFormal)) {
// confusing
String message;
if (varargsArg instanceof ASTArrayAllocation && ((ASTArrayAllocation) varargsArg).getArrayInitializer() != null) {
message = "Unclear if a varargs or non-varargs call is intended. Cast to {0} or {0}[], or pass varargs parameters separately to clarify intent.";
} else {
message = "Unclear if a varargs or non-varargs call is intended. Cast to {0} or {0}[] to clarify intent.";
}
asCtx(data).addViolationWithMessage(varargsArg, message, TypePrettyPrint.prettyPrintWithSimpleNames(expectedComponent));
}
return null;
}
}
@@ -258,8 +258,7 @@ public class ConsecutiveLiteralAppendsRule extends AbstractJavaRulechainRule {
private void checkForViolation(Object data) {
if (counter.isViolation()) {
assert counter.getReportNode() != null;
String[] param = { String.valueOf(counter.getCounter()) };
asCtx(data).addViolation(counter.getReportNode(), param);
asCtx(data).addViolation(counter.getReportNode(), String.valueOf(counter.getCounter()));
}
}
@@ -72,7 +72,7 @@ public class InsufficientStringBufferDeclarationRule extends AbstractJavaRulecha
}
public String[] getParamsForViolation() {
public Object[] getParamsForViolation() {
return new String[] { getTypeName(variable), String.valueOf(capacity), String.valueOf(anticipatedLength) };
}
@@ -1438,7 +1438,7 @@ class Foo{
<rule name="UnnecessaryVarargsArrayCreation"
language="java"
since="7.1.0"
message="Unnecessary explicit varargs array creation"
message="Unnecessary explicit array creation for varargs method call"
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UnnecessaryVarargsArrayCreationRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#unnecessaryvarargsarraycreation">
<description>
@@ -1451,30 +1451,6 @@ class Foo{
```java
Arrays.asList("foo", "bar");
```
This rule also reports such array creations when they are confusing, because the array is a subtype of the component type of the expected array type.
For instance if you have
```java
void varargs(Object... parm);
```
and call it like so
```java
varargs(new String[]{"a"});
```
it is not clear whether you intended the method to receive the value `new Object[]{ new String[] {"a"} }` or just `new String[] {"a"}` (the latter happens). This confusion occurs because `String[]` is both a subtype of `Object[]` and of `Object`. To clarify your intent in this case, use a cast or pass individual elements like so:
```java
// varargs call
// parm will be `new Object[] { "a" }`
varargs("a");
// non-varargs call
// parm will be `new String[] { "a" }`
varargs((Object[]) new String[]{"a"});
// varargs call
// parm will be `new Object[] { new String[] { "a" } }`
varargs((Object) new String[]{"a"});
```
</description>
<priority>3</priority>
<example><![CDATA[
@@ -1103,6 +1103,60 @@ boolean x = (y == Double.NaN);
</example>
</rule>
<rule name="ConfusingArgumentToVarargsMethod"
language="java"
since="7.1.0"
message="Unclear if a varargs or non-varargs call is intended. Cast to {0} or {0}[], or pass varargs parameters separately to clarify intent."
class="net.sourceforge.pmd.lang.java.rule.errorprone.ConfusingArgumentToVarargsMethodRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#confusingargumenttovarargsmethod">
<description>
Reports a confusing argument passed to a varargs method.
This can occur when an array is passed as a single varargs argument, when the array type is not exactly the
type of array that the varargs method expects. If, that array is a subtype of the component type of the expected
array type, then it might not be clear what value the called varargs method will receive.
For instance if you have:
```java
void varargs(Object... parm);
```
and call it like so:
```java
varargs(new String[]{"a"});
```
it is not clear whether you intended the method to receive the value `new Object[]{ new String[] {"a"} }` or
just `new String[] {"a"}` (the latter happens). This confusion occurs because `String[]` is both a subtype
of `Object[]` and of `Object`. To clarify your intent in this case, use a cast or pass individual elements like so:
```java
// varargs call
// parm will be `new Object[] { "a" }`
varargs("a");
// non-varargs call
// parm will be `new String[] { "a" }`
varargs((Object[]) new String[]{"a"});
// varargs call
// parm will be `new Object[] { new String[] { "a" } }`
varargs((Object) new String[]{"a"});
```
Another confusing case is when you pass `null` as the varargs argument. Here it is not clear whether you intended
to pass an array with a single null element, or a null array (the latter happens). This can similarly be clarified
with a cast.
</description>
<priority>3</priority>
<example><![CDATA[
import java.util.Arrays;
abstract class C {
abstract void varargs(Object... args);
static {
varargs(new String[] { "a" });
varargs(null);
}
}
]]></example>
</rule>
<rule name="ConstructorCallsOverridableMethod"
language="java"
@@ -0,0 +1,11 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.test.PmdRuleTst;
class ConfusingArgumentToVarargsMethodTest extends PmdRuleTst {
// no additional unit tests
}
Loaded 30 of 33 files, more files were not shown because too many files have changed in this diff. Show more