2 * Copyright 2000-2014 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.
16 package com.intellij.psi.impl.file.impl;
18 import com.intellij.openapi.module.Module;
19 import com.intellij.openapi.module.impl.scopes.LibraryRuntimeClasspathScope;
20 import com.intellij.openapi.progress.ProgressIndicatorProvider;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.roots.*;
23 import com.intellij.openapi.roots.impl.LibraryScopeCache;
24 import com.intellij.openapi.vfs.VirtualFile;
25 import com.intellij.openapi.vfs.VirtualFileWithId;
26 import com.intellij.psi.*;
27 import com.intellij.psi.impl.PsiManagerImpl;
28 import com.intellij.psi.impl.ResolveScopeManager;
29 import com.intellij.psi.impl.source.resolve.FileContextUtil;
30 import com.intellij.psi.search.DelegatingGlobalSearchScope;
31 import com.intellij.psi.search.GlobalSearchScope;
32 import com.intellij.psi.search.SearchScope;
33 import com.intellij.util.containers.ConcurrentFactoryMap;
34 import org.jetbrains.annotations.NotNull;
36 import java.util.ArrayList;
37 import java.util.List;
40 public class ResolveScopeManagerImpl extends ResolveScopeManager {
41 private final Project myProject;
42 private final ProjectRootManager myProjectRootManager;
43 private final PsiManager myManager;
45 private final Map<VirtualFile, GlobalSearchScope> myDefaultResolveScopesCache = new ConcurrentFactoryMap<VirtualFile, GlobalSearchScope>() {
47 protected GlobalSearchScope create(@NotNull VirtualFile key) {
48 GlobalSearchScope scope = null;
49 for(ResolveScopeProvider resolveScopeProvider: ResolveScopeProvider.EP_NAME.getExtensions()) {
50 scope = resolveScopeProvider.getResolveScope(key, myProject);
51 if (scope != null) break;
53 if (scope == null) scope = getInherentResolveScope(key);
54 for (ResolveScopeEnlarger enlarger : ResolveScopeEnlarger.EP_NAME.getExtensions()) {
55 final SearchScope extra = enlarger.getAdditionalResolveScope(key, myProject);
57 scope = scope.union(extra);
65 public ResolveScopeManagerImpl(Project project, ProjectRootManager projectRootManager, PsiManager psiManager) {
67 myProjectRootManager = projectRootManager;
68 myManager = psiManager;
70 ((PsiManagerImpl) psiManager).registerRunnableToRunOnChange(new Runnable() {
73 myDefaultResolveScopesCache.clear();
79 private GlobalSearchScope getResolveScopeFromProviders(@NotNull final VirtualFile vFile) {
80 return myDefaultResolveScopesCache.get(vFile);
83 private GlobalSearchScope getInherentResolveScope(VirtualFile vFile) {
84 ProjectFileIndex projectFileIndex = myProjectRootManager.getFileIndex();
85 Module module = projectFileIndex.getModuleForFile(vFile);
87 boolean includeTests = projectFileIndex.isInTestSourceContent(vFile);
88 return GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, includeTests);
91 // resolve references in libraries in context of all modules which contain it
92 List<Module> modulesLibraryUsedIn = new ArrayList<Module>();
93 List<OrderEntry> orderEntries = projectFileIndex.getOrderEntriesForFile(vFile);
95 LibraryOrderEntry lib = null;
96 for (OrderEntry entry : orderEntries) {
97 if (entry instanceof JdkOrderEntry) {
98 return LibraryScopeCache.getInstance(myProject).getScopeForSdk((JdkOrderEntry)entry);
101 if (entry instanceof LibraryOrderEntry) {
102 lib = (LibraryOrderEntry)entry;
103 modulesLibraryUsedIn.add(entry.getOwnerModule());
105 else if (entry instanceof ModuleOrderEntry) {
106 modulesLibraryUsedIn.add(entry.getOwnerModule());
110 GlobalSearchScope allCandidates = LibraryScopeCache.getInstance(myProject).getScopeForLibraryUsedIn(modulesLibraryUsedIn);
112 final LibraryRuntimeClasspathScope preferred = new LibraryRuntimeClasspathScope(myProject, lib);
113 // prefer current library
114 return new DelegatingGlobalSearchScope(allCandidates, preferred) {
116 public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
117 boolean c1 = preferred.contains(file1);
118 boolean c2 = preferred.contains(file2);
119 if (c1 && !c2) return 1;
120 if (c2 && !c1) return -1;
122 return super.compare(file1, file2);
126 return allCandidates;
132 public GlobalSearchScope getResolveScope(@NotNull PsiElement element) {
133 ProgressIndicatorProvider.checkCanceled();
136 final PsiFile contextFile;
137 if (element instanceof PsiDirectory) {
138 vFile = ((PsiDirectory)element).getVirtualFile();
142 final PsiFile containingFile = element.getContainingFile();
143 if (containingFile instanceof PsiCodeFragment) {
144 final GlobalSearchScope forcedScope = ((PsiCodeFragment)containingFile).getForcedResolveScope();
145 if (forcedScope != null) {
148 final PsiElement context = containingFile.getContext();
149 if (context == null) {
150 return GlobalSearchScope.allScope(myProject);
152 return getResolveScope(context);
155 contextFile = containingFile != null ? FileContextUtil.getContextFile(containingFile) : null;
156 if (contextFile == null) {
157 return GlobalSearchScope.allScope(myProject);
159 else if (contextFile instanceof FileResolveScopeProvider) {
160 return ((FileResolveScopeProvider) contextFile).getFileResolveScope();
162 vFile = contextFile.getOriginalFile().getVirtualFile();
164 if (vFile == null || contextFile == null) {
165 return GlobalSearchScope.allScope(myProject);
168 return getResolveScopeFromProviders(vFile);
173 public GlobalSearchScope getDefaultResolveScope(final VirtualFile vFile) {
174 final PsiFile psiFile = myManager.findFile(vFile);
175 assert psiFile != null;
176 return getResolveScopeFromProviders(vFile);
182 public GlobalSearchScope getUseScope(@NotNull PsiElement element) {
183 VirtualFile vDirectory;
184 final VirtualFile virtualFile;
185 final PsiFile containingFile;
186 final GlobalSearchScope allScope = GlobalSearchScope.allScope(myManager.getProject());
187 if (element instanceof PsiDirectory) {
188 vDirectory = ((PsiDirectory)element).getVirtualFile();
190 containingFile = null;
193 containingFile = element.getContainingFile();
194 if (containingFile == null) return allScope;
195 virtualFile = containingFile.getVirtualFile();
196 if (virtualFile == null) return allScope;
197 vDirectory = virtualFile.getParent();
200 if (vDirectory == null) return allScope;
201 final ProjectFileIndex projectFileIndex = myProjectRootManager.getFileIndex();
202 final Module module = projectFileIndex.getModuleForFile(vDirectory);
203 if (module == null) {
204 return containingFile == null || virtualFile.isDirectory() || allScope.contains(virtualFile)
205 ? allScope : GlobalSearchScope.fileScope(containingFile).uniteWith(allScope);
207 boolean isTest = projectFileIndex.isInTestSourceContent(vDirectory);
208 GlobalSearchScope scope = isTest
209 ? GlobalSearchScope.moduleTestsWithDependentsScope(module)
210 : GlobalSearchScope.moduleWithDependentsScope(module);
211 RefResolveService resolveService;
212 if (virtualFile instanceof VirtualFileWithId && RefResolveService.ENABLED && (resolveService = RefResolveService.getInstance(myProject)).isUpToDate()) {
213 return resolveService.restrictByBackwardIds(virtualFile, scope);