mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
inspection: fix bugs in "Suspicious package-private access" inspection (IDEA-200047)
Properly report references to protected constructors accessed not via subclass, and fix duplicating warning in Kotlin files. Also add tests for Kotlin.
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
||||
package xxx;
|
||||
|
||||
public class InnerClasses {
|
||||
static class PackagePrivateInnerClass {
|
||||
}
|
||||
|
||||
static class PackagePrivateInnerClassWithConstructor {
|
||||
PackagePrivateInnerClassWithConstructor() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClassWithPackagePrivateConstructor {
|
||||
ClassWithPackagePrivateConstructor() {
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package xxx;
|
||||
|
||||
class PackagePrivateClass {
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package xxx;
|
||||
|
||||
public class ProtectedConstructors {
|
||||
protected ProtectedConstructors() {
|
||||
}
|
||||
|
||||
protected ProtectedConstructors(int i) {
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package xxx;
|
||||
|
||||
public class ProtectedMembers {
|
||||
protected void method() {
|
||||
}
|
||||
|
||||
static protected void staticMethod() {
|
||||
}
|
||||
|
||||
protected static class StaticInner {
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright 2000-2018 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 xxx;
|
||||
|
||||
public class PublicClass {
|
||||
public String publicField;
|
||||
String packagePrivateField;
|
||||
static public String PUBLIC_STATIC_FIELD;
|
||||
static String PACKAGE_PRIVATE_STATIC_FIELD;
|
||||
|
||||
public void publicMethod() {}
|
||||
void packagePrivateMethod() {}
|
||||
|
||||
PublicClass() {}
|
||||
public PublicClass(int i) {}
|
||||
PublicClass(boolean b) {}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// Copyright 2000-2018 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 xxx;
|
||||
|
||||
public class PublicClassWithDefaultConstructor {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package xxx;
|
||||
|
||||
public class StaticMembers {
|
||||
static String IMPORTED_FIELD = "";
|
||||
static void importedMethod() {
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package xxx
|
||||
|
||||
import xxx.StaticMembers.*
|
||||
|
||||
/**
|
||||
* @see PackagePrivateClass
|
||||
* @see PublicClass.packagePrivateField
|
||||
*/
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class AccessingPackagePrivateMembers {
|
||||
private val property = <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass()</warning>
|
||||
|
||||
fun main() {
|
||||
<warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass()</warning>
|
||||
var variable: <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass</warning>
|
||||
|
||||
val aClass: PublicClass = PublicClass(1);
|
||||
val aClass2: PublicClassWithDefaultConstructor = PublicClassWithDefaultConstructor();
|
||||
<warning descr="Constructor PublicClass.PublicClass() is package-private, but declared in a different module 'dep'">PublicClass()</warning>
|
||||
<warning descr="Constructor PublicClass.PublicClass(boolean) is package-private, but declared in a different module 'dep'">PublicClass(true)</warning>
|
||||
|
||||
System.out.println(aClass.publicField)
|
||||
System.out.println(aClass.<warning descr="Field PublicClass.packagePrivateField is package-private, but declared in a different module 'dep'">packagePrivateField</warning>)
|
||||
System.out.println(PublicClass.PUBLIC_STATIC_FIELD)
|
||||
System.out.println(PublicClass.<warning descr="Field PublicClass.PACKAGE_PRIVATE_STATIC_FIELD is package-private, but declared in a different module 'dep'">PACKAGE_PRIVATE_STATIC_FIELD</warning>)
|
||||
|
||||
aClass.publicMethod()
|
||||
aClass.<warning descr="Method PublicClass.packagePrivateMethod() is package-private, but declared in a different module 'dep'">packagePrivateMethod()</warning>
|
||||
|
||||
System.out.println(<warning descr="Field StaticMembers.IMPORTED_FIELD is package-private, but declared in a different module 'dep'">IMPORTED_FIELD</warning>)
|
||||
<warning descr="Method StaticMembers.importedMethod() is package-private, but declared in a different module 'dep'">importedMethod</warning>()
|
||||
|
||||
InnerClasses.<warning descr="Class xxx.InnerClasses.PackagePrivateInnerClass is package-private, but declared in a different module 'dep'">PackagePrivateInnerClass()</warning>
|
||||
InnerClasses.<warning descr="Constructor PackagePrivateInnerClassWithConstructor.PackagePrivateInnerClassWithConstructor() is package-private, but declared in a different module 'dep'">PackagePrivateInnerClassWithConstructor()</warning>
|
||||
InnerClasses.<warning descr="Constructor ClassWithPackagePrivateConstructor.ClassWithPackagePrivateConstructor() is package-private, but declared in a different module 'dep'">ClassWithPackagePrivateConstructor()</warning>
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val staticProperty = <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass()</warning>
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package xxx
|
||||
|
||||
class AccessingProtectedMembersNotFromSubclass {
|
||||
fun foo() {
|
||||
val aClass: ProtectedMembers = ProtectedMembers()
|
||||
aClass.<warning descr="Method ProtectedMembers.method() is protected and used not through a subclass here, but declared in a different module 'dep'">method()</warning>
|
||||
ProtectedMembers.<warning descr="Method ProtectedMembers.staticMethod() is protected and used not through a subclass here, but declared in a different module 'dep'">staticMethod()</warning>
|
||||
<warning descr="Constructor ProtectedConstructors.ProtectedConstructors() is protected and used not through a subclass here, but declared in a different module 'dep'">ProtectedConstructors()</warning>
|
||||
<warning descr="Constructor ProtectedConstructors.ProtectedConstructors(int) is protected and used not through a subclass here, but declared in a different module 'dep'">ProtectedConstructors(1)</warning>
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class AccessingProtectedMembersFromSubclass : ProtectedMembers() {
|
||||
fun foo() {
|
||||
method()
|
||||
staticMethod()
|
||||
ProtectedMembers.staticMethod()
|
||||
|
||||
val aClass = ProtectedMembers()
|
||||
aClass.<warning descr="Method ProtectedMembers.method() is protected and used not through a subclass here, but declared in a different module 'dep'">method()</warning>
|
||||
val myInstance = AccessingProtectedMembersFromSubclass()
|
||||
myInstance.method()
|
||||
|
||||
var inner1: ProtectedMembers.StaticInner
|
||||
var inner2: StaticInner
|
||||
}
|
||||
|
||||
private class StaticInnerImpl1 : ProtectedMembers.StaticInner()
|
||||
|
||||
private class StaticInnerImpl2 : StaticInner()
|
||||
}
|
||||
|
||||
class AccessingDefaultProtectedConstructorFromSubclass : ProtectedConstructors()
|
||||
|
||||
class AccessingProtectedConstructorFromSubclass : ProtectedConstructors(1)
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package com.intellij.codeInspection.tests.kotlin
|
||||
|
||||
import com.intellij.jvm.analysis.JvmAnalysisKtTestsUtil
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import com.siyeh.ig.dependency.SuspiciousPackagePrivateAccessInspectionTestCase
|
||||
|
||||
@TestDataPath("/testData/codeInspection/suspiciousPackagePrivateAccess")
|
||||
class KtSuspiciousPackagePrivateAccessInspectionTest : SuspiciousPackagePrivateAccessInspectionTestCase("kt") {
|
||||
fun testAccessingPackagePrivateMembers() {
|
||||
doTestWithDependency()
|
||||
}
|
||||
|
||||
fun testAccessingProtectedMembers() {
|
||||
doTestWithDependency()
|
||||
}
|
||||
|
||||
override fun getBasePath() = "${JvmAnalysisKtTestsUtil.TEST_DATA_PROJECT_RELATIVE_BASE_PATH}/codeInspection/suspiciousPackagePrivateAccess"
|
||||
}
|
||||
+83
-17
@@ -15,6 +15,7 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUIUtil;
|
||||
import com.intellij.uast.UastVisitorAdapter;
|
||||
import com.intellij.ui.ContextHelpLabel;
|
||||
@@ -65,20 +66,49 @@ public class SuspiciousPackagePrivateAccessInspection extends AbstractBaseUastLo
|
||||
}
|
||||
PsiElement resolved = node.resolve();
|
||||
if (resolved instanceof PsiMember) {
|
||||
checkAccess(node.getSelector(), (PsiMember)resolved, receiver);
|
||||
checkAccess(node.getSelector(), (PsiMember)resolved, getAccessObjectType(receiver));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitSimpleNameReferenceExpression(@NotNull USimpleNameReferenceExpression node) {
|
||||
PsiElement resolved = node.resolve();
|
||||
if (resolved instanceof PsiMember) {
|
||||
checkAccess(node, (PsiMember)resolved, null);
|
||||
UElement uastParent = node.getUastParent();
|
||||
//we should skip 'checkAccess' here if node is part of UQualifiedReferenceExpression or UCallExpression node,
|
||||
// otherwise the same problem will be reported twice
|
||||
if (!isSelectorOfQualifiedReference(node)
|
||||
&& !(uastParent instanceof UCallExpression && isMethodReferenceOfCallExpression(node, (UCallExpression)uastParent)
|
||||
&& (((UCallExpression)uastParent).getKind() == UastCallKind.CONSTRUCTOR_CALL || isSelectorOfQualifiedReference((UExpression)uastParent)))) {
|
||||
PsiElement resolved = node.resolve();
|
||||
if (resolved instanceof PsiMember) {
|
||||
checkAccess(node, (PsiMember)resolved, null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isSelectorOfQualifiedReference(@Nullable UExpression expression) {
|
||||
if (expression == null) return false;
|
||||
UElement parent = expression.getUastParent();
|
||||
return parent instanceof UQualifiedReferenceExpression
|
||||
&& referToSameSourceElement(expression, ((UQualifiedReferenceExpression)parent).getSelector());
|
||||
}
|
||||
|
||||
private boolean isMethodReferenceOfCallExpression(@NotNull USimpleNameReferenceExpression expression, @NotNull UCallExpression parent) {
|
||||
UElement methodIdentifier = parent.getMethodIdentifier();
|
||||
UReferenceExpression classReference = parent.getClassReference();
|
||||
if (methodIdentifier == null && classReference != null) {
|
||||
methodIdentifier = classReference.getReferenceNameElement();
|
||||
}
|
||||
return referToSameSourceElement(expression.getReferenceNameElement(), methodIdentifier);
|
||||
}
|
||||
|
||||
private boolean referToSameSourceElement(@Nullable UElement element1, @Nullable UElement element2) {
|
||||
if (element1 == null || element2 == null) return false;
|
||||
PsiElement sourcePsi1 = element1.getSourcePsi();
|
||||
return sourcePsi1 != null && sourcePsi1.equals(element2.getSourcePsi());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitCallableReferenceExpression(@NotNull UCallableReferenceExpression node) {
|
||||
PsiElement resolve = node.resolve();
|
||||
@@ -86,18 +116,50 @@ public class SuspiciousPackagePrivateAccessInspection extends AbstractBaseUastLo
|
||||
PsiMember member = (PsiMember)resolve;
|
||||
UElement sourceNode = getReferenceNameElement(node);
|
||||
if (sourceNode != null) {
|
||||
checkAccess(sourceNode, member, node.getQualifierExpression());
|
||||
checkAccess(sourceNode, member, getAccessObjectType(node.getQualifierExpression()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkAccess(@NotNull UElement sourceNode, @NotNull PsiMember target, @Nullable UExpression receiver) {
|
||||
@Override
|
||||
public boolean visitTypeReferenceExpression(@NotNull UTypeReferenceExpression node) {
|
||||
//in Kotlin implementation of UAST USimpleNameReferenceExpression::resolve returns null for reference to type in local variable declaration,
|
||||
// so we need to have this case specifically
|
||||
if (!(node.getSourcePsi() instanceof PsiTypeElement)) {
|
||||
PsiClass resolved = PsiTypesUtil.getPsiClass(node.getType());
|
||||
if (resolved != null) {
|
||||
checkAccess(node, resolved, null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visitCallExpression(@NotNull UCallExpression node) {
|
||||
//regular method calls are handled by visitSimpleNameReferenceExpression or visitQualifiedReferenceExpression, but we need to handle
|
||||
// constructor calls in a special way because they may refer to classes
|
||||
if (!isSelectorOfQualifiedReference(node) && node.getKind() == UastCallKind.CONSTRUCTOR_CALL) {
|
||||
PsiMethod resolved = node.resolve();
|
||||
if (resolved != null) {
|
||||
checkAccess(node, resolved, null);
|
||||
}
|
||||
else {
|
||||
UReferenceExpression classReference = node.getClassReference();
|
||||
PsiElement resolvedClass = classReference != null ? classReference.resolve() : null;
|
||||
if (resolvedClass instanceof PsiClass) {
|
||||
checkAccess(node, (PsiClass)resolvedClass, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void checkAccess(@NotNull UElement sourceNode, @NotNull PsiMember target, @Nullable PsiClass accessObjectType) {
|
||||
if (target.hasModifier(JvmModifier.PACKAGE_LOCAL)) {
|
||||
checkPackageLocalAccess(sourceNode, target, "package-private");
|
||||
}
|
||||
else if (target.hasModifier(JvmModifier.PROTECTED) && receiver != null
|
||||
&& !(receiver instanceof UThisExpression) && !(receiver instanceof USuperExpression) && !canAccessProtectedMember(receiver, sourceNode, target)) {
|
||||
else if (target.hasModifier(JvmModifier.PROTECTED) && !canAccessProtectedMember(sourceNode, target, accessObjectType)) {
|
||||
checkPackageLocalAccess(sourceNode, target, "protected and used not through a subclass here");
|
||||
}
|
||||
}
|
||||
@@ -132,22 +194,26 @@ public class SuspiciousPackagePrivateAccessInspection extends AbstractBaseUastLo
|
||||
return node;
|
||||
}
|
||||
|
||||
private static boolean canAccessProtectedMember(UExpression receiver, UElement sourceNode, PsiMember member) {
|
||||
PsiClass memberClass = member.getContainingClass();
|
||||
if (memberClass == null) return false;
|
||||
@Nullable
|
||||
private static PsiClass getAccessObjectType(@Nullable UExpression receiver) {
|
||||
if (receiver == null || receiver instanceof UThisExpression || receiver instanceof USuperExpression) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiClass accessObjectType;
|
||||
PsiType type = receiver.getExpressionType();
|
||||
if (type != null) {
|
||||
if (!(type instanceof PsiClassType)) return false;
|
||||
accessObjectType = ((PsiClassType)type).resolve();
|
||||
if (accessObjectType == null) return false;
|
||||
if (!(type instanceof PsiClassType)) return null;
|
||||
return ((PsiClassType)type).resolve();
|
||||
}
|
||||
else {
|
||||
PsiElement element = ((UReferenceExpression)receiver).resolve();
|
||||
if (!(element instanceof PsiClass)) return false;
|
||||
accessObjectType = (PsiClass)element;
|
||||
return element instanceof PsiClass ? (PsiClass)element : null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canAccessProtectedMember(UElement sourceNode, PsiMember member, PsiClass accessObjectType) {
|
||||
PsiClass memberClass = member.getContainingClass();
|
||||
if (memberClass == null) return false;
|
||||
|
||||
PsiElement sourcePsi = sourceNode.getSourcePsi();
|
||||
UClass sourceClass = UastUtils.findContaining(sourcePsi, UClass.class);
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package xxx;
|
||||
|
||||
public class InnerClasses {
|
||||
static class PackagePrivateInnerClass {
|
||||
}
|
||||
|
||||
static class PackagePrivateInnerClassWithConstructor {
|
||||
PackagePrivateInnerClassWithConstructor() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class ClassWithPackagePrivateConstructor {
|
||||
ClassWithPackagePrivateConstructor() {
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package xxx;
|
||||
|
||||
public class ProtectedConstructors {
|
||||
protected ProtectedConstructors() {
|
||||
}
|
||||
|
||||
protected ProtectedConstructors(int i) {
|
||||
}
|
||||
}
|
||||
+4
@@ -9,4 +9,8 @@ public class PublicClass {
|
||||
|
||||
public void publicMethod() {}
|
||||
void packagePrivateMethod() {}
|
||||
|
||||
PublicClass() {}
|
||||
public PublicClass(int i) {}
|
||||
PublicClass(boolean b) {}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// Copyright 2000-2018 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 xxx;
|
||||
|
||||
public class PublicClassWithDefaultConstructor {
|
||||
}
|
||||
+13
-5
@@ -7,19 +7,23 @@ import static xxx.StaticMembers.*;
|
||||
* @see PublicClass#packagePrivateField
|
||||
*/
|
||||
public class AccessingPackagePrivateMembers {
|
||||
Object field = new <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass</warning>();
|
||||
static Object staticField = <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">new PackagePrivateClass()</warning>;
|
||||
Object field = <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">new PackagePrivateClass()</warning>;
|
||||
{
|
||||
new <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass</warning>();
|
||||
<warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">new PackagePrivateClass()</warning>;
|
||||
}
|
||||
static {
|
||||
new <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass</warning>();
|
||||
<warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">new PackagePrivateClass()</warning>;
|
||||
}
|
||||
|
||||
public void main() {
|
||||
new <warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass</warning>();
|
||||
<warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">new PackagePrivateClass()</warning>;
|
||||
<warning descr="Class xxx.PackagePrivateClass is package-private, but declared in a different module 'dep'">PackagePrivateClass</warning> variable;
|
||||
|
||||
PublicClass aClass = new PublicClass();
|
||||
PublicClass aClass = new PublicClass(1);
|
||||
PublicClassWithDefaultConstructor aClass2 = new PublicClassWithDefaultConstructor();
|
||||
<warning descr="Constructor PublicClass.PublicClass() is package-private, but declared in a different module 'dep'">new PublicClass()</warning>;
|
||||
<warning descr="Constructor PublicClass.PublicClass(boolean) is package-private, but declared in a different module 'dep'">new PublicClass(true)</warning>;
|
||||
|
||||
System.out.println(aClass.publicField);
|
||||
System.out.println(aClass.<warning descr="Field PublicClass.packagePrivateField is package-private, but declared in a different module 'dep'">packagePrivateField</warning>);
|
||||
@@ -32,5 +36,9 @@ public class AccessingPackagePrivateMembers {
|
||||
|
||||
System.out.println(<warning descr="Field StaticMembers.IMPORTED_FIELD is package-private, but declared in a different module 'dep'">IMPORTED_FIELD</warning>);
|
||||
<warning descr="Method StaticMembers.importedMethod() is package-private, but declared in a different module 'dep'">importedMethod</warning>();
|
||||
|
||||
<warning descr="Class xxx.InnerClasses.PackagePrivateInnerClass is package-private, but declared in a different module 'dep'">new InnerClasses.<warning descr="Class xxx.InnerClasses.PackagePrivateInnerClass is package-private, but declared in a different module 'dep'">PackagePrivateInnerClass</warning>()</warning>;
|
||||
<warning descr="Constructor PackagePrivateInnerClassWithConstructor.PackagePrivateInnerClassWithConstructor() is package-private, but declared in a different module 'dep'">new InnerClasses.<warning descr="Class xxx.InnerClasses.PackagePrivateInnerClassWithConstructor is package-private, but declared in a different module 'dep'">PackagePrivateInnerClassWithConstructor</warning>()</warning>;
|
||||
<warning descr="Constructor ClassWithPackagePrivateConstructor.ClassWithPackagePrivateConstructor() is package-private, but declared in a different module 'dep'">new InnerClasses.ClassWithPackagePrivateConstructor()</warning>;
|
||||
}
|
||||
}
|
||||
+33
@@ -5,6 +5,10 @@ class AccessingProtectedMembersNotFromSubclass {
|
||||
ProtectedMembers aClass = new ProtectedMembers();
|
||||
aClass.<warning descr="Method ProtectedMembers.method() is protected and used not through a subclass here, but declared in a different module 'dep'">method</warning>();
|
||||
ProtectedMembers.<warning descr="Method ProtectedMembers.staticMethod() is protected and used not through a subclass here, but declared in a different module 'dep'">staticMethod</warning>();
|
||||
<warning descr="Constructor ProtectedConstructors.ProtectedConstructors() is protected and used not through a subclass here, but declared in a different module 'dep'">new ProtectedConstructors()</warning>;
|
||||
<warning descr="Constructor ProtectedConstructors.ProtectedConstructors(int) is protected and used not through a subclass here, but declared in a different module 'dep'">new ProtectedConstructors(1)</warning>;
|
||||
new ProtectedConstructors() {};
|
||||
new ProtectedConstructors(1) {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +25,13 @@ class AccessingProtectedMembersFromSubclass extends ProtectedMembers {
|
||||
|
||||
ProtectedMembers.StaticInner inner1;
|
||||
StaticInner inner2;
|
||||
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
method();
|
||||
staticMethod();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class StaticInnerImpl1 extends ProtectedMembers.StaticInner {
|
||||
@@ -28,4 +39,26 @@ class AccessingProtectedMembersFromSubclass extends ProtectedMembers {
|
||||
|
||||
public static class StaticInnerImpl2 extends StaticInner {
|
||||
}
|
||||
|
||||
public class OwnInner {
|
||||
void bar() {
|
||||
method();
|
||||
staticMethod();
|
||||
}
|
||||
}
|
||||
|
||||
public static class OwnStaticInner {
|
||||
void bar() {
|
||||
staticMethod();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AccessingDefaultProtectedConstructorFromSubclass extends ProtectedConstructors {
|
||||
}
|
||||
|
||||
class AccessingProtectedConstructorFromSubclass extends ProtectedConstructors {
|
||||
AccessingProtectedConstructorFromSubclass() {
|
||||
super(1);
|
||||
}
|
||||
}
|
||||
+2
-94
@@ -1,27 +1,8 @@
|
||||
// Copyright 2000-2018 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.dependency;
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtension;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.siyeh.ig.LightInspectionTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootType;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SuspiciousPackagePrivateAccessInspectionTest extends LightInspectionTestCase {
|
||||
private final ProjectWithDepModuleDescriptor myProjectDescriptor = new ProjectWithDepModuleDescriptor(LanguageLevel.HIGHEST);
|
||||
public class SuspiciousPackagePrivateAccessInspectionTest extends SuspiciousPackagePrivateAccessInspectionTestCase {
|
||||
public SuspiciousPackagePrivateAccessInspectionTest() {super("java");}
|
||||
|
||||
public void testAccessingPackagePrivateMembers() {
|
||||
doTestWithDependency();
|
||||
@@ -30,77 +11,4 @@ public class SuspiciousPackagePrivateAccessInspectionTest extends LightInspectio
|
||||
public void testAccessingProtectedMembers() {
|
||||
doTestWithDependency();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.copyDirectoryToProject("dep", ProjectWithDepModuleDescriptor.getDepModuleSourceRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
try {
|
||||
myProjectDescriptor.cleanUpSources();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
addSuppressedException(e);
|
||||
}
|
||||
finally {
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
private void doTestWithDependency() {
|
||||
myFixture.configureByFile("src/" + getTestName(false) + ".java");
|
||||
myFixture.testHighlighting(true, false, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return myProjectDescriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
return new SuspiciousPackagePrivateAccessInspection();
|
||||
}
|
||||
|
||||
private static class ProjectWithDepModuleDescriptor extends ProjectDescriptor {
|
||||
private static final String DEP_MODULE_SOURCE_ROOT = "dep-module-src";
|
||||
private VirtualFile mySourceRoot;
|
||||
|
||||
ProjectWithDepModuleDescriptor(@NotNull LanguageLevel languageLevel) {
|
||||
super(languageLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpProject(@NotNull Project project, @NotNull SetupHandler handler) throws Exception {
|
||||
super.setUpProject(project, handler);
|
||||
WriteAction.run(() -> {
|
||||
Module mainModule = ModuleManager.getInstance(project).findModuleByName(TEST_MODULE_NAME);
|
||||
File depModuleDir = FileUtil.createTempDirectory("dep-module-", null);
|
||||
Module depModule = createModule(project, depModuleDir + "/dep.iml");
|
||||
ModuleRootModificationUtil.updateModel(depModule, model -> {
|
||||
model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(myLanguageLevel);
|
||||
model.setSdk(getSdk());
|
||||
mySourceRoot = createSourceRoot(depModule, DEP_MODULE_SOURCE_ROOT);
|
||||
model.addContentEntry(mySourceRoot).addSourceFolder(mySourceRoot, JavaSourceRootType.SOURCE);
|
||||
});
|
||||
ModuleRootModificationUtil.addDependency(mainModule, depModule);
|
||||
});
|
||||
}
|
||||
|
||||
public void cleanUpSources() throws IOException {
|
||||
if (mySourceRoot != null) {
|
||||
WriteAction.run(() -> mySourceRoot.delete(this));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getDepModuleSourceRoot() {
|
||||
return "../" + DEP_MODULE_SOURCE_ROOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
// Copyright 2000-2019 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.dependency;
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtension;
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.siyeh.ig.LightInspectionTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootType;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SuspiciousPackagePrivateAccessInspectionTestCase extends LightInspectionTestCase {
|
||||
private final ProjectWithDepModuleDescriptor myProjectDescriptor = new ProjectWithDepModuleDescriptor(LanguageLevel.HIGHEST);
|
||||
private final String myExtension;
|
||||
|
||||
public SuspiciousPackagePrivateAccessInspectionTestCase(String extension) {
|
||||
myExtension = extension;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myFixture.copyDirectoryToProject("dep", ProjectWithDepModuleDescriptor.getDepModuleSourceRoot());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
try {
|
||||
myProjectDescriptor.cleanUpSources();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
addSuppressedException(e);
|
||||
}
|
||||
finally {
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
protected void doTestWithDependency() {
|
||||
myFixture.configureByFile("src/" + getTestName(false) + "." + myExtension);
|
||||
myFixture.testHighlighting(true, false, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return myProjectDescriptor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
return new SuspiciousPackagePrivateAccessInspection();
|
||||
}
|
||||
|
||||
private static class ProjectWithDepModuleDescriptor extends ProjectDescriptor {
|
||||
private static final String DEP_MODULE_SOURCE_ROOT = "dep-module-src";
|
||||
private VirtualFile mySourceRoot;
|
||||
|
||||
ProjectWithDepModuleDescriptor(@NotNull LanguageLevel languageLevel) {
|
||||
super(languageLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUpProject(@NotNull Project project, @NotNull SetupHandler handler) throws Exception {
|
||||
super.setUpProject(project, handler);
|
||||
WriteAction.run(() -> {
|
||||
Module mainModule = ModuleManager.getInstance(project).findModuleByName(TEST_MODULE_NAME);
|
||||
File depModuleDir = FileUtil.createTempDirectory("dep-module-", null);
|
||||
Module depModule = createModule(project, depModuleDir + "/dep.iml");
|
||||
ModuleRootModificationUtil.updateModel(depModule, model -> {
|
||||
model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(myLanguageLevel);
|
||||
model.setSdk(getSdk());
|
||||
mySourceRoot = createSourceRoot(depModule, DEP_MODULE_SOURCE_ROOT);
|
||||
model.addContentEntry(mySourceRoot).addSourceFolder(mySourceRoot, JavaSourceRootType.SOURCE);
|
||||
});
|
||||
ModuleRootModificationUtil.addDependency(mainModule, depModule);
|
||||
});
|
||||
}
|
||||
|
||||
public void cleanUpSources() throws IOException {
|
||||
if (mySourceRoot != null) {
|
||||
WriteAction.run(() -> mySourceRoot.delete(this));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getDepModuleSourceRoot() {
|
||||
return "../" + DEP_MODULE_SOURCE_ROOT;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user