blob: c593d04464f0ec266d5b6ab3aa542b16475b844a [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created by IntelliJ IDEA.
* User: cdr
* Date: Jul 31, 2007
* Time: 2:39:56 PM
*/
package com.intellij.codeInsight.daemon;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ex.InspectionToolRegistrar;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection;
import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.SkipSlowTestLocally;
import com.intellij.util.text.CharArrayUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@SkipSlowTestLocally
public class HighlightStressTest extends LightDaemonAnalyzerTestCase {
@NotNull
@Override
protected LocalInspectionTool[] configureLocalInspectionTools() {
if ("RandomEditingForUnused".equals(getTestName(false))) {
return new LocalInspectionTool[]{new UnusedSymbolLocalInspection(), new UnusedImportLocalInspection(),};
}
List<InspectionToolWrapper> all = InspectionToolRegistrar.getInstance().createTools();
List<LocalInspectionTool> locals = new ArrayList<LocalInspectionTool>();
for (InspectionToolWrapper tool : all) {
if (tool instanceof LocalInspectionToolWrapper) {
LocalInspectionTool e = ((LocalInspectionToolWrapper)tool).getTool();
locals.add(e);
}
}
return locals.toArray(new LocalInspectionTool[locals.size()]);
}
@NonNls private static final String text = "import java.util.*; class X { void f ( ) { "
+ "List < String > ls = new ArrayList < String > ( 1 ) ; ls . toString ( ) ; \n"
+ "List < Integer > is = new ArrayList < Integer > ( 1 ) ; is . toString ( ) ; \n"
+ "List i = new ArrayList ( 1 ) ; i . toString ( ) ; \n"
+ "Collection < Number > l2 = new ArrayList < Number > ( 10 ) ; l2 . toString ( ) ; \n"
+ "Collection < Number > l22 = new ArrayList < Number > ( ) ; l22 . toString ( ) ; \n"
+ "Map < Number , String > l3 = new HashMap < Number , String > ( 10 ) ; l3 . toString ( ) ; \n"
+ "Map < String , String > m = new HashMap < String , String > ( ) ; m . toString ( ) ; \n"
+ "Map < String , String > m1 = new HashMap < String , String > ( ) ; m1 . toString ( ) ; \n"
+ "Map < String , String > m2 = new HashMap < String , String > ( ) ; m2 . toString ( ) ; \n"
+ "Map < String , String > m3 = new HashMap < String , String > ( ) ; m3 . toString ( ) ; \n"
+ "Map < String , String > mi = new HashMap < String , String > ( 1 ) ; mi . toString ( ) ; \n"
+ "Map < String , String > mi1 = new HashMap < String , String > ( 1 ) ; mi1 . toString ( ) ; \n"
+ "Map < String , String > mi2 = new HashMap < String , String > ( 1 ) ; mi2 . toString ( ) ; \n"
+ "Map < String , String > mi3 = new HashMap < String , String > ( 1 ) ; mi3 . toString ( ) ; \n"
+ "Map < Number , String > l4 = new HashMap < Number , String > ( ) ; l4 . toString ( ) ; \n"
+ "Map < Number , String > l5 = new HashMap < Number , String > ( l4 ) ; l5 . toString ( ) ; \n"
+ "HashMap < Number , String > l6 = new HashMap < Number , String > ( ) ; l6 . toString ( ) ; \n"
+ "Map < List < Integer > , Map < String , List < String > > > l7 = new HashMap ( 1 ) ; l7 . toString ( ) ; \n"
+ "java . util . Map < java . util . List < Integer > , java . util . Map < String , java . util . List < String > > > l77 = new java . util . HashMap ( 1 ) ; l77 . toString ( ) ; \n"
+ " } } ";
public void testAllTheseConcurrentThreadsDoNotCrashAnything() throws Exception {
long time = System.currentTimeMillis();
for (int i = 0; i < 20/*00000*/; i++) {
//System.out.println("i = " + i);
getPsiManager().dropResolveCaches();
((PsiManagerEx)getPsiManager()).getFileManager().cleanupForNextTest();
DaemonCodeAnalyzer.getInstance(getProject()).restart();
configureFromFileText("Stress.java", text);
List<HighlightInfo> infos = doHighlighting();
assertEmpty(DaemonAnalyzerTestCase.filter(infos, HighlightSeverity.ERROR));
UIUtil.dispatchAllInvocationEvents();
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
}
System.out.println(System.currentTimeMillis() - time+"ms");
}
public void _testHugeFile() throws Exception {
@NonNls String filePath = "/psi/resolve/Thinlet.java";
configureByFile(filePath);
doHighlighting();
int N = 42;
long[] time = new long[N];
for (int i = 0; i < N; i++) {
DaemonCodeAnalyzer.getInstance(getProject()).restart();
long start = System.currentTimeMillis();
doHighlighting();
long end = System.currentTimeMillis();
time[i] = end - start;
System.out.println("i = " + i + "; time= "+(end-start));
UIUtil.dispatchAllInvocationEvents();
}
System.out.println("Average among the N/3 median times: " + PlatformTestUtil.averageAmongMedians(time, 3) + "ms");
//System.out.println("JobLauncher.COUNT = " + JobLauncher.COUNT);
//System.out.println("JobLauncher.TINY = " + JobLauncher.TINY_COUNT);
//System.out.println("JobLauncher.LENGTH = " + JobLauncher.LENGTH);
//System.out.println("JobLauncher.ELAPSED = " + JobLauncher.ELAPSED);
//System.out.println("Ave length : "+(JobLauncher.LENGTH.get()/1.0/JobLauncher.COUNT.get()));
//System.out.println("Ave elapsed: "+(JobLauncher.ELAPSED.get()/1.0/JobLauncher.COUNT.get()));
//
//JobLauncher.lengths.sort();
//System.out.println("Lengths: "+JobLauncher.lengths);
}
public void testRandomEditingPerformance() throws Exception {
configureFromFileText("Stress.java", text);
List<HighlightInfo> list = doHighlighting();
int warnings = list.size();
Random random = new Random();
DaemonCodeAnalyzer.getInstance(getProject()).restart();
int N = 20;
long[] time = new long[N];
for (int i = 0; i < N; i++) {
long start = System.currentTimeMillis();
System.out.println("i = " + i);
String s = myFile.getText();
int offset;
while (true) {
offset = random.nextInt(s.length());
if (s.charAt(offset) == ' ') break;
}
myEditor.getCaretModel().moveToOffset(offset);
type("/*--*/");
Collection<HighlightInfo> infos = doHighlighting();
if (warnings != infos.size()) {
list = new ArrayList<HighlightInfo>(list);
Collections.sort(list, new Comparator<HighlightInfo>() {
@Override
public int compare(HighlightInfo o1, HighlightInfo o2) {
if (o1.equals(o2)) return 0;
if (o1.getActualStartOffset() != o2.getActualStartOffset()) return o1.getActualStartOffset() - o2.getActualStartOffset();
return (o1.getText() + o1.getDescription()).compareTo(o2.getText() + o2.getDescription());
}
});
infos = new ArrayList<HighlightInfo>(infos);
Collections.sort((ArrayList<HighlightInfo>)infos, new Comparator<HighlightInfo>() {
@Override
public int compare(HighlightInfo o1, HighlightInfo o2) {
if (o1.equals(o2)) return 0;
if (o1.getActualStartOffset() != o2.getActualStartOffset()) return o1.getActualStartOffset() - o2.getActualStartOffset();
return (o1.getText() + o1.getDescription()).compareTo(o2.getText() + o2.getDescription());
}
});
System.out.println(">--------------------");
for (HighlightInfo info : list) {
System.out.println(info);
}
System.out.println("---------------------");
for (HighlightInfo info : infos) {
System.out.println(info);
}
System.out.println("<--------------------");
}
assertEquals(infos.toString(), warnings, infos.size());
for (HighlightInfo info : infos) {
assertNotSame(info + "", HighlightSeverity.ERROR, info.getSeverity());
}
UIUtil.dispatchAllInvocationEvents();
long end = System.currentTimeMillis();
time[i] = end - start;
}
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
System.out.println("Average among the N/3 median times: " + PlatformTestUtil.averageAmongMedians(time, 3) + "ms");
}
public void testRandomEditingForUnused() throws Exception {
configureFromFileText("Stress.java", "class X {<caret>}");
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(getProject());
String[] names = cache.getAllClassNames();
final StringBuilder imports = new StringBuilder();
final StringBuilder usages = new StringBuilder();
int v = 0;
List<PsiClass> aclasses = new ArrayList<PsiClass>();
for (String name : names) {
PsiClass[] classes = cache.getClassesByName(name, GlobalSearchScope.allScope(getProject()));
if (classes.length == 0) continue;
PsiClass aClass = classes[0];
if (!aClass.hasModifierProperty(PsiModifier.PUBLIC)) continue;
if (aClass.getSuperClass() == null) continue;
PsiClassType[] superTypes = aClass.getSuperTypes();
if (superTypes.length == 0 || superTypes[0].resolve() == null) continue;
String qualifiedName = aClass.getQualifiedName();
if (qualifiedName.startsWith("java.lang.invoke")) continue; // java.lang.invoke.MethodHandle has weird access attributes in recent rt.jar which causes spurious highlighting errors
imports.append("import " + qualifiedName + ";\n");
usages.append("/**/ "+aClass.getName() + " var" + v + " = null; var" + v + ".toString();\n");
aclasses.add(aClass);
v++;
if (v>100) break;
}
final String text = imports + "\n class X {{\n" + usages + "}}";
WriteCommandAction.runWriteCommandAction(null, new Runnable() {
@Override
public void run() {
getEditor().getDocument().setText(text);
}
});
List<HighlightInfo> errors = DaemonAnalyzerTestCase.filter(doHighlighting(), HighlightSeverity.WARNING);
assertEmpty(errors);
Random random = new Random();
int unused = 0;
for (int i = 0; i < 100; i++) {
String s = myFile.getText();
int offset;
while (true) {
offset = random.nextInt(s.length());
if (CharArrayUtil.regionMatches(s, offset, "/**/") || CharArrayUtil.regionMatches(s, offset, "//")) break;
}
char next = offset < s.length()-1 ? s.charAt(offset+1) : 0;
if (next == '/') {
myEditor.getCaretModel().moveToOffset(offset + 1);
type("**");
unused--;
}
else if (next == '*') {
myEditor.getCaretModel().moveToOffset(offset + 1);
delete();
delete();
unused++;
}
else {
continue;
}
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
getFile().accept(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(PsiElement element) {
assertTrue(element.toString(), element.isValid());
super.visitElement(element);
}
});
System.out.println("i = " + i + " " + next + " at "+offset);
List<HighlightInfo> infos = doHighlighting();
errors = DaemonAnalyzerTestCase.filter(infos, HighlightSeverity.ERROR);
assertEmpty(errors);
List<HighlightInfo> warns = DaemonAnalyzerTestCase.filter(infos, HighlightSeverity.WARNING);
if (unused != warns.size()) {
assertEquals(warns.toString(), unused, warns.size());
}
}
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
}
}