diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index 535aee6ea37b..a28be95d2166 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -678,6 +678,7 @@ public class HighlightClassUtil { * @param extendRef points to the class in the extends list * @param resolved extendRef resolved */ + @Nullable public static HighlightInfo checkClassExtendsForeignInnerClass(final PsiJavaCodeReferenceElement extendRef, final PsiElement resolved) { PsiElement parent = extendRef.getParent(); if (!(parent instanceof PsiReferenceList)) { @@ -723,11 +724,10 @@ public class HighlightClassUtil { // must be inner class if (!PsiUtil.isInnerClass(base)) return; - if (resolve == resolved) { - if (!hasEnclosingInstanceInScope(baseClass, extendRef, true) && !qualifiedNewCalledInConstructors(aClass, baseClass)) { - String description = JavaErrorMessages.message("no.enclosing.instance.in.scope", HighlightUtil.formatClass(baseClass)); - infos[0] = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, extendRef, description); - } + if (resolve == resolved && baseClass != null && + !hasEnclosingInstanceInScope(baseClass, extendRef, true) && !qualifiedNewCalledInConstructors(aClass, baseClass)) { + String description = JavaErrorMessages.message("no.enclosing.instance.in.scope", HighlightUtil.formatClass(baseClass)); + infos[0] = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, extendRef, description); } } } @@ -796,6 +796,7 @@ public class HighlightClassUtil { return checkCreateInnerClassFromStaticContext(expression, qualifier, aClass); } + @Nullable public static HighlightInfo checkCreateInnerClassFromStaticContext(PsiElement element, @Nullable PsiExpression qualifier, PsiClass aClass) { if (!PsiUtil.isInnerClass(aClass)) return null; PsiClass outerClass = aClass.getContainingClass(); @@ -803,15 +804,14 @@ public class HighlightClassUtil { PsiElement placeToSearchEnclosingFrom; if (qualifier != null) { - PsiType qtype = qualifier.getType(); - placeToSearchEnclosingFrom = PsiUtil.resolveClassInType(qtype); + PsiType qType = qualifier.getType(); + placeToSearchEnclosingFrom = PsiUtil.resolveClassInType(qType); } else { placeToSearchEnclosingFrom = element; } - if (outerClass instanceof JspClass - || hasEnclosingInstanceInScope(outerClass, placeToSearchEnclosingFrom, true)) return null; + if (outerClass instanceof JspClass || hasEnclosingInstanceInScope(outerClass, placeToSearchEnclosingFrom, true)) return null; return reportIllegalEnclosingUsage(placeToSearchEnclosingFrom, aClass, outerClass, element); } @@ -837,7 +837,8 @@ public class HighlightClassUtil { @Nullable public static HighlightInfo reportIllegalEnclosingUsage(PsiElement place, - PsiClass aClass, PsiClass outerClass, + @Nullable PsiClass aClass, + PsiClass outerClass, PsiElement elementToHighlight) { if (outerClass != null && !PsiTreeUtil.isContextAncestor(outerClass, place, false)) { String description = JavaErrorMessages.message("is.not.an.enclosing.class", HighlightUtil.formatClass(outerClass)); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 81810fe6940a..1bbf4e34ad18 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -67,7 +67,7 @@ import static com.intellij.codeInsight.daemon.JavaHighlightingFilter.suppressed; /** * @author cdr - * Date: Jul 30, 2002 + * @since Jul 30, 2002 */ public class HighlightUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil"); @@ -82,8 +82,7 @@ public class HighlightUtil { @NonNls private static final String SERIAL_PERSISTENT_FIELDS_FIELD_NAME = "serialPersistentFields"; private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance(); - private HighlightUtil() { - } + private HighlightUtil() { } static { ourClassIncompatibleModifiers = new THashMap>(8); @@ -898,6 +897,7 @@ public class HighlightUtil { private static final Key TOO_BIG_CHAR_LITERAL_KEY = Key.create("too.big.char.literal"); + @Nullable public static String getLiteralExpressionParsingError(final PsiLiteralExpression expression) { final Object value = expression.getValue(); final PsiElement literal = expression.getFirstChild(); @@ -1145,8 +1145,7 @@ public class HighlightUtil { final List typeElements = PsiUtil.getParameterTypeElements(parameter); final Collection highlights = Lists.newArrayListWithCapacity(typeElements.size()); - for (int i = 0, size = typeElements.size(); i < size; i++) { - final PsiTypeElement typeElement = typeElements.get(i); + for (final PsiTypeElement typeElement : typeElements) { final PsiType catchType = typeElement.getType(); if (catchType instanceof PsiClassType && ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)catchType)) continue; @@ -1323,29 +1322,45 @@ public class HighlightUtil { } @Nullable - public static HighlightInfo checkThisOrSuperExpressionInIllegalContext(PsiExpression expr, @Nullable PsiJavaCodeReferenceElement qualifier) { + public static HighlightInfo checkThisOrSuperExpressionInIllegalContext(PsiExpression expr, + @Nullable PsiJavaCodeReferenceElement qualifier) { if (expr instanceof PsiSuperExpression && !(expr.getParent() instanceof PsiReferenceExpression)) { // like in 'Object o = super;' - return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expr.getTextRange().getEndOffset(), - expr.getTextRange().getEndOffset() + 1, - JavaErrorMessages.message("dot.expected.after.super.or.this")); + final int o = expr.getTextRange().getEndOffset(); + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, o, o + 1, JavaErrorMessages.message("dot.expected.after.super.or.this")); } - PsiElement resolved = null; - PsiClass aClass = qualifier == null ? PsiTreeUtil.getParentOfType(expr, PsiClass.class) : (resolved = qualifier.resolve()) instanceof PsiClass ? (PsiClass)resolved : null; - if (resolved != null && !(resolved instanceof PsiClass)) { - return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, qualifier, JavaErrorMessages.message("class.expected")); + + final PsiClass aClass; + if (qualifier != null) { + final PsiElement resolved = qualifier.resolve(); + if (resolved != null && !(resolved instanceof PsiClass)) { + return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, qualifier, JavaErrorMessages.message("class.expected")); + } + aClass = (PsiClass)resolved; + } + else { + aClass = PsiTreeUtil.getParentOfType(expr, PsiClass.class); } if (aClass == null) return null; - if (qualifier != null && aClass.isInterface()) { - return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, qualifier, JavaErrorMessages.message("no.interface.expected")); - } - if (!HighlightClassUtil.hasEnclosingInstanceInScope(aClass, expr, false)) { + + if (!HighlightClassUtil.hasEnclosingInstanceInScope(aClass, expr, false) && + !resolvesToImmediateSuperInterface(expr, qualifier, aClass)) { return HighlightClassUtil.reportIllegalEnclosingUsage(expr, null, aClass, expr); } return null; } + private static boolean resolvesToImmediateSuperInterface(PsiExpression expr, + @Nullable PsiJavaCodeReferenceElement qualifier, + PsiClass aClass) { + if (!(expr instanceof PsiSuperExpression) || qualifier == null || !PsiUtil.isLanguageLevel8OrHigher(expr)) return false; + final PsiType superType = expr.getType(); + if (!(superType instanceof PsiClassType)) return false; + final PsiClass superClass = ((PsiClassType)superType).resolve(); + return superClass != null && aClass.equals(superClass); + } + static String buildProblemWithStaticDescription(PsiElement refElement) { String type = LanguageFindUsages.INSTANCE.forLanguage(JavaLanguage.INSTANCE).getType(refElement); String name = HighlightMessageUtil.getSymbolName(refElement, PsiSubstitutor.EMPTY); @@ -1550,7 +1565,8 @@ public class HighlightUtil { return null; } - HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, JavaErrorMessages.message("array.initializer.not.allowed")); + HighlightInfo info = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, + JavaErrorMessages.message("array.initializer.not.allowed")); QuickFixAction.registerQuickFixAction(info, new AddNewArrayExpressionFix(expression)); return info; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSuperExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSuperExpressionImpl.java index e6637553395f..d50bfcb1a21d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSuperExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiSuperExpressionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,10 @@ import com.intellij.psi.impl.source.Constants; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.ChildRoleBase; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class PsiSuperExpressionImpl extends ExpressionPsiElement implements PsiSuperExpression, Constants { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiSuperExpressionImpl"); @@ -38,17 +41,20 @@ public class PsiSuperExpressionImpl extends ExpressionPsiElement implements PsiS @Override public PsiType getType() { - PsiJavaCodeReferenceElement qualifier = getQualifier(); - if (qualifier != null){ + final PsiJavaCodeReferenceElement qualifier = getQualifier(); + if (qualifier != null) { final PsiElement aClass = qualifier.resolve(); - return aClass instanceof PsiClass ? getSuperType((PsiClass)aClass) : null; + if (!(aClass instanceof PsiClass)) return null; + return getSuperType((PsiClass)aClass, PsiUtil.isLanguageLevel8OrHigher(this)); } - for(PsiElement scope = getContext(); scope != null; scope = scope.getContext()){ - if (scope instanceof PsiClass){ - PsiClass aClass = (PsiClass)scope; - return getSuperType(aClass); + + for (PsiElement scope = getContext(); scope != null; scope = scope.getContext()) { + if (scope instanceof PsiClass) { + final PsiClass aClass = (PsiClass)scope; + return getSuperType(aClass, false); } - if (scope instanceof PsiExpressionList && scope.getParent() instanceof PsiAnonymousClass){ + if (scope instanceof PsiExpressionList && scope.getParent() instanceof PsiAnonymousClass) { + //noinspection AssignmentToForLoopParameter scope = scope.getParent(); } else if (scope instanceof JavaCodeFragment) { @@ -56,55 +62,56 @@ public class PsiSuperExpressionImpl extends ExpressionPsiElement implements PsiS if (fragmentSuperType != null) return fragmentSuperType; } } + return null; } - private PsiType getSuperType(PsiClass aClass) { + @Nullable + private PsiType getSuperType(PsiClass aClass, boolean checkImmediateSuperInterfaces) { + if (CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) return null; + + final PsiClass containingClass = checkImmediateSuperInterfaces ? PsiTreeUtil.getParentOfType(this, PsiClass.class) : null; + if (containingClass != null) { + final PsiClassType[] superTypes; + if (containingClass.isInterface()) { + superTypes = containingClass.getExtendsListTypes(); + } + else if (containingClass instanceof PsiAnonymousClass) { + superTypes = new PsiClassType[]{((PsiAnonymousClass)containingClass).getBaseClassType()}; + } + else { + superTypes = containingClass.getImplementsListTypes(); + } + + for (PsiClassType superType : superTypes) { + final PsiClass superClass = superType.resolve(); + if (superClass != null && superClass.isInterface() && aClass.equals(superClass)) return superType; + } + } + if (aClass.isInterface()) { - JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); - return facade.getElementFactory().createType(facade.findClass("java.lang.Object", getResolveScope())); + return PsiType.getJavaLangObject(getManager(), getResolveScope()); } if (aClass instanceof PsiAnonymousClass) { final PsiClassType baseClassType = ((PsiAnonymousClass)aClass).getBaseClassType(); final PsiClass psiClass = baseClassType.resolve(); - if(psiClass != null && !psiClass.isInterface()){ - return baseClassType; - } - - return PsiType.getJavaLangObject(getManager(), getResolveScope()); + return psiClass != null && !psiClass.isInterface() ? baseClassType : PsiType.getJavaLangObject(getManager(), getResolveScope()); } - if ("java.lang.Object".equals(aClass.getQualifiedName())) return null; - PsiClassType[] superTypes = aClass.getExtendsListTypes(); - if (superTypes.length == 0) { - JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject()); - final PsiClass javaLangObject = facade.findClass("java.lang.Object", getResolveScope()); - if (javaLangObject != null) { - return facade.getElementFactory().createType(javaLangObject); - } - else { - return null; - } - } - - return superTypes[0]; + final PsiClassType[] superTypes = aClass.getExtendsListTypes(); + return superTypes.length == 0 ? PsiType.getJavaLangObject(getManager(), getResolveScope()) : superTypes[0]; } @Override public ASTNode findChildByRole(int role) { LOG.assertTrue(ChildRole.isUnique(role)); - switch(role){ + switch (role) { default: return null; case ChildRole.QUALIFIER: - if (getFirstChildNode().getElementType() == JAVA_CODE_REFERENCE){ - return getFirstChildNode(); - } - else{ - return null; - } + return getFirstChildNode().getElementType() == JAVA_CODE_REFERENCE ? getFirstChildNode() : null; case ChildRole.DOT: return findChildByType(DOT); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/Interface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/Interface.java index 1dc6b8c535c7..2d3c98953e1a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/Interface.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/Interface.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ interface i implements Runnable {} interface ii {} @@ -9,12 +24,12 @@ interface is3 extends cs {} abstract class Exercis { public static void main() { - Object o = java.lang.this; - - new Runnable() { - public void run() { - Runnable.this.run(); /// - } - }; - } + Object o = java.lang.this; + + new Runnable() { + public void run() { + Runnable.this.run(); + } + }; + } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ExtensionMethods.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ExtensionMethods.java index 909d08a364b9..26f1086ce5ad 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ExtensionMethods.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ExtensionMethods.java @@ -19,7 +19,20 @@ class C { void m() default { } } + interface II extends I { + void m() default { I.super.m(); } + void ma(); + } + void test() { new I(){}.m(); + + new II() { + public void ma() { + I.super.m(); + II.super.m(); + II.super.ma(); + } + }.m(); } } \ No newline at end of file