IG: add option to ignore accesses from inner classes (IDEA-184055)

This commit is contained in:
Bas Leijdekkers
2017-12-21 17:49:34 +01:00
parent 0babfe26af
commit eea03864da
5 changed files with 87 additions and 36 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2003-2011 Dave Griffith, Bas Leijdekkers
* Copyright 2003-2017 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.
@@ -16,21 +16,26 @@
package com.siyeh.ig.encapsulation;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.MethodUtils;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class UseOfAnotherObjectsPrivateFieldInspectionBase
extends BaseInspection {
public class UseOfAnotherObjectsPrivateFieldInspectionBase extends BaseInspection {
@SuppressWarnings({"PublicField"})
public boolean ignoreSameClass = false;
@SuppressWarnings({"PublicField"})
public boolean ignoreInnerClasses = false;
@SuppressWarnings({"PublicField"})
public boolean ignoreEquals = false;
@@ -56,34 +61,36 @@ public class UseOfAnotherObjectsPrivateFieldInspectionBase
@Override
public JComponent createOptionsPanel() {
final MultipleCheckboxOptionsPanel panel =
new MultipleCheckboxOptionsPanel(this);
panel.addCheckbox(InspectionGadgetsBundle.message(
"ignore.accesses.from.the.same.class"), "ignoreSameClass");
panel.addCheckbox(InspectionGadgetsBundle.message(
"ignore.accesses.from.equals.method"), "ignoreEquals");
final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this);
final JCheckBox box = panel.addCheckboxEx(InspectionGadgetsBundle.message("ignore.accesses.from.the.same.class"), "ignoreSameClass");
panel.addDependentCheckBox("Ignore accesses from inner classes", "ignoreInnerClasses", box);
panel.addCheckbox(InspectionGadgetsBundle.message("ignore.accesses.from.equals.method"), "ignoreEquals");
return panel;
}
@Override
public void writeSettings(@NotNull Element node) throws WriteExternalException {
// this inspection uses old style serialization, make sure newly introduced setting field does not change profile.
defaultWriteSettings(node, "ignoreInnerClasses");
writeBooleanOption(node, "ignoreInnerClasses", false);
}
@Override
public BaseInspectionVisitor buildVisitor() {
return new UseOfAnotherObjectsPrivateFieldVisitor();
}
private class UseOfAnotherObjectsPrivateFieldVisitor
extends BaseInspectionVisitor {
private class UseOfAnotherObjectsPrivateFieldVisitor extends BaseInspectionVisitor {
@Override
public void visitReferenceExpression(
@NotNull PsiReferenceExpression expression) {
public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
final PsiExpression qualifier = expression.getQualifierExpression();
if (qualifier == null || qualifier instanceof PsiThisExpression) {
return;
}
if (ignoreEquals) {
final PsiMethod method =
PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
if (MethodUtils.isEquals(method)) {
return;
}
@@ -94,10 +101,10 @@ public class UseOfAnotherObjectsPrivateFieldInspectionBase
}
final PsiField field = (PsiField)referent;
if (ignoreSameClass) {
final PsiClass parent =
PsiTreeUtil.getParentOfType(expression, PsiClass.class);
final PsiClass parent = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
final PsiClass containingClass = field.getContainingClass();
if (parent != null && parent.equals(containingClass)) {
if (parent != null && (parent.equals(containingClass) ||
ignoreInnerClasses && PsiTreeUtil.isAncestor(containingClass, parent, true))) {
return;
}
}
@@ -108,8 +115,7 @@ public class UseOfAnotherObjectsPrivateFieldInspectionBase
if (field.hasModifierProperty(PsiModifier.STATIC)) {
return;
}
final PsiElement fieldNameElement =
expression.getReferenceNameElement();
final PsiElement fieldNameElement = expression.getReferenceNameElement();
if (fieldNameElement == null) {
return;
}
@@ -10,6 +10,7 @@ using proxies.
<p>
Use the first checkbox below to ignore accesses from the same class and only report accesses
from inner or outer classes.
To ignore accesses from inner classes also, use the nested checkbox.
<p>
Use the second checkbox below to ignore accesses from an <b>equals()</b> method.
<p>
@@ -1,16 +0,0 @@
package com.siyeh.igtest.encapsulation;
public class UseOfAnotherObjectsPrivateFieldInspection {
public int foo;
protected int bar;
private int baz;
public void fooBar(UseOfAnotherObjectsPrivateFieldInspection copy)
{
foo = copy.foo;
bar = copy.bar;
baz = copy.baz;
foo = this.baz;
foo = baz;
}
}
@@ -0,0 +1,33 @@
/*
* Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/
package com.siyeh.igtest.encapsulation;
public class UseOfAnotherObjectsPrivateField {
public int foo;
protected int bar;
private int baz;
public void fooBar(UseOfAnotherObjectsPrivateField copy)
{
foo = copy.foo;
bar = copy.bar;
baz = copy.baz;
foo = this.baz;
foo = baz;
}
class Inside {
int f(UseOfAnotherObjectsPrivateField pugnacious) {
return pugnacious.baz;
}
}
}
class SomewhereElse {
void m(UseOfAnotherObjectsPrivateField tenacious) {
tenacious.<warning descr="Direct access of non-public field 'bar' on another object">bar</warning> = 1;
tenacious.foo = 2;
}
}
@@ -0,0 +1,27 @@
/*
* Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
*/
package com.siyeh.ig.encapsulation;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import org.jetbrains.annotations.Nullable;
/**
* @author Bas Leijdekkers
*/
public class UseOfAnotherObjectsPrivateFieldInspectionTest extends LightInspectionTestCase {
public void testUseOfAnotherObjectsPrivateField() {
doTest();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
final UseOfAnotherObjectsPrivateFieldInspection inspection = new UseOfAnotherObjectsPrivateFieldInspection();
inspection.ignoreSameClass = true;
inspection.ignoreInnerClasses = true;
return inspection;
}
}