2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 package com.intellij.psi.impl.source.resolve;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.projectRoots.JavaSdkVersion;
24 import com.intellij.openapi.projectRoots.JavaVersionService;
25 import com.intellij.psi.*;
26 import com.intellij.psi.impl.PsiImplUtil;
27 import com.intellij.psi.infos.CandidateInfo;
28 import com.intellij.psi.javadoc.PsiDocComment;
29 import com.intellij.psi.scope.PsiScopeProcessor;
30 import com.intellij.psi.util.InheritanceUtil;
31 import com.intellij.psi.util.PsiTreeUtil;
32 import com.intellij.psi.util.PsiUtil;
33 import org.jetbrains.annotations.NotNull;
34 import org.jetbrains.annotations.Nullable;
36 public class JavaResolveUtil {
37 public static PsiClass getContextClass(@NotNull PsiElement element) {
38 PsiElement prev = element;
39 PsiElement scope = element.getContext();
40 while (scope != null) {
41 if (scope instanceof PsiClass && (prev instanceof PsiMember || prev instanceof PsiDocComment)) {
42 return (PsiClass)scope;
45 scope = scope.getContext();
50 public static PsiElement findParentContextOfClass(PsiElement element, Class aClass, boolean strict){
51 PsiElement scope = strict ? element.getContext() : element;
52 while(scope != null && !aClass.isInstance(scope)){
53 scope = scope.getContext();
58 public static boolean isAccessible(@NotNull PsiMember member,
59 @Nullable PsiClass memberClass,
60 @Nullable PsiModifierList modifierList,
61 @NotNull PsiElement place,
62 @Nullable PsiClass accessObjectClass,
63 @Nullable PsiElement fileResolveScope) {
64 return isAccessible(member, memberClass, modifierList, place, accessObjectClass, fileResolveScope, place.getContainingFile());
67 public static boolean isAccessible(@NotNull PsiMember member,
68 @Nullable PsiClass memberClass,
69 @Nullable PsiModifierList modifierList,
70 @NotNull PsiElement place,
71 @Nullable PsiClass accessObjectClass,
72 @Nullable PsiElement fileResolveScope,
73 @Nullable PsiFile placeFile) {
74 if (modifierList == null || isInJavaDoc(place)) {
78 if (placeFile instanceof JavaCodeFragment) {
79 JavaCodeFragment fragment = (JavaCodeFragment)placeFile;
80 JavaCodeFragment.VisibilityChecker visibilityChecker = fragment.getVisibilityChecker();
81 if (visibilityChecker != null) {
82 JavaCodeFragment.VisibilityChecker.Visibility visibility = visibilityChecker.isDeclarationVisible(member, place);
83 if (visibility == JavaCodeFragment.VisibilityChecker.Visibility.VISIBLE) return true;
84 if (visibility == JavaCodeFragment.VisibilityChecker.Visibility.NOT_VISIBLE) return false;
87 else if (ignoreReferencedElementAccessibility(placeFile)) {
91 if (accessObjectClass != null) {
92 PsiClass containingClass = accessObjectClass.getContainingClass();
93 if (!isAccessible(accessObjectClass, containingClass, accessObjectClass.getModifierList(), place, null, null, placeFile)) {
98 PsiFile file = placeFile == null ? null : FileContextUtil.getContextFile(placeFile); //TODO: implementation method!!!!
99 if (PsiImplUtil.isInServerPage(file) && PsiImplUtil.isInServerPage(member.getContainingFile())) {
103 int effectiveAccessLevel = PsiUtil.getAccessLevel(modifierList);
104 if (ignoreReferencedElementAccessibility(file) || effectiveAccessLevel == PsiUtil.ACCESS_LEVEL_PUBLIC) {
108 PsiManager manager = member.getManager();
109 JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
111 if (effectiveAccessLevel == PsiUtil.ACCESS_LEVEL_PROTECTED) {
112 if (facade.arePackagesTheSame(member, place)) {
115 if (memberClass == null) {
118 PsiClass contextClass = member instanceof PsiClass ? getContextClass(place)
119 : PsiTreeUtil.getContextOfType(place, PsiClass.class, false);
120 while (contextClass != null) {
121 if (InheritanceUtil.isInheritorOrSelf(contextClass, memberClass, true)) {
122 if (member instanceof PsiClass ||
123 modifierList.hasModifierProperty(PsiModifier.STATIC) ||
124 accessObjectClass == null ||
125 InheritanceUtil.isInheritorOrSelf(accessObjectClass, contextClass, true)) {
130 contextClass = getContextClass(contextClass);
135 if (effectiveAccessLevel == PsiUtil.ACCESS_LEVEL_PRIVATE) {
136 if (memberClass == null) return true;
137 if (accessObjectClass != null) {
138 PsiClass topMemberClass = getTopLevelClass(memberClass, accessObjectClass);
139 PsiClass topAccessClass = getTopLevelClass(accessObjectClass, memberClass);
140 if (!manager.areElementsEquivalent(topMemberClass, topAccessClass)) return false;
141 if (accessObjectClass instanceof PsiAnonymousClass && accessObjectClass.isInheritor(memberClass, true)) {
142 if (place instanceof PsiMethodCallExpression) {
148 if (fileResolveScope == null) {
149 PsiClass placeTopLevelClass = getTopLevelClass(place, null);
150 PsiClass memberTopLevelClass = getTopLevelClass(memberClass, null);
151 return manager.areElementsEquivalent(placeTopLevelClass, memberTopLevelClass);
154 return fileResolveScope instanceof PsiClass &&
155 !((PsiClass)fileResolveScope).isInheritor(memberClass, true);
159 if (!facade.arePackagesTheSame(member, place)) return false;
160 //if (modifierList.hasModifierProperty(PsiModifier.STATIC)) return true;
161 // maybe inheritance lead through package-private class in other package ?
162 final PsiClass placeClass = getContextClass(place);
163 if (memberClass == null || placeClass == null) return true;
164 // check only classes since interface members are public, and if placeClass is interface,
165 // then its members are static, and cannot refer to non-static members of memberClass
166 if (memberClass.isInterface() || placeClass.isInterface()) return true;
167 PsiClass clazz = accessObjectClass != null ?
169 placeClass.getSuperClass(); //may start from super class
170 if (clazz != null && clazz.isInheritor(memberClass, true)) {
171 PsiClass superClass = clazz;
172 while (!manager.areElementsEquivalent(superClass, memberClass)) {
173 if (superClass == null || !facade.arePackagesTheSame(superClass, memberClass)) return false;
174 superClass = superClass.getSuperClass();
181 private static boolean ignoreReferencedElementAccessibility(PsiFile placeFile) {
182 return placeFile instanceof FileResolveScopeProvider &&
183 ((FileResolveScopeProvider) placeFile).ignoreReferencedElementAccessibility() &&
184 !PsiImplUtil.isInServerPage(placeFile);
187 public static boolean isInJavaDoc(final PsiElement place) {
188 PsiElement scope = place;
189 while(scope != null){
190 if (scope instanceof PsiDocComment) return true;
191 if (scope instanceof PsiMember || scope instanceof PsiMethodCallExpression || scope instanceof PsiFile) return false;
192 scope = scope.getContext();
197 private static PsiClass getTopLevelClass(@NotNull PsiElement place, PsiClass memberClass) {
198 PsiClass lastClass = null;
199 Boolean isAtLeast17 = null;
200 for (PsiElement placeParent = place; placeParent != null; placeParent = placeParent.getContext()) {
201 if (placeParent instanceof PsiClass && !(placeParent instanceof PsiAnonymousClass)) {
202 final boolean isTypeParameter = placeParent instanceof PsiTypeParameter;
203 if (isTypeParameter && isAtLeast17 == null) {
204 isAtLeast17 = JavaVersionService.getInstance().isAtLeast(placeParent, JavaSdkVersion.JDK_1_7);
206 if (!isTypeParameter || isAtLeast17) {
207 PsiClass aClass = (PsiClass)placeParent;
209 if (memberClass != null && aClass.isInheritor(memberClass, true)) return aClass;
219 public static boolean processImplicitlyImportedPackages(final PsiScopeProcessor processor,
220 final ResolveState state,
221 final PsiElement place,
222 PsiManager manager) {
223 PsiPackage defaultPackage = JavaPsiFacade.getInstance(manager.getProject()).findPackage("");
224 if (defaultPackage != null) {
225 if (!defaultPackage.processDeclarations(processor, state, null, place)) return false;
228 PsiPackage langPackage = JavaPsiFacade.getInstance(manager.getProject()).findPackage(CommonClassNames.DEFAULT_PACKAGE);
229 if (langPackage != null) {
230 if (!langPackage.processDeclarations(processor, state, null, place)) return false;
236 public static void substituteResults(@NotNull final PsiJavaCodeReferenceElement ref, @NotNull JavaResolveResult[] result) {
237 if (result.length > 0 && result[0].getElement() instanceof PsiClass) {
238 for (int i = 0; i < result.length; i++) {
239 final CandidateInfo resolveResult = (CandidateInfo)result[i];
240 final PsiElement resultElement = resolveResult.getElement();
241 if (resultElement instanceof PsiClass && ((PsiClass)resultElement).hasTypeParameters()) {
242 PsiSubstitutor substitutor = resolveResult.getSubstitutor();
243 result[i] = new CandidateInfo(resolveResult, substitutor) {
246 public PsiSubstitutor getSubstitutor() {
247 final PsiType[] parameters = ref.getTypeParameters();
248 return super.getSubstitutor().putAll((PsiClass)resultElement, parameters);
257 public static <T extends PsiPolyVariantReference> JavaResolveResult[] resolveWithContainingFile(@NotNull T ref,
258 @NotNull ResolveCache.PolyVariantContextResolver<T> resolver,
259 boolean needToPreventRecursion,
260 boolean incompleteCode,
261 @NotNull PsiFile containingFile) {
262 boolean valid = containingFile.isValid();
264 return JavaResolveResult.EMPTY_ARRAY;
266 Project project = containingFile.getProject();
267 ResolveResult[] results = ResolveCache.getInstance(project).resolveWithCaching(ref, resolver, needToPreventRecursion, incompleteCode,
269 return results.length == 0 ? JavaResolveResult.EMPTY_ARRAY : (JavaResolveResult[])results;