cleanup inspection context after redundant suppress inspection
[fedora-idea.git] / inspections / impl / com / intellij / codeInspection / ex / GlobalInspectionContextImpl.java
blob37550d0324be96a8d7ea4e422af55a06036ef9d8
1 /*
2 * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
3 */
5 package com.intellij.codeInspection.ex;
7 import com.intellij.CommonBundle;
8 import com.intellij.analysis.AnalysisScope;
9 import com.intellij.analysis.PerformAnalysisInBackgroundOption;
10 import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
11 import com.intellij.codeInsight.daemon.HighlightDisplayKey;
12 import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass;
13 import com.intellij.codeInspection.*;
14 import com.intellij.codeInspection.deadCode.DeadCodeInspection;
15 import com.intellij.codeInspection.reference.*;
16 import com.intellij.codeInspection.ui.InspectionResultsView;
17 import com.intellij.ide.util.projectWizard.JdkChooserPanel;
18 import com.intellij.openapi.actionSystem.ToggleAction;
19 import com.intellij.openapi.application.Application;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.components.PathMacroManager;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.fileTypes.StdFileTypes;
24 import com.intellij.openapi.module.Module;
25 import com.intellij.openapi.module.ModuleManager;
26 import com.intellij.openapi.progress.ProcessCanceledException;
27 import com.intellij.openapi.progress.ProgressIndicator;
28 import com.intellij.openapi.progress.ProgressManager;
29 import com.intellij.openapi.progress.util.ProgressIndicatorBase;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.projectRoots.ProjectJdk;
32 import com.intellij.openapi.ui.Messages;
33 import com.intellij.openapi.util.Computable;
34 import com.intellij.openapi.util.JDOMUtil;
35 import com.intellij.openapi.util.Pair;
36 import com.intellij.openapi.util.text.StringUtil;
37 import com.intellij.openapi.vfs.VfsUtil;
38 import com.intellij.openapi.vfs.VirtualFile;
39 import com.intellij.openapi.wm.ToolWindowId;
40 import com.intellij.openapi.wm.ToolWindowManager;
41 import com.intellij.peer.PeerFactory;
42 import com.intellij.pom.java.LanguageLevel;
43 import com.intellij.profile.Profile;
44 import com.intellij.profile.codeInspection.InspectionProfileManager;
45 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
46 import com.intellij.psi.*;
47 import com.intellij.psi.javadoc.PsiDocComment;
48 import com.intellij.psi.javadoc.PsiDocTag;
49 import com.intellij.psi.search.*;
50 import com.intellij.psi.util.PsiTreeUtil;
51 import com.intellij.psi.util.PsiUtil;
52 import com.intellij.ui.content.Content;
53 import com.intellij.ui.content.ContentManager;
54 import com.intellij.ui.content.ContentManagerAdapter;
55 import com.intellij.ui.content.ContentManagerEvent;
56 import com.intellij.util.Processor;
57 import com.intellij.util.containers.HashMap;
58 import gnu.trove.THashMap;
59 import org.jdom.Document;
60 import org.jdom.Element;
61 import org.jetbrains.annotations.NonNls;
62 import org.jetbrains.annotations.NotNull;
63 import org.jetbrains.annotations.Nullable;
65 import javax.swing.*;
66 import java.io.*;
67 import java.util.*;
68 import java.util.regex.Pattern;
70 public class GlobalInspectionContextImpl implements GlobalInspectionContext {
71 private RefManager myRefManager;
72 private ContentManager myContentManager;
73 private AnalysisScope myCurrentScope;
75 private final Project myProject;
76 private List<JobDescriptor> myJobDescriptors;
77 private InspectionResultsView myView = null;
78 private Content myContent = null;
80 private THashMap<PsiElement, List<DerivedMethodsProcessor>> myDerivedMethodsRequests;
81 private THashMap<PsiElement, List<DerivedClassesProcessor>> myDerivedClassesRequests;
82 private THashMap<PsiElement, List<UsagesProcessor>> myMethodUsagesRequests;
83 private THashMap<PsiElement, List<UsagesProcessor>> myFieldUsagesRequests;
84 private THashMap<PsiElement, List<UsagesProcessor>> myClassUsagesRequests;
85 private ProgressIndicator myProgressIndicator;
88 public static final JobDescriptor BUILD_GRAPH = new JobDescriptor(InspectionsBundle.message("inspection.processing.job.descriptor"));
89 public static final JobDescriptor FIND_EXTERNAL_USAGES =
90 new JobDescriptor(InspectionsBundle.message("inspection.processing.job.descriptor1"));
91 private static final JobDescriptor LOCAL_ANALYSIS = new JobDescriptor(InspectionsBundle.message("inspection.processing.job.descriptor2"));
94 private InspectionProfile myExternalProfile = null;
96 public boolean RUN_WITH_EDITOR_PROFILE = false;
97 private boolean RUN_GLOBAL_TOOLS_ONLY = false;
98 private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.GlobalInspectionContextImpl");
99 @NonNls public static final String SUPPRESS_INSPECTIONS_TAG_NAME = "noinspection";
100 public static final String SUPPRESS_INSPECTIONS_ANNOTATION_NAME = "java.lang.SuppressWarnings";
101 @NonNls public static final Pattern SUPPRESS_IN_LINE_COMMENT_PATTERN =
102 Pattern.compile("//\\s*" + SUPPRESS_INSPECTIONS_TAG_NAME + "\\s+(\\w+(,\\w+)*)");
104 private Map<String, Set<Pair<InspectionTool, InspectionProfile>>> myTools = new THashMap<String, Set<Pair<InspectionTool, InspectionProfile>>>();
106 private UIOptions myUIOptions;
108 public GlobalInspectionContextImpl(Project project, ContentManager contentManager) {
109 myProject = project;
111 myUIOptions = ((InspectionManagerEx)InspectionManager.getInstance(project)).getUIOptions().copy();
112 myRefManager = null;
113 myCurrentScope = null;
114 myContentManager = contentManager;
115 if (myContentManager != null) { //test || offline
116 myContentManager.addContentManagerListener(new ContentManagerAdapter() {
117 public void contentRemoved(ContentManagerEvent event) {
118 if (event.getContent() == myContent){
119 if (myView != null) {
120 close(false);
122 myContent = null;
129 @NotNull
130 public Project getProject() {
131 return myProject;
134 public ContentManager getContentManager() {
135 return myContentManager;
138 public InspectionProfile getCurrentProfile() {
139 if (myExternalProfile != null) return myExternalProfile;
140 InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManager.getInstance(myProject);
141 final InspectionProjectProfileManager inspectionProfileManager = InspectionProjectProfileManager.getInstance(myProject);
142 Profile profile = inspectionProfileManager.getProfiles().get(managerEx.getCurrentProfile());
143 if (profile == null) {
144 profile = InspectionProfileManager.getInstance().getProfile(managerEx.getCurrentProfile());
145 if (profile != null) return (InspectionProfile)profile;
147 final String[] avaliableProfileNames = inspectionProfileManager.getAvailableProfileNames();
148 if (avaliableProfileNames == null || avaliableProfileNames.length == 0) {
149 //can't be
150 return null;
152 profile = inspectionProfileManager.getProfile(avaliableProfileNames[0]);
154 return (InspectionProfile)profile;
157 public boolean isSuppressed(RefEntity entity, String id) {
158 return entity instanceof RefElement && ((RefElementImpl)entity).isSuppressed(id);
161 public boolean shouldCheck(RefEntity entity, GlobalInspectionTool tool) {
162 if (entity instanceof RefElement) {
163 final RefElementImpl refElement = (RefElementImpl)entity;
164 if (refElement.isSuppressed(tool.getShortName())) return false;
166 final PsiElement element = refElement.getElement();
168 if (element == null) return false;
170 if (RUN_WITH_EDITOR_PROFILE) {
171 final InspectionProfileEntry inspectionTool =
172 InspectionProjectProfileManager.getInstance(element.getProject()).getInspectionProfile(element)
173 .getInspectionTool(tool.getShortName());
174 if (inspectionTool instanceof GlobalInspectionToolWrapper && ((GlobalInspectionToolWrapper)inspectionTool).getTool() != tool) {
175 return false;
179 return true;
182 public boolean isSuppressed(PsiElement element, String id) {
183 final RefManagerImpl refManager = (RefManagerImpl)getRefManager();
184 if (refManager.isDeclarationsFound() && element instanceof PsiModifierListOwner) {
185 final RefElement refElement = refManager.getReference(element);
186 return refElement instanceof RefElementImpl && ((RefElementImpl)refElement).isSuppressed(id);
188 return element instanceof PsiDocCommentOwner && !isToCheckMember((PsiDocCommentOwner)element, id);
192 public void addView(InspectionResultsView view, String title) {
193 myView = view;
194 ContentManager contentManager = getContentManager();
195 myContent = PeerFactory.getInstance().getContentFactory().createContent(view, title, false);
197 myContent.setDisposer(myView);
198 contentManager.addContent(myContent);
199 contentManager.setSelectedContent(myContent);
201 ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.INSPECTION).activate(null);
204 private void addView(InspectionResultsView view) {
205 addView(view, view.getCurrentProfileName() == null
206 ? InspectionsBundle.message("inspection.results.title")
207 : InspectionsBundle.message("inspection.results.for.profile.toolwindow.title", view.getCurrentProfileName()));
212 public void enqueueClassUsagesProcessor(RefClass refClass, UsagesProcessor p) {
213 if (myClassUsagesRequests == null) myClassUsagesRequests = new THashMap<PsiElement, List<UsagesProcessor>>();
214 enqueueRequestImpl(refClass, myClassUsagesRequests, p);
217 public void enqueueDerivedClassesProcessor(RefClass refClass, DerivedClassesProcessor p) {
218 if (myDerivedClassesRequests == null) myDerivedClassesRequests = new THashMap<PsiElement, List<DerivedClassesProcessor>>();
219 enqueueRequestImpl(refClass, myDerivedClassesRequests, p);
222 public void enqueueDerivedMethodsProcessor(RefMethod refMethod, DerivedMethodsProcessor p) {
223 if (refMethod.isConstructor() || refMethod.isStatic()) return;
224 if (myDerivedMethodsRequests == null) myDerivedMethodsRequests = new THashMap<PsiElement, List<DerivedMethodsProcessor>>();
225 enqueueRequestImpl(refMethod, myDerivedMethodsRequests, p);
228 public void enqueueFieldUsagesProcessor(RefField refField, UsagesProcessor p) {
229 if (myFieldUsagesRequests == null) myFieldUsagesRequests = new THashMap<PsiElement, List<UsagesProcessor>>();
230 enqueueRequestImpl(refField, myFieldUsagesRequests, p);
233 public void enqueueMethodUsagesProcessor(RefMethod refMethod, UsagesProcessor p) {
234 if (myMethodUsagesRequests == null) myMethodUsagesRequests = new THashMap<PsiElement, List<UsagesProcessor>>();
235 enqueueRequestImpl(refMethod, myMethodUsagesRequests, p);
238 private static <T extends Processor> void enqueueRequestImpl(RefElement refElement, Map<PsiElement, List<T>> requestMap, T processor) {
239 List<T> requests = requestMap.get(refElement.getElement());
240 if (requests == null) {
241 requests = new ArrayList<T>();
242 requestMap.put(refElement.getElement(), requests);
244 requests.add(processor);
247 private void cleanup() {
248 myProgressIndicator = null;
250 myDerivedMethodsRequests = null;
251 myDerivedClassesRequests = null;
252 myMethodUsagesRequests = null;
253 myFieldUsagesRequests = null;
254 myClassUsagesRequests = null;
256 for (Set<Pair<InspectionTool, InspectionProfile>> tools : myTools.values()) {
257 for (Pair<InspectionTool, InspectionProfile> pair : tools) {
258 pair.first.cleanup();
261 myTools.clear();
263 EntryPointsManager.getInstance(getProject()).cleanup();
265 if (myRefManager != null) {
266 ((RefManagerImpl)myRefManager).cleanup();
267 myRefManager = null;
268 if (myCurrentScope != null){
269 myCurrentScope.invalidate();
270 myCurrentScope = null;
275 public void setCurrentScope(AnalysisScope currentScope) {
276 myCurrentScope = currentScope;
279 public void doInspections(final AnalysisScope scope, final InspectionManager manager) {
280 while (PsiManager.getInstance(getProject()).findClass("java.lang.Object", GlobalSearchScope.allScope(getProject())) == null) {
281 if (ModuleManager.getInstance(getProject()).getModules().length == 0) {
282 Messages.showMessageDialog(getProject(), InspectionsBundle.message("inspection.no.modules.error.message"),
283 CommonBundle.message("title.error"), Messages.getErrorIcon());
284 return;
286 Messages.showMessageDialog(getProject(), InspectionsBundle.message("inspection.no.jdk.error.message"),
287 CommonBundle.message("title.error"), Messages.getErrorIcon());
288 final ProjectJdk projectJdk = JdkChooserPanel.chooseAndSetJDK(myProject);
289 if (projectJdk == null) return;
292 cleanup();
293 getContentManager().removeContent(myContent);
295 ApplicationManager.getApplication().invokeLater(new Runnable() {
296 public void run() {
297 myCurrentScope = scope;
298 launchInspections(scope, manager);
304 @NotNull
305 public RefManager getRefManager() {
306 if (myRefManager == null) {
307 myRefManager = new RefManagerImpl(myProject, myCurrentScope, this);
310 return myRefManager;
313 public void launchInspectionsOffline(final AnalysisScope scope,
314 final String outputPath,
315 final boolean runWithEditorSettings,
316 final boolean runGlobalToolsOnly,
317 final InspectionManager manager) {
318 cleanup();
320 myCurrentScope = scope;
322 final boolean oldProfileSetting = RUN_WITH_EDITOR_PROFILE;
323 InspectionTool.setOutputPath(outputPath);
324 RUN_WITH_EDITOR_PROFILE = runWithEditorSettings;
325 final boolean oldToolsSettings = RUN_GLOBAL_TOOLS_ONLY;
326 RUN_GLOBAL_TOOLS_ONLY = runGlobalToolsOnly;
327 try {
328 ApplicationManager.getApplication().runReadAction(new Runnable() {
329 public void run() {
330 performInspectionsWithProgress(scope, manager);
331 @NonNls final String ext = ".xml";
332 for (String toolName : myTools.keySet()) {
333 final Element root = new Element(InspectionsBundle.message("inspection.problems"));
334 final Document doc = new Document(root);
335 final Set<Pair<InspectionTool, InspectionProfile>> sameTools = myTools.get(toolName);
336 boolean hasProblems = false;
337 boolean isLocalTool = false;
338 if (sameTools != null) {
339 for (Pair<InspectionTool, InspectionProfile> toolDescr : sameTools) {
340 final InspectionTool tool = toolDescr.first;
341 if (tool instanceof LocalInspectionToolWrapper) {
342 hasProblems = new File(outputPath, toolName + ext).exists();
343 isLocalTool = true;
345 else {
346 tool.updateContent();
347 if (tool.hasReportedProblems()) {
348 hasProblems = true;
349 tool.exportResults(root);
354 if (!hasProblems) continue;
355 @NonNls final String isLocalToolAttribute = "is_local_tool";
356 root.setAttribute(isLocalToolAttribute, String.valueOf(isLocalTool));
357 OutputStream outStream = null;
358 try {
359 new File(outputPath).mkdirs();
360 final File file = new File(outputPath, toolName + ext);
361 if (isLocalTool) {
362 outStream = localInspectionFilePreparations(file, outStream, isLocalToolAttribute, isLocalTool);
364 else {
365 PathMacroManager.getInstance(getProject()).collapsePaths(doc.getRootElement());
366 outStream = new BufferedOutputStream(new FileOutputStream(file));
367 JDOMUtil.writeDocument(doc, outStream, "\n");
370 catch (IOException e) {
371 LOG.error(e);
373 finally {
374 if (outStream != null) {
375 try {
376 outStream.close();
378 catch (IOException e) {
379 LOG.error(e);
388 finally {
389 InspectionTool.setOutputPath(null);
390 RUN_WITH_EDITOR_PROFILE = oldProfileSetting;
391 RUN_GLOBAL_TOOLS_ONLY = oldToolsSettings;
395 private static OutputStream localInspectionFilePreparations(final File file,
396 OutputStream outStream,
397 final String localToolAttribute,
398 final boolean localTool) throws IOException {
399 BufferedReader reader = null;
400 try {
401 StringBuilder buf = new StringBuilder();
402 reader = new BufferedReader(new FileReader(file));
403 String line = reader.readLine();
404 while (line != null) {
405 buf.append(line).append("\n");
406 line = reader.readLine();
408 outStream = new BufferedOutputStream(new FileOutputStream(file));
409 outStream.write(("<" + InspectionsBundle.message("inspection.problems") + " " + localToolAttribute + "=\"" + localTool + "\">").getBytes());
410 outStream.write(buf.toString().getBytes());
411 outStream.write(("</" + InspectionsBundle.message("inspection.problems") + ">").getBytes());
413 finally {
414 if (reader != null){
415 reader.close();
418 return outStream;
421 public void processSearchRequests() {
422 final PsiManager psiManager = PsiManager.getInstance(getProject());
423 final PsiSearchHelper helper = psiManager.getSearchHelper();
424 final RefManager refManager = getRefManager();
425 final AnalysisScope scope = refManager.getScope();
427 final ProgressIndicator progress =
428 myProgressIndicator == null ? null : new ProgressWrapper(myProgressIndicator);
429 ProgressManager.getInstance().runProcess(new Runnable() {
430 public void run() {
431 final SearchScope searchScope = new GlobalSearchScope() {
432 public boolean contains(VirtualFile file) {
433 return !scope.contains(file) || file.getFileType() != StdFileTypes.JAVA;
436 public int compare(VirtualFile file1, VirtualFile file2) {
437 return 0;
440 public boolean isSearchInModuleContent(Module aModule) {
441 return true;
444 public boolean isSearchInLibraries() {
445 return false;
448 final Application application = ApplicationManager.getApplication();
449 if (myDerivedClassesRequests != null) {
450 List<PsiElement> sortedIDs = getSortedIDs(myDerivedClassesRequests);
451 for (PsiElement sortedID : sortedIDs) {
452 final PsiClass psiClass = (PsiClass)sortedID;
453 incrementJobDoneAmount(FIND_EXTERNAL_USAGES, psiClass.getQualifiedName());
455 final List<DerivedClassesProcessor> processors = myDerivedClassesRequests.get(psiClass);
456 application.runReadAction(new Runnable() {
457 public void run() {
458 helper.processInheritors(new PsiElementProcessor<PsiClass>() {
459 public boolean execute(PsiClass inheritor) {
460 if (scope.contains(inheritor)) return true;
461 DerivedClassesProcessor[] processorsArrayed = processors.toArray(new DerivedClassesProcessor[processors.size()]);
462 for (DerivedClassesProcessor processor : processorsArrayed) {
463 if (!processor.process(inheritor)) {
464 processors.remove(processor);
467 return !processors.isEmpty();
469 }, psiClass, searchScope, false);
474 myDerivedClassesRequests = null;
477 if (myDerivedMethodsRequests != null) {
478 List<PsiElement> sortedIDs = getSortedIDs(myDerivedMethodsRequests);
479 for (PsiElement sortedID : sortedIDs) {
480 final PsiMethod psiMethod = (PsiMethod)sortedID;
481 final RefMethod refMethod = (RefMethod)refManager.getReference(psiMethod);
483 incrementJobDoneAmount(FIND_EXTERNAL_USAGES, RefUtil.getInstance().getQualifiedName(refMethod));
485 final List<DerivedMethodsProcessor> processors = myDerivedMethodsRequests.get(psiMethod);
486 application.runReadAction(new Runnable() {
487 public void run() {
488 helper.processOverridingMethods(new PsiElementProcessor<PsiMethod>() {
489 public boolean execute(PsiMethod derivedMethod) {
490 if (scope.contains(derivedMethod)) return true;
491 DerivedMethodsProcessor[] processorsArrayed = processors.toArray(new DerivedMethodsProcessor[processors.size()]);
492 for (DerivedMethodsProcessor processor : processorsArrayed) {
493 if (!processor.process(derivedMethod)) {
494 processors.remove(processor);
498 return !processors.isEmpty();
500 }, psiMethod, searchScope, true);
505 myDerivedMethodsRequests = null;
508 if (myFieldUsagesRequests != null) {
509 List<PsiElement> sortedIDs = getSortedIDs(myFieldUsagesRequests);
510 for (PsiElement sortedID : sortedIDs) {
511 final PsiField psiField = (PsiField)sortedID;
512 final List<UsagesProcessor> processors = myFieldUsagesRequests.get(psiField);
514 incrementJobDoneAmount(FIND_EXTERNAL_USAGES,
515 RefUtil.getInstance().getQualifiedName(refManager.getReference(psiField)));
517 application.runReadAction(new Runnable() {
518 public void run() {
519 helper.processReferences(createReferenceProcessor(processors), psiField, searchScope, false);
524 myFieldUsagesRequests = null;
527 if (myClassUsagesRequests != null) {
528 List<PsiElement> sortedIDs = getSortedIDs(myClassUsagesRequests);
529 for (PsiElement sortedID : sortedIDs) {
530 final PsiClass psiClass = (PsiClass)sortedID;
531 final List<UsagesProcessor> processors = myClassUsagesRequests.get(psiClass);
533 incrementJobDoneAmount(FIND_EXTERNAL_USAGES, psiClass.getQualifiedName());
535 application.runReadAction(new Runnable() {
536 public void run() {
537 helper.processReferences(createReferenceProcessor(processors), psiClass, searchScope, false);
542 myClassUsagesRequests = null;
545 if (myMethodUsagesRequests != null) {
546 List<PsiElement> sortedIDs = getSortedIDs(myMethodUsagesRequests);
547 for (PsiElement sortedID : sortedIDs) {
548 final PsiMethod psiMethod = (PsiMethod)sortedID;
549 final List<UsagesProcessor> processors = myMethodUsagesRequests.get(psiMethod);
551 incrementJobDoneAmount(FIND_EXTERNAL_USAGES,
552 RefUtil.getInstance().getQualifiedName(refManager.getReference(psiMethod)));
554 application.runReadAction(new Runnable() {
555 public void run() {
556 helper.processReferencesIncludingOverriding(createReferenceProcessor(processors), psiMethod, searchScope);
561 myMethodUsagesRequests = null;
564 }, progress);
567 public static boolean isToCheckMember(PsiDocCommentOwner owner, @NonNls String inspectionToolID) {
568 return getElementMemberSuppressedIn(owner, inspectionToolID) == null;
571 @Nullable
572 public static PsiElement getElementMemberSuppressedIn(final PsiDocCommentOwner owner, final String inspectionToolID) {
573 PsiElement element = getDocCommentToolSuppressedIn(owner, inspectionToolID);
574 if (element != null) return element;
575 element = getAnnotationMemberSuppressedIn(owner, inspectionToolID);
576 if (element != null) return element;
577 PsiDocCommentOwner classContainer = PsiTreeUtil.getParentOfType(owner, PsiClass.class);
578 while (classContainer != null) {
579 element = getDocCommentToolSuppressedIn(classContainer, inspectionToolID);
580 if (element != null) return element;
582 element = getAnnotationMemberSuppressedIn(classContainer, inspectionToolID);
583 if (element != null) return element;
585 classContainer = classContainer.getContainingClass();
587 return null;
590 @SuppressWarnings({"SimplifiableIfStatement"})
591 public boolean isToCheckMember(RefElement owner, InspectionTool tool) {
592 final PsiElement element = owner.getElement();
593 if (RUN_WITH_EDITOR_PROFILE && InspectionProjectProfileManager.getInstance(element.getProject()).getInspectionProfile(element)
594 .getInspectionTool(tool.getShortName()) != tool) {
595 return false;
597 return !((RefElementImpl)owner).isSuppressed(tool.getShortName());
600 @Nullable
601 public static PsiElement getAnnotationMemberSuppressedIn(final PsiModifierListOwner owner, final String inspectionToolID) {
602 PsiModifierList modifierList = owner.getModifierList();
603 Collection<String> suppressedIds = getInspectionIdsSuppressedInAnnotation(modifierList);
604 for (String ids : suppressedIds) {
605 if (isInspectionToolIdMentioned(ids, inspectionToolID)) {
606 return modifierList != null ? modifierList.findAnnotation(SUPPRESS_INSPECTIONS_ANNOTATION_NAME) : null;
609 return null;
612 @Nullable
613 private static PsiElement getDocCommentToolSuppressedIn(final PsiDocCommentOwner owner, final String inspectionToolID) {
614 PsiDocComment docComment = owner.getDocComment();
615 if (docComment != null) {
616 PsiDocTag inspectionTag = docComment.findTagByName(SUPPRESS_INSPECTIONS_TAG_NAME);
617 if (inspectionTag != null && inspectionTag.getValueElement() != null) {
618 String valueText = inspectionTag.getValueElement().getText();
619 if (isInspectionToolIdMentioned(valueText, inspectionToolID)) {
620 return docComment;
624 return null;
627 static boolean isInspectionToolIdMentioned(String inspectionsList, String inspectionToolID) {
628 Iterable<String> ids = StringUtil.tokenize(inspectionsList, "[,]");
630 for (@NonNls String id : ids) {
631 if (id.equals(inspectionToolID) || id.equals("ALL")) return true;
633 return false;
636 @NotNull
637 static Collection<String> getInspectionIdsSuppressedInAnnotation(final PsiModifierListOwner owner) {
638 if (LanguageLevel.JDK_1_5.compareTo(PsiUtil.getLanguageLevel(owner)) > 0) return Collections.emptyList();
639 PsiModifierList modifierList = owner.getModifierList();
640 return getInspectionIdsSuppressedInAnnotation(modifierList);
643 @NotNull
644 private static Collection<String> getInspectionIdsSuppressedInAnnotation(final PsiModifierList modifierList) {
645 if (modifierList == null) {
646 return Collections.emptyList();
648 PsiAnnotation annotation = modifierList.findAnnotation(SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
649 if (annotation == null) {
650 return Collections.emptyList();
652 final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
653 if (attributes.length == 0) {
654 return Collections.emptyList();
656 final PsiAnnotationMemberValue attributeValue = attributes[0].getValue();
657 Collection<String> result = new ArrayList<String>();
658 if (attributeValue instanceof PsiArrayInitializerMemberValue) {
659 final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)attributeValue).getInitializers();
660 for (PsiAnnotationMemberValue annotationMemberValue : initializers) {
661 if (annotationMemberValue instanceof PsiLiteralExpression) {
662 final Object value = ((PsiLiteralExpression)annotationMemberValue).getValue();
663 if (value instanceof String) {
664 result.add((String)value);
669 else if (attributeValue instanceof PsiLiteralExpression) {
670 final Object value = ((PsiLiteralExpression)attributeValue).getValue();
671 if (value instanceof String) {
672 result.add((String)value);
675 return result;
678 public void ignoreElement(final InspectionTool tool, final PsiElement element) {
679 final RefElement refElement = getRefManager().getReference(element);
680 final Set<Pair<InspectionTool, InspectionProfile>> tools = myTools.get(tool.getShortName());
681 if (tools != null){
682 for (Pair<InspectionTool, InspectionProfile> inspectionTool : tools) {
683 inspectionTool.first.ignoreElement(refElement);
688 public UIOptions getUIOptions() {
689 return myUIOptions;
692 public void setSplitterProportion(final float proportion) {
693 myUIOptions.SPLITTER_PROPORTION = proportion;
696 public ToggleAction createToggleAutoscrollAction() {
697 return myUIOptions.myAutoScrollToSourceHandler.createToggleAction();
700 public void installAutoscrollHandler(JTree tree) {
701 myUIOptions.myAutoScrollToSourceHandler.install(tree);
704 private static class ProgressWrapper extends ProgressIndicatorBase {
705 private ProgressIndicator myOriginal;
707 public ProgressWrapper(final ProgressIndicator original) {
708 myOriginal = original;
711 public boolean isCanceled() {
712 return myOriginal.isCanceled();
716 private int getRequestCount() {
717 int sum = 0;
719 sum += getRequestListSize(myClassUsagesRequests);
720 sum += getRequestListSize(myDerivedClassesRequests);
721 sum += getRequestListSize(myDerivedMethodsRequests);
722 sum += getRequestListSize(myFieldUsagesRequests);
723 sum += getRequestListSize(myMethodUsagesRequests);
725 return sum;
728 private static int getRequestListSize(THashMap list) {
729 if (list == null) return 0;
730 return list.size();
733 private static List<PsiElement> getSortedIDs(Map<PsiElement, ?> requests) {
734 final List<PsiElement> result = new ArrayList<PsiElement>();
735 for (PsiElement id : requests.keySet()) {
736 result.add(id);
739 ApplicationManager.getApplication().runReadAction(new Runnable() {
740 public void run() {
741 Collections.sort(result, new Comparator<PsiElement>() {
742 public int compare(PsiElement o1, PsiElement o2) {
743 final PsiFile psiFile1 = o1.getContainingFile();
744 LOG.assertTrue(psiFile1 != null);
745 final PsiFile psiFile2 = o2.getContainingFile();
746 LOG.assertTrue(psiFile2 != null);
747 return psiFile1.getName().compareTo(psiFile2.getName());
753 return result;
756 private PsiReferenceProcessor createReferenceProcessor(final List<UsagesProcessor> processors) {
757 return new PsiReferenceProcessor() {
758 public boolean execute(PsiReference reference) {
759 AnalysisScope scope = getRefManager().getScope();
760 if ((scope.contains(reference.getElement()) && reference.getElement().getContainingFile() instanceof PsiJavaFile) ||
761 PsiTreeUtil.getParentOfType(reference.getElement(), PsiDocComment.class) != null) {
762 return true;
764 UsagesProcessor[] processorsArrayed = processors.toArray(new UsagesProcessor[processors.size()]);
765 for (UsagesProcessor processor : processorsArrayed) {
766 if (!processor.process(reference)) {
767 processors.remove(processor);
771 return !processors.isEmpty();
776 private void launchInspections(final AnalysisScope scope, final InspectionManager manager) {
777 ApplicationManager.getApplication().runWriteAction(new Runnable() {
778 public void run() {
779 PsiDocumentManager.getInstance(myProject).commitAllDocuments();
784 LOG.info("Code inspection started");
786 Runnable runInspection = new Runnable() {
787 public void run() {
788 performInspectionsWithProgress(scope, manager);
793 final Runnable successRunnable = new Runnable() {
794 public void run() {
795 SwingUtilities.invokeLater(new Runnable() {
796 public void run() {
797 LOG.info("Code inspection finished");
799 final InspectionResultsView view = new InspectionResultsView(myProject, RUN_WITH_EDITOR_PROFILE ? null : getCurrentProfile(),
800 scope, GlobalInspectionContextImpl.this,
801 new InspectionRVContentProviderImpl(myProject));
802 if (!view.update() && !getUIOptions().SHOW_ONLY_DIFF) {
803 Messages.showMessageDialog(myProject, InspectionsBundle.message("inspection.no.problems.message"),
804 InspectionsBundle.message("inspection.no.problems.dialog.title"), Messages.getInformationIcon());
805 close(true);
807 else {
808 addView(view);
814 ProgressManager.getInstance()
815 .runProcessWithProgressAsynchronously(myProject, InspectionsBundle.message("inspection.progress.title"), runInspection,
816 successRunnable, null, new PerformAnalysisInBackgroundOption(myProject));
820 private void performInspectionsWithProgress(final AnalysisScope scope, final InspectionManager manager) {
821 try {
822 myProgressIndicator = ProgressManager.getInstance().getProgressIndicator();
823 final PsiManager psiManager = PsiManager.getInstance(myProject);
824 final Application application = ApplicationManager.getApplication();
825 try {
826 application.runReadAction(new Runnable(){
827 public void run() {
828 psiManager.startBatchFilesProcessingMode();
829 ((RefManagerImpl)getRefManager()).inspectionReadActionStarted(); //init manager in read action
832 try {
833 EntryPointsManager.getInstance(getProject()).resolveEntryPoints(getRefManager());
834 List<InspectionTool> needRepeatSearchRequest = new ArrayList<InspectionTool>();
835 runTools(needRepeatSearchRequest, scope, manager);
837 catch (ProcessCanceledException e) {
838 cleanup((InspectionManagerEx)manager);
839 throw e;
840 } catch (Exception e){
841 LOG.error(e);
844 finally {
845 application.runReadAction(new Runnable(){
846 public void run() {
847 psiManager.finishBatchFilesProcessingMode();
852 finally {
853 if (myRefManager != null) {
854 ((RefManagerImpl)getRefManager()).inspectionReadActionFinished();
859 private void performPostRunFindUsages(List<InspectionTool> needRepeatSearchRequest, final InspectionManager manager) {
860 FIND_EXTERNAL_USAGES.setTotalAmount(getRequestCount() * 2);
862 do {
863 processSearchRequests();
864 InspectionTool[] requestors = needRepeatSearchRequest.toArray(new InspectionTool[needRepeatSearchRequest.size()]);
865 for (InspectionTool requestor : requestors) {
866 if (!requestor.queryExternalUsagesRequests(manager)) needRepeatSearchRequest.remove(requestor);
868 int oldSearchRequestCount = FIND_EXTERNAL_USAGES.getTotalAmount();
869 float proportion = FIND_EXTERNAL_USAGES.getProgress();
870 int totalAmount = oldSearchRequestCount + getRequestCount() * 2;
871 FIND_EXTERNAL_USAGES.setTotalAmount(totalAmount);
872 FIND_EXTERNAL_USAGES.setDoneAmount((int)(totalAmount * proportion));
874 while (!needRepeatSearchRequest.isEmpty());
877 private void runTools(final List<InspectionTool> needRepeatSearchRequest, final AnalysisScope scope, final InspectionManager manager) {
878 ((RefManagerImpl)getRefManager()).initializeAnnotators();
879 final HashMap<String, Set<InspectionTool>> usedTools = new HashMap<String, Set<InspectionTool>>();
880 final Map<String, Set<InspectionTool>> localTools = new HashMap<String, Set<InspectionTool>>();
881 initializeTools(scope, usedTools, localTools);
882 for (Set<InspectionTool> tools : usedTools.values()) {
883 for (InspectionTool tool : tools) {
884 try {
885 if (tool.isGraphNeeded()) {
886 ((RefManagerImpl)tool.getRefManager()).findAllDeclarations();
888 tool.runInspection(scope, manager);
889 if (tool.queryExternalUsagesRequests(manager)) {
890 needRepeatSearchRequest.add(tool);
893 catch (ProcessCanceledException e) {
894 throw e;
896 catch (Exception e) {
897 LOG.error(e);
901 performPostRunFindUsages(needRepeatSearchRequest, manager);
902 if (RUN_GLOBAL_TOOLS_ONLY) return;
903 final Set<InspectionTool> currentProfileLocalTools = localTools.get(getCurrentProfile().getName());
904 if (RUN_WITH_EDITOR_PROFILE || currentProfileLocalTools != null && !currentProfileLocalTools.isEmpty()) {
905 final PsiManager psiManager = PsiManager.getInstance(myProject);
906 final InspectionProjectProfileManager profileManager = InspectionProjectProfileManager.getInstance(myProject);
907 scope.accept(new PsiRecursiveElementVisitor() {
908 public void visitReferenceExpression(PsiReferenceExpression expression) {
911 @Override
912 public void visitFile(PsiFile file) {
913 InspectionProfile profile;
914 if (RUN_WITH_EDITOR_PROFILE) {
915 profile = profileManager.getInspectionProfile(file);
917 else {
918 profile = getCurrentProfile();
920 final VirtualFile virtualFile = file.getVirtualFile();
921 if (virtualFile != null) {
922 incrementJobDoneAmount(LOCAL_ANALYSIS, VfsUtil.calcRelativeToProjectPath(virtualFile, myProject));
924 final Set<InspectionTool> tools = localTools.get(profile.getName());
925 final com.intellij.openapi.editor.Document document = ApplicationManager.getApplication().runReadAction(new Computable<com.intellij.openapi.editor.Document>() {
926 @Nullable
927 public com.intellij.openapi.editor.Document compute() {
928 final FileViewProvider viewProvider = psiManager.findViewProvider(virtualFile);
929 return viewProvider != null ? viewProvider.getDocument() : null;
932 if (document == null) return; //do not inspect binary files
933 final LocalInspectionsPass pass =
934 new LocalInspectionsPass(file, document,
936 file.getTextLength(),
937 DaemonCodeAnalyzer.getInstance(myProject).getDaemonExecutorService());
938 try {
939 pass.doInspectInBatch(((InspectionManagerEx)manager), tools.toArray(new InspectionTool[tools.size()]), myProgressIndicator);
941 catch (ProcessCanceledException e) {
942 throw e;
944 catch (Exception e) {
945 LOG.error(e);
947 psiManager.dropResolveCaches();
949 }, false);
953 public void initializeTools(AnalysisScope scope, Map<String, Set<InspectionTool>> tools, Map<String, Set<InspectionTool>> localTools) {
954 myJobDescriptors = new ArrayList<JobDescriptor>();
955 final InspectionProjectProfileManager profileManager = InspectionProjectProfileManager.getInstance(getProject());
956 if (RUN_WITH_EDITOR_PROFILE) {
957 final Set<String> profiles = scope.getActiveInspectionProfiles();
958 for (String profile : profiles) {
959 InspectionProfileWrapper inspectionProfile = profileManager.getProfileWrapper(profile);
960 if (inspectionProfile == null){
961 inspectionProfile = new InspectionProfileWrapper((InspectionProfile)profileManager.getProfile(profile));
962 inspectionProfile.init(getProject()); //offline inspections only
964 processProfileTools(inspectionProfile, tools, localTools);
967 else {
968 InspectionProfileWrapper profile = new InspectionProfileWrapper(getCurrentProfile());
969 processProfileTools(profile, tools, localTools);
970 profile.init(getProject()); //offline inspections only
973 BUILD_GRAPH.setTotalAmount(scope.getFileCount());
974 LOCAL_ANALYSIS.setTotalAmount(scope.getFileCount());
977 private void processProfileTools(final InspectionProfileWrapper inspectionProfile,
978 final Map<String, Set<InspectionTool>> tools,
979 final Map<String, Set<InspectionTool>> localTools) {
980 final InspectionTool[] usedTools = inspectionProfile.getInspectionTools();
981 final Set<InspectionTool> profileTools = new TreeSet<InspectionTool>(new Comparator<InspectionTool>() {
982 public int compare(final InspectionTool tool1, final InspectionTool tool2) {
983 if (tool1.getShortName().equals(DeadCodeInspection.SHORT_NAME)) return -1;
984 if (tool2.getShortName().equals(DeadCodeInspection.SHORT_NAME)) return 1;
985 return tool1.getShortName().compareTo(tool2.getShortName());
988 tools.put(inspectionProfile.getName(), profileTools);
989 final HashSet<InspectionTool> localProfileTools = new HashSet<InspectionTool>();
990 localTools.put(inspectionProfile.getName(), localProfileTools);
991 for (InspectionTool tool : usedTools) {
992 final String shortName = tool.getShortName();
993 final HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
994 if (inspectionProfile.isToolEnabled(key)) {
995 tool.initialize(this);
996 Set<Pair<InspectionTool, InspectionProfile>> sertainTools = myTools.get(shortName);
997 if (sertainTools == null){
998 sertainTools = new HashSet<Pair<InspectionTool, InspectionProfile>>();
999 myTools.put(shortName, sertainTools);
1001 sertainTools.add(Pair.create(tool, inspectionProfile.getInspectionProfile()));
1002 if (tool instanceof LocalInspectionToolWrapper) {
1003 localProfileTools.add(tool);
1004 appendJobDescriptor(LOCAL_ANALYSIS);
1006 else {
1007 profileTools.add(tool);
1008 JobDescriptor[] jobDescriptors = tool.getJobDescriptors();
1009 for (JobDescriptor jobDescriptor : jobDescriptors) {
1010 appendJobDescriptor(jobDescriptor);
1017 public Map<String, Set<Pair<InspectionTool, InspectionProfile>>> getTools() {
1018 return myTools;
1021 private void appendJobDescriptor(JobDescriptor job) {
1022 if (!myJobDescriptors.contains(job)) {
1023 myJobDescriptors.add(job);
1024 job.setDoneAmount(0);
1028 public void close(boolean noSuspisiousCodeFound) {
1029 if (!noSuspisiousCodeFound && (myView == null || myView.isRerun())) return;
1030 final InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManager.getInstance(myProject);
1031 cleanup(managerEx);
1032 managerEx.getUIOptions().save(myUIOptions);
1033 final ContentManager contentManager = getContentManager();
1034 if (contentManager != null) { //null for tests
1035 contentManager.removeContent(myContent);
1037 myView = null;
1040 private void cleanup(final InspectionManagerEx managerEx) {
1041 managerEx.closeRunningContext(this);
1042 for (Set<Pair<InspectionTool, InspectionProfile>> tools : myTools.values()) {
1043 for (Pair<InspectionTool, InspectionProfile> tool : tools) {
1044 tool.first.finalCleanup();
1047 cleanup();
1050 public void refreshViews() {
1051 if (myView != null) {
1052 myView.updateView(false);
1056 public void incrementJobDoneAmount(JobDescriptor job, String message) {
1057 if (myProgressIndicator == null) return;
1059 ProgressManager.getInstance().checkCanceled();
1061 int old = job.getDoneAmount();
1062 job.setDoneAmount(old + 1);
1064 int jobCount = myJobDescriptors.size();
1065 float totalProgress = 0;
1066 for (JobDescriptor jobDescriptor : myJobDescriptors) {
1067 totalProgress += jobDescriptor.getProgress();
1070 totalProgress /= jobCount;
1072 myProgressIndicator.setFraction(totalProgress);
1073 myProgressIndicator.setText(job.getDisplayName() + " " + message);
1077 public void setExternalProfile(InspectionProfile profile) {
1078 myExternalProfile = profile;