update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInspection / ex / GlobalJavaInspectionContextImpl.java
blob0fc5602f70ac4e05d72c278afbec7e619a48eb7c
1 /*
2 * Copyright 2000-2009 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.
18 * User: anna
19 * Date: 19-Dec-2007
21 package com.intellij.codeInspection.ex;
23 import com.intellij.CommonBundle;
24 import com.intellij.analysis.AnalysisScope;
25 import com.intellij.codeInspection.GlobalInspectionContext;
26 import com.intellij.codeInspection.GlobalJavaInspectionContext;
27 import com.intellij.codeInspection.InspectionProfileEntry;
28 import com.intellij.codeInspection.InspectionsBundle;
29 import com.intellij.codeInspection.deadCode.DeadCodeInspection;
30 import com.intellij.codeInspection.reference.*;
31 import com.intellij.lang.StdLanguages;
32 import com.intellij.openapi.application.ApplicationManager;
33 import com.intellij.openapi.diagnostic.Logger;
34 import com.intellij.openapi.fileTypes.StdFileTypes;
35 import com.intellij.openapi.module.Module;
36 import com.intellij.openapi.module.ModuleManager;
37 import com.intellij.openapi.project.Project;
38 import com.intellij.openapi.projectRoots.Sdk;
39 import com.intellij.openapi.roots.*;
40 import com.intellij.openapi.roots.libraries.Library;
41 import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService;
42 import com.intellij.openapi.ui.Messages;
43 import com.intellij.openapi.util.Computable;
44 import com.intellij.openapi.vfs.VirtualFile;
45 import com.intellij.psi.*;
46 import com.intellij.psi.javadoc.PsiDocComment;
47 import com.intellij.psi.search.*;
48 import com.intellij.psi.search.searches.ClassInheritorsSearch;
49 import com.intellij.psi.search.searches.MethodReferencesSearch;
50 import com.intellij.psi.search.searches.OverridingMethodsSearch;
51 import com.intellij.psi.search.searches.ReferencesSearch;
52 import com.intellij.psi.util.PsiTreeUtil;
53 import com.intellij.util.Processor;
54 import com.intellij.util.containers.ContainerUtil;
55 import gnu.trove.THashMap;
56 import org.jetbrains.annotations.NotNull;
58 import java.util.*;
60 public class GlobalJavaInspectionContextImpl extends GlobalJavaInspectionContext {
61 private static final Logger LOG = Logger.getInstance("#" + GlobalJavaInspectionContextImpl.class.getName());
63 private THashMap<SmartPsiElementPointer, List<DerivedMethodsProcessor>> myDerivedMethodsRequests;
64 private THashMap<SmartPsiElementPointer, List<DerivedClassesProcessor>> myDerivedClassesRequests;
65 private THashMap<SmartPsiElementPointer, List<UsagesProcessor>> myMethodUsagesRequests;
66 private THashMap<SmartPsiElementPointer, List<UsagesProcessor>> myFieldUsagesRequests;
67 private THashMap<SmartPsiElementPointer, List<UsagesProcessor>> myClassUsagesRequests;
70 public void enqueueClassUsagesProcessor(RefClass refClass, UsagesProcessor p) {
71 if (myClassUsagesRequests == null) myClassUsagesRequests = new THashMap<SmartPsiElementPointer, List<UsagesProcessor>>();
72 enqueueRequestImpl(refClass, myClassUsagesRequests, p);
75 public void enqueueDerivedClassesProcessor(RefClass refClass, DerivedClassesProcessor p) {
76 if (myDerivedClassesRequests == null) myDerivedClassesRequests = new THashMap<SmartPsiElementPointer, List<DerivedClassesProcessor>>();
77 enqueueRequestImpl(refClass, myDerivedClassesRequests, p);
80 public void enqueueDerivedMethodsProcessor(RefMethod refMethod, DerivedMethodsProcessor p) {
81 if (refMethod.isConstructor() || refMethod.isStatic()) return;
82 if (myDerivedMethodsRequests == null) myDerivedMethodsRequests = new THashMap<SmartPsiElementPointer, List<DerivedMethodsProcessor>>();
83 enqueueRequestImpl(refMethod, myDerivedMethodsRequests, p);
86 public void enqueueFieldUsagesProcessor(RefField refField, UsagesProcessor p) {
87 if (myFieldUsagesRequests == null) myFieldUsagesRequests = new THashMap<SmartPsiElementPointer, List<UsagesProcessor>>();
88 enqueueRequestImpl(refField, myFieldUsagesRequests, p);
91 public void enqueueMethodUsagesProcessor(RefMethod refMethod, UsagesProcessor p) {
92 if (myMethodUsagesRequests == null) myMethodUsagesRequests = new THashMap<SmartPsiElementPointer, List<UsagesProcessor>>();
93 enqueueRequestImpl(refMethod, myMethodUsagesRequests, p);
96 public EntryPointsManager getEntryPointsManager(final RefManager manager) {
97 return manager.getExtension(RefJavaManager.MANAGER).getEntryPointsManager();
100 @SuppressWarnings({"UseOfSystemOutOrSystemErr"})
101 public static boolean isInspectionsEnabled(final boolean online, Project project) {
102 final Module[] modules = ModuleManager.getInstance(project).getModules();
103 if (online) {
104 if (modules.length == 0) {
105 Messages.showMessageDialog(project, InspectionsBundle.message("inspection.no.modules.error.message"),
106 CommonBundle.message("title.error"), Messages.getErrorIcon());
107 return false;
109 while (isBadSdk(project, modules)) {
110 Messages.showMessageDialog(project, InspectionsBundle.message("inspection.no.jdk.error.message"),
111 CommonBundle.message("title.error"), Messages.getErrorIcon());
112 final Sdk projectJdk = ProjectSettingsService.getInstance(project).chooseAndSetSdk();
113 if (projectJdk == null) return false;
116 else {
117 if (modules.length == 0) {
118 System.err.println(InspectionsBundle.message("inspection.no.modules.error.message"));
119 return false;
121 if (isBadSdk(project, modules)) {
122 System.err.println(InspectionsBundle.message("inspection.no.jdk.error.message"));
123 System.err.println(
124 InspectionsBundle.message("offline.inspections.jdk.not.found", ProjectRootManager.getInstance(project).getProjectJdkName()));
125 return false;
127 for (Module module : modules) {
128 final ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
129 final Sdk jdk = rootManager.getSdk();
130 final OrderEntry[] entries = rootManager.getOrderEntries();
131 for (OrderEntry entry : entries) {
132 if (entry instanceof JdkOrderEntry) {
133 if (jdk == null) {
134 System.err.println(InspectionsBundle.message("offline.inspections.module.jdk.not.found", ((JdkOrderEntry)entry).getJdkName(),
135 module.getName()));
136 return false;
139 else if (entry instanceof LibraryOrderEntry) {
140 final LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry)entry;
141 final Library library = libraryOrderEntry.getLibrary();
142 if (library == null || library.getFiles(OrderRootType.CLASSES).length != library.getUrls(OrderRootType.CLASSES).length) {
143 System.err.println(InspectionsBundle.message("offline.inspections.library.was.not.resolved",
144 libraryOrderEntry.getPresentableName(), module.getName()));
150 return true;
153 private static boolean isBadSdk(final Project project, final Module[] modules) {
154 boolean anyModuleAcceptsSdk = false;
155 boolean anyModuleUsesProjectSdk = false;
156 Sdk projectSdk = ProjectRootManager.getInstance(project).getProjectJdk();
157 for (Module module : modules) {
158 if (ModuleRootManager.getInstance(module).isSdkInherited()) {
159 anyModuleUsesProjectSdk = true;
160 if (module.getModuleType().isValidSdk(module, projectSdk)) {
161 anyModuleAcceptsSdk = true;
165 return anyModuleUsesProjectSdk && !anyModuleAcceptsSdk;
168 private static <T extends Processor> void enqueueRequestImpl(RefElement refElement, Map<SmartPsiElementPointer, List<T>> requestMap, T processor) {
169 List<T> requests = requestMap.get(refElement.getPointer());
170 if (requests == null) {
171 requests = new ArrayList<T>();
172 requestMap.put(refElement.getPointer(), requests);
174 requests.add(processor);
177 public void cleanup() {
178 myDerivedMethodsRequests = null;
179 myDerivedClassesRequests = null;
180 myMethodUsagesRequests = null;
181 myFieldUsagesRequests = null;
182 myClassUsagesRequests = null;
186 public void processSearchRequests(final GlobalInspectionContext context) {
187 final RefManager refManager = context.getRefManager();
188 final AnalysisScope scope = refManager.getScope();
190 final SearchScope searchScope = new GlobalSearchScope(refManager.getProject()) {
191 public boolean contains(VirtualFile file) {
192 return !scope.contains(file) || file.getFileType() != StdFileTypes.JAVA;
195 public int compare(VirtualFile file1, VirtualFile file2) {
196 return 0;
199 public boolean isSearchInModuleContent(@NotNull Module aModule) {
200 return true;
203 public boolean isSearchInLibraries() {
204 return false;
208 if (myDerivedClassesRequests != null) {
209 final List<SmartPsiElementPointer> sortedIDs = getSortedIDs(myDerivedClassesRequests);
210 for (SmartPsiElementPointer sortedID : sortedIDs) {
211 final PsiClass psiClass = (PsiClass)sortedID.getElement();
212 if (psiClass == null) continue;
213 ((GlobalInspectionContextImpl)context).incrementJobDoneAmount(GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES, ApplicationManager.getApplication().runReadAction(
214 new Computable<String>() {
215 public String compute() {
216 return psiClass.getQualifiedName();
221 final List<DerivedClassesProcessor> processors = myDerivedClassesRequests.get(sortedID);
222 ClassInheritorsSearch.search(psiClass, searchScope, false)
223 .forEach(createMembersProcessor(processors, scope));
226 myDerivedClassesRequests = null;
229 if (myDerivedMethodsRequests != null) {
230 final List<SmartPsiElementPointer> sortedIDs = getSortedIDs(myDerivedMethodsRequests);
231 for (SmartPsiElementPointer sortedID : sortedIDs) {
232 final PsiMethod psiMethod = (PsiMethod)sortedID.getElement();
233 final RefMethod refMethod = (RefMethod)refManager.getReference(psiMethod);
235 ((GlobalInspectionContextImpl)context)
236 .incrementJobDoneAmount(GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES, refManager.getQualifiedName(refMethod));
238 final List<DerivedMethodsProcessor> processors = myDerivedMethodsRequests.get(sortedID);
239 OverridingMethodsSearch.search(psiMethod, searchScope, true)
240 .forEach(createMembersProcessor(processors, scope));
243 myDerivedMethodsRequests = null;
246 if (myFieldUsagesRequests != null) {
247 final List<SmartPsiElementPointer> sortedIDs = getSortedIDs(myFieldUsagesRequests);
248 for (SmartPsiElementPointer sortedID : sortedIDs) {
249 final PsiField psiField = (PsiField)sortedID.getElement();
250 if (psiField == null) continue;
251 final List<UsagesProcessor> processors = myFieldUsagesRequests.get(sortedID);
253 ((GlobalInspectionContextImpl)context)
254 .incrementJobDoneAmount(GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES, refManager.getQualifiedName(refManager.getReference(psiField)));
256 ReferencesSearch.search(psiField, searchScope, false)
257 .forEach(new PsiReferenceProcessorAdapter(createReferenceProcessor(processors, context)));
260 myFieldUsagesRequests = null;
263 if (myClassUsagesRequests != null) {
264 final List<SmartPsiElementPointer> sortedIDs = getSortedIDs(myClassUsagesRequests);
265 for (SmartPsiElementPointer sortedID : sortedIDs) {
266 final PsiClass psiClass = (PsiClass)sortedID.getElement();
267 if (psiClass == null) continue;
268 final List<UsagesProcessor> processors = myClassUsagesRequests.get(sortedID);
270 ((GlobalInspectionContextImpl)context).incrementJobDoneAmount(GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES, ApplicationManager.getApplication().runReadAction(
271 new Computable<String>() {
272 public String compute() {
273 return psiClass.getQualifiedName();
278 ReferencesSearch.search(psiClass, searchScope, false)
279 .forEach(new PsiReferenceProcessorAdapter(createReferenceProcessor(processors, context)));
282 myClassUsagesRequests = null;
285 if (myMethodUsagesRequests != null) {
286 List<SmartPsiElementPointer> sortedIDs = getSortedIDs(myMethodUsagesRequests);
287 for (SmartPsiElementPointer sortedID : sortedIDs) {
288 final PsiMethod psiMethod = (PsiMethod)sortedID.getElement();
289 if (psiMethod == null) continue;
290 final List<UsagesProcessor> processors = myMethodUsagesRequests.get(sortedID);
292 ((GlobalInspectionContextImpl)context)
293 .incrementJobDoneAmount(GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES, refManager.getQualifiedName(refManager.getReference(psiMethod)));
295 MethodReferencesSearch.search(psiMethod, searchScope, true)
296 .forEach(new PsiReferenceProcessorAdapter(createReferenceProcessor(processors, context)));
299 myMethodUsagesRequests = null;
304 private static <Member extends PsiMember, P extends Processor<Member>> PsiElementProcessorAdapter<Member> createMembersProcessor(final List<P> processors,
305 final AnalysisScope scope) {
306 return new PsiElementProcessorAdapter<Member>(new PsiElementProcessor<Member>() {
307 public boolean execute(Member member) {
308 if (scope.contains(member)) return true;
309 final List<P> processorsArrayed = new ArrayList<P>(processors);
310 for (P processor : processorsArrayed) {
311 if (!processor.process(member)) {
312 processors.remove(processor);
315 return !processors.isEmpty();
320 private int getRequestCount() {
321 int sum = 0;
323 sum += getRequestListSize(myClassUsagesRequests);
324 sum += getRequestListSize(myDerivedClassesRequests);
325 sum += getRequestListSize(myDerivedMethodsRequests);
326 sum += getRequestListSize(myFieldUsagesRequests);
327 sum += getRequestListSize(myMethodUsagesRequests);
329 return sum;
332 private static int getRequestListSize(THashMap list) {
333 if (list == null) return 0;
334 return list.size();
337 private static List<SmartPsiElementPointer> getSortedIDs(final Map<SmartPsiElementPointer, ?> requests) {
338 final List<SmartPsiElementPointer> result = new ArrayList<SmartPsiElementPointer>();
340 ApplicationManager.getApplication().runReadAction(new Runnable() {
341 public void run() {
342 for (SmartPsiElementPointer id : requests.keySet()) {
343 if (id != null) {
344 final PsiElement psi = id.getElement();
345 if (psi != null) {
346 result.add(id);
350 Collections.sort(result, new Comparator<SmartPsiElementPointer>() {
351 public int compare(final SmartPsiElementPointer o1, final SmartPsiElementPointer o2) {
352 PsiElement p1 = o1.getElement();
353 PsiElement p2 = o2.getElement();
354 final PsiFile psiFile1 = p1 != null ? p1.getContainingFile() : null;
355 LOG.assertTrue(psiFile1 != null);
356 final PsiFile psiFile2 = p2 != null ? p2.getContainingFile() : null;
357 LOG.assertTrue(psiFile2 != null);
358 return psiFile1.getName().compareTo(psiFile2.getName());
364 return result;
367 private static PsiReferenceProcessor createReferenceProcessor(@NotNull final List<UsagesProcessor> processors,
368 final GlobalInspectionContext context) {
369 return new PsiReferenceProcessor() {
370 public boolean execute(PsiReference reference) {
371 AnalysisScope scope = context.getRefManager().getScope();
372 if ((scope.contains(reference.getElement()) && reference.getElement().getLanguage() == StdLanguages.JAVA) ||
373 PsiTreeUtil.getParentOfType(reference.getElement(), PsiDocComment.class) != null) {
374 return true;
377 synchronized (processors) {
378 UsagesProcessor[] processorsArrayed = processors.toArray(new UsagesProcessor[processors.size()]);
379 for (UsagesProcessor processor : processorsArrayed) {
380 if (!processor.process(reference)) {
381 processors.remove(processor);
386 return !processors.isEmpty();
391 public void performPreRunActivities(final List<Tools> globalTools, final List<Tools> localTools,
392 final GlobalInspectionContext context) {
393 getEntryPointsManager(context.getRefManager()).resolveEntryPoints(context.getRefManager());
394 ContainerUtil.quickSort(globalTools, new Comparator<Tools>() {
395 public int compare(Tools o1, Tools o2) {
396 if (o1.getTool() instanceof DeadCodeInspection) return -1;
397 if (o2.getTool() instanceof DeadCodeInspection) return 1;
398 return 0;
405 public void performPostRunActivities(List<InspectionProfileEntry> needRepeatSearchRequest, final GlobalInspectionContext context) {
406 GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES.setTotalAmount(getRequestCount() * 2);
408 do {
409 processSearchRequests(context);
410 InspectionProfileEntry[] requestors = needRepeatSearchRequest.toArray(new InspectionProfileEntry[needRepeatSearchRequest.size()]);
411 for (InspectionProfileEntry requestor : requestors) {
412 if (requestor instanceof InspectionTool &&
413 !((InspectionTool)requestor).queryExternalUsagesRequests(InspectionManagerEx.getInstance(context.getProject()))) {
414 needRepeatSearchRequest.remove(requestor);
417 int oldSearchRequestCount = GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES.getTotalAmount();
418 float proportion = GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES.getProgress();
419 int totalAmount = oldSearchRequestCount + getRequestCount() * 2;
420 GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES.setTotalAmount(totalAmount);
421 GlobalInspectionContextImpl.FIND_EXTERNAL_USAGES.setDoneAmount((int)(totalAmount * proportion));
423 while (!needRepeatSearchRequest.isEmpty());