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; }
private boolean isAccessible(PsiClass otherClass) { if (otherClass.hasModifierProperty(PsiModifier.PRIVATE)) { final PsiClass containingClass = otherClass.getContainingClass(); PsiClass containingPlaceClass = PsiTreeUtil.getParentOfType(myPlace, PsiClass.class, false); while (containingPlaceClass != null) { if (containingClass == containingPlaceClass) { return true; } containingPlaceClass = PsiTreeUtil.getParentOfType(containingPlaceClass, PsiClass.class); } return false; } return true; }
@Override public boolean execute(@NotNull PsiElement element, ResolveState state) { if (!(element instanceof PsiClass)) return true; final PsiClass aClass = (PsiClass) element; final String name = aClass.getName(); if (!myClassName.equals(name)) { return true; } boolean accessible = myPlace == null || checkAccessibility(aClass); if (myCandidates == null) { myCandidates = new SmartList<ClassCandidateInfo>(); } else { String fqName = aClass.getQualifiedName(); if (fqName != null) { for (int i = myCandidates.size() - 1; i >= 0; i--) { ClassCandidateInfo info = myCandidates.get(i); Domination domination = dominates(aClass, accessible && isAccessible(aClass), fqName, info); if (domination == Domination.DOMINATED_BY) { return true; } else if (domination == Domination.DOMINATES) { myCandidates.remove(i); } } } } myHasAccessibleCandidate |= accessible; myHasInaccessibleCandidate |= !accessible; myCandidates.add( new ClassCandidateInfo( aClass, state.get(PsiSubstitutor.KEY), !accessible, myCurrentFileContext)); myResult = null; if (!accessible) return true; if (aClass.hasModifierProperty(PsiModifier.PRIVATE)) { final PsiClass containingPlaceClass = PsiTreeUtil.getParentOfType(myPlace, PsiClass.class, false); if (containingPlaceClass != null && !PsiTreeUtil.isAncestor(containingPlaceClass, aClass, true)) { return true; } } return myCurrentFileContext instanceof PsiImportStatementBase; }
private boolean checkAccessibility(final PsiClass aClass) { // We don't care about accessibility in javadoc if (JavaResolveUtil.isInJavaDoc(myPlace)) { return true; } if (PsiImplUtil.isInServerPage(aClass.getContainingFile())) { PsiFile file = FileContextUtil.getContextFile(myPlace); if (PsiImplUtil.isInServerPage(file)) { return true; } } boolean accessible = true; if (aClass instanceof PsiTypeParameter) { accessible = !myStaticContext; } PsiManager manager = aClass.getManager(); if (aClass.hasModifierProperty(PsiModifier.PRIVATE)) { PsiElement parent = aClass.getParent(); while (true) { PsiElement parentScope = parent.getParent(); if (parentScope instanceof PsiJavaFile) break; parent = parentScope; if (!(parentScope instanceof PsiClass)) break; } if (parent instanceof PsiDeclarationStatement) { parent = parent.getParent(); } accessible = false; for (PsiElement placeParent = myPlace; placeParent != null; placeParent = placeParent.getContext()) { if (manager.areElementsEquivalent(placeParent, parent)) accessible = true; } } final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); if (aClass.hasModifierProperty(PsiModifier.PROTECTED)) { accessible = false; if (myPlace != null && facade.arePackagesTheSame(aClass, myPlace)) { accessible = true; } else { if (aClass.getContainingClass() != null) { accessible = myAccessClass == null || myPlace != null && facade.getResolveHelper().isAccessible(aClass, myPlace, myAccessClass); } } } if (aClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { if (myPlace == null || !facade.arePackagesTheSame(aClass, myPlace)) { accessible = false; } } return accessible; }
private boolean isOnDemand(PsiElement fileContext, PsiClass psiClass) { if (isImported(fileContext)) { return ((PsiImportStatementBase) fileContext).isOnDemand(); } String fqn = psiClass.getQualifiedName(); if (fqn == null) return false; PsiFile file = myPlace == null ? null : FileContextUtil.getContextFile(myPlace); String[] defaultPackages = file instanceof PsiJavaFile ? ((PsiJavaFile) file).getImplicitlyImportedPackages() : DEFAULT_PACKAGES; String packageName = StringUtil.getPackageName(fqn); for (String defaultPackage : defaultPackages) { if (defaultPackage.equals(packageName)) return true; } // class from my package imported implicitly return file instanceof PsiJavaFile && ((PsiJavaFile) file).getPackageName().equals(packageName); }
private Domination dominates( PsiClass aClass, boolean accessible, String fqName, ClassCandidateInfo info) { final PsiClass otherClass = info.getElement(); assert otherClass != null; String otherQName = otherClass.getQualifiedName(); if (fqName.equals(otherQName)) { return Domination.DOMINATED_BY; } final PsiClass containingClass1 = aClass.getContainingClass(); final PsiClass containingClass2 = otherClass.getContainingClass(); if (myAccessClass != null && !Comparing.equal(containingClass1, containingClass2)) { if (myAccessClass.equals(containingClass1)) return Domination.DOMINATES; if (myAccessClass.equals(containingClass2)) return Domination.DOMINATED_BY; } // 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() && isAccessible(otherClass); if (infoAccessible && !accessible) { return Domination.DOMINATED_BY; } if (!infoAccessible && accessible) { return Domination.DOMINATES; } // everything wins over class from default package boolean isDefault = StringUtil.getPackageName(fqName).length() == 0; boolean otherDefault = otherQName != null && StringUtil.getPackageName(otherQName).length() == 0; if (isDefault && !otherDefault) { return Domination.DOMINATED_BY; } if (!isDefault && otherDefault) { return Domination.DOMINATES; } // single import wins over on-demand boolean myOnDemand = isOnDemand(myCurrentFileContext, aClass); boolean otherOnDemand = isOnDemand(info.getCurrentFileResolveScope(), otherClass); if (myOnDemand && !otherOnDemand) { return Domination.DOMINATED_BY; } if (!myOnDemand && otherOnDemand) { return Domination.DOMINATES; } return Domination.EQUAL; }