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.search.DelegatingGlobalSearchScope;
30 import com.intellij.psi.search.GlobalSearchScope;
31 import com.intellij.psi.search.SearchScope;
32 import com.intellij.util.containers.ConcurrentFactoryMap;
33 import org.jetbrains.annotations.NotNull;
35 import java.util.ArrayList;
36 import java.util.List;
39 public class ResolveScopeManagerImpl extends ResolveScopeManager {
40 private final Project myProject;
41 private final ProjectRootManager myProjectRootManager;
42 private final PsiManager myManager;
44 private final Map<VirtualFile, GlobalSearchScope> myDefaultResolveScopesCache = new ConcurrentFactoryMap<VirtualFile, GlobalSearchScope>() {
46 protected GlobalSearchScope create(@NotNull VirtualFile key) {
47 GlobalSearchScope scope = null;
48 for(ResolveScopeProvider resolveScopeProvider: ResolveScopeProvider.EP_NAME.getExtensions()) {
49 scope = resolveScopeProvider.getResolveScope(key, myProject);
50 if (scope != null) break;
52 if (scope == null) scope = getInherentResolveScope(key);
53 for (ResolveScopeEnlarger enlarger : ResolveScopeEnlarger.EP_NAME.getExtensions()) {
54 final SearchScope extra = enlarger.getAdditionalResolveScope(key, myProject);
56 scope = scope.union(extra);
64 public ResolveScopeManagerImpl(Project project, ProjectRootManager projectRootManager, PsiManager psiManager) {
66 myProjectRootManager = projectRootManager;
67 myManager = psiManager;
69 ((PsiManagerImpl) psiManager).registerRunnableToRunOnChange(new Runnable() {
72 myDefaultResolveScopesCache.clear();
78 private GlobalSearchScope getResolveScopeFromProviders(@NotNull final VirtualFile vFile) {
79 return myDefaultResolveScopesCache.get(vFile);
82 private GlobalSearchScope getInherentResolveScope(VirtualFile vFile) {
83 ProjectFileIndex projectFileIndex = myProjectRootManager.getFileIndex();
84 Module module = projectFileIndex.getModuleForFile(vFile);
86 boolean includeTests = projectFileIndex.isInTestSourceContent(vFile);
87 return GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module, includeTests);
90 // resolve references in libraries in context of all modules which contain it
91 List<Module> modulesLibraryUsedIn = new ArrayList<Module>();
92 List<OrderEntry> orderEntries = projectFileIndex.getOrderEntriesForFile(vFile);
94 LibraryOrderEntry lib = null;
95 for (OrderEntry entry : orderEntries) {
96 if (entry instanceof JdkOrderEntry) {
97 return LibraryScopeCache.getInstance(myProject).getScopeForSdk((JdkOrderEntry)entry);
100 if (entry instanceof LibraryOrderEntry) {
101 lib = (LibraryOrderEntry)entry;
102 modulesLibraryUsedIn.add(entry.getOwnerModule());
104 else if (entry instanceof ModuleOrderEntry) {
105 modulesLibraryUsedIn.add(entry.getOwnerModule());
109 GlobalSearchScope allCandidates = LibraryScopeCache.getInstance(myProject).getScopeForLibraryUsedIn(modulesLibraryUsedIn);
111 final LibraryRuntimeClasspathScope preferred = new LibraryRuntimeClasspathScope(myProject, lib);
112 // prefer current library
113 return new DelegatingGlobalSearchScope(allCandidates, preferred) {
115 public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
116 boolean c1 = preferred.contains(file1);
117 boolean c2 = preferred.contains(file2);
118 if (c1 && !c2) return 1;
119 if (c2 && !c1) return -1;
121 return super.compare(file1, file2);
125 return allCandidates;
131 public GlobalSearchScope getResolveScope(@NotNull PsiElement element) {
132 ProgressIndicatorProvider.checkCanceled();
135 final PsiFile contextFile;
136 if (element instanceof PsiDirectory) {
137 vFile = ((PsiDirectory)element).getVirtualFile();
141 final PsiFile containingFile = element.getContainingFile();
142 if (containingFile instanceof PsiCodeFragment) {
143 final GlobalSearchScope forcedScope = ((PsiCodeFragment)containingFile).getForcedResolveScope();
144 if (forcedScope != null) {
149 if (containingFile != null) {
150 PsiElement context = containingFile.getContext();
151 if (context != null) {
152 return getResolveScope(context);
156 contextFile = containingFile;
157 if (containingFile == null) {
158 return GlobalSearchScope.allScope(myProject);
160 else if (contextFile instanceof FileResolveScopeProvider) {
161 return ((FileResolveScopeProvider) contextFile).getFileResolveScope();
163 vFile = contextFile.getOriginalFile().getVirtualFile();
165 if (vFile == null || contextFile == null) {
166 return GlobalSearchScope.allScope(myProject);
169 return getResolveScopeFromProviders(vFile);
174 public GlobalSearchScope getDefaultResolveScope(final VirtualFile vFile) {
175 final PsiFile psiFile = myManager.findFile(vFile);
176 assert psiFile != null;
177 return getResolveScopeFromProviders(vFile);
183 public GlobalSearchScope getUseScope(@NotNull PsiElement element) {
184 VirtualFile vDirectory;
185 final VirtualFile virtualFile;
186 final PsiFile containingFile;
187 final GlobalSearchScope allScope = GlobalSearchScope.allScope(myManager.getProject());
188 if (element instanceof PsiDirectory) {
189 vDirectory = ((PsiDirectory)element).getVirtualFile();
191 containingFile = null;
194 containingFile = element.getContainingFile();
195 if (containingFile == null) return allScope;
196 virtualFile = containingFile.getVirtualFile();
197 if (virtualFile == null) return allScope;
198 vDirectory = virtualFile.getParent();
201 if (vDirectory == null) return allScope;
202 final ProjectFileIndex projectFileIndex = myProjectRootManager.getFileIndex();
203 final Module module = projectFileIndex.getModuleForFile(vDirectory);
204 if (module == null) {
205 return containingFile == null || virtualFile.isDirectory() || allScope.contains(virtualFile)
206 ? allScope : GlobalSearchScope.fileScope(containingFile).uniteWith(allScope);
208 boolean isTest = projectFileIndex.isInTestSourceContent(vDirectory);
209 GlobalSearchScope scope = isTest
210 ? GlobalSearchScope.moduleTestsWithDependentsScope(module)
211 : GlobalSearchScope.moduleWithDependentsScope(module);
212 RefResolveService resolveService;
213 if (virtualFile instanceof VirtualFileWithId && RefResolveService.ENABLED && (resolveService = RefResolveService.getInstance(myProject)).isUpToDate()) {
214 return resolveService.restrictByBackwardIds(virtualFile, scope);