1 package com
.intellij
.codeInsight
.daemon
;
3 import com
.intellij
.codeHighlighting
.HighlightDisplayLevel
;
4 import com
.intellij
.codeHighlighting
.Pass
;
5 import com
.intellij
.codeHighlighting
.TextEditorHighlightingPass
;
6 import com
.intellij
.codeInsight
.CodeInsightTestCase
;
7 import com
.intellij
.codeInsight
.daemon
.impl
.*;
8 import com
.intellij
.codeInsight
.daemon
.quickFix
.LightQuickFixTestCase
;
9 import com
.intellij
.codeInsight
.intention
.IntentionAction
;
10 import com
.intellij
.codeInspection
.InspectionProfileEntry
;
11 import com
.intellij
.codeInspection
.InspectionToolProvider
;
12 import com
.intellij
.codeInspection
.LocalInspectionTool
;
13 import com
.intellij
.codeInspection
.ModifiableModel
;
14 import com
.intellij
.codeInspection
.ex
.InspectionProfileImpl
;
15 import com
.intellij
.codeInspection
.ex
.InspectionTool
;
16 import com
.intellij
.codeInspection
.ex
.LocalInspectionToolWrapper
;
17 import com
.intellij
.codeInspection
.ex
.ToolsImpl
;
18 import com
.intellij
.ide
.startup
.StartupManagerEx
;
19 import com
.intellij
.ide
.startup
.impl
.StartupManagerImpl
;
20 import com
.intellij
.lang
.annotation
.HighlightSeverity
;
21 import com
.intellij
.openapi
.Disposable
;
22 import com
.intellij
.openapi
.editor
.Document
;
23 import com
.intellij
.openapi
.editor
.Editor
;
24 import com
.intellij
.openapi
.fileTypes
.FileType
;
25 import com
.intellij
.openapi
.fileTypes
.FileTypeManager
;
26 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
27 import com
.intellij
.openapi
.module
.Module
;
28 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
29 import com
.intellij
.openapi
.roots
.ModuleRootManager
;
30 import com
.intellij
.openapi
.startup
.StartupManager
;
31 import com
.intellij
.openapi
.util
.Disposer
;
32 import com
.intellij
.openapi
.util
.Pair
;
33 import com
.intellij
.openapi
.util
.TextRange
;
34 import com
.intellij
.openapi
.util
.io
.FileUtil
;
35 import com
.intellij
.openapi
.vfs
.LocalFileSystem
;
36 import com
.intellij
.openapi
.vfs
.VfsUtil
;
37 import com
.intellij
.openapi
.vfs
.VirtualFile
;
38 import com
.intellij
.openapi
.vfs
.VirtualFileFilter
;
39 import com
.intellij
.openapi
.vfs
.impl
.VirtualFilePointerManagerImpl
;
40 import com
.intellij
.profile
.codeInspection
.InspectionProfileManager
;
41 import com
.intellij
.profile
.codeInspection
.InspectionProjectProfileManager
;
42 import com
.intellij
.psi
.*;
43 import com
.intellij
.psi
.impl
.JavaPsiFacadeEx
;
44 import com
.intellij
.psi
.impl
.source
.tree
.TreeElement
;
45 import com
.intellij
.psi
.impl
.source
.tree
.TreeUtil
;
46 import com
.intellij
.psi
.search
.GlobalSearchScope
;
47 import com
.intellij
.psi
.search
.UsageSearchContext
;
48 import com
.intellij
.testFramework
.ExpectedHighlightingData
;
49 import com
.intellij
.util
.IncorrectOperationException
;
50 import gnu
.trove
.THashMap
;
51 import gnu
.trove
.THashSet
;
52 import gnu
.trove
.TIntArrayList
;
53 import org
.jetbrains
.annotations
.NonNls
;
54 import org
.jetbrains
.annotations
.NotNull
;
57 import java
.io
.IOException
;
60 public abstract class DaemonAnalyzerTestCase
extends CodeInsightTestCase
{
61 private final Map
<String
, LocalInspectionTool
> myAvailableTools
= new THashMap
<String
, LocalInspectionTool
>();
62 private final Map
<String
, LocalInspectionToolWrapper
> myAvailableLocalTools
= new THashMap
<String
, LocalInspectionToolWrapper
>();
63 private boolean toInitializeDaemon
;
64 protected final Set
<VirtualFile
> myAddedClasses
= new THashSet
<VirtualFile
>();
66 protected void setUp() throws Exception
{
68 ((VirtualFilePointerManagerImpl
)VirtualFilePointerManagerImpl
.getInstance()).cleanupForNextTest();
70 final LocalInspectionTool
[] tools
= configureLocalInspectionTools();
71 for (LocalInspectionTool tool
: tools
) {
72 enableInspectionTool(tool
);
75 final InspectionProfileImpl profile
= new InspectionProfileImpl(PROFILE
) {
77 public ModifiableModel
getModifiableModel() {
83 public InspectionProfileEntry
[] getInspectionTools(PsiElement element
) {
84 final Collection
<LocalInspectionToolWrapper
> tools
= myAvailableLocalTools
.values();
85 return tools
.toArray(new LocalInspectionToolWrapper
[tools
.size()]);
89 public List
<ToolsImpl
> getAllEnabledInspectionTools() {
90 List
<ToolsImpl
> result
= new ArrayList
<ToolsImpl
>();
91 for (InspectionProfileEntry entry
: getInspectionTools(null)) {
92 result
.add(new ToolsImpl(entry
, entry
.getDefaultLevel(), true));
97 public boolean isToolEnabled(HighlightDisplayKey key
, PsiElement element
) {
98 return key
!= null && myAvailableTools
.containsKey(key
.toString());
101 public HighlightDisplayLevel
getErrorLevel(@NotNull HighlightDisplayKey key
, PsiElement element
) {
102 final LocalInspectionTool localInspectionTool
= key
== null ?
null : myAvailableTools
.get(key
.toString());
103 return localInspectionTool
!= null ? localInspectionTool
.getDefaultLevel() : HighlightDisplayLevel
.WARNING
;
106 public InspectionTool
getInspectionTool(@NotNull String shortName
, @NotNull PsiElement element
) {
107 return myAvailableLocalTools
.get(shortName
);
110 final InspectionProfileManager inspectionProfileManager
= InspectionProfileManager
.getInstance();
111 inspectionProfileManager
.addProfile(profile
);
112 inspectionProfileManager
.setRootProfile(PROFILE
);
113 Disposer
.register(getProject(), new Disposable() {
114 public void dispose() {
115 inspectionProfileManager
.deleteProfile(PROFILE
);
118 InspectionProjectProfileManager
.getInstance(getProject()).updateProfile(profile
);
119 InspectionProjectProfileManager
.getInstance(getProject()).setProjectProfile(profile
.getName());
120 DaemonCodeAnalyzerImpl daemonCodeAnalyzer
= (DaemonCodeAnalyzerImpl
)DaemonCodeAnalyzer
.getInstance(getProject());
121 toInitializeDaemon
= !daemonCodeAnalyzer
.isInitialized();
122 if (toInitializeDaemon
) {
123 daemonCodeAnalyzer
.projectOpened();
125 ((StartupManagerImpl
)StartupManagerEx
.getInstanceEx(getProject())).runStartupActivities();
126 ((StartupManagerImpl
)StartupManagerEx
.getInstanceEx(getProject())).runPostStartupActivities();
129 protected void tearDown() throws Exception
{
130 ((StartupManagerImpl
)StartupManager
.getInstance(getProject())).checkCleared();
131 if (toInitializeDaemon
) {
132 DaemonCodeAnalyzer
.getInstance(getProject()).projectClosed();
135 ((VirtualFilePointerManagerImpl
)VirtualFilePointerManagerImpl
.getInstance()).assertPointersDisposed();
138 protected void enableInspectionTool(LocalInspectionTool tool
){
139 final String shortName
= tool
.getShortName();
140 final HighlightDisplayKey key
= HighlightDisplayKey
.find(shortName
);
142 HighlightDisplayKey
.register(shortName
, tool
.getDisplayName(), tool
.getID());
144 myAvailableTools
.put(shortName
, tool
);
145 myAvailableLocalTools
.put(shortName
, new LocalInspectionToolWrapper(tool
));
148 protected void enableInspectionToolsFromProvider(InspectionToolProvider toolProvider
){
150 for(Class c
:toolProvider
.getInspectionClasses()) {
151 enableInspectionTool((LocalInspectionTool
)c
.newInstance());
154 catch (Exception e
) {
155 throw new RuntimeException(e
);
159 protected void disableInspectionTool(String shortName
){
160 myAvailableTools
.remove(shortName
);
161 myAvailableLocalTools
.remove(shortName
);
164 protected LocalInspectionTool
[] configureLocalInspectionTools() {
165 return new LocalInspectionTool
[0];
168 protected static LocalInspectionTool
[] createLocalInspectionTools(final InspectionToolProvider
... provider
) {
169 final ArrayList
<LocalInspectionTool
> result
= new ArrayList
<LocalInspectionTool
>();
170 for (InspectionToolProvider toolProvider
: provider
) {
171 for (Class aClass
: toolProvider
.getInspectionClasses()) {
174 tool
= aClass
.newInstance();
175 assertTrue(tool
instanceof LocalInspectionTool
);
176 result
.add((LocalInspectionTool
)tool
);
178 catch (Exception e
) {
183 return result
.toArray(new LocalInspectionTool
[result
.size()]);
186 protected void doTest(String filePath
, boolean checkWarnings
, boolean checkInfos
, boolean checkWeakWarnings
) throws Exception
{
187 configureByFile(filePath
);
188 doDoTest(checkWarnings
, checkInfos
, checkWeakWarnings
);
191 protected void doTest(String filePath
, boolean checkWarnings
, boolean checkInfos
) throws Exception
{
192 doTest(filePath
, checkWarnings
, checkInfos
, false);
195 protected void doTest(@NonNls String filePath
, @NonNls String projectRoot
, boolean checkWarnings
, boolean checkInfos
) throws Exception
{
196 configureByFile(filePath
, projectRoot
);
197 doDoTest(checkWarnings
, checkInfos
);
200 protected void doTest(VirtualFile vFile
, boolean checkWarnings
, boolean checkInfos
) throws Exception
{
201 doTest(new VirtualFile
[] { vFile
}, checkWarnings
, checkInfos
);
204 protected void doTest(VirtualFile
[] vFile
, boolean checkWarnings
, boolean checkInfos
) throws Exception
{
205 configureByFiles(null, vFile
);
206 doDoTest(checkWarnings
, checkInfos
);
209 protected Collection
<HighlightInfo
> doDoTest(boolean checkWarnings
, boolean checkInfos
) {
210 return doDoTest(checkWarnings
, checkInfos
, false);
213 protected Collection
<HighlightInfo
> doDoTest(boolean checkWarnings
, boolean checkInfos
, boolean checkWeakWarnings
) {
215 return checkHighlighting(new ExpectedHighlightingData(myEditor
.getDocument(),checkWarnings
, checkWeakWarnings
, checkInfos
, myFile
));
218 protected Collection
<HighlightInfo
> checkHighlighting(final ExpectedHighlightingData data
) {
219 PsiDocumentManager
.getInstance(myProject
).commitAllDocuments();
222 TreeUtil
.clearCaches((TreeElement
)myFile
.getNode());
224 //to initialize caches
225 myPsiManager
.getCacheManager().getFilesWithWord("XXX", UsageSearchContext
.IN_COMMENTS
, GlobalSearchScope
.allScope(myProject
), true);
226 VirtualFileFilter javaFilesFilter
= new VirtualFileFilter() {
227 public boolean accept(VirtualFile file
) {
228 if (myAddedClasses
.contains(file
)) return false;
230 FileType fileType
= FileTypeManager
.getInstance().getFileTypeByFile(file
);
231 return (fileType
== StdFileTypes
.JAVA
|| fileType
== StdFileTypes
.CLASS
) && !file
.getName().equals("package-info.java");
234 final JavaPsiFacadeEx facade
= getJavaFacade();
235 if (facade
!= null) {
236 facade
.setAssertOnFileLoadingFilter(javaFilesFilter
); // check repository work
239 Collection
<HighlightInfo
> infos
= doHighlighting();
241 if (facade
!= null) {
242 facade
.setAssertOnFileLoadingFilter(VirtualFileFilter
.NONE
);
245 String text
= myEditor
.getDocument().getText();
246 data
.checkLineMarkers(DaemonCodeAnalyzerImpl
.getLineMarkers(getDocument(getFile()), getProject()), text
);
247 data
.checkResult(infos
, text
);
251 public void allowTreeAccessForFile(final VirtualFile file
) {
252 myAddedClasses
.add(file
);
255 protected Collection
<HighlightInfo
> highlightErrors() {
256 return filter(doHighlighting(), HighlightSeverity
.ERROR
);
259 protected List
<HighlightInfo
> doHighlighting() {
260 PsiDocumentManager
.getInstance(myProject
).commitAllDocuments();
262 TIntArrayList toIgnore
= new TIntArrayList();
263 if (!doTestLineMarkers()) {
264 toIgnore
.add(Pass
.UPDATE_OVERRIDEN_MARKERS
);
265 toIgnore
.add(Pass
.VISIBLE_LINE_MARKERS
);
266 toIgnore
.add(Pass
.LINE_MARKERS
);
268 ProgressIndicator progress
= new DaemonProgressIndicator();
269 List
<TextEditorHighlightingPass
> passes
= TextEditorHighlightingPassRegistrarEx
.getInstanceEx(getProject()).instantiatePasses(getFile(), getEditor(), toIgnore
.toNativeArray());
271 for(Iterator
<TextEditorHighlightingPass
> i
= passes
.iterator();i
.hasNext();) {
272 final TextEditorHighlightingPass pass
= i
.next();
274 if ((!(pass
instanceof ExternalToolPass
) && forceExternalValidation()) ||
275 (pass
instanceof ExternalToolPass
&& !forceExternalValidation() && !doExternalValidation())
281 for (TextEditorHighlightingPass pass
: passes
) {
282 pass
.collectInformation(progress
);
284 for (TextEditorHighlightingPass pass
: passes
) {
285 pass
.applyInformationToEditor();
288 if (doTestLineMarkers()) {
289 Document document
= getDocument(getFile());
290 assertTrue(((DaemonCodeAnalyzerImpl
)DaemonCodeAnalyzer
.getInstance(getProject())).getFileStatusMap().allDirtyScopesAreNull(document
));
293 List
<HighlightInfo
> infos
= DaemonCodeAnalyzerImpl
.getHighlights(getEditor().getDocument(), getProject());
294 return infos
== null ? Collections
.<HighlightInfo
>emptyList() : new ArrayList
<HighlightInfo
>(infos
);
297 public static List
<HighlightInfo
> filter(final List
<HighlightInfo
> infos
, HighlightSeverity minSeverity
) {
298 ArrayList
<HighlightInfo
> result
= new ArrayList
<HighlightInfo
>();
299 for (final HighlightInfo info
: infos
) {
300 if (info
.getSeverity().compareTo(minSeverity
) >= 0) result
.add(info
);
305 protected boolean doTestLineMarkers() {
309 protected boolean doExternalValidation() {
313 protected boolean forceExternalValidation() {
317 protected static void findAndInvokeIntentionAction(final Collection
<HighlightInfo
> infos
, String intentionActionName
, final Editor editor
,
318 final PsiFile file
) throws IncorrectOperationException
{
319 IntentionAction intentionAction
= findIntentionAction(infos
, intentionActionName
, editor
, file
);
321 assertNotNull(intentionAction
);
322 intentionAction
.invoke(file
.getProject(), editor
, file
);
325 protected static IntentionAction
findIntentionAction(final Collection
<HighlightInfo
> infos
, final String intentionActionName
, final Editor editor
,
326 final PsiFile file
) {
327 List
<IntentionAction
> actions
= LightQuickFixTestCase
.getAvailableActions(editor
, file
);
328 IntentionAction intentionAction
= LightQuickFixTestCase
.findActionWithText(actions
, intentionActionName
);
330 if (intentionAction
== null) {
331 final List
<IntentionAction
> availableActions
= new ArrayList
<IntentionAction
>();
333 for (HighlightInfo info
:infos
) {
334 if (info
.quickFixActionRanges
!= null) {
335 for (Pair
<HighlightInfo
.IntentionActionDescriptor
, TextRange
> pair
: info
.quickFixActionRanges
) {
336 IntentionAction action
= pair
.first
.getAction();
337 if (action
.isAvailable(file
.getProject(), editor
, file
)) availableActions
.add(action
);
342 intentionAction
= LightQuickFixTestCase
.findActionWithText(
347 return intentionAction
;
350 public void checkHighlighting(Editor editor
, boolean checkWarnings
, boolean checkInfos
) {
351 setActiveEditor(editor
);
352 doDoTest(checkWarnings
, checkInfos
);
355 public PsiClass
createClass(String text
) throws IOException
{
356 return createClass(myModule
, text
);
359 protected PsiClass
createClass(final Module module
, final String text
) throws IOException
{
360 final String qname
= ((PsiJavaFile
)PsiFileFactory
.getInstance(getProject()).createFileFromText("a.java", text
)).getClasses()[0].getQualifiedName();
361 final VirtualFile
[] files
= ModuleRootManager
.getInstance(module
).getSourceRoots();
363 if (files
.length
> 0) {
364 dir
= VfsUtil
.virtualToIoFile(files
[0]);
367 dir
= createTempDir("unitTest");
368 VirtualFile vDir
= LocalFileSystem
.getInstance().refreshAndFindFileByPath(dir
.getCanonicalPath().replace(File
.separatorChar
, '/'));
369 addSourceContentToRoots(module
, vDir
);
372 File file
= new File(dir
, qname
.replace('.', '/') + ".java");
373 FileUtil
.createIfDoesntExist(file
);
374 VirtualFile vFile
= LocalFileSystem
.getInstance().refreshAndFindFileByPath(file
.getCanonicalPath().replace(File
.separatorChar
, '/'));
375 VfsUtil
.saveText(vFile
, text
);
376 return ((PsiJavaFile
)myPsiManager
.findFile(vFile
)).getClasses()[0];