From df27149ec66393164f2541754bb601eda6c1c671 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Thu, 23 May 2019 11:04:03 +0700 Subject: [PATCH] IDEA-187209 JavaReflectionMemberAccess: false-positive when array is initialized after creation GitOrigin-RevId: c58c4d78086cc56f80112d1a2f5d6823ac62538c --- .../JavaReflectionInvocationInspection.java | 4 ++-- .../impl/JavaLangClassMemberReference.java | 4 ++-- .../impl/JavaReflectionReferenceUtil.java | 20 ++++++++++++------- .../ClassArray.java | 12 +++++++++++ .../JavaReflectionMemberAccessTest.kt | 4 ++-- 5 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 java/java-tests/testData/inspection/javaReflectionMemberAccess/ClassArray.java diff --git a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionInvocationInspection.java b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionInvocationInspection.java index 1611fe830fb0..e714eb4ff14b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionInvocationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/reflectiveAccess/JavaReflectionInvocationInspection.java @@ -126,9 +126,9 @@ public class JavaReflectionInvocationInspection extends AbstractBaseJavaLocalIns @Nullable static Arguments getActualMethodArguments(PsiExpression[] arguments, int argumentOffset, boolean allowVarargAsArray) { if (allowVarargAsArray && arguments.length == argumentOffset + 1) { - final PsiExpression[] expressions = getVarargAsArray(arguments[argumentOffset]); + final List expressions = getVarargs(arguments[argumentOffset]); if (expressions != null) { - return new Arguments(expressions, true); + return new Arguments(expressions.toArray(PsiExpression.EMPTY_ARRAY), true); } } if (arguments.length >= argumentOffset) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java index 26d329ef58c6..b1fc2bd6df4a 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaLangClassMemberReference.java @@ -229,9 +229,9 @@ public class JavaLangClassMemberReference extends PsiReferenceBase arrayElements = getVarargs(arguments[argumentOffset]); if (arrayElements != null) { - return Arrays.asList(arrayElements); + return arrayElements; } } if (arguments.length >= argumentOffset) { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java index ebe8dfc432ca..cdebcfc95e18 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/JavaReflectionReferenceUtil.java @@ -468,26 +468,32 @@ public class JavaReflectionReferenceUtil { return MethodCallUtils.isCallToMethod(methodCall, className, null, methodName, (PsiType[])null); } + /** + * Tries to unwrap array and find its components + * @param maybeArray an array to unwrap + * @return list of unwrapped array components, some or all of them could be null if unknown (but the length is known); + * returns null if nothing is known. + */ @Nullable - public static PsiExpression[] getVarargAsArray(@Nullable PsiExpression maybeArray) { + public static List getVarargs(@Nullable PsiExpression maybeArray) { if (ExpressionUtils.isNullLiteral(maybeArray)) { - return PsiExpression.EMPTY_ARRAY; + return Collections.emptyList(); } if (isVarargAsArray(maybeArray)) { final PsiExpression argumentsDefinition = findDefinition(maybeArray); if (argumentsDefinition instanceof PsiArrayInitializerExpression) { - return ((PsiArrayInitializerExpression)argumentsDefinition).getInitializers(); + return Arrays.asList(((PsiArrayInitializerExpression)argumentsDefinition).getInitializers()); } if (argumentsDefinition instanceof PsiNewExpression) { final PsiArrayInitializerExpression arrayInitializer = ((PsiNewExpression)argumentsDefinition).getArrayInitializer(); if (arrayInitializer != null) { - return arrayInitializer.getInitializers(); + return Arrays.asList(arrayInitializer.getInitializers()); } final PsiExpression[] dimensions = ((PsiNewExpression)argumentsDefinition).getArrayDimensions(); - if (dimensions.length == 1) { // special case: new Object[0] + if (dimensions.length == 1) { // new Object[length] or new Class[length] final Integer itemCount = computeConstantExpression(findDefinition(dimensions[0]), Integer.class); - if (itemCount != null && itemCount == 0) { - return PsiExpression.EMPTY_ARRAY; + if (itemCount != null && itemCount >= 0 && itemCount < 256) { + return Collections.nCopies(itemCount, null); } } } diff --git a/java/java-tests/testData/inspection/javaReflectionMemberAccess/ClassArray.java b/java/java-tests/testData/inspection/javaReflectionMemberAccess/ClassArray.java new file mode 100644 index 000000000000..00d87f0f144d --- /dev/null +++ b/java/java-tests/testData/inspection/javaReflectionMemberAccess/ClassArray.java @@ -0,0 +1,12 @@ +class X { + void test() throws NoSuchMethodException { + Class[] params = new Class[3]; + params[0] = byte[].class; + params[1] = int.class; + params[2] = int.class; + String.class.getDeclaredMethod("checkBounds", params); + Class[] params2 = {byte[].class, int.class, int.class}; + String.class.getDeclaredMethod("checkBounds", params2); + String.class.getDeclaredMethod("checkBounds", byte[].class, int.class, int.class); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/JavaReflectionMemberAccessTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInspection/JavaReflectionMemberAccessTest.kt index 2e8ed733da23..27fa9054de7f 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/JavaReflectionMemberAccessTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/JavaReflectionMemberAccessTest.kt @@ -32,8 +32,7 @@ class JavaReflectionMemberAccessTest : LightCodeInsightFixtureTestCase() { myFixture.enableInspections(inspection) } - override fun getProjectDescriptor(): LightProjectDescriptor = - LightCodeInsightFixtureTestCase.JAVA_8 // older mock JREs are missing some bits + override fun getProjectDescriptor(): LightProjectDescriptor = JAVA_8 // older mock JREs are missing some bits override fun getBasePath() = JavaTestUtil.getRelativeJavaTestDataPath() + "/inspection/javaReflectionMemberAccess" @@ -47,6 +46,7 @@ class JavaReflectionMemberAccessTest : LightCodeInsightFixtureTestCase() { fun testNewInstance() = doTest(true) fun testBugs() = doTest(true) + fun testClassArray() = doTest(true) private fun doTest(checkExists: Boolean = false) {