IDEA-61219 ("'assertEquals()' called on array" inspection)

This commit is contained in:
Bas Leijdekkers
2010-11-13 19:59:11 +01:00
parent ec0fee29ea
commit df0b12c48e
4 changed files with 146 additions and 11 deletions
@@ -143,7 +143,7 @@ object.comparison.display.name=Object comparison using ==, instead of 'equals()'
object.comparison.enumerated.ignore.option=Ignore == between enumerated types
object.comparison.klass.ignore.option=Ignore == on java.lang.Class objects
object.comparison.problem.description=Object values are compared using <code>#ref</code>, not 'equals()' #loc
object.comparison.replace.quickfix=Replace with equals()
object.comparison.replace.quickfix=Replace with 'equals()'
object.equals.null.problem.descriptor=<code>.equals(#ref)</code> is probably not what was intended #loc
default.tostring.call.display.name=Call to default 'toString()'
default.tostring.call.problem.descriptor=Call to default 'toString()' on <code>#ref</code> #loc
@@ -1201,8 +1201,8 @@ serializable.inner.class.with.non.serializable.outer.class.ignore.option=Ignore
serializable.with.unconstructable.ancestor.problem.descriptor=<code>#ref</code> has an non-serializable ancestor ''{0}'' without a no-arg constructor #loc
transient.field.in.non.serializable.class.problem.descriptor=Field ''{0}'' is marked <code>#ref</code>, in non-Serializable class #loc
transient.field.in.non.serializable.class.remove.quickfix=Remove 'transient'
condition.signal.replace.quickfix=Replace with signalAll()
object.notify.replace.quickfix=Replace with notifyAll()
condition.signal.replace.quickfix=Replace with 'signalAll()'
object.notify.replace.quickfix=Replace with 'notifyAll()'
safe.lock.problem.descriptor=''{0}'' should be locked in front of a try block and unlocked in the corresponding finally block #loc
synchronized.method.problem.descriptor=Method ''{0}()'' declared <code>#ref</code> #loc
synchronized.method.include.option=Include native methods
@@ -1238,7 +1238,7 @@ big.decimal.equals.replace.quickfix=replace with 'compareTo()==0'
cast.that.loses.precision.problem.descriptor=Cast to <code>#ref</code> from ''{0}'' may result in loss of precision #loc
comparison.to.nan.problem.descriptor1=Comparison to <code>#ref</code> is always false #loc
comparison.to.nan.problem.descriptor2=Comparison to <code>#ref</code> is always true #loc
comparison.to.nan.replace.quickfix=replace with call to 'isNaN()'
comparison.to.nan.replace.quickfix=replace with 'isNaN()'
confusing.floating.point.literal.change.quickfix=Change To canonical form
implicit.numeric.conversion.ignore.widening.conversion.option=Ignore widening conversions
implicit.numeric.conversion.ignore.char.conversion.option=Ignore conversions from and to char
@@ -1247,7 +1247,7 @@ implicit.numeric.conversion.problem.descriptor=Implicit numeric conversion of <c
implicit.numeric.conversion.convert.quickfix=Convert to ''{0}'' literal
implicit.numeric.conversion.make.explicit.quickfix=Make conversion explicit
long.literals.ending.with.lowercase.l.replace.quickfix=Replace 'l' with 'L'
non.reproducible.math.call.replace.quickfix=Replace with StrictMath call
non.reproducible.math.call.replace.quickfix=Replace with 'StrictMath' call
overly.complex.arithmetic.expression.max.number.option=Maximum number of terms:
expression.can.be.replaced.problem.descriptor=<code>#ref</code> can be replaced with ''{0}'' #loc
method.complexity.limit.option=Method complexity limit:
@@ -1283,10 +1283,10 @@ manual.array.copy.replace.quickfix=Replace with 'System.arrayCopy()'
manual.array.to.collection.copy.replace.quickfix=Replace with 'Collection.addAll(Arrays.asList())'
method.may.be.static.only.option=Only check private or final methods
method.may.be.static.empty.option=Ignore empty methods
random.double.for.random.integer.replace.quickfix=replace with 'nextInt()'
random.double.for.random.integer.replace.quickfix=Replace with 'nextInt()'
string.buffer.replaceable.by.string.builder.replace.quickfix=Replace with StringBuilder
string.buffer.to.string.in.concatenation.remove.quickfix=Remove 'toString()'
string.concatenation.in.loops.only.option=only warn if string is repeatedly appended
string.concatenation.in.loops.only.option=Only warn if string is repeatedly appended
string.concatenation.inside.string.buffer.append.replace.quickfix=Replace with chained append() calls
string.equals.empty.string.replace.quickfix=Replace with 'length()==0'
tail.recursion.replace.quickfix=Replace tail recursion with iteration
@@ -1586,7 +1586,7 @@ assertequals.between.inconvertible.types.display.name='assertEquals()' between o
assertequals.between.inconvertible.types.problem.descriptor=<code>#ref()</code> between objects of inconvertible types ''{0}'' and ''{1}'' #loc
enumeration.can.be.iteration.display.name=Enumeration can be iteration
enumeration.can.be.iteration.problem.descriptor=<code>#ref()</code> can be replaced with ''{0}'' construct #loc
enumeration.can.be.iteration.quickfix=Replace with Iterator construct
enumeration.can.be.iteration.quickfix=Replace with 'Iterator' construct
missing.override.annotation.jdk6.option=Use JDK6 @Override rules
equals.hashcode.called.on.url.display.name='equals()' or 'hashCode()' called on java.net.URL object
equals.hashcode.called.on.url.problem.descriptor=Call to <code>#ref()</code> on URL object #loc
@@ -1741,9 +1741,9 @@ class.new.instance.problem.descriptor=Call to <code>#ref()</code> may throw unde
class.new.instance.quickfix=Replace with 'Class.getConstructor().newInstance()' call
dynamic.regex.replaceable.by.compiled.pattern.display.name=Dynamic regular expression could be replaced by compiled Pattern
dynamic.regex.replaceable.by.compiled.pattern.problem.descriptor=<code>#ref()</code> could be replaced with compiled java.util.regex.Pattern construct #loc
dynamic.regex.replaceable.by.compiled.pattern.quickfix=Replace with call to method of compiled Pattern constant
ignore.serializable.option=ignore java.io.Serializable
ignore.cloneable.option=ignore java.lang.Cloneable
dynamic.regex.replaceable.by.compiled.pattern.quickfix=Replace with call to method of compiled 'Pattern' constant
ignore.serializable.option=Ignore java.io.Serializable
ignore.cloneable.option=Ignore java.lang.Cloneable
listener.may.use.adapter.display.name=Class may extend adapter instead of implementing listener
listener.may.use.adapter.problem.descriptor=Class ''{0}'' may extend ''{1}'' instead of implementing <code>#ref</code> #loc
listener.may.use.adapter.quickfix=Replace with ''extends {0}''
@@ -1798,3 +1798,6 @@ unnecessarily.qualified.inner.class.access.display.name=Unnecessarily qualified
unnecessarily.qualified.inner.class.access.quickfix=Remove qualifier
synchronization.on.static.field.display.name=Synchronization on static field
synchronization.on.static.field.problem.descriptor=Synchronization on static field <code>#ref</code> #loc
assertequals.called.on.arrays.display.name='assertEquals()' called on array
assertequals.called.on.arrays.problem.descriptor=<code>#ref()</code> called on array #loc
assertequals.called.on.arrays.quickfix=Replace with 'assertArrayEquals()'
@@ -1045,6 +1045,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent,
private void registerJUnitInspections() {
m_inspectionClasses.add(AssertEqualsBetweenInconvertibleTypesInspection.class);
m_inspectionClasses.add(AssertEqualsMayBeAssertSameInspection.class);
m_inspectionClasses.add(AssertEqualsCalledOnArrayInspection.class);
m_inspectionClasses.add(AssertsWithoutMessagesInspection.class);
m_inspectionClasses.add(BeforeClassOrAfterClassIsPublicStaticVoidNoArgInspection.class);
m_inspectionClasses.add(BeforeOrAfterIsPublicVoidNoArgInspection.class);
@@ -0,0 +1,123 @@
/*
* Copyright 2010 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/package com.siyeh.ig.junit;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class AssertEqualsCalledOnArrayInspection extends BaseInspection {
@Nls
@NotNull
@Override
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"assertequals.called.on.arrays.display.name");
}
@NotNull
@Override
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"assertequals.called.on.arrays.problem.descriptor");
}
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
return new AssertEqualsCalledOnArrayFix();
}
private static class AssertEqualsCalledOnArrayFix
extends InspectionGadgetsFix {
@NotNull
public String getName() {
return InspectionGadgetsBundle.message(
"assertequals.called.on.arrays.quickfix");
}
@Override
protected void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
final PsiElement methodNameIdentifier = descriptor.getPsiElement();
final PsiReferenceExpression methodExpression =
(PsiReferenceExpression)methodNameIdentifier.getParent();
if (methodExpression == null) {
return;
}
final PsiExpression qualifier =
methodExpression.getQualifierExpression();
if (qualifier == null) {
replaceExpression(methodExpression, "assertArrayEquals");
} else {
final String qualifierText = qualifier.getText();
replaceExpression(methodExpression,
qualifierText + ".assertArrayEquals");
}
}
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new AssertEqualsOnArrayVisitor();
}
private static class AssertEqualsOnArrayVisitor
extends BaseInspectionVisitor {
@Override
public void visitMethodCallExpression(
PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
final PsiReferenceExpression methodExpression =
expression.getMethodExpression();
@NonNls final String methodName =
methodExpression.getReferenceName();
if (!"assertEquals".equals(methodName)) {
return;
}
final PsiExpressionList argumentList = expression.getArgumentList();
final PsiExpression[] arguments = argumentList.getExpressions();
final PsiType type1;
final PsiType type2;
if (arguments.length == 2) {
final PsiExpression argument0 = arguments[0];
type1 = argument0.getType();
final PsiExpression argument1 = arguments[1];
type2 = argument1.getType();
} else if (arguments.length == 3) {
final PsiExpression argument0 = arguments[1];
type1 = argument0.getType();
final PsiExpression argument1 = arguments[2];
type2 = argument1.getType();
} else {
return;
}
if (!(type1 instanceof PsiArrayType) ||
!(type2 instanceof PsiArrayType)) {
return;
}
registerMethodCallError(expression);
}
}
}
@@ -0,0 +1,8 @@
<html>
<body><table> <tr> <td valign="top" height="150">
<font face="verdana" size="-1">
This inspection reports any calls to JUnit's <b><font color="#000080">assertEquals()</font></b>
method with arguments of type array. Arrays should be checked with one of the
<b><font color="#000080">assertArrayEquals()</font></b> methods.
</font></td> </tr> <tr> <td height="20"> <font face="verdana" size="-2">New in 10, Powered by InspectionGadgets </font> </td> </tr> </table> </body>
</html>