diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index be9f257bed05..1955127e61ec 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -1547,6 +1547,9 @@ key="inner.class.may.be.static.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.memory.issues" enabledByDefault="false" level="WARNING" runForWholeFile="true" implementationClass="com.siyeh.ig.memory.InnerClassMayBeStaticInspection"/> + diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 949ae7667e76..a53ec7abe88f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -2117,3 +2117,7 @@ junit3.method.naming.convention.problem.descriptor.regex.mismatch=JUnit 3 test m introduce.holder.class.quickfix=Introduce holder class double.brace.initialization.display.name=Double brace initialization double.brace.initialization.quickfix=Replace with regular initialization +return.of.inner.class.display.name=Return of instance of anonymous, local or inner class +return.of.anonymous.class.problem.descriptor=Return of instance of anonymous class #loc +return.of.local.class.problem.descriptor=Return of instance of local class {0} #loc +return.of.inner.class.problem.descriptor=Return of instance of non-static inner class {0} #loc diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/ReturnOfInnerClassInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/ReturnOfInnerClassInspection.java new file mode 100644 index 000000000000..f8d9f8e17226 --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/ReturnOfInnerClassInspection.java @@ -0,0 +1,107 @@ +/* + * Copyright 2000-2014 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.memory; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class ReturnOfInnerClassInspection extends BaseInspection { + + private enum ClassType { ANONYMOUS_CLASS, LOCAL_CLASS, INNER_CLASS } + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("return.of.inner.class.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + switch ((ClassType)infos[0]) { + case ANONYMOUS_CLASS: + return InspectionGadgetsBundle.message("return.of.anonymous.class.problem.descriptor"); + case LOCAL_CLASS: { + final PsiClass aClass = (PsiClass)infos[1]; + return InspectionGadgetsBundle.message("return.of.local.class.problem.descriptor", aClass.getName()); + } + case INNER_CLASS: { + final PsiClass aClass = (PsiClass)infos[1]; + return InspectionGadgetsBundle.message("return.of.inner.class.problem.descriptor", aClass.getName()); + } + default: + throw new UnsupportedOperationException(); + } + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new ReturnOfInnerClassVisitor(); + } + + private static class ReturnOfInnerClassVisitor extends BaseInspectionVisitor { + + @Override + public void visitReturnStatement(PsiReturnStatement statement) { + super.visitReturnStatement(statement); + final PsiExpression expression = ParenthesesUtils.stripParentheses(statement.getReturnValue()); + if (expression == null) { + return; + } + final PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, true, PsiLambdaExpression.class); + if (method == null || method.hasModifierProperty(PsiModifier.PRIVATE)) { + return; + } + if (expression instanceof PsiNewExpression) { + final PsiNewExpression newExpression = (PsiNewExpression)expression; + final PsiAnonymousClass anonymousClass = newExpression.getAnonymousClass(); + if (anonymousClass != null) { + registerStatementError(statement, ClassType.ANONYMOUS_CLASS); + return; + } + } + final PsiType type = expression.getType(); + if (!(type instanceof PsiClassType)) { + return; + } + final PsiClassType classType = (PsiClassType)type; + final PsiClass aClass = classType.resolve(); + if (aClass == null) { + return; + } + if (PsiUtil.isLocalClass(aClass)) { + registerStatementError(statement, ClassType.LOCAL_CLASS, aClass); + return; + } + final PsiClass containingClass = aClass.getContainingClass(); + if (containingClass == null || aClass.hasModifierProperty(PsiModifier.STATIC)) { + return; + } + registerStatementError(statement, ClassType.INNER_CLASS, aClass); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/return_of_inner_class/ReturnOfInnerClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/return_of_inner_class/ReturnOfInnerClass.java new file mode 100644 index 000000000000..bcf8358a776a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/return_of_inner_class/ReturnOfInnerClass.java @@ -0,0 +1,20 @@ +public class ReturnOfInnerClass { + + public Object one() { + return new Object() {}; + } + + public Object two() { + class A {} + return new A(); + } + + class B {} + public Object three() { + return new B(); + } + + private Object four() { + return new B(); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/ReturnOfInnerClassInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/ReturnOfInnerClassInspectionTest.java new file mode 100644 index 000000000000..3c01ea57ac5f --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/ReturnOfInnerClassInspectionTest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2014 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.memory; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import junit.framework.TestCase; +import org.jetbrains.annotations.Nullable; + +/** + * @author Bas Leijdekkers + */ +public class ReturnOfInnerClassInspectionTest extends LightInspectionTestCase { + + public void testReturnOfInnerClass() { doTest(); } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new ReturnOfInnerClassInspection(); + } +} \ No newline at end of file