[java] New rule ConfusingArgumentToVarargsMethod (#4971)
Merge pull request #4971 from oowekyala:new-rule-UnnecessaryVarargsArrayCreation
This commit is contained in:
33 files changed
+319
-129
No files matched your search
@@ -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
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+6
-14
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -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;
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+4
-6
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+4
-4
@@ -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;
|
||||
|
||||
+2
-6
@@ -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;
|
||||
}
|
||||
|
||||
+6
-10
@@ -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;
|
||||
}
|
||||
|
||||
+2
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+62
@@ -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;
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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"
|
||||
|
||||
+11
@@ -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
Reference in new issue
Block a user