diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java
index d3847146e4a1..f649a2ef5d4a 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java
@@ -628,6 +628,7 @@ public class PsiClassImplUtil {
PsiElement place,
ResolveState state,
boolean isRaw, PsiElementFactory factory) {
+ boolean resolved = false;
for (final PsiClassType superType : aClass.getSuperTypes()) {
final PsiClassType.ClassResolveResult superTypeResolveResult = superType.resolveGenerics();
PsiClass superClass = superTypeResolveResult.getElement();
@@ -635,10 +636,10 @@ public class PsiClassImplUtil {
PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superTypeResolveResult.getSubstitutor(), aClass, state.get(PsiSubstitutor.KEY),
place, factory);
if (!processDeclarationsInClass(superClass, processor, state.put(PsiSubstitutor.KEY, finalSubstitutor), visited, last, place, isRaw)) {
- return false;
+ resolved = true;
}
}
- return true;
+ return !resolved;
}
@Nullable
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ClassResolverProcessor.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ClassResolverProcessor.java
index d1bcc1f39828..8d75323420f6 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ClassResolverProcessor.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/ClassResolverProcessor.java
@@ -15,17 +15,15 @@
*/
package com.intellij.psi.impl.source.resolve;
+import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.ClassCandidateInfo;
-import com.intellij.psi.scope.BaseScopeProcessor;
-import com.intellij.psi.scope.ElementClassHint;
-import com.intellij.psi.scope.JavaScopeProcessorEvent;
-import com.intellij.psi.scope.NameHint;
-import com.intellij.psi.scope.PsiScopeProcessor;
+import com.intellij.psi.scope.*;
+import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.SmartList;
import java.util.Iterator;
@@ -49,15 +47,21 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
if (((JavaCodeFragment)file).getVisibilityChecker() != null) place = null;
}
myPlace = place;
- if (place instanceof PsiReferenceExpression) {
- final PsiReferenceExpression expression = (PsiReferenceExpression)place;
- final PsiExpression qualifierExpression = expression.getQualifierExpression();
- if (qualifierExpression != null) {
- final PsiType type = qualifierExpression.getType();
+ if (place instanceof PsiJavaCodeReferenceElement) {
+ final PsiJavaCodeReferenceElement expression = (PsiJavaCodeReferenceElement)place;
+ final PsiElement qualifierExpression = expression.getQualifier();
+ if (qualifierExpression instanceof PsiExpression) {
+ final PsiType type = ((PsiExpression)qualifierExpression).getType();
if (type instanceof PsiClassType) {
myAccessClass = ((PsiClassType)type).resolve();
}
}
+ else if (qualifierExpression instanceof PsiJavaCodeReferenceElement) {
+ final PsiElement resolve = ((PsiJavaCodeReferenceElement)qualifierExpression).resolve();
+ if (resolve instanceof PsiClass) {
+ myAccessClass = (PsiClass)resolve;
+ }
+ }
}
}
@@ -132,13 +136,23 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
final PsiClass containingClass1 = aClass.getContainingClass();
final PsiClass containingClass2 = otherClass.getContainingClass();
- if (containingClass1 != null && containingClass2 != null && containingClass2.isInheritor(containingClass1, true) &&
- !isImported(myCurrentFileContext)) {
- // shadowing
- return Domination.DOMINATED_BY;
+ if (myAccessClass != null && !Comparing.equal(containingClass1, containingClass2)) {
+ if (myAccessClass.equals(containingClass1)) return Domination.DOMINATES;
+ if (myAccessClass.equals(containingClass2)) return Domination.DOMINATED_BY;
}
- boolean infoAccessible = info.isAccessible();
+ //JLS 8.5:
+ //A class may inherit two or more type declarations with the same name, either from two interfaces or from its superclass and an interface.
+ //It is a compile-time error to attempt to refer to any ambiguously inherited class or interface by its simple name.
+ if (containingClass1 != null && containingClass2 != null && containingClass2.isInheritor(containingClass1, true) &&
+ !isImported(myCurrentFileContext)) {
+ if (!isAmbiguousInherited(containingClass1)) {
+ // shadowing
+ return Domination.DOMINATED_BY;
+ }
+ }
+
+ boolean infoAccessible = info.isAccessible() && !otherClass.hasModifierProperty(PsiModifier.PRIVATE);
if (infoAccessible && !accessible) {
return Domination.DOMINATED_BY;
}
@@ -169,6 +183,17 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
return Domination.EQUAL;
}
+ private boolean isAmbiguousInherited(PsiClass containingClass1) {
+ PsiClass psiClass = PsiTreeUtil.getParentOfType(myPlace, PsiClass.class);
+ while (psiClass != null) {
+ if (psiClass.isInheritor(containingClass1, false)) {
+ return true;
+ }
+ psiClass = psiClass.getContainingClass();
+ }
+ return false;
+ }
+
@Override
public boolean execute(PsiElement element, ResolveState state) {
if (!(element instanceof PsiClass)) return true;
@@ -187,7 +212,7 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
for (int i = myCandidates.size()-1; i>=0; i--) {
ClassCandidateInfo info = myCandidates.get(i);
- Domination domination = dominates(aClass, accessible, fqName, info);
+ Domination domination = dominates(aClass, accessible && !aClass.hasModifierProperty(PsiModifier.PRIVATE), fqName, info);
if (domination == Domination.DOMINATED_BY) {
return true;
}
@@ -202,7 +227,7 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
myHasInaccessibleCandidate |= !accessible;
myCandidates.add(new ClassCandidateInfo(aClass, state.get(PsiSubstitutor.KEY), !accessible, myCurrentFileContext));
myResult = null;
- if (!accessible) return true;
+ if (!accessible || aClass.hasModifierProperty(PsiModifier.PRIVATE)) return true;
return myCurrentFileContext instanceof PsiImportStatementBase;
}
@@ -219,6 +244,23 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
}
}
+ /* if (myPlace instanceof PsiJavaCodeReferenceElement) {
+ final PsiElement element =
+ PsiTreeUtil.skipParentsOfType(myPlace, PsiJavaCodeReferenceElement.class, PsiTypeElement.class, PsiReferenceParameterList.class);
+ if (element instanceof PsiReferenceList) {
+ final PsiElement pparent = element.getParent();
+ if (pparent instanceof PsiClass) {
+ final PsiClass parentClass = (PsiClass)pparent;
+ if (element.equals(parentClass.getExtendsList()) || element.equals(parentClass.getImplementsList())) {
+ final PsiClass containingClass = aClass.getContainingClass();
+ if (containingClass != null && !PsiTreeUtil.isAncestor(containingClass, parentClass, false)) {
+ final PsiElement qualifier = ((PsiJavaCodeReferenceElement)myPlace).getQualifier();
+ if (qualifier instanceof PsiReference && parentClass == ((PsiReference)qualifier).resolve()) return false;
+ }
+ }
+ }
+ }
+ }*/
boolean accessible = true;
if (aClass instanceof PsiTypeParameter) {
accessible = !myStaticContext;
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/InnerClassesShadowing.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/InnerClassesShadowing.java
new file mode 100644
index 000000000000..825d9d62f4cf
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/InnerClassesShadowing.java
@@ -0,0 +1,70 @@
+public class Main {
+ static interface A
+ {
+ interface B { }
+ }
+
+ static class D implements A
+ {
+ private interface B { }
+ }
+
+
+ static class C extends D implements A
+ {
+ interface E extends B { }
+ interface E1 extends D.B { }
+ interface E2 extends A.B { }
+ }
+
+}
+
+
+
+class Main1 {
+ static interface A
+ {
+ interface B { }
+ }
+
+ static class D implements A
+ {
+ interface B { }
+ }
+
+
+ static class C extends D implements A
+ {
+ interface E extends B { }
+ interface E1 extends D.B {
+ }
+ interface E2 extends A.B { }
+ }
+
+}
+
+
+interface A
+{
+ interface B { }
+ interface B1 { }
+}
+
+class D implements A
+{
+ private interface B { }
+ interface B1 { }
+}
+
+
+class C extends D implements A
+{
+ interface E extends B { }
+ interface E1 extends D.B { }
+ interface E2 extends A.B { }
+
+ interface F extends B1 { }
+ interface F1 extends D.B1 { }
+ interface F2 extends A.B1 { }
+
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java
index 2524776bddac..509b1cd13a31 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingTest.java
@@ -194,6 +194,7 @@ public class LightAdvHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testDefaultPackageClassInStaticImport() throws Exception { doTest(false, false); }
public void testUnusedParamsOfPublicMethod() throws Exception { doTest(true, false); }
+ public void testInnerClassesShadowing() throws Exception { doTest(false, false); }
public void testUnusedParamsOfPublicMethodDisabled() throws Exception {
myUnusedSymbolLocalInspection.REPORT_PARAMETER_FOR_PUBLIC_METHODS = false;