diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/InnerClasses.java b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/InnerClasses.java new file mode 100644 index 000000000000..5c465b31df5b --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/InnerClasses.java @@ -0,0 +1,16 @@ +package xxx; + +public class InnerClasses { + static class PackagePrivateInnerClass { + } + + static class PackagePrivateInnerClassWithConstructor { + PackagePrivateInnerClassWithConstructor() { + } + } + + public static class ClassWithPackagePrivateConstructor { + ClassWithPackagePrivateConstructor() { + } + } +} \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PackagePrivateClass.java b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PackagePrivateClass.java new file mode 100644 index 000000000000..afd175aa6cd6 --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PackagePrivateClass.java @@ -0,0 +1,4 @@ +package xxx; + +class PackagePrivateClass { +} \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/ProtectedConstructors.java b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/ProtectedConstructors.java new file mode 100644 index 000000000000..5d30de8de61a --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/ProtectedConstructors.java @@ -0,0 +1,9 @@ +package xxx; + +public class ProtectedConstructors { + protected ProtectedConstructors() { + } + + protected ProtectedConstructors(int i) { + } +} \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/ProtectedMembers.java b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/ProtectedMembers.java new file mode 100644 index 000000000000..3bae60a51cf9 --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/ProtectedMembers.java @@ -0,0 +1,12 @@ +package xxx; + +public class ProtectedMembers { + protected void method() { + } + + static protected void staticMethod() { + } + + protected static class StaticInner { + } +} \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PublicClass.java b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PublicClass.java new file mode 100644 index 000000000000..02fdb18bc7f3 --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PublicClass.java @@ -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) {} +} \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PublicClassWithDefaultConstructor.java b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PublicClassWithDefaultConstructor.java new file mode 100644 index 000000000000..c71e3139f08c --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/PublicClassWithDefaultConstructor.java @@ -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 { +} \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/StaticMembers.java b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/StaticMembers.java new file mode 100644 index 000000000000..75b10e0e5008 --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/dep/xxx/StaticMembers.java @@ -0,0 +1,7 @@ +package xxx; + +public class StaticMembers { + static String IMPORTED_FIELD = ""; + static void importedMethod() { + } +} \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/src/AccessingPackagePrivateMembers.kt b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/src/AccessingPackagePrivateMembers.kt new file mode 100644 index 000000000000..befe8347739c --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/src/AccessingPackagePrivateMembers.kt @@ -0,0 +1,41 @@ +package xxx + +import xxx.StaticMembers.* + +/** + * @see PackagePrivateClass + * @see PublicClass.packagePrivateField + */ +@Suppress("UNUSED_VARIABLE") +class AccessingPackagePrivateMembers { + private val property = PackagePrivateClass() + + fun main() { + PackagePrivateClass() + var variable: PackagePrivateClass + + val aClass: PublicClass = PublicClass(1); + val aClass2: PublicClassWithDefaultConstructor = PublicClassWithDefaultConstructor(); + PublicClass() + PublicClass(true) + + System.out.println(aClass.publicField) + System.out.println(aClass.packagePrivateField) + System.out.println(PublicClass.PUBLIC_STATIC_FIELD) + System.out.println(PublicClass.PACKAGE_PRIVATE_STATIC_FIELD) + + aClass.publicMethod() + aClass.packagePrivateMethod() + + System.out.println(IMPORTED_FIELD) + importedMethod() + + InnerClasses.PackagePrivateInnerClass() + InnerClasses.PackagePrivateInnerClassWithConstructor() + InnerClasses.ClassWithPackagePrivateConstructor() + } + + companion object { + private val staticProperty = PackagePrivateClass() + } +} \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/src/AccessingProtectedMembers.kt b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/src/AccessingProtectedMembers.kt new file mode 100644 index 000000000000..4fc4709420a9 --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testData/codeInspection/suspiciousPackagePrivateAccess/src/AccessingProtectedMembers.kt @@ -0,0 +1,36 @@ +package xxx + +class AccessingProtectedMembersNotFromSubclass { + fun foo() { + val aClass: ProtectedMembers = ProtectedMembers() + aClass.method() + ProtectedMembers.staticMethod() + ProtectedConstructors() + ProtectedConstructors(1) + } +} + +@Suppress("UNUSED_VARIABLE") +class AccessingProtectedMembersFromSubclass : ProtectedMembers() { + fun foo() { + method() + staticMethod() + ProtectedMembers.staticMethod() + + val aClass = ProtectedMembers() + aClass.method() + 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) \ No newline at end of file diff --git a/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/tests/kotlin/KtSuspiciousPackagePrivateAccessInspectionTest.kt b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/tests/kotlin/KtSuspiciousPackagePrivateAccessInspectionTest.kt new file mode 100644 index 000000000000..837a5bb49182 --- /dev/null +++ b/jvm/jvm-analysis-kotlin-tests/testSrc/com/intellij/codeInspection/tests/kotlin/KtSuspiciousPackagePrivateAccessInspectionTest.kt @@ -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" +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspection.java index 03103ec3d6f7..e8c411826e41 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspection.java @@ -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); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/InnerClasses.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/InnerClasses.java new file mode 100644 index 000000000000..5c465b31df5b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/InnerClasses.java @@ -0,0 +1,16 @@ +package xxx; + +public class InnerClasses { + static class PackagePrivateInnerClass { + } + + static class PackagePrivateInnerClassWithConstructor { + PackagePrivateInnerClassWithConstructor() { + } + } + + public static class ClassWithPackagePrivateConstructor { + ClassWithPackagePrivateConstructor() { + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/ProtectedConstructors.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/ProtectedConstructors.java new file mode 100644 index 000000000000..5d30de8de61a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/ProtectedConstructors.java @@ -0,0 +1,9 @@ +package xxx; + +public class ProtectedConstructors { + protected ProtectedConstructors() { + } + + protected ProtectedConstructors(int i) { + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/PublicClass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/PublicClass.java index 22012cd714b6..02fdb18bc7f3 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/PublicClass.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/PublicClass.java @@ -9,4 +9,8 @@ public class PublicClass { public void publicMethod() {} void packagePrivateMethod() {} + + PublicClass() {} + public PublicClass(int i) {} + PublicClass(boolean b) {} } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/PublicClassWithDefaultConstructor.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/PublicClassWithDefaultConstructor.java new file mode 100644 index 000000000000..c71e3139f08c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/dep/xxx/PublicClassWithDefaultConstructor.java @@ -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 { +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/src/AccessingPackagePrivateMembers.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/src/AccessingPackagePrivateMembers.java index 097d61e795cf..5c609bca49dd 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/src/AccessingPackagePrivateMembers.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/src/AccessingPackagePrivateMembers.java @@ -7,19 +7,23 @@ import static xxx.StaticMembers.*; * @see PublicClass#packagePrivateField */ public class AccessingPackagePrivateMembers { - Object field = new PackagePrivateClass(); + static Object staticField = new PackagePrivateClass(); + Object field = new PackagePrivateClass(); { - new PackagePrivateClass(); + new PackagePrivateClass(); } static { - new PackagePrivateClass(); + new PackagePrivateClass(); } public void main() { - new PackagePrivateClass(); + new PackagePrivateClass(); PackagePrivateClass variable; - PublicClass aClass = new PublicClass(); + PublicClass aClass = new PublicClass(1); + PublicClassWithDefaultConstructor aClass2 = new PublicClassWithDefaultConstructor(); + new PublicClass(); + new PublicClass(true); System.out.println(aClass.publicField); System.out.println(aClass.packagePrivateField); @@ -32,5 +36,9 @@ public class AccessingPackagePrivateMembers { System.out.println(IMPORTED_FIELD); importedMethod(); + + new InnerClasses.PackagePrivateInnerClass(); + new InnerClasses.PackagePrivateInnerClassWithConstructor(); + new InnerClasses.ClassWithPackagePrivateConstructor(); } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/src/AccessingProtectedMembers.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/src/AccessingProtectedMembers.java index 09d2a28d15d4..bc20f0d11cef 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/src/AccessingProtectedMembers.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/suspicious_package_private_access/src/AccessingProtectedMembers.java @@ -5,6 +5,10 @@ class AccessingProtectedMembersNotFromSubclass { ProtectedMembers aClass = new ProtectedMembers(); aClass.method(); ProtectedMembers.staticMethod(); + new ProtectedConstructors(); + new ProtectedConstructors(1); + 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); + } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspectionTest.java index fed29d115f44..126d372e89d3 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspectionTest.java @@ -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; - } - } } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspectionTestCase.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspectionTestCase.java new file mode 100644 index 000000000000..53b9164c761c --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/dependency/SuspiciousPackagePrivateAccessInspectionTestCase.java @@ -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; + } + } +}