mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-88191 (inconsistent "'this' reference escaped in object construction" when using static method import)
This commit is contained in:
+34
-82
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+30
@@ -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);
|
||||
}
|
||||
}
|
||||
+14
-15
@@ -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;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>ThisEscapedInConstructorInspection.java</file>
|
||||
<line>7</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'this' reference escaped in object construction</problem_class>
|
||||
<description>Escape of <code>ThisEscapedInConstructorInspection.this</code> during object construction #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ThisEscapedInConstructorInspection.java</file>
|
||||
<line>7</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'this' reference escaped in object construction</problem_class>
|
||||
<description>Escape of <code>this</code> during object construction #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ThisEscapedInConstructorInspection.java</file>
|
||||
<line>12</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'this' reference escaped in object construction</problem_class>
|
||||
<description>Escape of <code>this</code> during object construction #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ThisEscapedInConstructorInspection.java</file>
|
||||
<line>18</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'this' reference escaped in object construction</problem_class>
|
||||
<description>Escape of <code>this</code> during object construction #loc</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>ThisEscapedInConstructorInspection.java</file>
|
||||
<line>19</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'this' reference escaped in object construction</problem_class>
|
||||
<description>Escape of <code>this</code> during object construction #loc</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+10
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user