diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicCompletionContributor.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicCompletionContributor.java index 7ff8528279b2..af501c1e95e8 100644 --- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicCompletionContributor.java @@ -58,7 +58,7 @@ public final class MagicCompletionContributor extends CompletionContributor impl public static MagicConstantUtils.AllowedValues getAllowedValues(@NotNull PsiElement pos) { MagicConstantUtils.AllowedValues allowedValues = null; for (Pair pair : getMembersWithAllowedValues(pos)) { - MagicConstantUtils.AllowedValues values = MagicConstantUtils.getAllowedValues(pair.first, pair.second); + MagicConstantUtils.AllowedValues values = MagicConstantUtils.getAllowedValues(pair.first, pair.second, pos); if (values == null) continue; if (allowedValues == null) { allowedValues = values; @@ -89,15 +89,10 @@ public final class MagicCompletionContributor extends CompletionContributor impl Set> result = new HashSet<>(); if (IN_METHOD_CALL_ARGUMENT.accepts(pos)) { PsiCall call = PsiTreeUtil.getParentOfType(pos, PsiCall.class); - if (!(call instanceof PsiExpression)) return Collections.emptyList(); - PsiType type = ((PsiExpression)call).getType(); + if (call == null) return Collections.emptyList(); PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(call.getProject()).getResolveHelper(); - JavaResolveResult[] methods = call instanceof PsiMethodCallExpression - ? ((PsiMethodCallExpression)call).getMethodExpression().multiResolve(true) - : call instanceof PsiNewExpression && type instanceof PsiClassType - ? resolveHelper.multiResolveConstructor((PsiClassType)type, call.getArgumentList(), call) - : JavaResolveResult.EMPTY_ARRAY; + JavaResolveResult[] methods = getMethodCandidates(call, resolveHelper); for (JavaResolveResult resolveResult : methods) { PsiElement element = resolveResult.getElement(); if (!(element instanceof PsiMethod)) return Collections.emptyList(); @@ -180,6 +175,26 @@ public final class MagicCompletionContributor extends CompletionContributor impl return new ArrayList<>(result); } + private static @NotNull JavaResolveResult @NotNull [] getMethodCandidates(PsiCall call, PsiResolveHelper resolveHelper) { + if (call instanceof PsiMethodCallExpression) { + return ((PsiMethodCallExpression)call).getMethodExpression().multiResolve(true); + } + if (call instanceof PsiNewExpression) { + PsiType type = ((PsiExpression)call).getType(); + PsiExpressionList argumentList = call.getArgumentList(); + if (type instanceof PsiClassType && argumentList != null) { + return resolveHelper.multiResolveConstructor((PsiClassType)type, argumentList, call); + } + } + if (call instanceof PsiEnumConstant) { + JavaResolveResult result = call.resolveMethodGenerics(); + if (result != JavaResolveResult.EMPTY) { + return new JavaResolveResult[]{result}; + } + } + return JavaResolveResult.EMPTY_ARRAY; + } + private static void addCompletionVariants(@NotNull final CompletionParameters parameters, @NotNull final CompletionResultSet result, PsiElement pos, diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java index e5a937883437..4a330c9ac742 100644 --- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantInspection.java @@ -80,6 +80,11 @@ public final class MagicConstantInspection extends AbstractBaseJavaLocalInspecti } } + @Override + public void visitEnumConstant(PsiEnumConstant enumConstant) { + checkCall(enumConstant, holder); + } + @Override public void visitCallExpression(PsiCallExpression callExpression) { checkCall(callExpression, holder); @@ -203,7 +208,7 @@ public final class MagicConstantInspection extends AbstractBaseJavaLocalInspecti @NotNull PsiModifierListOwner owner, @Nullable PsiType type, @NotNull ProblemsHolder holder) { - AllowedValues allowed = MagicConstantUtils.getAllowedValues(owner, type); + AllowedValues allowed = MagicConstantUtils.getAllowedValues(owner, type, expression); checkExpression(expression, holder, allowed); } @@ -218,7 +223,7 @@ public final class MagicConstantInspection extends AbstractBaseJavaLocalInspecti } } - private static void checkCall(@NotNull PsiCallExpression methodCall, @NotNull ProblemsHolder holder) { + private static void checkCall(@NotNull PsiCall methodCall, @NotNull ProblemsHolder holder) { PsiExpressionList argumentList = methodCall.getArgumentList(); if (argumentList == null) return; PsiMethod method = methodCall.resolveMethod(); @@ -233,7 +238,7 @@ public final class MagicConstantInspection extends AbstractBaseJavaLocalInspecti type = ((PsiEllipsisType)type).getComponentType(); stopArg = arguments.length - 1; } - AllowedValues values = MagicConstantUtils.getAllowedValues(parameter, type); + AllowedValues values = MagicConstantUtils.getAllowedValues(parameter, type, methodCall); if (values == null) continue; if (i >= arguments.length) break; for (int j = i; j <= stopArg; j++) { @@ -432,7 +437,7 @@ public final class MagicConstantInspection extends AbstractBaseJavaLocalInspecti } if (allowedForRef == null && resolved instanceof PsiModifierListOwner) { - allowedForRef = MagicConstantUtils.getAllowedValues((PsiModifierListOwner)resolved, getType((PsiModifierListOwner)resolved)); + allowedForRef = MagicConstantUtils.getAllowedValues((PsiModifierListOwner)resolved, getType((PsiModifierListOwner)resolved), expression); } if (allowedForRef != null && allowedForRef.isSubsetOf(allowedValues, manager)) { return true; diff --git a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantUtils.java b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantUtils.java index b82fe676fadd..533be5e9c059 100644 --- a/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantUtils.java +++ b/java/java-impl/src/com/intellij/codeInspection/magicConstant/MagicConstantUtils.java @@ -24,7 +24,8 @@ import java.util.*; public final class MagicConstantUtils { private static AllowedValues getAllowedValuesFromMagic(@NotNull PsiType type, @NotNull PsiAnnotation magic, - @NotNull PsiManager manager) { + @NotNull PsiManager manager, + @Nullable PsiElement context) { PsiAnnotationMemberValue[] allowedValues = PsiAnnotationMemberValue.EMPTY_ARRAY; boolean values = false; boolean flags = false; @@ -62,12 +63,12 @@ public final class MagicConstantUtils { return null; //other types not supported } - PsiAnnotationMemberValue[] valuesFromClass = readFromClass("valuesFromClass", magic, type, manager); + PsiAnnotationMemberValue[] valuesFromClass = readFromClass("valuesFromClass", magic, type, manager, context); if (valuesFromClass != null) { allowedValues = ArrayUtil.mergeArrays(allowedValues, valuesFromClass, PsiAnnotationMemberValue.ARRAY_FACTORY); values = true; } - PsiAnnotationMemberValue[] flagsFromClass = readFromClass("flagsFromClass", magic, type, manager); + PsiAnnotationMemberValue[] flagsFromClass = readFromClass("flagsFromClass", magic, type, manager, context); if (flagsFromClass != null) { allowedValues = ArrayUtil.mergeArrays(allowedValues, flagsFromClass, PsiAnnotationMemberValue.ARRAY_FACTORY); flags = true; @@ -85,19 +86,29 @@ public final class MagicConstantUtils { private static PsiAnnotationMemberValue[] readFromClass(@NonNls @NotNull String attributeName, @NotNull PsiAnnotation magic, @NotNull PsiType type, - @NotNull PsiManager manager) { + @NotNull PsiManager manager, + @Nullable PsiElement context) { PsiAnnotationMemberValue fromClassAttr = magic.findAttributeValue(attributeName); - PsiType fromClassType = fromClassAttr instanceof PsiClassObjectAccessExpression ? ((PsiClassObjectAccessExpression)fromClassAttr).getOperand().getType() : null; + PsiType fromClassType = fromClassAttr instanceof PsiClassObjectAccessExpression + ? ((PsiClassObjectAccessExpression)fromClassAttr).getOperand().getType() + : null; PsiClass fromClass = fromClassType instanceof PsiClassType ? ((PsiClassType)fromClassType).resolve() : null; if (fromClass == null) return null; String fqn = fromClass.getQualifiedName(); if (fqn == null) return null; List constants = new ArrayList<>(); for (PsiField field : fromClass.getFields()) { - if (!field.hasModifierProperty(PsiModifier.PUBLIC) || !field.hasModifierProperty(PsiModifier.STATIC) || !field.hasModifierProperty(PsiModifier.FINAL)) continue; + if (!field.hasModifierProperty(PsiModifier.STATIC) || !field.hasModifierProperty(PsiModifier.FINAL)) continue; + if (!field.hasModifierProperty(PsiModifier.PUBLIC)) { + if (context == null || + !JavaPsiFacade.getInstance(manager.getProject()).getResolveHelper().isAccessible(field, context, null)) { + continue; + } + } PsiType fieldType = field.getType(); if (!Comparing.equal(fieldType, type)) continue; - PsiAssignmentExpression e = (PsiAssignmentExpression)JavaPsiFacade.getElementFactory(manager.getProject()).createExpressionFromText("x="+fqn + "." + field.getName(), field); + PsiAssignmentExpression e = (PsiAssignmentExpression)JavaPsiFacade.getElementFactory(manager.getProject()) + .createExpressionFromText("x=" + fqn + "." + field.getName(), field); PsiReferenceExpression refToField = (PsiReferenceExpression)e.getRExpression(); constants.add(refToField); } @@ -106,17 +117,37 @@ public final class MagicConstantUtils { return constants.toArray(PsiAnnotationMemberValue.EMPTY_ARRAY); } + /** + * @deprecated used {@link #getAllowedValues(PsiModifierListOwner, PsiType, PsiElement)} + */ + @Deprecated @Nullable public static AllowedValues getAllowedValues(@NotNull PsiModifierListOwner element, @Nullable PsiType type) { return getAllowedValues(element, type, null); } + /** + * @param element element with possible MagicConstant annotation + * @param type element type + * @param context context where annotation is applied (to check the accessibility of magic constant) + * @return possible allowed values to be used instead of constant literal; null if no MagicConstant annotation found + */ @Nullable - static AllowedValues getAllowedValues(@NotNull PsiModifierListOwner element, @Nullable PsiType type, @Nullable Set visited) { + public static AllowedValues getAllowedValues(@NotNull PsiModifierListOwner element, + @Nullable PsiType type, + @Nullable PsiElement context) { + return getAllowedValues(element, type, context, null); + } + + @Nullable + static AllowedValues getAllowedValues(@NotNull PsiModifierListOwner element, + @Nullable PsiType type, + @Nullable PsiElement context, + @Nullable Set visited) { PsiManager manager = element.getManager(); for (PsiAnnotation annotation : getAllAnnotations(element)) { if (type != null && MagicConstant.class.getName().equals(annotation.getQualifiedName())) { - AllowedValues values = getAllowedValuesFromMagic(type, annotation, manager); + AllowedValues values = getAllowedValuesFromMagic(type, annotation, manager, context); if (values != null) return values; } @@ -129,7 +160,7 @@ public final class MagicConstantUtils { if (!visited.add(aClass)) { continue; } - AllowedValues values = getAllowedValues(aClass, type, visited); + AllowedValues values = getAllowedValues(aClass, type, context, visited); if (values != null) { return values; } diff --git a/java/java-tests/testData/inspection/magic/EnumConstructor.java b/java/java-tests/testData/inspection/magic/EnumConstructor.java new file mode 100644 index 000000000000..578684488910 --- /dev/null +++ b/java/java-tests/testData/inspection/magic/EnumConstructor.java @@ -0,0 +1,16 @@ +import org.intellij.lang.annotations.MagicConstant; + +enum EnumConstructor { + FOO(1), + ; + + private final int magicConstant; + + EnumConstructor(@MagicConstant(valuesFromClass = MagicConstantIds.class) int magicConstant) { + this.magicConstant = magicConstant; + } +} +class MagicConstantIds { + static final int ONE = 1; + private static final int TWO = 2; +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/MagicConstantCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/MagicConstantCompletionTest.groovy index 5053af3bd6dc..12ad63f70870 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/MagicConstantCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/MagicConstantCompletionTest.groovy @@ -81,6 +81,31 @@ interface Foo { myFixture.assertPreferredCompletionItems 0, 'BAR', 'FOO' } + @NeedsIndex.ForStandardLibrary + void "test completion in enum constructor"() { + addMagicConstant() + myFixture.configureByText "a.java", """ +import org.intellij.lang.annotations.MagicConstant; + +enum MagicConstantTest { + FOO(), + ; + + private final int magicConstant; + + MagicConstantTest(@MagicConstant(valuesFromClass = MagicConstantIds.class) int magicConstant) { + this.magicConstant = magicConstant; + } +} +class MagicConstantIds { + static final int ONE = 1; + static final int TWO = 2; +} +""" + myFixture.completeBasic() + myFixture.assertPreferredCompletionItems 0, 'ONE', 'TWO' + } + void "test magic constant in equality before another equality"() { addMagicConstant() diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/MagicConstantInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/MagicConstantInspectionTest.java index 9d7453624fd4..77fc37f9ddbc 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/MagicConstantInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/MagicConstantInspectionTest.java @@ -46,6 +46,7 @@ public class MagicConstantInspectionTest extends LightJavaCodeInsightFixtureTest public void testWithLibrary() { doTest(); } public void testSpecialCases() { doTest(); } public void testVarargMethodCall() { doTest(); } + public void testEnumConstructor() { doTest(); } private void doTest() { myFixture.configureByFile(getTestName(false) + ".java"); diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchbranches/CreateMissingSwitchBranchesAction.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchbranches/CreateMissingSwitchBranchesAction.java index 501cfc970c9e..6d16ff1c63c1 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchbranches/CreateMissingSwitchBranchesAction.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/switchbranches/CreateMissingSwitchBranchesAction.java @@ -100,22 +100,22 @@ public class CreateMissingSwitchBranchesAction extends PsiElementBaseIntentionAc } if (expression instanceof PsiReferenceExpression) { PsiModifierListOwner target = ObjectUtils.tryCast(((PsiReferenceExpression)expression).resolve(), PsiModifierListOwner.class); - List values = getValues(target, type); + List values = getValues(target, type, expression); if (values != null) return values; } else if (expression instanceof PsiMethodCallExpression) { PsiModifierListOwner target = ObjectUtils.tryCast(((PsiMethodCallExpression)expression).resolveMethod(), PsiModifierListOwner.class); - List values = getValues(target, type); + List values = getValues(target, type, expression); if (values != null) return values; } return Collections.emptyList(); } - private static List getValues(PsiModifierListOwner target, PsiType type) { + private static List getValues(PsiModifierListOwner target, PsiType type, PsiElement context) { if (target == null) { return null; } - MagicConstantUtils.AllowedValues values = MagicConstantUtils.getAllowedValues(target, type); + MagicConstantUtils.AllowedValues values = MagicConstantUtils.getAllowedValues(target, type, context); if (values != null && !values.isFlagSet() && values.getValues().length <= MAX_NUMBER_OF_BRANCHES) { List result = new ArrayList<>(); for (PsiAnnotationMemberValue value : values.getValues()) {