Merge remote-tracking branch 'origin/master'

This commit is contained in:
Yann Cébron
2016-10-19 15:26:37 +02:00
8 changed files with 137 additions and 106 deletions
+1
View File
@@ -16,5 +16,6 @@
<orderEntry type="module" module-name="platform-resources-en" exported="" />
<orderEntry type="library" name="automaton" level="project" />
<orderEntry type="library" name="CGLIB" level="project" />
<orderEntry type="library" name="ASM" level="project" />
</component>
</module>
@@ -15,14 +15,13 @@
*/
package com.intellij.util;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.util.Condition;
import com.intellij.util.containers.ConcurrentFactoryMap;
import net.sf.cglib.asm.$ClassVisitor;
import net.sf.cglib.asm.$Label;
import net.sf.cglib.asm.$Type;
import net.sf.cglib.core.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.ClassWriter;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import java.lang.reflect.Modifier;
@@ -33,13 +32,6 @@ public class InstanceofCheckerGenerator {
private static final InstanceofCheckerGenerator ourInstance;
static {
try {
ClassGenerator.class.getDeclaredMethod("generateClass", $ClassVisitor.class);
}
catch (NoSuchMethodException e) {
throw new IllegalStateException("Incorrect cglib version in the classpath, source=" + PathManager.getJarPathForClass(ClassGenerator.class));
}
try {
ourInstance = new InstanceofCheckerGenerator();
}
@@ -52,6 +44,7 @@ public class InstanceofCheckerGenerator {
return ourInstance;
}
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final ConcurrentFactoryMap<Class, Condition<Object>> myCache = new ConcurrentFactoryMap<Class, Condition<Object>>() {
@Override
protected Condition<Object> create(final Class key) {
@@ -64,76 +57,73 @@ public class InstanceofCheckerGenerator {
};
}
return new InstanceofClassGenerator(key).createClass();
String name = "com.intellij.util.InstanceofChecker$$$$$" + key.getName().replace('.', '$');
//noinspection unchecked
return (Condition<Object>)ReflectionUtil.newInstance(obtainClass(key, name, generateConditionClass(key, name)));
}
};
private synchronized Class obtainClass(Class checkedClass, String name, byte[] bytes) {
ClassLoader loader = checkedClass.getClassLoader();
if (loader == null) loader = InstanceofCheckerGenerator.class.getClassLoader();
try {
return loader.loadClass(name);
}
catch (ClassNotFoundException ignore) {
}
try {
return ReflectionUtil.defineClass(name, bytes, loader);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@NotNull
public Condition<Object> getInstanceofChecker(final Class<?> someClass) {
return myCache.get(someClass);
}
private static String toInternalName(Class<?> someClass) {
return someClass.getName().replace('.', '/');
return toInternalName(someClass.getName());
}
private static class InstanceofClassGenerator extends AbstractClassGenerator {
private static final Source SOURCE = new Source("IntellijInstanceof");
private final Class<?> myCheckedClass;
public InstanceofClassGenerator(Class<?> checkedClass) {
super(SOURCE);
myCheckedClass = checkedClass;
}
@Override
protected ClassLoader getDefaultClassLoader() {
return myCheckedClass.getClassLoader();
}
public Condition<Object> createClass() {
return (Condition<Object>)super.create(myCheckedClass);
}
@Override
protected Object firstInstance(Class type) throws Exception {
return type.newInstance();
}
@Override
protected Object nextInstance(Object instance) throws Exception {
return instance;
}
@Override
public void generateClass($ClassVisitor classVisitor) throws Exception {
ClassEmitter cv = new ClassEmitter(classVisitor);
cv.visit(Constants.V1_2, Modifier.PUBLIC, "com/intellij/util/InstanceofChecker$$$$$" + myCheckedClass.getName().replace('.', '$'), null, toInternalName(Object.class), new String[]{toInternalName(Condition.class)});
cv.visitSource(Constants.SOURCE_FILE, null);
final Signature signature = new Signature("<init>", "()V");
final CodeEmitter cons = cv.begin_method(Modifier.PUBLIC, signature, new $Type[0]);
cons.load_this();
cons.dup();
cons.super_invoke_constructor(signature);
cons.return_value();
cons.end_method();
final CodeEmitter e = cv.begin_method(Modifier.PUBLIC, new Signature("value", "(L" + toInternalName(Object.class) + ";)Z"), new $Type[0]);
e.load_arg(0);
e.instance_of($Type.getType(myCheckedClass));
$Label fail = e.make_label();
e.if_jump(CodeEmitter.EQ, fail);
e.push(true);
e.return_value();
e.mark(fail);
e.push(false);
e.return_value();
e.end_method();
cv.visitEnd();
}
@NotNull
private static String toInternalName(String name) {
return name.replace('.', '/');
}
private static byte[] generateConditionClass(Class<?> checkedClass, final String generatedName) {
ClassWriter cv = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cv.visit(Opcodes.V1_2, Modifier.PUBLIC, toInternalName(generatedName), null, toInternalName(Object.class), new String[]{toInternalName(Condition.class)});
defaultConstructor(cv);
conditionValue(checkedClass, cv);
cv.visitEnd();
return cv.toByteArray();
}
private static void defaultConstructor(ClassWriter cv) {
MethodVisitor mv = cv.visitMethod(Modifier.PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, toInternalName(Object.class), "<init>", "()V", false);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private static void conditionValue(Class<?> checkedClass, ClassWriter cv) {
MethodVisitor mv = cv.visitMethod(Modifier.PUBLIC, "value", "(L" + toInternalName(Object.class) + ";)Z", null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitTypeInsn(Opcodes.INSTANCEOF, Type.getType(checkedClass).getInternalName());
mv.visitInsn(Opcodes.IRETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
@@ -292,8 +292,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
public void commitDocument(@NotNull final Document doc) {
final Document document = doc instanceof DocumentWindow ? ((DocumentWindow)doc).getDelegate() : doc;
VirtualFile vFile = getVirtualFile(document);
if (vFile != null && !isFreeThreaded(vFile)) {
if (isEventSystemEnabled(document)) {
((TransactionGuardImpl)TransactionGuard.getInstance()).assertWriteActionAllowed();
}
@@ -302,6 +301,14 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
}
}
private boolean isEventSystemEnabled(Document document) {
VirtualFile vFile = getVirtualFile(document);
if (vFile == null || isFreeThreaded(vFile)) return false;
FileViewProvider viewProvider = getCachedViewProvider(document);
return viewProvider != null && viewProvider.isEventSystemEnabled();
}
// public for Upsource
public boolean finishCommit(@NotNull final Document document,
@NotNull final List<Processor<Document>> finishProcessors,
@@ -435,9 +435,9 @@ public abstract class ChooseByNameBase {
group.add(new ShowFindUsagesAction() {
@Override
public PsiElement[][] getElements() {
final Object[] objects = myListModel.toArray();
final List<PsiElement> prefixMatchElements = new ArrayList<>(objects.length);
final List<PsiElement> nonPrefixMatchElements = new ArrayList<>(objects.length);
final List<Object> objects = myListModel.getItems();
final List<PsiElement> prefixMatchElements = new ArrayList<>(objects.size());
final List<PsiElement> nonPrefixMatchElements = new ArrayList<>(objects.size());
List<PsiElement> curElements = prefixMatchElements;
for (Object object : objects) {
if (object instanceof PsiElement) {
@@ -782,7 +782,7 @@ public abstract class ChooseByNameBase {
close(ok);
clearPostponedOkAction(ok);
myListModel.clear();
myListModel.removeAll();
}
protected boolean closeForbidden(boolean ok) {
@@ -973,7 +973,7 @@ public abstract class ChooseByNameBase {
final String text = getTrimmedText();
if (!canShowListForEmptyPattern() && text.isEmpty()) {
myListModel.clear();
myListModel.removeAll();
hideList();
myTextFieldPanel.hideHint();
myCard.show(myCardContainer, CHECK_BOX_CARD);
@@ -1033,7 +1033,7 @@ public abstract class ChooseByNameBase {
}
}
if (elements.isEmpty()) {
myListModel.clear();
myListModel.removeAll();
myTextField.setForeground(JBColor.red);
myListUpdater.cancelAll();
hideList();
@@ -1041,7 +1041,7 @@ public abstract class ChooseByNameBase {
return;
}
Object[] oldElements = myListModel.toArray();
Object[] oldElements = myListModel.getItems().toArray();
Object[] newElements = elements.toArray();
List<ModelDiff.Cmd> commands = ModelDiff.createDiffCmds(myListModel, oldElements, newElements);
if (commands == null) {
@@ -1055,7 +1055,7 @@ public abstract class ChooseByNameBase {
pos = calcSelectedIndex(newElements, getTrimmedText());
}
ScrollingUtil.selectItem(myList, Math.min(pos, myListModel.size() - 1));
ScrollingUtil.selectItem(myList, Math.min(pos, myListModel.getSize() - 1));
myList.setVisibleRowCount(Math.min(VISIBLE_LIST_SIZE_LIMIT, myList.getModel().getSize()));
showList();
myTextFieldPanel.repositionHint();
@@ -1113,21 +1113,21 @@ public abstract class ChooseByNameBase {
return "choose_by_name#" + myModel.getPromptText() + "#" + myCheckBox.isSelected() + "#" + getTrimmedText();
}
private static class MyListModel<T> extends DefaultListModel implements ModelDiff.Model<T> {
private static class MyListModel<T> extends CollectionListModel<T> implements ModelDiff.Model<T> {
@Override
public void addToModel(int idx, T element) {
if (idx < size()) {
add(idx, element);
}
else {
addElement(element);
}
add(Math.min(idx, getSize()), element);
}
@Override
public void addAllToModel(int index, List<T> elements) {
addAll(Math.min(index, getSize()), elements);
}
@Override
public void removeRangeFromModel(int start, int end) {
if (start < size() && size() != 0) {
removeRange(start, Math.min(end, size()-1));
if (start < getSize() && !isEmpty()) {
removeRange(start, Math.min(end, getSize() - 1));
}
}
}
@@ -1175,8 +1175,8 @@ public abstract class ChooseByNameBase {
myTextFieldPanel.repositionHint();
if (!myListModel.isEmpty()) {
int pos = selectionPos <= 0 ? calcSelectedIndex(myListModel.toArray(), ChooseByNameBase.this.getTrimmedText()) : selectionPos;
ScrollingUtil.selectItem(myList, Math.min(pos, myListModel.size() - 1));
int pos = selectionPos <= 0 ? calcSelectedIndex(myListModel.getItems().toArray(), ChooseByNameBase.this.getTrimmedText()) : selectionPos;
ScrollingUtil.selectItem(myList, Math.min(pos, myListModel.getSize() - 1));
}
}
}
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class ModelDiff {
@@ -48,9 +49,8 @@ public class ModelDiff {
}
if (change.inserted > 0) {
for (int i = 0; i < change.inserted; i++) {
commands.add(new InsertCmd<>(listModel, change.line0 + i + inserted - deleted, newElements[change.line1 + i]));
}
List<Object> elements = new ArrayList<>(Arrays.asList(newElements).subList(change.line1, change.line1 + change.inserted));
commands.add(new InsertCmd<>(listModel, change.line0 + inserted - deleted, elements));
}
deleted += change.deleted;
@@ -67,6 +67,13 @@ public class ModelDiff {
public interface Model<T> {
void addToModel(int index, T element);
default void addAllToModel(int index, List<T> elements) {
for (int i = 0; i < elements.size(); i++) {
addToModel(index + i, elements.get(i));
}
}
void removeRangeFromModel(int start, int end);
}
@@ -102,18 +109,18 @@ public class ModelDiff {
private static class InsertCmd<T> implements Cmd {
private final Model<T> myListModel;
private final int idx;
private final T element;
private final List<T> elements;
private InsertCmd(@NotNull Model<T> model, final int idx, @NotNull T element) {
private InsertCmd(@NotNull Model<T> model, final int idx, @NotNull List<T> elements) {
myListModel = model;
this.idx = idx;
this.element = element;
this.elements = elements;
}
@Override
public void apply() {
//System.out.println("Adding: "+this+"-> "+element);
myListModel.addToModel(idx, element);
myListModel.addAllToModel(idx, elements);
}
@Override
@@ -66,7 +66,4 @@ public class CollectionComboBoxModel<T> extends CollectionListModel<T> implement
super.fireContentsChanged(this, -1, -1);
}
public boolean contains(T item) {
return getElementIndex(item) != -1;
}
}
@@ -75,10 +75,14 @@ public class CollectionListModel<T> extends AbstractListModel<T> implements Edit
}
public void add(@NotNull final List<? extends T> elements) {
addAll(myItems.size(), elements);
}
public void addAll(int index, @NotNull final List<? extends T> elements) {
if (elements.isEmpty()) return;
int i = myItems.size();
myItems.addAll(elements);
fireIntervalAdded(this, i, i + elements.size() - 1);
myItems.addAll(index, elements);
fireIntervalAdded(this, index, index + elements.size() - 1);
}
public void remove(@NotNull T element) {
@@ -167,4 +171,19 @@ public class CollectionListModel<T> extends AbstractListModel<T> implements Edit
public boolean isEmpty() {
return myItems.isEmpty();
}
public boolean contains(T item) {
return getElementIndex(item) >= 0;
}
public void removeRange(int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException("fromIndex must be <= toIndex");
}
for(int i = toIndex; i >= fromIndex; i--) {
itemReplaced(myItems.remove(i), null);
}
fireIntervalRemoved(this, fromIndex, toIndex);
}
}
@@ -592,4 +592,14 @@ public class ReflectionUtil {
return JBIterable.of(aClass.getSuperclass()).append(aClass.getInterfaces());
}
};
private static final Method DEFINE_CLASS =
ObjectUtils.assertNotNull(getDeclaredMethod(ClassLoader.class, "defineClass", String.class, byte[].class, int.class, int.class));
public static Class defineClass(@NotNull String className, @NotNull byte[] bytes, ClassLoader loader) throws Exception {
Class c = (Class)DEFINE_CLASS.invoke(loader, className, bytes, 0, bytes.length);
Class.forName(className, true, loader);
return c;
}
}