From e9beee7c6606c8394e00acb7ee6804ebac50aeb8 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 29 Dec 2014 16:44:18 +0100 Subject: [PATCH] warn when accessing static method of interfaces in language levels prior to 1.8 (IDEA-134814) --- .../impl/analysis/HighlightMethodUtil.java | 6 +++-- .../src/com/intellij/psi/LambdaUtil.java | 27 ++++++++++++++----- .../AccessToStaticMethodsFromInterfaces.java | 14 ++++++++++ .../daemon/LightAdvHighlightingJdk7Test.java | 1 + 4 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/AccessToStaticMethodsFromInterfaces.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 68b97f73fdd5..664948b6c7cf 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -347,8 +347,10 @@ public class HighlightMethodUtil { TextRange fixRange = getFixRange(methodCall); highlightInfo = HighlightUtil.checkUnhandledExceptions(methodCall, fixRange); if (highlightInfo == null) { - if (!LambdaUtil.isValidQualifier4InterfaceStaticMethodCall((PsiMethod)resolved, methodCall.getMethodExpression(), resolveResult.getCurrentFileResolveScope(), languageLevel)) { - highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip("Static method may be invoked on containing interface class only").range(fixRange).create(); + final String invalidCallMessage = + LambdaUtil.getInvalidQualifier4StaticInterfaceMethodMessage((PsiMethod)resolved, methodCall.getMethodExpression(), resolveResult.getCurrentFileResolveScope(), languageLevel); + if (invalidCallMessage != null) { + highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(invalidCallMessage).range(fixRange).create(); } else { highlightInfo = GenericsHighlightUtil.checkInferredIntersections(substitutor, fixRange); } diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java index 31fb45a139de..8f072b7853e9 100644 --- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java @@ -457,15 +457,28 @@ public class LambdaUtil { public static boolean isValidQualifier4InterfaceStaticMethodCall(@NotNull PsiMethod method, @NotNull PsiReferenceExpression methodReferenceExpression, @Nullable PsiElement scope, @NotNull LanguageLevel languageLevel) { - if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { - final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression(); - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null && containingClass.isInterface() && method.hasModifierProperty(PsiModifier.STATIC)) { - return qualifierExpression == null && (scope instanceof PsiImportStaticStatement || PsiTreeUtil.isAncestor(containingClass, methodReferenceExpression, true))|| - qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() == containingClass; + return getInvalidQualifier4StaticInterfaceMethodMessage(method, methodReferenceExpression, scope, languageLevel) == null; + } + + @Nullable + public static String getInvalidQualifier4StaticInterfaceMethodMessage(@NotNull PsiMethod method, + @NotNull PsiReferenceExpression methodReferenceExpression, + @Nullable PsiElement scope, @NotNull LanguageLevel languageLevel) { + final PsiExpression qualifierExpression = methodReferenceExpression.getQualifierExpression(); + final PsiClass containingClass = method.getContainingClass(); + if (containingClass != null && containingClass.isInterface() && method.hasModifierProperty(PsiModifier.STATIC)) { + if (!languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { + return "Static interface method invocations are not supported at this language level"; } + + if (qualifierExpression == null && + (scope instanceof PsiImportStaticStatement || PsiTreeUtil.isAncestor(containingClass, methodReferenceExpression, true)) || + qualifierExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifierExpression).resolve() == containingClass) { + return null; + } + return "Static method may be invoked on containing interface class only"; } - return true; + return null; } //JLS 14.8 Expression Statements diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/AccessToStaticMethodsFromInterfaces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/AccessToStaticMethodsFromInterfaces.java new file mode 100644 index 000000000000..b2b0bb1feb9e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/AccessToStaticMethodsFromInterfaces.java @@ -0,0 +1,14 @@ +class Test { + interface I { + static void foo() {} + } + + abstract class IImpl implements I {} + interface I2 extends I {} + + { + I.foo(); + IImpl.foo(); + I2.foo(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index 36861062d1a0..1c41cd93ea5d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -187,4 +187,5 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { public void testIDEA111420() { doTest(false, false); } public void testIDEA111450() { doTest(true, false); } public void testExternalizable() { doTest(true, false); } + public void testAccessToStaticMethodsFromInterfaces() { doTest(true, false); } }