@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 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; }