mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java: Look for classes which escape their scope in all parts of the method's signature (IDEA-166535)
This commit is contained in:
+37
-49
@@ -16,13 +16,16 @@
|
||||
package com.siyeh.ig.visibility;
|
||||
|
||||
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 org.intellij.lang.annotations.Pattern;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ClassEscapesItsScopeInspection extends BaseInspection {
|
||||
|
||||
@Pattern(VALID_ID_PATTERN)
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
@@ -47,70 +50,55 @@ public class ClassEscapesItsScopeInspection extends BaseInspection {
|
||||
}
|
||||
|
||||
private static class ClassEscapesItsScopeVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NotNull PsiMethod method) {
|
||||
//no call to super, so we don't drill into anonymous classes
|
||||
if (method.isConstructor()) {
|
||||
return;
|
||||
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
PsiElement parent = reference.getParent();
|
||||
if (parent instanceof PsiTypeElement || parent instanceof PsiReferenceList) {
|
||||
PsiElement grandParent = PsiTreeUtil.skipParentsOfType(reference, PsiTypeElement.class, PsiReferenceList.class,
|
||||
PsiParameter.class, PsiParameterList.class,
|
||||
PsiReferenceParameterList.class, PsiJavaCodeReferenceElement.class,
|
||||
PsiTypeParameter.class, PsiTypeParameterList.class);
|
||||
if (grandParent instanceof PsiField || grandParent instanceof PsiMethod) {
|
||||
PsiMember member = (PsiMember)grandParent;
|
||||
if (!isPrivate(member)) {
|
||||
PsiElement resolved = reference.resolve();
|
||||
if (resolved instanceof PsiClass && !(resolved instanceof PsiTypeParameter)) {
|
||||
PsiClass psiClass = (PsiClass)resolved;
|
||||
if (isLessRestrictiveScope(member, psiClass)) {
|
||||
registerError(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (method.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
return;
|
||||
}
|
||||
checkForEscaping(method, method.getReturnType(), method.getReturnTypeElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitField(@NotNull PsiField field) {
|
||||
//no call to super, so we don't drill into anonymous classes
|
||||
if (field.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
return;
|
||||
private static boolean isPrivate(@NotNull PsiMember member) {
|
||||
if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
return true;
|
||||
}
|
||||
final PsiClass containingClass = field.getContainingClass();
|
||||
if (containingClass == null) {
|
||||
return;
|
||||
PsiClass containingClass = member.getContainingClass();
|
||||
if (containingClass != null && isPrivate(containingClass)) {
|
||||
return true;
|
||||
}
|
||||
if (containingClass.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
return;
|
||||
}
|
||||
checkForEscaping(field, field.getType(), field.getTypeElement());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkForEscaping(PsiMember member, PsiType type, PsiTypeElement typeElement) {
|
||||
if (type == null || typeElement == null) {
|
||||
return;
|
||||
}
|
||||
final PsiType componentType = type.getDeepComponentType();
|
||||
if (!(componentType instanceof PsiClassType)) {
|
||||
return;
|
||||
}
|
||||
final PsiClass fieldClass = ((PsiClassType)componentType).resolve();
|
||||
if (fieldClass == null || fieldClass instanceof PsiTypeParameter) {
|
||||
return;
|
||||
}
|
||||
if (!isLessRestrictiveScope(member, fieldClass)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiJavaCodeReferenceElement baseTypeElement = typeElement.getInnermostComponentReferenceElement();
|
||||
if (baseTypeElement == null) {
|
||||
return;
|
||||
}
|
||||
registerError(baseTypeElement);
|
||||
}
|
||||
|
||||
private static boolean isLessRestrictiveScope(PsiMember method, PsiClass aClass) {
|
||||
final int methodScopeOrder = getScopeOrder(method);
|
||||
private static boolean isLessRestrictiveScope(@NotNull PsiMember member, @NotNull PsiClass aClass) {
|
||||
final int methodScopeOrder = getScopeOrder(member);
|
||||
final int classScopeOrder = getScopeOrder(aClass);
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
if (containingClass != null && containingClass.getQualifiedName() == null) {
|
||||
final PsiClass containingClass = member.getContainingClass();
|
||||
if (containingClass == null ||
|
||||
containingClass.getQualifiedName() == null) {
|
||||
return false;
|
||||
}
|
||||
final int containingClassScopeOrder = getScopeOrder(containingClass);
|
||||
return methodScopeOrder > classScopeOrder && containingClassScopeOrder > classScopeOrder;
|
||||
}
|
||||
|
||||
private static int getScopeOrder(PsiModifierListOwner element) {
|
||||
private static int getScopeOrder(@NotNull PsiModifierListOwner element) {
|
||||
if (element.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
+8
@@ -5,7 +5,15 @@ public class ClassEscapesItsScope<T> {
|
||||
public <warning descr="Class 'A' is made visible outside its defined scope">A</warning> giveMeA() {
|
||||
return new A();
|
||||
}
|
||||
void printA(<warning descr="Class 'A' is made visible outside its defined scope">A</warning> a) {
|
||||
System.out.println(a);
|
||||
}
|
||||
private class A {}
|
||||
|
||||
void throwsE() throws <warning descr="Class 'E' is made visible outside its defined scope">E</warning> {
|
||||
throw new E();
|
||||
}
|
||||
private static class E extends Exception {}
|
||||
}
|
||||
|
||||
class BarInside {
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.
|
||||
*/
|
||||
import java.util.*;
|
||||
public class GenericParameterEscapesItsScope {
|
||||
public List<A> as;
|
||||
public List<<warning descr="Class 'B' is made visible outside its defined scope">B</warning>> bs;
|
||||
|
||||
public List<<warning descr="Class 'B' is made visible outside its defined scope">B</warning>> getBs() { return bs; }
|
||||
public void setBs(List<<warning descr="Class 'B' is made visible outside its defined scope">B</warning>> bs) { this.bs = bs; }
|
||||
|
||||
public List<A> getAs() { return as; }
|
||||
public void setAs(List<A> as) { this.as = as; }
|
||||
|
||||
public class Inner extends B implements Getter<B>, Setter<B> {
|
||||
public <warning descr="Class 'B' is made visible outside its defined scope">B</warning> b;
|
||||
@Override
|
||||
public <warning descr="Class 'B' is made visible outside its defined scope">B</warning> get() {
|
||||
return b;
|
||||
}
|
||||
@Override
|
||||
public void set(<warning descr="Class 'B' is made visible outside its defined scope">B</warning> b) {
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
public Data<<warning descr="Class 'B' is made visible outside its defined scope">B</warning>> foo() {
|
||||
class Local extends B implements Data<B> {
|
||||
public B b;
|
||||
@Override
|
||||
public B get() {
|
||||
return b;
|
||||
}
|
||||
@Override
|
||||
public void set(B b) {
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
return new Local();
|
||||
}
|
||||
|
||||
public static class A {}
|
||||
static class B extends A {}
|
||||
|
||||
public interface Getter<T> { T get(); }
|
||||
interface Setter<T> { void set(T t); }
|
||||
public interface Data<T> extends Getter<T>, Setter<T> { }
|
||||
}
|
||||
+2
@@ -27,6 +27,8 @@ public class ClassEscapesItsScopeInspectionTest extends LightInspectionTestCase
|
||||
|
||||
public void testClassEscapesItsScope() { doTest(); }
|
||||
|
||||
public void testGenericParameterEscapesItsScope() { doTest(); }
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
|
||||
Reference in New Issue
Block a user