From 7acaf1bd4fccf2140c1ae2aec590ff4c84bfe68c Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 15 Jan 2015 11:40:07 +0100 Subject: [PATCH] IG: clone() method may throw any exception to prevent cloning --- .../CloneCallsSuperCloneInspection.java | 13 +++---- .../CloneInNonCloneableClassInspection.java | 5 +-- .../src/com/siyeh/ig/psiutils/CloneUtils.java | 32 ++++++----------- .../CloneCallsSuperCloneInspection.java | 15 -------- .../CloneCallsSuperClone.java | 36 +++++++++++++++++++ .../CloneCallsSuperCloneInspectionTest.java | 36 +++++++++++++++++++ 6 files changed, 88 insertions(+), 49 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsSuperCloneInspection.java create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_calls_super_clone/CloneCallsSuperClone.java create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspectionTest.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspection.java index 43317990ac9b..646a5929795c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspection.java @@ -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; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/CloneInNonCloneableClassInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/CloneInNonCloneableClassInspection.java index f23e9c16991a..d726500808c9 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/CloneInNonCloneableClassInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/cloneable/CloneInNonCloneableClassInspection.java @@ -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); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/CloneUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/CloneUtils.java index 4513a60bd033..0da1027ebafc 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/CloneUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/CloneUtils.java @@ -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; } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsSuperCloneInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsSuperCloneInspection.java deleted file mode 100644 index 2d18b36fdcae..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/CloneCallsSuperCloneInspection.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.siyeh.igtest.cloneable; - -public class CloneCallsSuperCloneInspection implements Cloneable -{ - - public void foo() - { - - } - - public Object clone() - { - return this; - } -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_calls_super_clone/CloneCallsSuperClone.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_calls_super_clone/CloneCallsSuperClone.java new file mode 100644 index 000000000000..3a95546ee4f8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/cloneable/clone_calls_super_clone/CloneCallsSuperClone.java @@ -0,0 +1,36 @@ +package com.siyeh.igtest.cloneable.clone_calls_super_clone; + +public class CloneCallsSuperClone implements Cloneable +{ + + public void foo() + { + + } + + public Object clone() + { + 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 clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } +} +class Four { + public final Four clone() { + throw new UnsupportedOperationException(); + } +} diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspectionTest.java new file mode 100644 index 000000000000..2c9ee37c6482 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/cloneable/CloneCallsSuperCloneInspectionTest.java @@ -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(); + } +}