From 1102dade63f8327f688b856a37772cdc111f6912 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 16 Jul 2012 22:19:54 +0200 Subject: [PATCH] IDEA-88191 (inconsistent "'this' reference escaped in object construction" when using static method import) --- .../ThisEscapedInConstructorInspection.java | 116 +++++------------- .../MethodUsers.java | 30 +++++ .../ThisEscapedInConstructorInspection.java | 29 +++-- .../this_escaped_in_constructor/expected.xml | 37 ++++++ ...hisEscapedInConstructorInspectionTest.java | 10 ++ 5 files changed, 125 insertions(+), 97 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/MethodUsers.java rename plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/{ => this_escaped_in_constructor}/ThisEscapedInConstructorInspection.java (74%) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/expected.xml create mode 100644 plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/ThisEscapedInConstructorInspectionTest.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/ThisEscapedInConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/ThisEscapedInConstructorInspection.java index b249db503445..7ac77f49dec6 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/ThisEscapedInConstructorInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/ThisEscapedInConstructorInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2012 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. @@ -25,29 +25,30 @@ import org.jetbrains.annotations.NotNull; public class ThisEscapedInConstructorInspection extends BaseInspection { + @Override @NotNull public String getID() { return "ThisEscapedInObjectConstruction"; } + @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message( - "this.reference.escaped.in.construction.display.name"); + return InspectionGadgetsBundle.message("this.reference.escaped.in.construction.display.name"); } + @Override @NotNull public String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "this.reference.escaped.in.construction.problem.descriptor"); + return InspectionGadgetsBundle.message("this.reference.escaped.in.construction.problem.descriptor"); } + @Override public BaseInspectionVisitor buildVisitor() { return new ThisExposedInConstructorInspectionVisitor(); } - private static class ThisExposedInConstructorInspectionVisitor - extends BaseInspectionVisitor { + private static class ThisExposedInConstructorInspectionVisitor extends BaseInspectionVisitor { @Override public void visitThisExpression(PsiThisExpression expression) { @@ -55,10 +56,8 @@ public class ThisEscapedInConstructorInspection extends BaseInspection { if (!isInInitializer(expression)) { return; } - final PsiJavaCodeReferenceElement qualifier = - expression.getQualifier(); - final PsiClass containingClass = - ClassUtils.getContainingClass(expression); + final PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); + final PsiClass containingClass = ClassUtils.getContainingClass(expression); if (qualifier != null) { final PsiElement element = qualifier.resolve(); if (!(element instanceof PsiClass)) { @@ -71,8 +70,7 @@ public class ThisEscapedInConstructorInspection extends BaseInspection { } final PsiElement parent = expression.getParent(); if (parent instanceof PsiAssignmentExpression) { - final PsiAssignmentExpression assignmentExpression = - (PsiAssignmentExpression)parent; + final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent; if (!thisEscapesToField(expression, assignmentExpression)) { return; } @@ -81,16 +79,14 @@ public class ThisEscapedInConstructorInspection extends BaseInspection { else if (parent instanceof PsiExpressionList) { final PsiElement grandParent = parent.getParent(); if (grandParent instanceof PsiNewExpression) { - final PsiNewExpression newExpression = - (PsiNewExpression)grandParent; + final PsiNewExpression newExpression = (PsiNewExpression)grandParent; if (!thisEscapesToConstructor(expression, newExpression)) { return; } registerError(expression); } else if (grandParent instanceof PsiMethodCallExpression) { - final PsiMethodCallExpression methodCallExpression = - (PsiMethodCallExpression)grandParent; + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)grandParent; if (!thisEscapesToMethod(expression, methodCallExpression)) { return; } @@ -99,83 +95,47 @@ public class ThisEscapedInConstructorInspection extends BaseInspection { } } - private static boolean thisEscapesToMethod( - PsiThisExpression expression, - PsiMethodCallExpression methodCallExpression) { - final PsiMethod method = - methodCallExpression.resolveMethod(); + private static boolean thisEscapesToMethod(PsiThisExpression expression, PsiMethodCallExpression methodCallExpression) { + final PsiMethod method = methodCallExpression.resolveMethod(); if (method == null) { return false; } - final PsiClass containingClass = - ClassUtils.getContainingClass(expression); + final PsiClass containingClass = ClassUtils.getContainingClass(expression); if (containingClass == null) { return false; } final PsiClass methodClass = method.getContainingClass(); - if (!method.hasModifierProperty(PsiModifier.STATIC) && - containingClass.isInheritor(methodClass, true)) { - return false; + if (method.hasModifierProperty(PsiModifier.STATIC)) { + return true; } - - // Make sure using this with members of self or superclasses - // doesn't trigger - final PsiReferenceExpression methodExpression = - methodCallExpression.getMethodExpression(); - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); - if (!(qualifier instanceof PsiReferenceExpression)) { - return false; - } - final PsiReferenceExpression qualifiedExpression = - (PsiReferenceExpression)qualifier; - final PsiElement referent = qualifiedExpression.resolve(); - if (referent instanceof PsiField) { - final PsiField field = (PsiField)referent; - final PsiClass fieldClass = field.getContainingClass(); - - if (containingClass.equals(fieldClass) || - containingClass.isInheritor(fieldClass, true)) { - return false; - } - } - return true; + return methodClass != null && !containingClass.isInheritor(methodClass, true); } - private static boolean thisEscapesToConstructor( - PsiThisExpression expression, PsiNewExpression newExpression) { - final PsiClass containingClass = - ClassUtils.getContainingClass(expression); - final PsiJavaCodeReferenceElement referenceElement = - newExpression.getClassReference(); + private static boolean thisEscapesToConstructor(PsiThisExpression expression, PsiNewExpression newExpression) { + final PsiClass containingClass = ClassUtils.getContainingClass(expression); + final PsiJavaCodeReferenceElement referenceElement = newExpression.getClassReference(); if (referenceElement == null) { return false; } - final PsiElement element = - referenceElement.resolve(); + final PsiElement element = referenceElement.resolve(); if (!(element instanceof PsiClass)) { return false; } final PsiClass constructorClass = (PsiClass)element; - return !PsiTreeUtil.isAncestor(containingClass, - constructorClass, false) || + return !PsiTreeUtil.isAncestor(containingClass, constructorClass, false) || constructorClass.hasModifierProperty(PsiModifier.STATIC); } - private static boolean thisEscapesToField( - PsiThisExpression expression, - PsiAssignmentExpression assignmentExpression) { + private static boolean thisEscapesToField(PsiThisExpression expression, PsiAssignmentExpression assignmentExpression) { final PsiExpression rhs = assignmentExpression.getRExpression(); if (!expression.equals(rhs)) { return false; } - final PsiExpression lExpression = - assignmentExpression.getLExpression(); + final PsiExpression lExpression = assignmentExpression.getLExpression(); if (!(lExpression instanceof PsiReferenceExpression)) { return false; } - final PsiReferenceExpression leftExpression = - (PsiReferenceExpression)lExpression; + final PsiReferenceExpression leftExpression = (PsiReferenceExpression)lExpression; final PsiElement element = leftExpression.resolve(); if (!(element instanceof PsiField)) { return false; @@ -184,35 +144,27 @@ public class ThisEscapedInConstructorInspection extends BaseInspection { if (field.hasModifierProperty(PsiModifier.STATIC)) { return true; } - // Inheritance check - final PsiClass assignmentClass = - ClassUtils.getContainingClass(assignmentExpression); + final PsiClass assignmentClass = ClassUtils.getContainingClass(assignmentExpression); final PsiClass fieldClass = field.getContainingClass(); - return !(assignmentClass == null || - assignmentClass.isInheritor(fieldClass, true) || + return !(assignmentClass == null || fieldClass == null || assignmentClass.isInheritor(fieldClass, true) || PsiTreeUtil.isAncestor(assignmentClass, fieldClass, false)); } /** * @return true if CallExpression is in a constructor, instance - * initializer, or field initializaer. Otherwise it returns - * false + * initializer, or field initializer. Otherwise false */ private static boolean isInInitializer(PsiElement call) { - final PsiMethod method = - PsiTreeUtil.getParentOfType(call, PsiMethod.class); + final PsiMethod method = PsiTreeUtil.getParentOfType(call, PsiMethod.class, true, PsiClass.class); if (method != null) { return method.isConstructor(); } - final PsiField field = - PsiTreeUtil.getParentOfType(call, PsiField.class); + final PsiField field = PsiTreeUtil.getParentOfType(call, PsiField.class, true, PsiClass.class); if (field != null) { return true; } - final PsiClassInitializer classInitializer = - PsiTreeUtil.getParentOfType(call, PsiClassInitializer.class); - return classInitializer != null && - !classInitializer.hasModifierProperty(PsiModifier.STATIC); + final PsiClassInitializer classInitializer = PsiTreeUtil.getParentOfType(call, PsiClassInitializer.class, true, PsiClass.class); + return classInitializer != null && !classInitializer.hasModifierProperty(PsiModifier.STATIC); } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/MethodUsers.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/MethodUsers.java new file mode 100644 index 000000000000..192dfc2bfa5c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/MethodUsers.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2012 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.initialization.this_escaped_in_constructor; + +import java.io.ByteArrayInputStream; +import static java.lang.System.*; + +class MethodUsers extends ByteArrayInputStream { + + { + setIn(this); + } + + public MethodUsers(byte[] buf) { + super(buf); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/ThisEscapedInConstructorInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/ThisEscapedInConstructorInspection.java similarity index 74% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/ThisEscapedInConstructorInspection.java rename to plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/ThisEscapedInConstructorInspection.java index 3e30f53bb161..73de1d9f22d1 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/ThisEscapedInConstructorInspection.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/ThisEscapedInConstructorInspection.java @@ -1,22 +1,8 @@ -package com.siyeh.igtest.initialization; +package com.siyeh.igtest.initialization.this_escaped_in_constructor; import java.util.ArrayList; import java.util.List; -class Testing -{ - Object boom; - - public static boolean foo(Object val) - { - return true; - } - - public static boolean foo(Object o1, Object o2) { - return false; - } -} - public class ThisEscapedInConstructorInspection{ private boolean foo = Testing.foo(ThisEscapedInConstructorInspection.this, this); @@ -40,3 +26,16 @@ public class ThisEscapedInConstructorInspection{ } } } +class Testing +{ + Object boom; + + public static boolean foo(Object val) + { + return true; + } + + public static boolean foo(Object o1, Object o2) { + return false; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/expected.xml new file mode 100644 index 000000000000..d60cfb8ef4c1 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/this_escaped_in_constructor/expected.xml @@ -0,0 +1,37 @@ + + + + ThisEscapedInConstructorInspection.java + 7 + 'this' reference escaped in object construction + Escape of <code>ThisEscapedInConstructorInspection.this</code> during object construction #loc + + + + ThisEscapedInConstructorInspection.java + 7 + 'this' reference escaped in object construction + Escape of <code>this</code> during object construction #loc + + + + ThisEscapedInConstructorInspection.java + 12 + 'this' reference escaped in object construction + Escape of <code>this</code> during object construction #loc + + + + ThisEscapedInConstructorInspection.java + 18 + 'this' reference escaped in object construction + Escape of <code>this</code> during object construction #loc + + + + ThisEscapedInConstructorInspection.java + 19 + 'this' reference escaped in object construction + Escape of <code>this</code> during object construction #loc + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/ThisEscapedInConstructorInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/ThisEscapedInConstructorInspectionTest.java new file mode 100644 index 000000000000..6da0dc928fe4 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/ThisEscapedInConstructorInspectionTest.java @@ -0,0 +1,10 @@ +package com.siyeh.ig.initialization; + +import com.siyeh.ig.IGInspectionTestCase; + +public class ThisEscapedInConstructorInspectionTest extends IGInspectionTestCase { + + public void test() throws Exception { + doTest("com/siyeh/igtest/initialization/this_escaped_in_constructor", new ThisEscapedInConstructorInspection()); + } +} \ No newline at end of file