fix SingleInspectionProfilePanelTest
[idea/community.git] / java / testFramework / src / com / intellij / codeInsight / daemon / DaemonAnalyzerTestCase.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.codeInsight.daemon;
17
18 import com.intellij.codeHighlighting.Pass;
19 import com.intellij.codeInsight.CodeInsightTestCase;
20 import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx;
21 import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
22 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
23 import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase;
24 import com.intellij.codeInsight.intention.IntentionAction;
25 import com.intellij.codeInsight.intention.IntentionManager;
26 import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler;
27 import com.intellij.codeInspection.InspectionProfile;
28 import com.intellij.codeInspection.InspectionProfileEntry;
29 import com.intellij.codeInspection.InspectionToolProvider;
30 import com.intellij.codeInspection.LocalInspectionTool;
31 import com.intellij.codeInspection.ex.InspectionProfileImpl;
32 import com.intellij.ide.highlighter.JavaFileType;
33 import com.intellij.ide.startup.StartupManagerEx;
34 import com.intellij.ide.startup.impl.StartupManagerImpl;
35 import com.intellij.lang.ExternalAnnotatorsFilter;
36 import com.intellij.lang.LanguageAnnotators;
37 import com.intellij.lang.StdLanguages;
38 import com.intellij.lang.annotation.HighlightSeverity;
39 import com.intellij.lang.injection.InjectedLanguageManager;
40 import com.intellij.lang.java.JavaLanguage;
41 import com.intellij.openapi.application.Result;
42 import com.intellij.openapi.application.ex.PathManagerEx;
43 import com.intellij.openapi.command.WriteCommandAction;
44 import com.intellij.openapi.editor.Document;
45 import com.intellij.openapi.editor.Editor;
46 import com.intellij.openapi.extensions.Extensions;
47 import com.intellij.openapi.module.Module;
48 import com.intellij.openapi.project.Project;
49 import com.intellij.openapi.roots.ModuleRootManager;
50 import com.intellij.openapi.startup.StartupManager;
51 import com.intellij.openapi.util.Pair;
52 import com.intellij.openapi.util.TextRange;
53 import com.intellij.openapi.util.io.FileUtil;
54 import com.intellij.openapi.vfs.*;
55 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
56 import com.intellij.psi.*;
57 import com.intellij.psi.impl.PsiManagerEx;
58 import com.intellij.psi.impl.search.IndexPatternBuilder;
59 import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
60 import com.intellij.psi.xml.XmlFileNSInfoProvider;
61 import com.intellij.testFramework.ExpectedHighlightingData;
62 import com.intellij.testFramework.FileTreeAccessFilter;
63 import com.intellij.testFramework.HighlightTestInfo;
64 import com.intellij.testFramework.InspectionsKt;
65 import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl;
66 import com.intellij.util.IncorrectOperationException;
67 import com.intellij.util.containers.ContainerUtil;
68 import com.intellij.util.ui.UIUtil;
69 import com.intellij.xml.XmlSchemaProvider;
70 import gnu.trove.TIntArrayList;
71 import org.jetbrains.annotations.NonNls;
72 import org.jetbrains.annotations.NotNull;
73
74 import java.io.File;
75 import java.io.IOException;
76 import java.lang.annotation.ElementType;
77 import java.lang.annotation.Retention;
78 import java.lang.annotation.RetentionPolicy;
79 import java.lang.annotation.Target;
80 import java.util.ArrayList;
81 import java.util.Collection;
82 import java.util.List;
83
84 public abstract class DaemonAnalyzerTestCase extends CodeInsightTestCase {
85   private VirtualFileFilter myVirtualFileFilter = new FileTreeAccessFilter();
86
87   @Override
88   protected void setUp() throws Exception {
89     super.setUp();
90
91     final LocalInspectionTool[] tools = configureLocalInspectionTools();
92
93     InspectionsKt.configureInspections(tools, getProject(), getTestRootDisposable());
94
95     DaemonCodeAnalyzerImpl daemonCodeAnalyzer = (DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject());
96     daemonCodeAnalyzer.prepareForTest();
97     final StartupManagerImpl startupManager = (StartupManagerImpl)StartupManagerEx.getInstanceEx(getProject());
98     startupManager.runStartupActivities();
99     startupManager.startCacheUpdate();
100     startupManager.runPostStartupActivities();
101     DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(false);
102
103     if (isPerformanceTest()) {
104       IntentionManager.getInstance().getAvailableIntentionActions();  // hack to avoid slowdowns in PyExtensionFactory
105       PathManagerEx.getTestDataPath(); // to cache stuff
106       ReferenceProvidersRegistry.getInstance(); // pre-load tons of classes
107       InjectedLanguageManager.getInstance(getProject()); // zillion of Dom Sem classes
108       LanguageAnnotators.INSTANCE.allForLanguage(JavaLanguage.INSTANCE); // pile of annotator classes loads
109       LanguageAnnotators.INSTANCE.allForLanguage(StdLanguages.XML);
110       ProblemHighlightFilter.EP_NAME.getExtensions();
111       Extensions.getExtensions(ImplicitUsageProvider.EP_NAME);
112       Extensions.getExtensions(XmlSchemaProvider.EP_NAME);
113       Extensions.getExtensions(XmlFileNSInfoProvider.EP_NAME);
114       Extensions.getExtensions(ExternalAnnotatorsFilter.EXTENSION_POINT_NAME);
115       Extensions.getExtensions(IndexPatternBuilder.EP_NAME);
116     }
117   }
118
119   @Override
120   protected void tearDown() throws Exception {
121     try {
122       DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(true); // return default value to avoid unnecessary save
123       final Project project = getProject();
124       if (project != null) {
125         ((StartupManagerImpl)StartupManager.getInstance(project)).checkCleared();
126         ((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(project)).cleanupAfterTest();
127       }
128     }
129     finally {
130       super.tearDown();
131     }
132     //((VirtualFilePointerManagerImpl)VirtualFilePointerManager.getInstance()).assertPointersDisposed();
133   }
134
135   protected void enableInspectionTool(@NotNull InspectionProfileEntry tool) {
136     InspectionsKt.enableInspectionTool(getProject(), tool, getTestRootDisposable());
137   }
138
139   protected void enableInspectionTools(@NotNull InspectionProfileEntry... tools) {
140     for (InspectionProfileEntry tool : tools) {
141       enableInspectionTool(tool);
142     }
143   }
144
145   protected void enableInspectionToolsFromProvider(InspectionToolProvider toolProvider){
146     try {
147       for (Class c : toolProvider.getInspectionClasses()) {
148         enableInspectionTool((InspectionProfileEntry)c.newInstance());
149       }
150     }
151     catch (Exception e) {
152       throw new RuntimeException(e);
153     }
154   }
155
156   protected void disableInspectionTool(@NotNull String shortName){
157     InspectionProfile profile = InspectionProjectProfileManager.getInstance(getProject()).getCurrentProfile();
158     if (profile.getInspectionTool(shortName, getProject()) != null) {
159       ((InspectionProfileImpl)profile).disableTool(shortName, getProject());
160     }
161   }
162
163   protected LocalInspectionTool[] configureLocalInspectionTools() {
164     return LocalInspectionTool.EMPTY_ARRAY;
165   }
166
167   protected static LocalInspectionTool[] createLocalInspectionTools(final InspectionToolProvider... provider) {
168     final ArrayList<LocalInspectionTool> result = new ArrayList<>();
169     for (InspectionToolProvider toolProvider : provider) {
170       for (Class aClass : toolProvider.getInspectionClasses()) {
171         try {
172           final Object tool = aClass.newInstance();
173           assertTrue(tool instanceof LocalInspectionTool);
174           result.add((LocalInspectionTool)tool);
175         }
176         catch (Exception e) {
177           LOG.error(e);
178         }
179       }
180     }
181     return result.toArray(new LocalInspectionTool[result.size()]);
182   }
183
184   protected void doTest(@NonNls @NotNull String filePath, boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings) throws Exception {
185     configureByFile(filePath);
186     doDoTest(checkWarnings, checkInfos, checkWeakWarnings);
187   }
188
189   protected void doTest(@NonNls @NotNull String filePath, boolean checkWarnings, boolean checkInfos) throws Exception {
190     doTest(filePath, checkWarnings, checkInfos, false);
191   }
192
193   protected void doTest(@NonNls @NotNull String filePath, @NonNls String projectRoot, boolean checkWarnings, boolean checkInfos) throws Exception {
194     configureByFile(filePath, projectRoot);
195     doDoTest(checkWarnings, checkInfos);
196   }
197
198   @NotNull
199   @SuppressWarnings("TestMethodWithIncorrectSignature")
200   protected HighlightTestInfo testFile(@NonNls @NotNull String... filePath) {
201     return new HighlightTestInfo(getTestRootDisposable(), filePath) {
202       @Override
203       public HighlightTestInfo doTest() {
204         try { configureByFiles(projectRoot, filePaths); }
205         catch (Exception e) { throw new RuntimeException(e); }
206         ExpectedHighlightingData data = new JavaExpectedHighlightingData(myEditor.getDocument(), checkWarnings, checkWeakWarnings, checkInfos, myFile);
207         if (checkSymbolNames) data.checkSymbolNames();
208         checkHighlighting(data);
209         return this;
210       }
211     };
212   }
213
214   protected void doTest(@NotNull VirtualFile vFile, boolean checkWarnings, boolean checkInfos) throws Exception {
215     doTest(new VirtualFile[] { vFile }, checkWarnings, checkInfos );
216   }
217
218   protected void doTest(@NotNull VirtualFile[] vFile, boolean checkWarnings, boolean checkInfos) throws Exception {
219     configureByFiles(null, vFile);
220     doDoTest(checkWarnings, checkInfos);
221   }
222
223   protected void doTest(boolean checkWarnings, boolean checkInfos, @NotNull String ... files) throws Exception {
224     configureByFiles(null, files);
225     doDoTest(checkWarnings, checkInfos);
226   }
227
228   @NotNull
229   protected Collection<HighlightInfo> doDoTest(boolean checkWarnings, boolean checkInfos) {
230     return doDoTest(checkWarnings, checkInfos, false);
231   }
232
233   protected Collection<HighlightInfo> doDoTest(final boolean checkWarnings, final boolean checkInfos, final boolean checkWeakWarnings) {
234     return ContainerUtil.filter(
235       checkHighlighting(new ExpectedHighlightingData(myEditor.getDocument(), checkWarnings, checkWeakWarnings, checkInfos, myFile)),
236       info -> info.getSeverity() == HighlightSeverity.INFORMATION && checkInfos ||
237              info.getSeverity() == HighlightSeverity.WARNING && checkWarnings ||
238              info.getSeverity() == HighlightSeverity.WEAK_WARNING && checkWeakWarnings ||
239               info.getSeverity().compareTo(HighlightSeverity.WARNING) > 0);
240   }
241
242   @NotNull
243   protected Collection<HighlightInfo> checkHighlighting(@NotNull final ExpectedHighlightingData data) {
244     data.init();
245     PsiDocumentManager.getInstance(myProject).commitAllDocuments();
246
247     PsiManagerEx.getInstanceEx(getProject()).setAssertOnFileLoadingFilter(myVirtualFileFilter, myTestRootDisposable);
248
249     try {
250       Collection<HighlightInfo> infos = doHighlighting();
251
252       String text = myEditor.getDocument().getText();
253       data.checkLineMarkers(DaemonCodeAnalyzerImpl.getLineMarkers(getDocument(getFile()), getProject()), text);
254       data.checkResult(infos, text);
255       return infos;
256     }
257     finally {
258       PsiManagerEx.getInstanceEx(getProject()).setAssertOnFileLoadingFilter(VirtualFileFilter.NONE, myTestRootDisposable);
259     }
260   }
261
262   @Override
263   protected Editor createEditor(@NotNull VirtualFile file) {
264     if (myVirtualFileFilter instanceof FileTreeAccessFilter) {
265       allowTreeAccessForFile(file);
266     }
267     return super.createEditor(file);
268   }
269
270   protected void setVirtualFileFilter(@NotNull VirtualFileFilter filter) {
271     myVirtualFileFilter = filter;
272   }
273
274   protected void allowTreeAccessForFile(@NotNull VirtualFile file) {
275     assert myVirtualFileFilter instanceof FileTreeAccessFilter : "configured filter does not support this method";
276     ((FileTreeAccessFilter)myVirtualFileFilter).allowTreeAccessForFile(file);
277   }
278
279   protected void allowTreeAccessForAllFiles() {
280     assert myVirtualFileFilter instanceof FileTreeAccessFilter : "configured filter does not support this method";
281     ((FileTreeAccessFilter)myVirtualFileFilter).allowTreeAccessForAllFiles();
282   }
283
284   @NotNull
285   protected List<HighlightInfo> highlightErrors() {
286     return doHighlighting(HighlightSeverity.ERROR);
287   }
288
289   @NotNull
290   protected List<HighlightInfo> doHighlighting(@NotNull HighlightSeverity minSeverity) {
291     return filter(doHighlighting(), minSeverity);
292   }
293
294   @NotNull
295   protected List<HighlightInfo> doHighlighting() {
296     PsiDocumentManager.getInstance(myProject).commitAllDocuments();
297
298     TIntArrayList toIgnore = new TIntArrayList();
299     if (!doTestLineMarkers()) {
300       toIgnore.add(Pass.UPDATE_OVERRIDDEN_MARKERS);
301       toIgnore.add(Pass.VISIBLE_LINE_MARKERS);
302       toIgnore.add(Pass.LINE_MARKERS);
303     }
304
305     if (!doExternalValidation()) {
306       toIgnore.add(Pass.EXTERNAL_TOOLS);
307     }
308     if (forceExternalValidation()) {
309       toIgnore.add(Pass.LINE_MARKERS);
310       toIgnore.add(Pass.LOCAL_INSPECTIONS);
311       toIgnore.add(Pass.WHOLE_FILE_LOCAL_INSPECTIONS);
312       toIgnore.add(Pass.POPUP_HINTS);
313       toIgnore.add(Pass.UPDATE_ALL);
314       toIgnore.add(Pass.UPDATE_OVERRIDDEN_MARKERS);
315       toIgnore.add(Pass.VISIBLE_LINE_MARKERS);
316     }
317
318     boolean canChange = canChangeDocumentDuringHighlighting();
319     List<HighlightInfo> infos = CodeInsightTestFixtureImpl.instantiateAndRun(getFile(), getEditor(), toIgnore.toNativeArray(), canChange);
320
321     if (!canChange) {
322       Document document = getDocument(getFile());
323       DaemonCodeAnalyzerEx daemonCodeAnalyzer = DaemonCodeAnalyzerEx.getInstanceEx(myProject);
324       daemonCodeAnalyzer.getFileStatusMap().assertAllDirtyScopesAreNull(document);
325     }
326
327     return infos;
328   }
329
330   @Retention(RetentionPolicy.RUNTIME)
331   @Target({ElementType.METHOD, ElementType.TYPE})
332   public @interface CanChangeDocumentDuringHighlighting {}
333
334   private boolean canChangeDocumentDuringHighlighting() {
335     return annotatedWith(CanChangeDocumentDuringHighlighting.class);
336   }
337
338   @NotNull
339   public static List<HighlightInfo> filter(@NotNull List<HighlightInfo> infos, @NotNull HighlightSeverity minSeverity) {
340     ArrayList<HighlightInfo> result = new ArrayList<>();
341     for (final HighlightInfo info : infos) {
342       if (info.getSeverity().compareTo(minSeverity) >= 0) result.add(info);
343     }
344     return result;
345   }
346
347   protected boolean doTestLineMarkers() {
348     return false;
349   }
350
351   protected boolean doExternalValidation() {
352     return true;
353   }
354
355   protected boolean forceExternalValidation() {
356     return false;
357   }
358
359   protected static void findAndInvokeIntentionAction(@NotNull Collection<HighlightInfo> infos, @NotNull String intentionActionName, @NotNull Editor editor,
360                                                      @NotNull PsiFile file) throws IncorrectOperationException {
361     IntentionAction intentionAction = findIntentionAction(infos, intentionActionName, editor, file);
362
363     assertNotNull(intentionActionName, intentionAction);
364     assertTrue(ShowIntentionActionsHandler.chooseActionAndInvoke(file, editor, intentionAction, intentionActionName));
365     UIUtil.dispatchAllInvocationEvents();
366   }
367
368   protected static IntentionAction findIntentionAction(@NotNull Collection<HighlightInfo> infos, @NotNull String intentionActionName, @NotNull Editor editor,
369                                                        @NotNull PsiFile file) {
370     List<IntentionAction> actions = LightQuickFixTestCase.getAvailableActions(editor, file);
371     IntentionAction intentionAction = LightQuickFixTestCase.findActionWithText(actions, intentionActionName);
372
373     if (intentionAction == null) {
374       final List<IntentionAction> availableActions = new ArrayList<>();
375
376       for (HighlightInfo info :infos) {
377         if (info.quickFixActionRanges != null) {
378           for (Pair<HighlightInfo.IntentionActionDescriptor, TextRange> pair : info.quickFixActionRanges) {
379             IntentionAction action = pair.first.getAction();
380             if (action.isAvailable(file.getProject(), editor, file)) availableActions.add(action);
381           }
382         }
383       }
384
385       intentionAction = LightQuickFixTestCase.findActionWithText(
386         availableActions,
387         intentionActionName
388       );
389     }
390     return intentionAction;
391   }
392
393   public void checkHighlighting(Editor editor, boolean checkWarnings, boolean checkInfos) {
394     setActiveEditor(editor);
395     doDoTest(checkWarnings, checkInfos);
396   }
397
398   public PsiClass createClass(String text) throws IOException {
399     return createClass(myModule, text);
400   }
401
402   protected PsiClass createClass(final Module module, final String text) throws IOException {
403     return new WriteCommandAction<PsiClass>(getProject()) {
404       @Override
405       protected void run(@NotNull Result<PsiClass> result) throws Throwable {
406         final PsiFileFactory factory = PsiFileFactory.getInstance(getProject());
407         final PsiJavaFile javaFile = (PsiJavaFile)factory.createFileFromText("a.java", JavaFileType.INSTANCE, text);
408         final String qname = javaFile.getClasses()[0].getQualifiedName();
409         assertNotNull(qname);
410         final VirtualFile[] files = ModuleRootManager.getInstance(module).getSourceRoots();
411         File dir;
412         if (files.length > 0) {
413           dir = VfsUtilCore.virtualToIoFile(files[0]);
414         }
415         else {
416           dir = createTempDirectory();
417           VirtualFile vDir =
418             LocalFileSystem.getInstance().refreshAndFindFileByPath(dir.getCanonicalPath().replace(File.separatorChar, '/'));
419           addSourceContentToRoots(module, vDir);
420         }
421
422         File file = new File(dir, qname.replace('.', '/') + ".java");
423         FileUtil.createIfDoesntExist(file);
424         VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(file.getCanonicalPath().replace(File.separatorChar, '/'));
425         assertNotNull(vFile);
426         VfsUtil.saveText(vFile, text);
427         PsiJavaFile psiFile = (PsiJavaFile)myPsiManager.findFile(vFile);
428         assertNotNull(psiFile);
429         PsiClass psiClass = psiFile.getClasses()[0];
430         result.setResult(psiClass);
431
432       }
433     }.execute().throwException().getResultObject();
434   }
435 }