IG: clone() method may throw any exception to prevent cloning

This commit is contained in:
Bas Leijdekkers
2015-01-17 17:00:42 +01:00
parent 54f4eba443
commit 7acaf1bd4f
6 changed files with 88 additions and 49 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
* 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.
@@ -77,15 +77,10 @@ public class CloneCallsSuperCloneInspection extends BaseInspection {
containingClass.isAnnotationType()) {
return;
}
if (CloneUtils.onlyThrowsCloneNotSupportedException(method)) {
if (method.hasModifierProperty(PsiModifier.FINAL) ||
containingClass.hasModifierProperty(
PsiModifier.FINAL)) {
return;
}
if (CloneUtils.onlyThrowsException(method)) {
return;
}
final CallToSuperCloneVisitor visitor =
new CallToSuperCloneVisitor();
final CallToSuperCloneVisitor visitor = new CallToSuperCloneVisitor();
method.accept(visitor);
if (visitor.isCallToSuperCloneFound()) {
return;
@@ -104,10 +104,7 @@ public class CloneInNonCloneableClassInspection extends BaseInspection {
return;
}
final PsiClass containingClass = method.getContainingClass();
if (CloneUtils.isCloneable(containingClass)) {
return;
}
if (method.hasModifierProperty(PsiModifier.FINAL) && CloneUtils.onlyThrowsCloneNotSupportedException(method)) {
if (CloneUtils.isCloneable(containingClass) || CloneUtils.onlyThrowsException(method)) {
return;
}
registerMethodError(method, containingClass);
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
* 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.
@@ -60,32 +60,22 @@ public class CloneUtils {
HardcodedMethodConstants.CLONE, PsiType.EMPTY_ARRAY);
}
public static boolean onlyThrowsCloneNotSupportedException(
@NotNull PsiMethod method) {
public static boolean onlyThrowsException(@NotNull PsiMethod method) {
if (!method.hasModifierProperty(PsiModifier.FINAL)) {
final PsiClass aClass = method.getContainingClass();
if (aClass == null || !aClass.hasModifierProperty(PsiModifier.FINAL)) {
return false;
}
}
final PsiCodeBlock body = method.getBody();
if (body == null) {
return false;
}
final PsiStatement[] statements = body.getStatements();
if (statements.length != 1) {
if (statements.length == 0) {
return false;
}
final PsiStatement statement = statements[0];
if (!(statement instanceof PsiThrowStatement)) {
return false;
}
final PsiThrowStatement throwStatement = (PsiThrowStatement)statement;
final PsiExpression exception = ParenthesesUtils.stripParentheses(throwStatement.getException());
if (!(exception instanceof PsiNewExpression)) {
return false;
}
final PsiNewExpression newExpression = (PsiNewExpression)exception;
final PsiJavaCodeReferenceElement classReference =
newExpression.getClassReference();
if (classReference == null) {
return false;
}
final String qualifiedName = classReference.getQualifiedName();
return qualifiedName.equals("java.lang.CloneNotSupportedException");
final PsiStatement statement = statements[statements.length - 1];
return statement instanceof PsiThrowStatement;
}
}
@@ -1,15 +0,0 @@
package com.siyeh.igtest.cloneable;
public class CloneCallsSuperCloneInspection implements Cloneable
{
public void foo()
{
}
public Object clone()
{
return this;
}
}
@@ -0,0 +1,36 @@
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();
}
}
@@ -0,0 +1,36 @@
/*
* 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();
}
}