IG: merge "Method does not call super method" inspections

This commit is contained in:
Bas Leijdekkers
2016-08-03 18:26:33 +02:00
parent 9fb57c9460
commit d03dce7ead
27 changed files with 248 additions and 782 deletions
@@ -369,6 +369,23 @@ public class InspectionProfileTest extends LightIdeaTestCase {
"</profile>");
}
public void testMergedMethodDoesntCallSuperMethodInspections() throws Exception {
checkMergedNoChanges("<profile version=\"1.0\">\n" +
" <option name=\"myName\" value=\"" + PROFILE + "\" />\n" +
" <inspection_tool class=\"CloneCallsSuperClone\" enabled=\"false\" level=\"WARNING\" enabled_by_default=\"false\" />\n" +
" <inspection_tool class=\"FinalizeCallsSuperFinalize\" enabled=\"false\" level=\"WARNING\" enabled_by_default=\"false\">\n" +
" <option name=\"ignoreObjectSubclasses\" value=\"false\" />\n" +
" <option name=\"ignoreTrivialFinalizers\" value=\"true\" />\n" +
" </inspection_tool>\n" +
" <inspection_tool class=\"RefusedBequest\" enabled=\"false\" level=\"WARNING\" enabled_by_default=\"false\">\n" +
" <option name=\"ignoreEmptySuperMethods\" value=\"false\" />\n" +
" <option name=\"onlyReportWhenAnnotated\" value=\"true\" />\n" +
" </inspection_tool>\n" +
" <inspection_tool class=\"SetupCallsSuperSetup\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n" +
" <inspection_tool class=\"TeardownCallsSuperTeardown\" enabled=\"true\" level=\"WARNING\" enabled_by_default=\"true\" />\n" +
"</profile>");
}
public void testMergedThrowableNotThrownInspections() throws Exception {
checkMergedNoChanges("<profile version=\"1.0\">\n" +
" <option name=\"myName\" value=\"" + PROFILE + "\" />\n" +
@@ -85,9 +85,11 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool {
final InspectionElementsMerger merger = InspectionElementsMerger.getMerger(getShortName());
if (merger != null) {
for (String sourceToolId : merger.getSourceToolNames()) {
String[] suppressIds = merger.getSuppressIds();
String[] sourceToolIds = suppressIds.length != 0 ? suppressIds : merger.getSourceToolNames();
for (String sourceToolId : sourceToolIds) {
for (InspectionSuppressor suppressor : suppressors) {
if (isSuppressed(sourceToolId, suppressor, element)) {
if (suppressor.isSuppressedFor(element, sourceToolId)) {
return true;
}
}
@@ -17,6 +17,7 @@ package com.intellij.codeInspection.ex;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.util.ArrayUtilRt;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
@@ -45,4 +46,8 @@ public abstract class InspectionElementsMerger {
public abstract String getMergedToolName();
public abstract String[] getSourceToolNames();
public String[] getSuppressIds() {
return ArrayUtilRt.EMPTY_STRING_ARRAY;
}
}
@@ -5,6 +5,7 @@
<inspectionElementsMerger implementation="com.siyeh.ig.bugs.ThrowableNeverThrownInspectionMerger"/>
<inspectionElementsMerger implementation="com.siyeh.ig.naming.MisspelledMethodNameInspectionMerger"/>
<inspectionElementsMerger implementation="com.siyeh.ig.junit.MalformedSetUpTearDownInspectionMerger"/>
<inspectionElementsMerger implementation="com.siyeh.ig.inheritance.MethodDoesntCallSuperMethodInspectionMerger"/>
<!--group.names.abstraction.issues-->
<localInspection groupPath="Java" language="JAVA" shortName="BooleanParameter" bundle="com.siyeh.InspectionGadgetsBundle" key="boolean.parameter.display.name"
@@ -559,10 +560,6 @@
key="clone.instantiates.objects.with.constructor.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.cloning.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.cloneable.CloneCallsConstructorsInspection"/>
<localInspection groupPath="Java" language="JAVA" suppressId="CloneDoesntCallSuperClone" shortName="CloneCallsSuperClone" bundle="com.siyeh.InspectionGadgetsBundle"
key="clone.doesnt.call.super.clone.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.cloning.issues" enabledByDefault="true" level="WARNING"
implementationClass="com.siyeh.ig.cloneable.CloneCallsSuperCloneInspection"/>
<localInspection groupPath="Java" language="JAVA" suppressId="CloneDoesntDeclareCloneNotSupportedException" shortName="CloneDeclaresCloneNotSupported"
bundle="com.siyeh.InspectionGadgetsBundle" key="clone.doesnt.declare.clonenotsupportedexception.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.cloning.issues" enabledByDefault="true" level="WARNING"
@@ -983,10 +980,6 @@
implementationClass="com.siyeh.ig.errorhandling.ThrowsRuntimeExceptionInspection"/>
<!--group.names.finalization.issues-->
<localInspection groupPath="Java" language="JAVA" suppressId="FinalizeDoesntCallSuperFinalize" shortName="FinalizeCallsSuperFinalize"
bundle="com.siyeh.InspectionGadgetsBundle" key="finalize.doesnt.call.super.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.finalization.issues" enabledByDefault="true"
level="WARNING" implementationClass="com.siyeh.ig.finalization.FinalizeCallsSuperFinalizeInspection"/>
<localInspection groupPath="Java" language="JAVA" suppressId="FinalizeDeclaration" shortName="Finalize" bundle="com.siyeh.InspectionGadgetsBundle"
key="finalize.declaration.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.finalization.issues" enabledByDefault="false" level="WARNING"
@@ -1077,7 +1070,7 @@
key="redundant.method.override.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.inheritance.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.inheritance.RedundantMethodOverrideInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="RefusedBequest" bundle="com.siyeh.InspectionGadgetsBundle" key="refused.bequest.display.name"
<localInspection groupPath="Java" language="JAVA" suppressId="MethodDoesntCallSuperMethod" shortName="RefusedBequest" bundle="com.siyeh.InspectionGadgetsBundle" key="refused.bequest.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.inheritance.issues" enabledByDefault="true"
level="WARNING" implementationClass="com.siyeh.ig.inheritance.RefusedBequestInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="StaticInheritance" bundle="com.siyeh.InspectionGadgetsBundle" key="static.inheritance.display.name"
@@ -1483,9 +1476,6 @@
bundle="com.siyeh.InspectionGadgetsBundle" key="test.case.with.constructor.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.junit.TestCaseWithConstructorInspection"/>
<localInspection groupPath="Java" language="JAVA" suppressId="SetUpDoesntCallSuperSetUp" shortName="SetupCallsSuperSetup" bundle="com.siyeh.InspectionGadgetsBundle"
key="setup.calls.super.setup.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues"
enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.junit.SetupCallsSuperSetupInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="SimplifiableJUnitAssertion" bundle="com.siyeh.InspectionGadgetsBundle"
key="simplifiable.junit.assertion.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
@@ -1504,10 +1494,6 @@
key="test.case.with.no.test.methods.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.junit.TestCaseWithNoTestMethodsInspection"/>
<localInspection groupPath="Java" language="JAVA" suppressId="TearDownDoesntCallSuperTearDown" shortName="TeardownCallsSuperTeardown"
bundle="com.siyeh.InspectionGadgetsBundle" key="teardown.calls.super.teardown.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.junit.TeardownCallsSuperTeardownInspection"/>
<localInspection groupPath="Java" language="JAVA" suppressId="JUnitTestMethodInProductSource" shortName="TestMethodInProductCode"
bundle="com.siyeh.InspectionGadgetsBundle" key="test.method.in.product.code.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
@@ -192,10 +192,7 @@ non.constant.logger.display.name=Non-constant logger
non.constant.logger.problem.descriptor=Non-constant logger field <code>#ref</code> #loc
public.method.without.logging.display.name='public' method without logging
public.method.without.logging.problem.descriptor='public' method <code>#ref()</code> has no logging call #loc
finalize.doesnt.call.super.display.name='finalize()' does not call 'super.finalize()'
finalize.doesnt.call.super.ignore.option=Ignore for direct subclasses of 'java.lang.Object'
ignore.trivial.finalizers.option=Ignore for trivial 'finalize()' implementations
finalize.doesnt.call.super.problem.descriptor=<code>#ref()</code> #loc does not call 'super.finalize()'
finalize.declaration.display.name='finalize()' declaration
finalize.declaration.problem.descriptor=<code>#ref()</code> declared #loc
finalize.not.declared.protected.display.name='finalize()' not declared 'protected'
@@ -220,8 +217,6 @@ unused.import.display.name=Unused import
unused.import.problem.descriptor=Unused import <code>#ref</code> #loc
clone.instantiates.objects.with.constructor.display.name='clone()' instantiates objects with constructor
clone.instantiates.objects.with.constructor.problem.descriptor='clone()' creates new <code>#ref</code> instances #loc
clone.doesnt.call.super.clone.display.name='clone()' does not call 'super.clone()'
clone.doesnt.call.super.clone.problem.descriptor=<code>#ref()</code> does not call 'super.clone()' #loc
clone.doesnt.declare.clonenotsupportedexception.display.name='clone()' does not declare 'CloneNotSupportedException'
clone.doesnt.declare.clonenotsupportedexception.problem.descriptor=<code>#ref()</code> #loc does not declare 'CloneNotSupportedException'
clone.doesnt.declare.clonenotsupportedexception.declare.quickfix=Declare 'CloneNotSupportedException'
@@ -662,7 +657,6 @@ parameter.name.differs.from.overridden.parameter.display.name=Parameter name dif
final.private.method.display.name='private' method declared 'final'
enum.switch.statement.which.misses.cases.display.name=Enum 'switch' statement that misses case
enum.switch.statement.which.misses.cases.option=Ignore switch statements with a default branch
setup.calls.super.setup.display.name='setUp()' does not call 'super.setUp()'
unconstructable.test.case.display.name=Unconstructable JUnit TestCase
volatile.long.or.double.field.display.name=Volatile long or double field
string.buffer.must.have.initial.capacity.display.name=StringBuffer or StringBuilder without initial capacity
@@ -789,7 +783,6 @@ three.negations.per.method.display.name=Method with more than three negations
conditional.expression.display.name=Conditional expression (?:)
unnecessary.enum.modifier.display.name=Unnecessary enum modifier
string.equals.empty.string.display.name='String.equals("")'
teardown.calls.super.teardown.display.name='tearDown()' does not call 'super.tearDown()'
synchronize.on.lock.display.name=Synchronization on a Lock object
synchronized.on.literal.object.name=Synchronization on an object initialized with a literal
field.may.be.static.display.name=Field may be 'static'
@@ -1074,8 +1067,6 @@ test.case.with.constructor.problem.descriptor=Initialization logic in constructo
test.case.with.constructor.problem.descriptor.initializer=Initialization logic in initializer instead of 'setUp()'
misordered.assert.equals.arguments.problem.descriptor=Arguments to <code>#ref()</code> in wrong order #loc
static.suite.problem.descriptor=JUnit <code>#ref()</code> methods not declared 'static' #loc
setup.calls.super.setup.problem.descriptor=<code>#ref()</code> does not call 'super.setUp()' #loc
teardown.calls.super.teardown.problem.descriptor=<code>#ref()</code> does not call 'super.tearDown()' #loc
simplifiable.junit.assertion.problem.descriptor=<code>#ref()</code> can be simplified to ''{0}'' #loc
test.method.without.assertion.problem.descriptor=JUnit test method <code>#ref()</code> contains no assertions #loc
test.case.with.no.test.methods.problem.descriptor=JUnit test case <code>#ref</code> has no tests #loc
@@ -1155,9 +1146,7 @@ foreach.replace.quickfix=Replace with 'foreach'
unnecessary.boxing.remove.quickfix=Remove boxing
unnecessary.unboxing.remove.quickfix=Remove unboxing
misordered.assert.equals.arguments.flip.quickfix=Flip compared arguments
setup.calls.super.setup.add.quickfix=Add call to 'super.setUp()'
simplify.junit.assertion.simplify.quickfix=Simplify assertion
teardown.calls.super.teardown.add.quickfix=Add call to 'super.tearDown()'
test.method.is.public.void.no.arg.problem.descriptor1=Test method <code>#ref()</code> should probably not have parameters #loc
test.method.is.public.void.no.arg.problem.descriptor2=Test method <code>#ref()</code> is not declared 'public void' #loc
test.method.is.public.void.no.arg.problem.descriptor3=Test method <code>#ref()</code> should not be 'static' #loc
@@ -1,91 +0,0 @@
/*
* Copyright 2003-2016 Dave Griffith, 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.cloneable;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import com.siyeh.HardcodedMethodConstants;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.CloneUtils;
import com.siyeh.ig.psiutils.MethodCallUtils;
import org.jetbrains.annotations.NotNull;
public class CloneCallsSuperCloneInspection extends BaseInspection {
@Override
@NotNull
public String getID() {
return "CloneDoesntCallSuperClone";
}
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"clone.doesnt.call.super.clone.display.name");
}
@Override
@NotNull
public String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"clone.doesnt.call.super.clone.problem.descriptor");
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new NoExplicitCloneCallsVisitor();
}
private static class NoExplicitCloneCallsVisitor
extends BaseInspectionVisitor {
@Override
public void visitMethod(@NotNull PsiMethod method) {
//note: no call to super;
if (!CloneUtils.isClone(method)) {
return;
}
if (method.hasModifierProperty(PsiModifier.ABSTRACT) ||
method.hasModifierProperty(PsiModifier.NATIVE)) {
return;
}
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) {
return;
}
if (containingClass.isInterface() ||
containingClass.isAnnotationType()) {
return;
}
if (CloneUtils.onlyThrowsException(method)) {
return;
}
if (MethodCallUtils.containsSuperMethodCall(method)) {
return;
}
registerMethodError(method);
}
}
}
@@ -1,120 +0,0 @@
/*
* Copyright 2003-2015 Dave Griffith, 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.finalization;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.psi.*;
import com.siyeh.HardcodedMethodConstants;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.MethodCallUtils;
import com.siyeh.ig.psiutils.MethodUtils;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class FinalizeCallsSuperFinalizeInspection extends BaseInspection {
@SuppressWarnings("PublicField")
public boolean ignoreObjectSubclasses = false;
@SuppressWarnings("PublicField")
public boolean ignoreTrivialFinalizers = true;
@Override
@NotNull
public String getID() {
return "FinalizeDoesntCallSuperFinalize";
}
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"finalize.doesnt.call.super.display.name");
}
@Override
@NotNull
public String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"finalize.doesnt.call.super.problem.descriptor");
}
@Override
public boolean isEnabledByDefault() {
return true;
}
@Override
public JComponent createOptionsPanel() {
final MultipleCheckboxOptionsPanel optionsPanel =
new MultipleCheckboxOptionsPanel(this);
optionsPanel.addCheckbox(InspectionGadgetsBundle.message(
"finalize.doesnt.call.super.ignore.option"),
"ignoreObjectSubclasses");
optionsPanel.addCheckbox(InspectionGadgetsBundle.message(
"ignore.trivial.finalizers.option"),
"ignoreTrivialFinalizers");
return optionsPanel;
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new NoExplicitFinalizeCallsVisitor();
}
private class NoExplicitFinalizeCallsVisitor extends BaseInspectionVisitor {
@Override
public void visitMethod(@NotNull PsiMethod method) {
//note: no call to super;
final String methodName = method.getName();
if (!HardcodedMethodConstants.FINALIZE.equals(methodName)) {
return;
}
if (method.hasModifierProperty(PsiModifier.NATIVE) ||
method.hasModifierProperty(PsiModifier.ABSTRACT)) {
return;
}
final PsiClass containingClass = method.getContainingClass();
if (containingClass == null) {
return;
}
if (ignoreObjectSubclasses) {
final PsiClass superClass = containingClass.getSuperClass();
if (superClass != null) {
final String superClassName = superClass.getQualifiedName();
if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClassName)) {
return;
}
}
}
final PsiParameterList parameterList = method.getParameterList();
if (parameterList.getParametersCount() != 0) {
return;
}
if (MethodCallUtils.containsSuperMethodCall(method)) {
return;
}
if (ignoreTrivialFinalizers && MethodUtils.isTrivial(method, false)) {
return;
}
registerMethodError(method);
}
}
}
@@ -0,0 +1,49 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* 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.inheritance;
import com.intellij.codeInspection.ex.InspectionElementsMerger;
/**
* @author Bas Leijdekkers
*/
public class MethodDoesntCallSuperMethodInspectionMerger extends InspectionElementsMerger {
@Override
public String getMergedToolName() {
return "RefusedBequest";
}
@Override
public String[] getSourceToolNames() {
return new String[] {
"RefusedBequest",
"CloneCallsSuperClone",
"SetupCallsSuperSetUp",
"TeardownCallsSuperTearDown",
"FinalizeCallsSuperFinalize"
};
}
@Override
public String[] getSuppressIds() {
return new String[] {
"CloneDoesntCallSuperClone",
"SetUpDoesntCallSuperSetUp",
"TearDownDoesntCallSuperTearDown",
"FinalizeDoesntCallSuperFinalize"};
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2015 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2016 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,10 +19,13 @@ import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.siyeh.HardcodedMethodConstants;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.ClassUtils;
import com.siyeh.ig.psiutils.CloneUtils;
import com.siyeh.ig.psiutils.MethodCallUtils;
import com.siyeh.ig.psiutils.MethodUtils;
import com.siyeh.ig.ui.ExternalizableStringSet;
import org.jdom.Element;
@@ -38,6 +41,12 @@ public class RefusedBequestInspectionBase extends BaseInspection {
@SuppressWarnings("PublicField") boolean onlyReportWhenAnnotated = true;
@Override
@NotNull
public String getID() {
return "MethodDoesntCallSuperMethod";
}
@Override
public void writeSettings(@NotNull Element node) throws WriteExternalException {
super.writeSettings(node);
@@ -103,10 +112,15 @@ public class RefusedBequestInspectionBase extends BaseInspection {
if (leastConcreteSuperMethod == null) {
return;
}
final PsiClass objectClass = ClassUtils.findObjectClass(method);
final PsiMethod[] superMethods = method.findSuperMethods(objectClass);
if (superMethods.length > 0) {
return;
final String methodName = method.getName();
if (!HardcodedMethodConstants.CLONE.equals(methodName)) {
final PsiClass superClass = leastConcreteSuperMethod.getContainingClass();
if (superClass != null) {
final String superClassName = superClass.getQualifiedName();
if (CommonClassNames.JAVA_LANG_OBJECT.equals(superClassName)) {
return;
}
}
}
if (ignoreEmptySuperMethods) {
final PsiElement element = leastConcreteSuperMethod.getNavigationElement();
@@ -115,17 +129,34 @@ public class RefusedBequestInspectionBase extends BaseInspection {
return;
}
}
if (onlyReportWhenAnnotated) {
if (onlyReportWhenAnnotated && !CloneUtils.isClone(method) && !isJUnitSetUpOrTearDown(method)) {
if (!AnnotationUtil.isAnnotated(leastConcreteSuperMethod, annotations)) {
return;
}
}
if (containsSuperCall(body, leastConcreteSuperMethod)) {
final PsiClass aClass = method.getContainingClass();
if ((aClass != null && aClass.hasModifierProperty(PsiModifier.FINAL) || method.hasModifierProperty(PsiModifier.FINAL)) &&
MethodUtils.isTrivial(method, true)) {
return;
}
if (MethodCallUtils.containsSuperMethodCall(method)) {
return;
}
registerMethodError(method);
}
private boolean isJUnitSetUpOrTearDown(PsiMethod method) {
final String name = method.getName();
if (!"setUp".equals(name) && !"tearDown".equals(name)) {
return false;
}
if (method.getParameterList().getParametersCount() != 0) {
return false;
}
final PsiClass aClass = method.getContainingClass();
return InheritanceUtil.isInheritor(aClass, "junit.framework.TestCase");
}
@Nullable
private PsiMethod getDirectSuperMethod(PsiMethod method) {
final PsiMethod superMethod = MethodUtils.getSuper(method);
@@ -138,58 +169,5 @@ public class RefusedBequestInspectionBase extends BaseInspection {
}
return superMethod;
}
private boolean containsSuperCall(@NotNull PsiElement context, @NotNull PsiMethod method) {
final SuperCallVisitor visitor = new SuperCallVisitor(method);
context.accept(visitor);
return visitor.hasSuperCall();
}
}
private static class SuperCallVisitor extends JavaRecursiveElementWalkingVisitor {
private final PsiMethod methodToSearchFor;
private boolean hasSuperCall;
SuperCallVisitor(PsiMethod methodToSearchFor) {
this.methodToSearchFor = methodToSearchFor;
}
@Override
public void visitElement(@NotNull PsiElement element) {
if (hasSuperCall) {
return;
}
super.visitElement(element);
}
@Override
public void visitMethodCallExpression(
@NotNull PsiMethodCallExpression expression) {
if (hasSuperCall) {
return;
}
super.visitMethodCallExpression(expression);
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
final PsiExpression qualifier = methodExpression.getQualifierExpression();
if (qualifier == null) {
return;
}
final String text = qualifier.getText();
if (!PsiKeyword.SUPER.equals(text)) {
return;
}
final PsiMethod method = expression.resolveMethod();
if (method == null) {
return;
}
if (method.equals(methodToSearchFor)) {
hasSuperCall = true;
}
}
boolean hasSuperCall() {
return hasSuperCall;
}
}
}
@@ -1,96 +0,0 @@
/*
* Copyright 2003-2015 Dave Griffith, 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.psi.codeStyle.CodeStyleManager;
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.NotNull;
public class SetupCallsSuperSetupInspection extends BaseInspection {
@Override
@NotNull
public String getID() {
return "SetUpDoesntCallSuperSetUp";
}
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"setup.calls.super.setup.display.name");
}
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"setup.calls.super.setup.problem.descriptor");
}
private static class AddSuperSetUpCall extends InspectionGadgetsFix {
@Override
@NotNull
public String getFamilyName() {
return getName();
}
@Override
@NotNull
public String getName() {
return InspectionGadgetsBundle.message(
"setup.calls.super.setup.add.quickfix");
}
@Override
public void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
final PsiElement methodName = descriptor.getPsiElement();
final PsiMethod method = (PsiMethod)methodName.getParent();
assert method != null;
final PsiCodeBlock body = method.getBody();
if (body == null) {
return;
}
final PsiElementFactory factory =
JavaPsiFacade.getElementFactory(project);
final PsiStatement newStatement =
factory.createStatementFromText("super.setUp();", null);
final CodeStyleManager styleManager =
CodeStyleManager.getInstance(project);
final PsiJavaToken brace = body.getLBrace();
body.addAfter(newStatement, brace);
styleManager.reformat(body);
}
}
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
return new AddSuperSetUpCall();
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new TeardownCallsSuperTeardownInspection.TeardownCallsSuperTeardownVisitor("setUp");
}
}
@@ -1,140 +0,0 @@
/*
* Copyright 2003-2016 Dave Griffith, 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.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.InheritanceUtil;
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 com.siyeh.ig.psiutils.MethodCallUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class TeardownCallsSuperTeardownInspection extends BaseInspection {
@Override
@NotNull
public String getID() {
return "TearDownDoesntCallSuperTearDown";
}
@Override
@NotNull
public String getDisplayName() {
return InspectionGadgetsBundle.message(
"teardown.calls.super.teardown.display.name");
}
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"teardown.calls.super.teardown.problem.descriptor");
}
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
return new AddSuperTearDownCall();
}
private static class AddSuperTearDownCall extends InspectionGadgetsFix {
@Override
@NotNull
public String getName() {
return InspectionGadgetsBundle.message(
"teardown.calls.super.teardown.add.quickfix");
}
@Override
@NotNull
public String getFamilyName() {
return getName();
}
@Override
public void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
final PsiElement methodName = descriptor.getPsiElement();
final PsiMethod method = (PsiMethod)methodName.getParent();
if (method == null) {
return;
}
final PsiCodeBlock body = method.getBody();
if (body == null) {
return;
}
final PsiElementFactory factory =
JavaPsiFacade.getElementFactory(project);
final PsiStatement newStatement =
factory.createStatementFromText("super.tearDown();", null);
final CodeStyleManager styleManager =
CodeStyleManager.getInstance(project);
final PsiJavaToken brace = body.getRBrace();
body.addBefore(newStatement, brace);
styleManager.reformat(body);
}
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new TeardownCallsSuperTeardownVisitor("tearDown");
}
public static class TeardownCallsSuperTeardownVisitor extends BaseInspectionVisitor {
private final String myMethodName;
public TeardownCallsSuperTeardownVisitor(String methodName) {
myMethodName = methodName;
}
@Override
public void visitMethod(@NotNull PsiMethod method) {
//note: no call to super;
@NonNls final String methodName = method.getName();
if (!myMethodName.equals(methodName)) {
return;
}
if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
return;
}
if (method.getBody() == null) {
return;
}
final PsiParameterList parameterList = method.getParameterList();
if (parameterList.getParametersCount() != 0) {
return;
}
final PsiClass targetClass = method.getContainingClass();
if (targetClass == null) {
return;
}
if (!InheritanceUtil.isInheritor(targetClass, "junit.framework.TestCase")) {
return;
}
if (MethodCallUtils.containsSuperMethodCall(method)) {
return;
}
registerMethodError(method);
}
}
}
@@ -244,6 +244,9 @@ public class MethodUtils {
* also when it is a constructor which only calls super, contains empty statements or "if (false)" statements.
*/
public static boolean isTrivial(PsiMethod method, boolean throwIsTrivial) {
if (method.hasModifierProperty(PsiModifier.NATIVE)) {
return false;
}
return isTrivial(method.getBody(), throwIsTrivial);
}
@@ -1,9 +0,0 @@
<html>
<body>
Reports <b>clone()</b> methods which do not call <b>super.clone()</b>.
Cloning an object without calling <b>super.clone()</b> may result in objects being improperly initialized.
<!-- tooltip end -->
<p>
</body>
</html>
@@ -1,18 +0,0 @@
<html>
<body>
Reports any implementations of the <b>Object.finalize()</b> method
which do not call <b>super.finalize()</b>. Failing to call <b>super.finalize()</b> may result in objects failing to properly
free any resources held or do other cleanup activities.
<!-- tooltip end -->
<p>
Use the checkboxes below to ignore direct subclasses of <b>java.lang.Object</b>
or to ignore <b>finalize()</b> implementations with an empty
method body or a body containing only if statements which have a condition which
evaluates to false at compile time. For performance reasons it can be beneficial to
override a non-trivial <b>finalize()</b> with an empty
implementation in a subclass. An empty final <b>finalize()</b>
implementation can also be used to prevent subclasses from overriding.
<p>
</body>
</html>
@@ -1,9 +0,0 @@
<html>
<body>
Reports JUnit classes whose <b>setUp()</b> method
does not call <b>super.setUp()</b>.
<!-- tooltip end -->
<p>
</body>
</html>
@@ -1,9 +0,0 @@
<html>
<body>
Reports JUnit classes whose <b>tearDown()</b> method
does not call <b>super.tearDown()</b>.
<!-- tooltip end -->
<p>
</body>
</html>
@@ -1,36 +0,0 @@
package com.siyeh.igtest.cloneable.clone_calls_super_clone;
public class CloneCallsSuperClone implements Cloneable
{
public void foo()
{
}
public Object <warning descr="'clone()' does not call 'super.clone()'">clone</warning>()
{
return this;
}
}
class One {
public final One clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
final class Two {
public Two clone() throws CloneNotSupportedException {
throw (new CloneNotSupportedException());
}
}
class Three {
public Three <warning descr="'clone()' does not call 'super.clone()'">clone</warning>() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
class Four {
public final Four clone() {
throw new UnsupportedOperationException();
}
}
@@ -1,40 +0,0 @@
package com.siyeh.igtest.finalization.finalize_calls_super_finalize;
import java.lang.Override;
import java.lang.Throwable;
public class FinalizeCallsSuperFinalize
{
public FinalizeCallsSuperFinalize()
{
}
protected void finalize()
{
}
class X {
@Override
protected void <warning descr="'finalize()' does not call 'super.finalize()'">finalize</warning>() throws Throwable {
System.out.println("");
}
}
class Y {
protected void <warning descr="'finalize()' does not call 'super.finalize()'">finalize</warning>() throws Throwable {
if (false) {
super.finalize(); // not reached, thus not called.
}
System.out.println("non trivial");
}
}
}
class A {
public void finalize(int random) {}
}
class B extends A {
protected void <warning descr="'finalize()' does not call 'super.finalize()'">finalize</warning>() throws Throwable {
super.finalize(1);
}
}
@@ -0,0 +1,51 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* 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.igtest.cloneable.clone_calls_super_clone;
public class CloneCallsSuperClone implements Cloneable
{
public void foo()
{
}
public Object <warning descr="Method 'clone()' does not call 'super.clone()'">clone</warning>()
{
return this;
}
}
class One {
public final One clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
final class Two {
public Two clone() throws CloneNotSupportedException {
throw (new CloneNotSupportedException());
}
}
class Three {
public Three <warning descr="Method 'clone()' does not call 'super.clone()'">clone</warning>() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
class Four {
public final Four clone() {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,44 @@
package com.siyeh.igtest.finalization.finalize_calls_super_finalize;
import java.lang.Override;
import java.lang.Throwable;
public class FinalizeCallsSuperFinalize
{
public FinalizeCallsSuperFinalize()
{
}
@Override
protected void finalize()
{
System.out.println("something");
}
class X extends FinalizeCallsSuperFinalize {
@Override
protected void <warning descr="Method 'finalize()' does not call 'super.finalize()'">finalize</warning>() throws <error descr="'finalize()' in 'com.siyeh.igtest.finalization.finalize_calls_super_finalize.FinalizeCallsSuperFinalize.X' clashes with 'finalize()' in 'com.siyeh.igtest.finalization.finalize_calls_super_finalize.FinalizeCallsSuperFinalize'; overridden method does not throw 'java.lang.Throwable'">Throwable</error> {
System.out.println("");
}
}
class Y extends FinalizeCallsSuperFinalize {
protected void <warning descr="Method 'finalize()' does not call 'super.finalize()'">finalize</warning>() throws <error descr="'finalize()' in 'com.siyeh.igtest.finalization.finalize_calls_super_finalize.FinalizeCallsSuperFinalize.Y' clashes with 'finalize()' in 'com.siyeh.igtest.finalization.finalize_calls_super_finalize.FinalizeCallsSuperFinalize'; overridden method does not throw 'java.lang.Throwable'">Throwable</error> {
if (false) {
super.finalize(); // not reached, thus not called.
}
System.out.println("non trivial");
}
}
}
class A {
public void finalize(int random) {}
protected void finalize() {
System.out.println("non trivial");
}
}
class B extends A {
protected void <warning descr="Method 'finalize()' does not call 'super.finalize()'">finalize</warning>() throws <error descr="'finalize()' in 'com.siyeh.igtest.finalization.finalize_calls_super_finalize.B' clashes with 'finalize()' in 'com.siyeh.igtest.finalization.finalize_calls_super_finalize.A'; overridden method does not throw 'java.lang.Throwable'">Throwable</error> {
super.finalize(1);
}
}
@@ -20,7 +20,7 @@ class A {
class B extends A {
@Override
public String toString() {
public String <warning descr="Method 'toString()' does not call 'super.toString()'">toString</warning>() {
return "B.toString";
}
}
@@ -0,0 +1,23 @@
import junit.framework.TestCase;
class SetupCallsSuperSetup extends TestCase {
protected void <warning descr="Method 'setUp()' does not call 'super.setUp()'">setUp</warning>() throws Exception {
System.out.println("foo");
}
}
class OK extends TestCase {
protected void setUp() throws Exception {
super.setUp();
}
}
class NotCalled2 extends TestCase {
protected void <warning descr="Method 'setUp()' does not call 'super.setUp()'">setUp</warning>() throws Exception {
if (false) super.setUp();
}
}
class Suppressed extends TestCase {
@SuppressWarnings("SetUpDoesntCallSuperSetUp")
protected void setUp() throws Exception {
}
}
@@ -1,18 +0,0 @@
import junit.framework.TestCase;
class SetupCallsSuperSetup extends TestCase {
protected void <warning descr="'setUp()' does not call 'super.setUp()'">setUp</warning>() throws Exception {
System.out.println("foo");
}
}
class OK extends TestCase {
protected void setUp() throws Exception {
super.setUp();
}
}
class NotCalled2 extends TestCase {
protected void <warning descr="'setUp()' does not call 'super.setUp()'">setUp</warning>() throws Exception {
if (false) super.setUp();
}
}
@@ -1,36 +0,0 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* 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.cloneable;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import org.jetbrains.annotations.Nullable;
/**
* @author Bas Leijdekkers.
*/
public class CloneCallsSuperCloneInspectionTest extends LightInspectionTestCase {
public void testCloneCallsSuperClone() {
doTest();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
return new CloneCallsSuperCloneInspection();
}
}
@@ -1,18 +0,0 @@
package com.siyeh.ig.finalization;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import org.jetbrains.annotations.Nullable;
public class FinalizeCallsSuperFinalizeInspectionTest extends LightInspectionTestCase {
public void testFinalizeCallsSuperFinalize() throws Exception {
doTest();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
return new FinalizeCallsSuperFinalizeInspection();
}
}
@@ -6,9 +6,10 @@ import org.jetbrains.annotations.Nullable;
public class RefusedBequestInspectionTest extends LightInspectionTestCase {
public void testRefusedBequest() throws Exception {
doTest();
}
public void testRefusedBequest() { doTest(); }
public void testCloneCallsSuperClone() { doTest(); }
public void testSetupCallsSuperSetup() { doTest(); }
public void testFinalizeCallsSuperFinalize() { doTest(); }
@Nullable
@Override
@@ -25,6 +26,12 @@ public class RefusedBequestInspectionTest extends LightInspectionTestCase {
"@Retention(RetentionPolicy.RUNTIME)\n" +
"@Target(ElementType.METHOD)\n" +
"public @interface Before {\n" +
"}",
"package junit.framework;" +
"public abstract class TestCase {" +
" protected void setUp() throws Exception {}" +
" protected void tearDown() throws Exception {}" +
"}"
};
}
@@ -1,48 +0,0 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* 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.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import junit.framework.TestCase;
import org.jetbrains.annotations.Nullable;
/**
* @author Bas Leijdekkers
*/
public class SetupCallsSuperSetupInspectionTest extends LightInspectionTestCase {
public void testSetupCallsSuperSetup() {
doTest();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
return new SetupCallsSuperSetupInspection();
}
@Override
protected String[] getEnvironmentClasses() {
return new String[] {
"package junit.framework;" +
"public abstract class TestCase {" +
" protected void setUp() throws Exception {}" +
" protected void tearDown() throws Exception {}" +
"}"
};
}
}