2 * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved.
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
;
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
) {
111 myUIOptions
= ((InspectionManagerEx
)InspectionManager
.getInstance(project
)).getUIOptions().copy();
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) {
130 public Project
getProject() {
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) {
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
) {
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
) {
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();
263 EntryPointsManager
.getInstance(getProject()).cleanup();
265 if (myRefManager
!= null) {
266 ((RefManagerImpl
)myRefManager
).cleanup();
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());
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;
293 getContentManager().removeContent(myContent
);
295 ApplicationManager
.getApplication().invokeLater(new Runnable() {
297 myCurrentScope
= scope
;
298 launchInspections(scope
, manager
);
305 public RefManager
getRefManager() {
306 if (myRefManager
== null) {
307 myRefManager
= new RefManagerImpl(myProject
, myCurrentScope
, this);
313 public void launchInspectionsOffline(final AnalysisScope scope
,
314 final String outputPath
,
315 final boolean runWithEditorSettings
,
316 final boolean runGlobalToolsOnly
,
317 final InspectionManager manager
) {
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
;
328 ApplicationManager
.getApplication().runReadAction(new Runnable() {
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();
346 tool
.updateContent();
347 if (tool
.hasReportedProblems()) {
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;
359 new File(outputPath
).mkdirs();
360 final File file
= new File(outputPath
, toolName
+ ext
);
362 outStream
= localInspectionFilePreparations(file
, outStream
, isLocalToolAttribute
, isLocalTool
);
365 PathMacroManager
.getInstance(getProject()).collapsePaths(doc
.getRootElement());
366 outStream
= new BufferedOutputStream(new FileOutputStream(file
));
367 JDOMUtil
.writeDocument(doc
, outStream
, "\n");
370 catch (IOException e
) {
374 if (outStream
!= null) {
378 catch (IOException e
) {
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;
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());
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() {
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
) {
440 public boolean isSearchInModuleContent(Module aModule
) {
444 public boolean isSearchInLibraries() {
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() {
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() {
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() {
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() {
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() {
556 helper
.processReferencesIncludingOverriding(createReferenceProcessor(processors
), psiMethod
, searchScope
);
561 myMethodUsagesRequests
= null;
567 public static boolean isToCheckMember(PsiDocCommentOwner owner
, @NonNls String inspectionToolID
) {
568 return getElementMemberSuppressedIn(owner
, inspectionToolID
) == null;
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();
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
) {
597 return !((RefElementImpl
)owner
).isSuppressed(tool
.getShortName());
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;
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
)) {
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;
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
);
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
);
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());
682 for (Pair
<InspectionTool
, InspectionProfile
> inspectionTool
: tools
) {
683 inspectionTool
.first
.ignoreElement(refElement
);
688 public UIOptions
getUIOptions() {
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() {
719 sum
+= getRequestListSize(myClassUsagesRequests
);
720 sum
+= getRequestListSize(myDerivedClassesRequests
);
721 sum
+= getRequestListSize(myDerivedMethodsRequests
);
722 sum
+= getRequestListSize(myFieldUsagesRequests
);
723 sum
+= getRequestListSize(myMethodUsagesRequests
);
728 private static int getRequestListSize(THashMap list
) {
729 if (list
== null) return 0;
733 private static List
<PsiElement
> getSortedIDs(Map
<PsiElement
, ?
> requests
) {
734 final List
<PsiElement
> result
= new ArrayList
<PsiElement
>();
735 for (PsiElement id
: requests
.keySet()) {
739 ApplicationManager
.getApplication().runReadAction(new Runnable() {
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());
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) {
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() {
779 PsiDocumentManager
.getInstance(myProject
).commitAllDocuments();
784 LOG
.info("Code inspection started");
786 Runnable runInspection
= new Runnable() {
788 performInspectionsWithProgress(scope
, manager
);
793 final Runnable successRunnable
= new Runnable() {
795 SwingUtilities
.invokeLater(new Runnable() {
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());
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
) {
822 myProgressIndicator
= ProgressManager
.getInstance().getProgressIndicator();
823 final PsiManager psiManager
= PsiManager
.getInstance(myProject
);
824 final Application application
= ApplicationManager
.getApplication();
826 application
.runReadAction(new Runnable(){
828 psiManager
.startBatchFilesProcessingMode();
829 ((RefManagerImpl
)getRefManager()).inspectionReadActionStarted(); //init manager in read action
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
);
840 } catch (Exception e
){
845 application
.runReadAction(new Runnable(){
847 psiManager
.finishBatchFilesProcessingMode();
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);
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
) {
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
) {
896 catch (Exception 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
) {
912 public void visitFile(PsiFile file
) {
913 InspectionProfile profile
;
914 if (RUN_WITH_EDITOR_PROFILE
) {
915 profile
= profileManager
.getInspectionProfile(file
);
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
>() {
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());
939 pass
.doInspectInBatch(((InspectionManagerEx
)manager
), tools
.toArray(new InspectionTool
[tools
.size()]), myProgressIndicator
);
941 catch (ProcessCanceledException e
) {
944 catch (Exception e
) {
947 psiManager
.dropResolveCaches();
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
);
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
);
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() {
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
);
1032 managerEx
.getUIOptions().save(myUIOptions
);
1033 final ContentManager contentManager
= getContentManager();
1034 if (contentManager
!= null) { //null for tests
1035 contentManager
.removeContent(myContent
);
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();
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
;